1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "hw/hw.h"
21#include "qemu/timer.h"
22#include "hw/arm/omap.h"
23
24
25struct omap_gp_timer_s {
26 MemoryRegion iomem;
27 qemu_irq irq;
28 qemu_irq wkup;
29 qemu_irq in;
30 qemu_irq out;
31 omap_clk clk;
32 QEMUTimer *timer;
33 QEMUTimer *match;
34 struct omap_target_agent_s *ta;
35
36 int in_val;
37 int out_val;
38 int64_t time;
39 int64_t rate;
40 int64_t ticks_per_sec;
41
42 int16_t config;
43 int status;
44 int it_ena;
45 int wu_ena;
46 int enable;
47 int inout;
48 int capt2;
49 int pt;
50 enum {
51 gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
52 } trigger;
53 enum {
54 gpt_capture_none, gpt_capture_rising,
55 gpt_capture_falling, gpt_capture_both
56 } capture;
57 int scpwm;
58 int ce;
59 int pre;
60 int ptv;
61 int ar;
62 int st;
63 int posted;
64 uint32_t val;
65 uint32_t load_val;
66 uint32_t capture_val[2];
67 uint32_t match_val;
68 int capt_num;
69
70 uint16_t writeh;
71 uint16_t readh;
72};
73
74#define GPT_TCAR_IT (1 << 2)
75#define GPT_OVF_IT (1 << 1)
76#define GPT_MAT_IT (1 << 0)
77
78static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
79{
80 if (timer->it_ena & it) {
81 if (!timer->status)
82 qemu_irq_raise(timer->irq);
83
84 timer->status |= it;
85
86
87 }
88
89 if (timer->wu_ena & it)
90 qemu_irq_pulse(timer->wkup);
91}
92
93static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
94{
95 if (!timer->inout && timer->out_val != level) {
96 timer->out_val = level;
97 qemu_set_irq(timer->out, level);
98 }
99}
100
101static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
102{
103 uint64_t distance;
104
105 if (timer->st && timer->rate) {
106 distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time;
107 distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
108
109 if (distance >= 0xffffffff - timer->val)
110 return 0xffffffff;
111 else
112 return timer->val + distance;
113 } else
114 return timer->val;
115}
116
117static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
118{
119 if (timer->st) {
120 timer->val = omap_gp_timer_read(timer);
121 timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
122 }
123}
124
125static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
126{
127 int64_t expires, matches;
128
129 if (timer->st && timer->rate) {
130 expires = muldiv64(0x100000000ll - timer->val,
131 timer->ticks_per_sec, timer->rate);
132 timer_mod(timer->timer, timer->time + expires);
133
134 if (timer->ce && timer->match_val >= timer->val) {
135 matches = muldiv64(timer->match_val - timer->val,
136 timer->ticks_per_sec, timer->rate);
137 timer_mod(timer->match, timer->time + matches);
138 } else
139 timer_del(timer->match);
140 } else {
141 timer_del(timer->timer);
142 timer_del(timer->match);
143 omap_gp_timer_out(timer, timer->scpwm);
144 }
145}
146
147static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
148{
149 if (timer->pt)
150
151
152 omap_gp_timer_out(timer, !timer->out_val);
153 else
154
155 qemu_irq_pulse(timer->out);
156}
157
158static void omap_gp_timer_tick(void *opaque)
159{
160 struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
161
162 if (!timer->ar) {
163 timer->st = 0;
164 timer->val = 0;
165 } else {
166 timer->val = timer->load_val;
167 timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
168 }
169
170 if (timer->trigger == gpt_trigger_overflow ||
171 timer->trigger == gpt_trigger_both)
172 omap_gp_timer_trigger(timer);
173
174 omap_gp_timer_intr(timer, GPT_OVF_IT);
175 omap_gp_timer_update(timer);
176}
177
178static void omap_gp_timer_match(void *opaque)
179{
180 struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
181
182 if (timer->trigger == gpt_trigger_both)
183 omap_gp_timer_trigger(timer);
184
185 omap_gp_timer_intr(timer, GPT_MAT_IT);
186}
187
188static void omap_gp_timer_input(void *opaque, int line, int on)
189{
190 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
191 int trigger;
192
193 switch (s->capture) {
194 default:
195 case gpt_capture_none:
196 trigger = 0;
197 break;
198 case gpt_capture_rising:
199 trigger = !s->in_val && on;
200 break;
201 case gpt_capture_falling:
202 trigger = s->in_val && !on;
203 break;
204 case gpt_capture_both:
205 trigger = (s->in_val == !on);
206 break;
207 }
208 s->in_val = on;
209
210 if (s->inout && trigger && s->capt_num < 2) {
211 s->capture_val[s->capt_num] = omap_gp_timer_read(s);
212
213 if (s->capt2 == s->capt_num ++)
214 omap_gp_timer_intr(s, GPT_TCAR_IT);
215 }
216}
217
218static void omap_gp_timer_clk_update(void *opaque, int line, int on)
219{
220 struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
221
222 omap_gp_timer_sync(timer);
223 timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
224 omap_gp_timer_update(timer);
225}
226
227static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
228{
229 omap_clk_adduser(timer->clk,
230 qemu_allocate_irq(omap_gp_timer_clk_update, timer, 0));
231 timer->rate = omap_clk_getrate(timer->clk);
232}
233
234void omap_gp_timer_reset(struct omap_gp_timer_s *s)
235{
236 s->config = 0x000;
237 s->status = 0;
238 s->it_ena = 0;
239 s->wu_ena = 0;
240 s->inout = 0;
241 s->capt2 = 0;
242 s->capt_num = 0;
243 s->pt = 0;
244 s->trigger = gpt_trigger_none;
245 s->capture = gpt_capture_none;
246 s->scpwm = 0;
247 s->ce = 0;
248 s->pre = 0;
249 s->ptv = 0;
250 s->ar = 0;
251 s->st = 0;
252 s->posted = 1;
253 s->val = 0x00000000;
254 s->load_val = 0x00000000;
255 s->capture_val[0] = 0x00000000;
256 s->capture_val[1] = 0x00000000;
257 s->match_val = 0x00000000;
258 omap_gp_timer_update(s);
259}
260
261static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
262{
263 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
264
265 switch (addr) {
266 case 0x00:
267 return 0x21;
268
269 case 0x10:
270 return s->config;
271
272 case 0x14:
273
274 return 1;
275
276 case 0x18:
277 return s->status;
278
279 case 0x1c:
280 return s->it_ena;
281
282 case 0x20:
283 return s->wu_ena;
284
285 case 0x24:
286 return (s->inout << 14) |
287 (s->capt2 << 13) |
288 (s->pt << 12) |
289 (s->trigger << 10) |
290 (s->capture << 8) |
291 (s->scpwm << 7) |
292 (s->ce << 6) |
293 (s->pre << 5) |
294 (s->ptv << 2) |
295 (s->ar << 1) |
296 (s->st << 0);
297
298 case 0x28:
299 return omap_gp_timer_read(s);
300
301 case 0x2c:
302 return s->load_val;
303
304 case 0x30:
305 return 0xffffffff;
306
307 case 0x34:
308 return 0x00000000;
309
310 case 0x38:
311 return s->match_val;
312
313 case 0x3c:
314 return s->capture_val[0];
315
316 case 0x40:
317 return s->posted << 2;
318
319 case 0x44:
320 return s->capture_val[1];
321 }
322
323 OMAP_BAD_REG(addr);
324 return 0;
325}
326
327static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
328{
329 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
330 uint32_t ret;
331
332 if (addr & 2)
333 return s->readh;
334 else {
335 ret = omap_gp_timer_readw(opaque, addr);
336 s->readh = ret >> 16;
337 return ret & 0xffff;
338 }
339}
340
341static void omap_gp_timer_write(void *opaque, hwaddr addr,
342 uint32_t value)
343{
344 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
345
346 switch (addr) {
347 case 0x00:
348 case 0x14:
349 case 0x34:
350 case 0x3c:
351 case 0x44:
352 OMAP_RO_REG(addr);
353 break;
354
355 case 0x10:
356 s->config = value & 0x33d;
357 if (((value >> 3) & 3) == 3)
358 fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
359 __FUNCTION__);
360 if (value & 2)
361 omap_gp_timer_reset(s);
362 break;
363
364 case 0x18:
365 if (value & GPT_TCAR_IT)
366 s->capt_num = 0;
367 if (s->status && !(s->status &= ~value))
368 qemu_irq_lower(s->irq);
369 break;
370
371 case 0x1c:
372 s->it_ena = value & 7;
373 break;
374
375 case 0x20:
376 s->wu_ena = value & 7;
377 break;
378
379 case 0x24:
380 omap_gp_timer_sync(s);
381 s->inout = (value >> 14) & 1;
382 s->capt2 = (value >> 13) & 1;
383 s->pt = (value >> 12) & 1;
384 s->trigger = (value >> 10) & 3;
385 if (s->capture == gpt_capture_none &&
386 ((value >> 8) & 3) != gpt_capture_none)
387 s->capt_num = 0;
388 s->capture = (value >> 8) & 3;
389 s->scpwm = (value >> 7) & 1;
390 s->ce = (value >> 6) & 1;
391 s->pre = (value >> 5) & 1;
392 s->ptv = (value >> 2) & 7;
393 s->ar = (value >> 1) & 1;
394 s->st = (value >> 0) & 1;
395 if (s->inout && s->trigger != gpt_trigger_none)
396 fprintf(stderr, "%s: GP timer pin must be an output "
397 "for this trigger mode\n", __FUNCTION__);
398 if (!s->inout && s->capture != gpt_capture_none)
399 fprintf(stderr, "%s: GP timer pin must be an input "
400 "for this capture mode\n", __FUNCTION__);
401 if (s->trigger == gpt_trigger_none)
402 omap_gp_timer_out(s, s->scpwm);
403
404 s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0);
405 omap_gp_timer_update(s);
406 break;
407
408 case 0x28:
409 s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
410 s->val = value;
411 omap_gp_timer_update(s);
412 break;
413
414 case 0x2c:
415 s->load_val = value;
416 break;
417
418 case 0x30:
419 s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
420 s->val = s->load_val;
421 omap_gp_timer_update(s);
422 break;
423
424 case 0x38:
425 omap_gp_timer_sync(s);
426 s->match_val = value;
427 omap_gp_timer_update(s);
428 break;
429
430 case 0x40:
431 s->posted = (value >> 2) & 1;
432 if (value & 2)
433 omap_gp_timer_reset(s);
434 break;
435
436 default:
437 OMAP_BAD_REG(addr);
438 }
439}
440
441static void omap_gp_timer_writeh(void *opaque, hwaddr addr,
442 uint32_t value)
443{
444 struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
445
446 if (addr & 2)
447 omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
448 else
449 s->writeh = (uint16_t) value;
450}
451
452static const MemoryRegionOps omap_gp_timer_ops = {
453 .old_mmio = {
454 .read = {
455 omap_badwidth_read32,
456 omap_gp_timer_readh,
457 omap_gp_timer_readw,
458 },
459 .write = {
460 omap_badwidth_write32,
461 omap_gp_timer_writeh,
462 omap_gp_timer_write,
463 },
464 },
465 .endianness = DEVICE_NATIVE_ENDIAN,
466};
467
468struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
469 qemu_irq irq, omap_clk fclk, omap_clk iclk)
470{
471 struct omap_gp_timer_s *s = g_new0(struct omap_gp_timer_s, 1);
472
473 s->ta = ta;
474 s->irq = irq;
475 s->clk = fclk;
476 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s);
477 s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s);
478 s->in = qemu_allocate_irq(omap_gp_timer_input, s, 0);
479 omap_gp_timer_reset(s);
480 omap_gp_timer_clk_setup(s);
481
482 memory_region_init_io(&s->iomem, NULL, &omap_gp_timer_ops, s, "omap.gptimer",
483 omap_l4_region_size(ta, 0));
484 omap_l4_attach(ta, 0, &s->iomem);
485
486 return s;
487}
488