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