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