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.va + 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.va + 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 omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
247 CLKCTRL_IDLEST_DISABLED),
248 MAX_MODULE_READY_TIME, i);
249
250 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
251}
252
253
254
255
256
257
258
259
260
261
262static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
263 u16 clkctrl_offs)
264{
265 u32 v;
266
267 v = am33xx_cm_read_reg(inst, clkctrl_offs);
268 v &= ~AM33XX_MODULEMODE_MASK;
269 v |= mode << AM33XX_MODULEMODE_SHIFT;
270 am33xx_cm_write_reg(v, inst, clkctrl_offs);
271}
272
273
274
275
276
277
278
279
280
281static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
282{
283 u32 v;
284
285 v = am33xx_cm_read_reg(inst, clkctrl_offs);
286 v &= ~AM33XX_MODULEMODE_MASK;
287 am33xx_cm_write_reg(v, inst, clkctrl_offs);
288}
289
290
291
292
293
294static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
295{
296 am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
297 return 0;
298}
299
300static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
301{
302 am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
303 return 0;
304}
305
306static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
307{
308 am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
309}
310
311static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
312{
313 am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
314}
315
316static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
317{
318 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
319 return am33xx_clkdm_wakeup(clkdm);
320
321 return 0;
322}
323
324static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
325{
326 bool hwsup = false;
327
328 hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
329
330 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
331 am33xx_clkdm_sleep(clkdm);
332
333 return 0;
334}
335
336struct clkdm_ops am33xx_clkdm_operations = {
337 .clkdm_sleep = am33xx_clkdm_sleep,
338 .clkdm_wakeup = am33xx_clkdm_wakeup,
339 .clkdm_allow_idle = am33xx_clkdm_allow_idle,
340 .clkdm_deny_idle = am33xx_clkdm_deny_idle,
341 .clkdm_clk_enable = am33xx_clkdm_clk_enable,
342 .clkdm_clk_disable = am33xx_clkdm_clk_disable,
343};
344
345static struct cm_ll_data am33xx_cm_ll_data = {
346 .wait_module_ready = &am33xx_cm_wait_module_ready,
347 .wait_module_idle = &am33xx_cm_wait_module_idle,
348 .module_enable = &am33xx_cm_module_enable,
349 .module_disable = &am33xx_cm_module_disable,
350};
351
352int __init am33xx_cm_init(const struct omap_prcm_init_data *data)
353{
354 return cm_register(&am33xx_cm_ll_data);
355}
356
357static void __exit am33xx_cm_exit(void)
358{
359 cm_unregister(&am33xx_cm_ll_data);
360}
361__exitcall(am33xx_cm_exit);
362