|
|
1.1 root 1: /*
2: * TI OMAP2 general purpose timers emulation.
3: *
4: * Copyright (C) 2007-2008 Nokia Corporation
5: * Written by Andrzej Zaborowski <[email protected]>
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: #include "hw.h"
21: #include "qemu-timer.h"
22: #include "omap.h"
23:
24: /* GP timers */
25: struct omap_gp_timer_s {
1.1.1.4 ! root 26: MemoryRegion iomem;
1.1 root 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; /* LSB */
71: uint16_t readh; /* MSB */
72: };
73:
74: #define GPT_TCAR_IT (1 << 2)
75: #define GPT_OVF_IT (1 << 1)
76: #define GPT_MAT_IT (1 << 0)
77:
78: static 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: /* Or are the status bits set even when masked?
86: * i.e. is masking applied before or after the status register? */
87: }
88:
89: if (timer->wu_ena & it)
90: qemu_irq_pulse(timer->wkup);
91: }
92:
93: static 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:
101: static 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) {
1.1.1.2 root 106: distance = qemu_get_clock_ns(vm_clock) - timer->time;
1.1 root 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:
117: static 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);
1.1.1.2 root 121: timer->time = qemu_get_clock_ns(vm_clock);
1.1 root 122: }
123: }
124:
125: static 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: qemu_mod_timer(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: qemu_mod_timer(timer->match, timer->time + matches);
138: } else
139: qemu_del_timer(timer->match);
140: } else {
141: qemu_del_timer(timer->timer);
142: qemu_del_timer(timer->match);
143: omap_gp_timer_out(timer, timer->scpwm);
144: }
145: }
146:
147: static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
148: {
149: if (timer->pt)
150: /* TODO in overflow-and-match mode if the first event to
151: * occur is the match, don't toggle. */
152: omap_gp_timer_out(timer, !timer->out_val);
153: else
154: /* TODO inverted pulse on timer->out_val == 1? */
155: qemu_irq_pulse(timer->out);
156: }
157:
158: static 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;
1.1.1.2 root 167: timer->time = qemu_get_clock_ns(vm_clock);
1.1 root 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:
178: static 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:
188: static 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:
218: static 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:
227: static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
228: {
229: omap_clk_adduser(timer->clk,
230: qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
231: timer->rate = omap_clk_getrate(timer->clk);
232: }
233:
234: void 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:
261: static uint32_t omap_gp_timer_readw(void *opaque, target_phys_addr_t addr)
262: {
263: struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
264:
265: switch (addr) {
266: case 0x00: /* TIDR */
267: return 0x21;
268:
269: case 0x10: /* TIOCP_CFG */
270: return s->config;
271:
272: case 0x14: /* TISTAT */
273: /* ??? When's this bit reset? */
274: return 1; /* RESETDONE */
275:
276: case 0x18: /* TISR */
277: return s->status;
278:
279: case 0x1c: /* TIER */
280: return s->it_ena;
281:
282: case 0x20: /* TWER */
283: return s->wu_ena;
284:
285: case 0x24: /* TCLR */
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: /* TCRR */
299: return omap_gp_timer_read(s);
300:
301: case 0x2c: /* TLDR */
302: return s->load_val;
303:
304: case 0x30: /* TTGR */
305: return 0xffffffff;
306:
307: case 0x34: /* TWPS */
308: return 0x00000000; /* No posted writes pending. */
309:
310: case 0x38: /* TMAR */
311: return s->match_val;
312:
313: case 0x3c: /* TCAR1 */
314: return s->capture_val[0];
315:
316: case 0x40: /* TSICR */
317: return s->posted << 2;
318:
319: case 0x44: /* TCAR2 */
320: return s->capture_val[1];
321: }
322:
323: OMAP_BAD_REG(addr);
324: return 0;
325: }
326:
327: static uint32_t omap_gp_timer_readh(void *opaque, target_phys_addr_t 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:
341: static void omap_gp_timer_write(void *opaque, target_phys_addr_t 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: /* TIDR */
348: case 0x14: /* TISTAT */
349: case 0x34: /* TWPS */
350: case 0x3c: /* TCAR1 */
351: case 0x44: /* TCAR2 */
352: OMAP_RO_REG(addr);
353: break;
354:
355: case 0x10: /* TIOCP_CFG */
356: s->config = value & 0x33d;
357: if (((value >> 3) & 3) == 3) /* IDLEMODE */
358: fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
359: __FUNCTION__);
360: if (value & 2) /* SOFTRESET */
361: omap_gp_timer_reset(s);
362: break;
363:
364: case 0x18: /* TISR */
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: /* TIER */
372: s->it_ena = value & 7;
373: break;
374:
375: case 0x20: /* TWER */
376: s->wu_ena = value & 7;
377: break;
378:
379: case 0x24: /* TCLR */
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: /* TODO: make sure this doesn't overflow 32-bits */
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: /* TCRR */
1.1.1.2 root 409: s->time = qemu_get_clock_ns(vm_clock);
1.1 root 410: s->val = value;
411: omap_gp_timer_update(s);
412: break;
413:
414: case 0x2c: /* TLDR */
415: s->load_val = value;
416: break;
417:
418: case 0x30: /* TTGR */
1.1.1.2 root 419: s->time = qemu_get_clock_ns(vm_clock);
1.1 root 420: s->val = s->load_val;
421: omap_gp_timer_update(s);
422: break;
423:
424: case 0x38: /* TMAR */
425: omap_gp_timer_sync(s);
426: s->match_val = value;
427: omap_gp_timer_update(s);
428: break;
429:
430: case 0x40: /* TSICR */
431: s->posted = (value >> 2) & 1;
432: if (value & 2) /* How much exactly are we supposed to reset? */
433: omap_gp_timer_reset(s);
434: break;
435:
436: default:
437: OMAP_BAD_REG(addr);
438: }
439: }
440:
441: static void omap_gp_timer_writeh(void *opaque, target_phys_addr_t 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: return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
448: else
449: s->writeh = (uint16_t) value;
450: }
451:
1.1.1.4 ! root 452: static 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,
1.1 root 466: };
467:
468: struct 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 = (struct omap_gp_timer_s *)
1.1.1.3 root 472: g_malloc0(sizeof(struct omap_gp_timer_s));
1.1 root 473:
474: s->ta = ta;
475: s->irq = irq;
476: s->clk = fclk;
1.1.1.2 root 477: s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s);
478: s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s);
1.1 root 479: s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
480: omap_gp_timer_reset(s);
481: omap_gp_timer_clk_setup(s);
482:
1.1.1.4 ! root 483: memory_region_init_io(&s->iomem, &omap_gp_timer_ops, s, "omap.gptimer",
! 484: omap_l4_region_size(ta, 0));
! 485: omap_l4_attach(ta, 0, &s->iomem);
1.1 root 486:
487: return s;
488: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.