1 /*
2 * TI OMAP2 general purpose timers emulation.
3 *
4 * Copyright (C) 2007-2008 Nokia Corporation
5 * Written by Andrzej Zaborowski <andrew@openedhand.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 or
10 * (at your option) any later version of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "qemu/osdep.h"
22 #include "hw/irq.h"
23 #include "qemu/timer.h"
24 #include "hw/arm/omap.h"
25
26 /* GP timers */
27 struct omap_gp_timer_s {
28 MemoryRegion iomem;
29 qemu_irq irq;
30 qemu_irq wkup;
31 qemu_irq in;
32 qemu_irq out;
33 omap_clk clk;
34 QEMUTimer *timer;
35 QEMUTimer *match;
36 struct omap_target_agent_s *ta;
37
38 int in_val;
39 int out_val;
40 int64_t time;
41 int64_t rate;
42 int64_t ticks_per_sec;
43
44 int16_t config;
45 int status;
46 int it_ena;
47 int wu_ena;
48 int enable;
49 int inout;
50 int capt2;
51 int pt;
52 enum {
53 gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
54 } trigger;
55 enum {
56 gpt_capture_none, gpt_capture_rising,
57 gpt_capture_falling, gpt_capture_both
58 } capture;
59 int scpwm;
60 int ce;
61 int pre;
62 int ptv;
63 int ar;
64 int st;
65 int posted;
66 uint32_t val;
67 uint32_t load_val;
68 uint32_t capture_val[2];
69 uint32_t match_val;
70 int capt_num;
71
72 uint16_t writeh; /* LSB */
73 uint16_t readh; /* MSB */
74 };
75
76 #define GPT_TCAR_IT (1 << 2)
77 #define GPT_OVF_IT (1 << 1)
78 #define GPT_MAT_IT (1 << 0)
79
omap_gp_timer_intr(struct omap_gp_timer_s * timer,int it)80 static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
81 {
82 if (timer->it_ena & it) {
83 if (!timer->status)
84 qemu_irq_raise(timer->irq);
85
86 timer->status |= it;
87 /* Or are the status bits set even when masked?
88 * i.e. is masking applied before or after the status register? */
89 }
90
91 if (timer->wu_ena & it)
92 qemu_irq_pulse(timer->wkup);
93 }
94
omap_gp_timer_out(struct omap_gp_timer_s * timer,int level)95 static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
96 {
97 if (!timer->inout && timer->out_val != level) {
98 timer->out_val = level;
99 qemu_set_irq(timer->out, level);
100 }
101 }
102
omap_gp_timer_read(struct omap_gp_timer_s * timer)103 static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
104 {
105 uint64_t distance;
106
107 if (timer->st && timer->rate) {
108 distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time;
109 distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
110
111 if (distance >= 0xffffffff - timer->val)
112 return 0xffffffff;
113 else
114 return timer->val + distance;
115 } else
116 return timer->val;
117 }
118
omap_gp_timer_sync(struct omap_gp_timer_s * timer)119 static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
120 {
121 if (timer->st) {
122 timer->val = omap_gp_timer_read(timer);
123 timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
124 }
125 }
126
omap_gp_timer_update(struct omap_gp_timer_s * timer)127 static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
128 {
129 int64_t expires, matches;
130
131 if (timer->st && timer->rate) {
132 expires = muldiv64(0x100000000ll - timer->val,
133 timer->ticks_per_sec, timer->rate);
134 timer_mod(timer->timer, timer->time + expires);
135
136 if (timer->ce && timer->match_val >= timer->val) {
137 matches = muldiv64(timer->ticks_per_sec,
138 timer->match_val - timer->val, timer->rate);
139 timer_mod(timer->match, timer->time + matches);
140 } else
141 timer_del(timer->match);
142 } else {
143 timer_del(timer->timer);
144 timer_del(timer->match);
145 omap_gp_timer_out(timer, timer->scpwm);
146 }
147 }
148
omap_gp_timer_trigger(struct omap_gp_timer_s * timer)149 static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
150 {
151 if (timer->pt)
152 /* TODO in overflow-and-match mode if the first event to
153 * occur is the match, don't toggle. */
154 omap_gp_timer_out(timer, !timer->out_val);
155 else
156 /* TODO inverted pulse on timer->out_val == 1? */
157 qemu_irq_pulse(timer->out);
158 }
159
omap_gp_timer_tick(void * opaque)160 static void omap_gp_timer_tick(void *opaque)
161 {
162 struct omap_gp_timer_s *timer = opaque;
163
164 if (!timer->ar) {
165 timer->st = 0;
166 timer->val = 0;
167 } else {
168 timer->val = timer->load_val;
169 timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
170 }
171
172 if (timer->trigger == gpt_trigger_overflow ||
173 timer->trigger == gpt_trigger_both)
174 omap_gp_timer_trigger(timer);
175
176 omap_gp_timer_intr(timer, GPT_OVF_IT);
177 omap_gp_timer_update(timer);
178 }
179
omap_gp_timer_match(void * opaque)180 static void omap_gp_timer_match(void *opaque)
181 {
182 struct omap_gp_timer_s *timer = opaque;
183
184 if (timer->trigger == gpt_trigger_both)
185 omap_gp_timer_trigger(timer);
186
187 omap_gp_timer_intr(timer, GPT_MAT_IT);
188 }
189
omap_gp_timer_input(void * opaque,int line,int on)190 static void omap_gp_timer_input(void *opaque, int line, int on)
191 {
192 struct omap_gp_timer_s *s = opaque;
193 int trigger;
194
195 switch (s->capture) {
196 default:
197 case gpt_capture_none:
198 trigger = 0;
199 break;
200 case gpt_capture_rising:
201 trigger = !s->in_val && on;
202 break;
203 case gpt_capture_falling:
204 trigger = s->in_val && !on;
205 break;
206 case gpt_capture_both:
207 trigger = (s->in_val == !on);
208 break;
209 }
210 s->in_val = on;
211
212 if (s->inout && trigger && s->capt_num < 2) {
213 s->capture_val[s->capt_num] = omap_gp_timer_read(s);
214
215 if (s->capt2 == s->capt_num ++)
216 omap_gp_timer_intr(s, GPT_TCAR_IT);
217 }
218 }
219
omap_gp_timer_clk_update(void * opaque,int line,int on)220 static void omap_gp_timer_clk_update(void *opaque, int line, int on)
221 {
222 struct omap_gp_timer_s *timer = opaque;
223
224 omap_gp_timer_sync(timer);
225 timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
226 omap_gp_timer_update(timer);
227 }
228
omap_gp_timer_clk_setup(struct omap_gp_timer_s * timer)229 static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
230 {
231 omap_clk_adduser(timer->clk,
232 qemu_allocate_irq(omap_gp_timer_clk_update, timer, 0));
233 timer->rate = omap_clk_getrate(timer->clk);
234 }
235
omap_gp_timer_reset(struct omap_gp_timer_s * s)236 void omap_gp_timer_reset(struct omap_gp_timer_s *s)
237 {
238 s->config = 0x000;
239 s->status = 0;
240 s->it_ena = 0;
241 s->wu_ena = 0;
242 s->inout = 0;
243 s->capt2 = 0;
244 s->capt_num = 0;
245 s->pt = 0;
246 s->trigger = gpt_trigger_none;
247 s->capture = gpt_capture_none;
248 s->scpwm = 0;
249 s->ce = 0;
250 s->pre = 0;
251 s->ptv = 0;
252 s->ar = 0;
253 s->st = 0;
254 s->posted = 1;
255 s->val = 0x00000000;
256 s->load_val = 0x00000000;
257 s->capture_val[0] = 0x00000000;
258 s->capture_val[1] = 0x00000000;
259 s->match_val = 0x00000000;
260 omap_gp_timer_update(s);
261 }
262
omap_gp_timer_readw(void * opaque,hwaddr addr)263 static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
264 {
265 struct omap_gp_timer_s *s = opaque;
266
267 switch (addr) {
268 case 0x00: /* TIDR */
269 return 0x21;
270
271 case 0x10: /* TIOCP_CFG */
272 return s->config;
273
274 case 0x14: /* TISTAT */
275 /* ??? When's this bit reset? */
276 return 1; /* RESETDONE */
277
278 case 0x18: /* TISR */
279 return s->status;
280
281 case 0x1c: /* TIER */
282 return s->it_ena;
283
284 case 0x20: /* TWER */
285 return s->wu_ena;
286
287 case 0x24: /* TCLR */
288 return (s->inout << 14) |
289 (s->capt2 << 13) |
290 (s->pt << 12) |
291 (s->trigger << 10) |
292 (s->capture << 8) |
293 (s->scpwm << 7) |
294 (s->ce << 6) |
295 (s->pre << 5) |
296 (s->ptv << 2) |
297 (s->ar << 1) |
298 (s->st << 0);
299
300 case 0x28: /* TCRR */
301 return omap_gp_timer_read(s);
302
303 case 0x2c: /* TLDR */
304 return s->load_val;
305
306 case 0x30: /* TTGR */
307 return 0xffffffff;
308
309 case 0x34: /* TWPS */
310 return 0x00000000; /* No posted writes pending. */
311
312 case 0x38: /* TMAR */
313 return s->match_val;
314
315 case 0x3c: /* TCAR1 */
316 return s->capture_val[0];
317
318 case 0x40: /* TSICR */
319 return s->posted << 2;
320
321 case 0x44: /* TCAR2 */
322 return s->capture_val[1];
323 }
324
325 OMAP_BAD_REG(addr);
326 return 0;
327 }
328
omap_gp_timer_readh(void * opaque,hwaddr addr)329 static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
330 {
331 struct omap_gp_timer_s *s = opaque;
332 uint32_t ret;
333
334 if (addr & 2)
335 return s->readh;
336 else {
337 ret = omap_gp_timer_readw(opaque, addr);
338 s->readh = ret >> 16;
339 return ret & 0xffff;
340 }
341 }
342
omap_gp_timer_write(void * opaque,hwaddr addr,uint32_t value)343 static void omap_gp_timer_write(void *opaque, hwaddr addr, uint32_t value)
344 {
345 struct omap_gp_timer_s *s = opaque;
346
347 switch (addr) {
348 case 0x00: /* TIDR */
349 case 0x14: /* TISTAT */
350 case 0x34: /* TWPS */
351 case 0x3c: /* TCAR1 */
352 case 0x44: /* TCAR2 */
353 OMAP_RO_REG(addr);
354 break;
355
356 case 0x10: /* TIOCP_CFG */
357 s->config = value & 0x33d;
358 if (((value >> 3) & 3) == 3) /* IDLEMODE */
359 fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
360 __func__);
361 if (value & 2) /* SOFTRESET */
362 omap_gp_timer_reset(s);
363 break;
364
365 case 0x18: /* TISR */
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: /* TIER */
373 s->it_ena = value & 7;
374 break;
375
376 case 0x20: /* TWER */
377 s->wu_ena = value & 7;
378 break;
379
380 case 0x24: /* TCLR */
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", __func__);
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", __func__);
402 if (s->trigger == gpt_trigger_none)
403 omap_gp_timer_out(s, s->scpwm);
404 /* TODO: make sure this doesn't overflow 32-bits */
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: /* TCRR */
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: /* TLDR */
416 s->load_val = value;
417 break;
418
419 case 0x30: /* TTGR */
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: /* TMAR */
426 omap_gp_timer_sync(s);
427 s->match_val = value;
428 omap_gp_timer_update(s);
429 break;
430
431 case 0x40: /* TSICR */
432 s->posted = (value >> 2) & 1;
433 if (value & 2) /* How much exactly are we supposed to reset? */
434 omap_gp_timer_reset(s);
435 break;
436
437 default:
438 OMAP_BAD_REG(addr);
439 }
440 }
441
omap_gp_timer_writeh(void * opaque,hwaddr addr,uint32_t value)442 static void omap_gp_timer_writeh(void *opaque, hwaddr addr, uint32_t value)
443 {
444 struct omap_gp_timer_s *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
omap_gp_timer_readfn(void * opaque,hwaddr addr,unsigned size)452 static uint64_t omap_gp_timer_readfn(void *opaque, hwaddr addr,
453 unsigned size)
454 {
455 switch (size) {
456 case 1:
457 return omap_badwidth_read32(opaque, addr);
458 case 2:
459 return omap_gp_timer_readh(opaque, addr);
460 case 4:
461 return omap_gp_timer_readw(opaque, addr);
462 default:
463 g_assert_not_reached();
464 }
465 }
466
omap_gp_timer_writefn(void * opaque,hwaddr addr,uint64_t value,unsigned size)467 static void omap_gp_timer_writefn(void *opaque, hwaddr addr,
468 uint64_t value, unsigned size)
469 {
470 switch (size) {
471 case 1:
472 omap_badwidth_write32(opaque, addr, value);
473 break;
474 case 2:
475 omap_gp_timer_writeh(opaque, addr, value);
476 break;
477 case 4:
478 omap_gp_timer_write(opaque, addr, value);
479 break;
480 default:
481 g_assert_not_reached();
482 }
483 }
484
485 static const MemoryRegionOps omap_gp_timer_ops = {
486 .read = omap_gp_timer_readfn,
487 .write = omap_gp_timer_writefn,
488 .valid.min_access_size = 1,
489 .valid.max_access_size = 4,
490 .endianness = DEVICE_NATIVE_ENDIAN,
491 };
492
omap_gp_timer_init(struct omap_target_agent_s * ta,qemu_irq irq,omap_clk fclk,omap_clk iclk)493 struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
494 qemu_irq irq, omap_clk fclk, omap_clk iclk)
495 {
496 struct omap_gp_timer_s *s = g_new0(struct omap_gp_timer_s, 1);
497
498 s->ta = ta;
499 s->irq = irq;
500 s->clk = fclk;
501 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s);
502 s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s);
503 s->in = qemu_allocate_irq(omap_gp_timer_input, s, 0);
504 omap_gp_timer_reset(s);
505 omap_gp_timer_clk_setup(s);
506
507 memory_region_init_io(&s->iomem, NULL, &omap_gp_timer_ops, s, "omap.gptimer",
508 omap_l4_region_size(ta, 0));
509 omap_l4_attach(ta, 0, &s->iomem);
510
511 return s;
512 }
513