|
|
1.1 root 1: /*
2: * Intel XScale PXA255/270 OS Timers.
3: *
4: * Copyright (c) 2006 Openedhand Ltd.
5: * Copyright (c) 2006 Thorsten Zitterell
6: *
1.1.1.7 ! root 7: * This code is licensed under the GPL.
1.1 root 8: */
9:
10: #include "hw.h"
11: #include "qemu-timer.h"
12: #include "sysemu.h"
13: #include "pxa.h"
1.1.1.7 ! root 14: #include "sysbus.h"
1.1 root 15:
16: #define OSMR0 0x00
17: #define OSMR1 0x04
18: #define OSMR2 0x08
19: #define OSMR3 0x0c
20: #define OSMR4 0x80
21: #define OSMR5 0x84
22: #define OSMR6 0x88
23: #define OSMR7 0x8c
24: #define OSMR8 0x90
25: #define OSMR9 0x94
26: #define OSMR10 0x98
27: #define OSMR11 0x9c
28: #define OSCR 0x10 /* OS Timer Count */
29: #define OSCR4 0x40
30: #define OSCR5 0x44
31: #define OSCR6 0x48
32: #define OSCR7 0x4c
33: #define OSCR8 0x50
34: #define OSCR9 0x54
35: #define OSCR10 0x58
36: #define OSCR11 0x5c
37: #define OSSR 0x14 /* Timer status register */
38: #define OWER 0x18
39: #define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */
40: #define OMCR4 0xc0 /* OS Match Control registers */
41: #define OMCR5 0xc4
42: #define OMCR6 0xc8
43: #define OMCR7 0xcc
44: #define OMCR8 0xd0
45: #define OMCR9 0xd4
46: #define OMCR10 0xd8
47: #define OMCR11 0xdc
48: #define OSNR 0x20
49:
50: #define PXA25X_FREQ 3686400 /* 3.6864 MHz */
51: #define PXA27X_FREQ 3250000 /* 3.25 MHz */
52:
53: static int pxa2xx_timer4_freq[8] = {
54: [0] = 0,
55: [1] = 32768,
56: [2] = 1000,
57: [3] = 1,
58: [4] = 1000000,
59: /* [5] is the "Externally supplied clock". Assign if necessary. */
60: [5 ... 7] = 0,
61: };
62:
1.1.1.7 ! root 63: typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
! 64:
1.1.1.3 root 65: typedef struct {
1.1 root 66: uint32_t value;
67: qemu_irq irq;
68: QEMUTimer *qtimer;
69: int num;
1.1.1.7 ! root 70: PXA2xxTimerInfo *info;
1.1.1.3 root 71: } PXA2xxTimer0;
1.1 root 72:
1.1.1.3 root 73: typedef struct {
74: PXA2xxTimer0 tm;
1.1 root 75: int32_t oldclock;
76: int32_t clock;
77: uint64_t lastload;
78: uint32_t freq;
79: uint32_t control;
1.1.1.3 root 80: } PXA2xxTimer4;
1.1 root 81:
1.1.1.7 ! root 82: struct PXA2xxTimerInfo {
! 83: SysBusDevice busdev;
! 84: uint32_t flags;
! 85:
1.1 root 86: int32_t clock;
87: int32_t oldclock;
88: uint64_t lastload;
89: uint32_t freq;
1.1.1.3 root 90: PXA2xxTimer0 timer[4];
1.1 root 91: uint32_t events;
92: uint32_t irq_enabled;
93: uint32_t reset3;
94: uint32_t snapshot;
1.1.1.7 ! root 95:
! 96: qemu_irq irq4;
! 97: PXA2xxTimer4 tm4[8];
! 98: };
! 99:
! 100: #define PXA2XX_TIMER_HAVE_TM4 0
! 101:
! 102: static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
! 103: {
! 104: return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
! 105: }
1.1 root 106:
107: static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
108: {
1.1.1.7 ! root 109: PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1.1 root 110: int i;
111: uint32_t now_vm;
112: uint64_t new_qemu;
113:
114: now_vm = s->clock +
1.1.1.4 root 115: muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec());
1.1 root 116:
117: for (i = 0; i < 4; i ++) {
118: new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
1.1.1.4 root 119: get_ticks_per_sec(), s->freq);
1.1 root 120: qemu_mod_timer(s->timer[i].qtimer, new_qemu);
121: }
122: }
123:
124: static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
125: {
1.1.1.7 ! root 126: PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1.1 root 127: uint32_t now_vm;
128: uint64_t new_qemu;
129: static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
130: int counter;
131:
132: if (s->tm4[n].control & (1 << 7))
133: counter = n;
134: else
135: counter = counters[n];
136:
137: if (!s->tm4[counter].freq) {
138: qemu_del_timer(s->tm4[n].tm.qtimer);
139: return;
140: }
141:
142: now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
143: s->tm4[counter].lastload,
1.1.1.4 root 144: s->tm4[counter].freq, get_ticks_per_sec());
1.1 root 145:
146: new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
1.1.1.4 root 147: get_ticks_per_sec(), s->tm4[counter].freq);
1.1 root 148: qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu);
149: }
150:
151: static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
152: {
1.1.1.7 ! root 153: PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1.1 root 154: int tm = 0;
155:
156: switch (offset) {
157: case OSMR3: tm ++;
158: case OSMR2: tm ++;
159: case OSMR1: tm ++;
160: case OSMR0:
161: return s->timer[tm].value;
162: case OSMR11: tm ++;
163: case OSMR10: tm ++;
164: case OSMR9: tm ++;
165: case OSMR8: tm ++;
166: case OSMR7: tm ++;
167: case OSMR6: tm ++;
168: case OSMR5: tm ++;
169: case OSMR4:
1.1.1.7 ! root 170: if (!pxa2xx_timer_has_tm4(s))
1.1 root 171: goto badreg;
172: return s->tm4[tm].tm.value;
173: case OSCR:
1.1.1.7 ! root 174: return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) -
1.1.1.4 root 175: s->lastload, s->freq, get_ticks_per_sec());
1.1 root 176: case OSCR11: tm ++;
177: case OSCR10: tm ++;
178: case OSCR9: tm ++;
179: case OSCR8: tm ++;
180: case OSCR7: tm ++;
181: case OSCR6: tm ++;
182: case OSCR5: tm ++;
183: case OSCR4:
1.1.1.7 ! root 184: if (!pxa2xx_timer_has_tm4(s))
1.1 root 185: goto badreg;
186:
187: if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
188: if (s->tm4[tm - 1].freq)
189: s->snapshot = s->tm4[tm - 1].clock + muldiv64(
1.1.1.7 ! root 190: qemu_get_clock_ns(vm_clock) -
1.1 root 191: s->tm4[tm - 1].lastload,
1.1.1.4 root 192: s->tm4[tm - 1].freq, get_ticks_per_sec());
1.1 root 193: else
194: s->snapshot = s->tm4[tm - 1].clock;
195: }
196:
197: if (!s->tm4[tm].freq)
198: return s->tm4[tm].clock;
1.1.1.7 ! root 199: return s->tm4[tm].clock + muldiv64(qemu_get_clock_ns(vm_clock) -
1.1.1.4 root 200: s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec());
1.1 root 201: case OIER:
202: return s->irq_enabled;
203: case OSSR: /* Status register */
204: return s->events;
205: case OWER:
206: return s->reset3;
207: case OMCR11: tm ++;
208: case OMCR10: tm ++;
209: case OMCR9: tm ++;
210: case OMCR8: tm ++;
211: case OMCR7: tm ++;
212: case OMCR6: tm ++;
213: case OMCR5: tm ++;
214: case OMCR4:
1.1.1.7 ! root 215: if (!pxa2xx_timer_has_tm4(s))
1.1 root 216: goto badreg;
217: return s->tm4[tm].control;
218: case OSNR:
219: return s->snapshot;
220: default:
221: badreg:
1.1.1.3 root 222: hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
1.1 root 223: }
224:
225: return 0;
226: }
227:
228: static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
229: uint32_t value)
230: {
231: int i, tm = 0;
1.1.1.7 ! root 232: PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1.1 root 233:
234: switch (offset) {
235: case OSMR3: tm ++;
236: case OSMR2: tm ++;
237: case OSMR1: tm ++;
238: case OSMR0:
239: s->timer[tm].value = value;
1.1.1.7 ! root 240: pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock));
1.1 root 241: break;
242: case OSMR11: tm ++;
243: case OSMR10: tm ++;
244: case OSMR9: tm ++;
245: case OSMR8: tm ++;
246: case OSMR7: tm ++;
247: case OSMR6: tm ++;
248: case OSMR5: tm ++;
249: case OSMR4:
1.1.1.7 ! root 250: if (!pxa2xx_timer_has_tm4(s))
1.1 root 251: goto badreg;
252: s->tm4[tm].tm.value = value;
1.1.1.7 ! root 253: pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
1.1 root 254: break;
255: case OSCR:
256: s->oldclock = s->clock;
1.1.1.7 ! root 257: s->lastload = qemu_get_clock_ns(vm_clock);
1.1 root 258: s->clock = value;
259: pxa2xx_timer_update(s, s->lastload);
260: break;
261: case OSCR11: tm ++;
262: case OSCR10: tm ++;
263: case OSCR9: tm ++;
264: case OSCR8: tm ++;
265: case OSCR7: tm ++;
266: case OSCR6: tm ++;
267: case OSCR5: tm ++;
268: case OSCR4:
1.1.1.7 ! root 269: if (!pxa2xx_timer_has_tm4(s))
1.1 root 270: goto badreg;
271: s->tm4[tm].oldclock = s->tm4[tm].clock;
1.1.1.7 ! root 272: s->tm4[tm].lastload = qemu_get_clock_ns(vm_clock);
1.1 root 273: s->tm4[tm].clock = value;
274: pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
275: break;
276: case OIER:
277: s->irq_enabled = value & 0xfff;
278: break;
279: case OSSR: /* Status register */
1.1.1.7 ! root 280: value &= s->events;
1.1 root 281: s->events &= ~value;
1.1.1.7 ! root 282: for (i = 0; i < 4; i ++, value >>= 1)
! 283: if (value & 1)
1.1 root 284: qemu_irq_lower(s->timer[i].irq);
1.1.1.7 ! root 285: if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
! 286: qemu_irq_lower(s->irq4);
1.1 root 287: break;
288: case OWER: /* XXX: Reset on OSMR3 match? */
289: s->reset3 = value;
290: break;
291: case OMCR7: tm ++;
292: case OMCR6: tm ++;
293: case OMCR5: tm ++;
294: case OMCR4:
1.1.1.7 ! root 295: if (!pxa2xx_timer_has_tm4(s))
1.1 root 296: goto badreg;
297: s->tm4[tm].control = value & 0x0ff;
298: /* XXX Stop if running (shouldn't happen) */
299: if ((value & (1 << 7)) || tm == 0)
300: s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
301: else {
302: s->tm4[tm].freq = 0;
1.1.1.7 ! root 303: pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
1.1 root 304: }
305: break;
306: case OMCR11: tm ++;
307: case OMCR10: tm ++;
308: case OMCR9: tm ++;
309: case OMCR8: tm += 4;
1.1.1.7 ! root 310: if (!pxa2xx_timer_has_tm4(s))
1.1 root 311: goto badreg;
312: s->tm4[tm].control = value & 0x3ff;
313: /* XXX Stop if running (shouldn't happen) */
314: if ((value & (1 << 7)) || !(tm & 1))
315: s->tm4[tm].freq =
316: pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)];
317: else {
318: s->tm4[tm].freq = 0;
1.1.1.7 ! root 319: pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
1.1 root 320: }
321: break;
322: default:
323: badreg:
1.1.1.3 root 324: hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
1.1 root 325: }
326: }
327:
1.1.1.4 root 328: static CPUReadMemoryFunc * const pxa2xx_timer_readfn[] = {
1.1 root 329: pxa2xx_timer_read,
330: pxa2xx_timer_read,
331: pxa2xx_timer_read,
332: };
333:
1.1.1.4 root 334: static CPUWriteMemoryFunc * const pxa2xx_timer_writefn[] = {
1.1 root 335: pxa2xx_timer_write,
336: pxa2xx_timer_write,
337: pxa2xx_timer_write,
338: };
339:
340: static void pxa2xx_timer_tick(void *opaque)
341: {
1.1.1.3 root 342: PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
1.1.1.7 ! root 343: PXA2xxTimerInfo *i = t->info;
1.1 root 344:
345: if (i->irq_enabled & (1 << t->num)) {
346: i->events |= 1 << t->num;
347: qemu_irq_raise(t->irq);
348: }
349:
350: if (t->num == 3)
351: if (i->reset3 & 1) {
352: i->reset3 = 0;
353: qemu_system_reset_request();
354: }
355: }
356:
357: static void pxa2xx_timer_tick4(void *opaque)
358: {
1.1.1.3 root 359: PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
1.1.1.7 ! root 360: PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
1.1 root 361:
362: pxa2xx_timer_tick(&t->tm);
363: if (t->control & (1 << 3))
364: t->clock = 0;
365: if (t->control & (1 << 6))
1.1.1.7 ! root 366: pxa2xx_timer_update4(i, qemu_get_clock_ns(vm_clock), t->tm.num - 4);
! 367: if (i->events & 0xff0)
! 368: qemu_irq_raise(i->irq4);
1.1 root 369: }
370:
1.1.1.7 ! root 371: static int pxa25x_timer_post_load(void *opaque, int version_id)
1.1 root 372: {
1.1.1.7 ! root 373: PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
1.1 root 374: int64_t now;
375: int i;
376:
1.1.1.7 ! root 377: now = qemu_get_clock_ns(vm_clock);
1.1 root 378: pxa2xx_timer_update(s, now);
379:
1.1.1.7 ! root 380: if (pxa2xx_timer_has_tm4(s))
! 381: for (i = 0; i < 8; i ++)
1.1 root 382: pxa2xx_timer_update4(s, now, i);
383:
384: return 0;
385: }
386:
1.1.1.7 ! root 387: static int pxa2xx_timer_init(SysBusDevice *dev)
1.1 root 388: {
389: int i;
390: int iomemtype;
1.1.1.7 ! root 391: PXA2xxTimerInfo *s;
1.1 root 392:
1.1.1.7 ! root 393: s = FROM_SYSBUS(PXA2xxTimerInfo, dev);
1.1 root 394: s->irq_enabled = 0;
395: s->oldclock = 0;
396: s->clock = 0;
1.1.1.7 ! root 397: s->lastload = qemu_get_clock_ns(vm_clock);
1.1 root 398: s->reset3 = 0;
399:
400: for (i = 0; i < 4; i ++) {
401: s->timer[i].value = 0;
1.1.1.7 ! root 402: sysbus_init_irq(dev, &s->timer[i].irq);
1.1 root 403: s->timer[i].info = s;
404: s->timer[i].num = i;
1.1.1.7 ! root 405: s->timer[i].qtimer = qemu_new_timer_ns(vm_clock,
1.1 root 406: pxa2xx_timer_tick, &s->timer[i]);
407: }
1.1.1.7 ! root 408: if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
! 409: sysbus_init_irq(dev, &s->irq4);
! 410:
! 411: for (i = 0; i < 8; i ++) {
! 412: s->tm4[i].tm.value = 0;
! 413: s->tm4[i].tm.info = s;
! 414: s->tm4[i].tm.num = i + 4;
! 415: s->tm4[i].freq = 0;
! 416: s->tm4[i].control = 0x0;
! 417: s->tm4[i].tm.qtimer = qemu_new_timer_ns(vm_clock,
! 418: pxa2xx_timer_tick4, &s->tm4[i]);
! 419: }
! 420: }
1.1 root 421:
1.1.1.3 root 422: iomemtype = cpu_register_io_memory(pxa2xx_timer_readfn,
1.1.1.6 root 423: pxa2xx_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
1.1.1.7 ! root 424: sysbus_init_mmio(dev, 0x00001000, iomemtype);
1.1 root 425:
1.1.1.7 ! root 426: return 0;
1.1 root 427: }
428:
1.1.1.7 ! root 429: static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
! 430: .name = "pxa2xx_timer0",
! 431: .version_id = 2,
! 432: .minimum_version_id = 2,
! 433: .minimum_version_id_old = 2,
! 434: .fields = (VMStateField[]) {
! 435: VMSTATE_UINT32(value, PXA2xxTimer0),
! 436: VMSTATE_END_OF_LIST(),
! 437: },
! 438: };
! 439:
! 440: static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
! 441: .name = "pxa2xx_timer4",
! 442: .version_id = 1,
! 443: .minimum_version_id = 1,
! 444: .minimum_version_id_old = 1,
! 445: .fields = (VMStateField[]) {
! 446: VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
! 447: vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
! 448: VMSTATE_INT32(oldclock, PXA2xxTimer4),
! 449: VMSTATE_INT32(clock, PXA2xxTimer4),
! 450: VMSTATE_UINT64(lastload, PXA2xxTimer4),
! 451: VMSTATE_UINT32(freq, PXA2xxTimer4),
! 452: VMSTATE_UINT32(control, PXA2xxTimer4),
! 453: VMSTATE_END_OF_LIST(),
! 454: },
! 455: };
! 456:
! 457: static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
1.1 root 458: {
1.1.1.7 ! root 459: return pxa2xx_timer_has_tm4(opaque);
1.1 root 460: }
461:
1.1.1.7 ! root 462: static const VMStateDescription vmstate_pxa2xx_timer_regs = {
! 463: .name = "pxa2xx_timer",
! 464: .version_id = 1,
! 465: .minimum_version_id = 1,
! 466: .minimum_version_id_old = 1,
! 467: .post_load = pxa25x_timer_post_load,
! 468: .fields = (VMStateField[]) {
! 469: VMSTATE_INT32(clock, PXA2xxTimerInfo),
! 470: VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
! 471: VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
! 472: VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
! 473: vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
! 474: VMSTATE_UINT32(events, PXA2xxTimerInfo),
! 475: VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
! 476: VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
! 477: VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
! 478: VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
! 479: pxa2xx_timer_has_tm4_test, 0,
! 480: vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
! 481: VMSTATE_END_OF_LIST(),
1.1 root 482: }
1.1.1.7 ! root 483: };
! 484:
! 485: static SysBusDeviceInfo pxa25x_timer_dev_info = {
! 486: .init = pxa2xx_timer_init,
! 487: .qdev.name = "pxa25x-timer",
! 488: .qdev.desc = "PXA25x timer",
! 489: .qdev.size = sizeof(PXA2xxTimerInfo),
! 490: .qdev.vmsd = &vmstate_pxa2xx_timer_regs,
! 491: .qdev.props = (Property[]) {
! 492: DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
! 493: DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
! 494: PXA2XX_TIMER_HAVE_TM4, false),
! 495: DEFINE_PROP_END_OF_LIST(),
! 496: },
! 497: };
! 498:
! 499: static SysBusDeviceInfo pxa27x_timer_dev_info = {
! 500: .init = pxa2xx_timer_init,
! 501: .qdev.name = "pxa27x-timer",
! 502: .qdev.desc = "PXA27x timer",
! 503: .qdev.size = sizeof(PXA2xxTimerInfo),
! 504: .qdev.vmsd = &vmstate_pxa2xx_timer_regs,
! 505: .qdev.props = (Property[]) {
! 506: DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
! 507: DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
! 508: PXA2XX_TIMER_HAVE_TM4, true),
! 509: DEFINE_PROP_END_OF_LIST(),
! 510: },
! 511: };
! 512:
! 513: static void pxa2xx_timer_register(void)
! 514: {
! 515: sysbus_register_withprop(&pxa25x_timer_dev_info);
! 516: sysbus_register_withprop(&pxa27x_timer_dev_info);
! 517: };
! 518: device_init(pxa2xx_timer_register);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.