1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/kernel.h>
20#include <linux/types.h>
21#include <linux/errno.h>
22#include <linux/err.h>
23#include <linux/io.h>
24
25#include "clockdomain.h"
26#include "cm.h"
27#include "cm33xx.h"
28#include "cm-regbits-34xx.h"
29#include "cm-regbits-33xx.h"
30#include "prm33xx.h"
31
32
33
34
35
36
37
38
39
40
41
42
43#define CLKCTRL_IDLEST_FUNCTIONAL 0x0
44#define CLKCTRL_IDLEST_INTRANSITION 0x1
45#define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
46#define CLKCTRL_IDLEST_DISABLED 0x3
47
48
49
50
51static inline u32 am33xx_cm_read_reg(u16 inst, u16 idx)
52{
53 return readl_relaxed(cm_base + inst + idx);
54}
55
56
57static inline void am33xx_cm_write_reg(u32 val, u16 inst, u16 idx)
58{
59 writel_relaxed(val, cm_base + inst + idx);
60}
61
62
63static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
64{
65 u32 v;
66
67 v = am33xx_cm_read_reg(inst, idx);
68 v &= ~mask;
69 v |= bits;
70 am33xx_cm_write_reg(v, inst, idx);
71
72 return v;
73}
74
75
76
77
78
79
80
81
82
83static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs)
84{
85 u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
86 v &= AM33XX_IDLEST_MASK;
87 v >>= AM33XX_IDLEST_SHIFT;
88 return v;
89}
90
91
92
93
94
95
96
97
98
99static bool _is_module_ready(u16 inst, u16 clkctrl_offs)
100{
101 u32 v;
102
103 v = _clkctrl_idlest(inst, clkctrl_offs);
104
105 return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
106 v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
107}
108
109
110
111
112
113
114
115
116
117
118static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs)
119{
120 u32 v;
121
122 v = am33xx_cm_read_reg(inst, cdoffs);
123 v &= ~AM33XX_CLKTRCTRL_MASK;
124 v |= c << AM33XX_CLKTRCTRL_SHIFT;
125 am33xx_cm_write_reg(v, inst, cdoffs);
126}
127
128
129
130
131
132
133
134
135
136
137
138static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
139{
140 u32 v;
141
142 v = am33xx_cm_read_reg(inst, cdoffs);
143 v &= AM33XX_CLKTRCTRL_MASK;
144 v >>= AM33XX_CLKTRCTRL_SHIFT;
145
146 return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
147}
148
149
150
151
152
153
154
155
156
157static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
158{
159 _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
160}
161
162
163
164
165
166
167
168
169
170
171static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
172{
173 _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
174}
175
176
177
178
179
180
181
182
183
184static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
185{
186 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
187}
188
189
190
191
192
193
194
195
196
197static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
198{
199 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
200}
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
219 u8 bit_shift)
220{
221 int i = 0;
222
223 omap_test_timeout(_is_module_ready(inst, clkctrl_offs),
224 MAX_MODULE_READY_TIME, i);
225
226 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
227}
228
229
230
231
232
233
234
235
236
237
238
239
240
241static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
242 u8 bit_shift)
243{
244 int i = 0;
245
246 if (!clkctrl_offs)
247 return 0;
248
249 omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
250 CLKCTRL_IDLEST_DISABLED),
251 MAX_MODULE_READY_TIME, i);
252
253 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
254}
255
256
257
258
259
260
261
262
263
264
265static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
266 u16 clkctrl_offs)
267{
268 u32 v;
269
270 v = am33xx_cm_read_reg(inst, clkctrl_offs);
271 v &= ~AM33XX_MODULEMODE_MASK;
272 v |= mode << AM33XX_MODULEMODE_SHIFT;
273 am33xx_cm_write_reg(v, inst, clkctrl_offs);
274}
275
276
277
278
279
280
281
282
283
284static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
285{
286 u32 v;
287
288 v = am33xx_cm_read_reg(inst, clkctrl_offs);
289 v &= ~AM33XX_MODULEMODE_MASK;
290 am33xx_cm_write_reg(v, inst, clkctrl_offs);
291}
292
293
294
295
296
297static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
298{
299 am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
300 return 0;
301}
302
303static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
304{
305 am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
306 return 0;
307}
308
309static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
310{
311 am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
312}
313
314static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
315{
316 am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
317}
318
319static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
320{
321 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
322 return am33xx_clkdm_wakeup(clkdm);
323
324 return 0;
325}
326
327static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
328{
329 bool hwsup = false;
330
331 hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
332
333 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
334 am33xx_clkdm_sleep(clkdm);
335
336 return 0;
337}
338
339struct clkdm_ops am33xx_clkdm_operations = {
340 .clkdm_sleep = am33xx_clkdm_sleep,
341 .clkdm_wakeup = am33xx_clkdm_wakeup,
342 .clkdm_allow_idle = am33xx_clkdm_allow_idle,
343 .clkdm_deny_idle = am33xx_clkdm_deny_idle,
344 .clkdm_clk_enable = am33xx_clkdm_clk_enable,
345 .clkdm_clk_disable = am33xx_clkdm_clk_disable,
346};
347
348static struct cm_ll_data am33xx_cm_ll_data = {
349 .wait_module_ready = &am33xx_cm_wait_module_ready,
350 .wait_module_idle = &am33xx_cm_wait_module_idle,
351 .module_enable = &am33xx_cm_module_enable,
352 .module_disable = &am33xx_cm_module_disable,
353};
354
355int __init am33xx_cm_init(const struct omap_prcm_init_data *data)
356{
357 return cm_register(&am33xx_cm_ll_data);
358}
359
360static void __exit am33xx_cm_exit(void)
361{
362 cm_unregister(&am33xx_cm_ll_data);
363}
364__exitcall(am33xx_cm_exit);
365