blob: 130e9dc3454a1efe1aa917cbdc19bbe16cbdad7a [file] [log] [blame]
balroga171fe32007-04-30 01:48:07 +00001/*
2 * Intel XScale PXA255/270 OS Timers.
3 *
4 * Copyright (c) 2006 Openedhand Ltd.
5 * Copyright (c) 2006 Thorsten Zitterell
6 *
Matthew Fernandez8e31bf32011-06-26 12:21:35 +10007 * This code is licensed under the GPL.
balroga171fe32007-04-30 01:48:07 +00008 */
9
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010010#include "hw/hw.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010011#include "qemu/timer.h"
Paolo Bonzini9c17d612012-12-17 18:20:04 +010012#include "sysemu/sysemu.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010013#include "hw/arm/pxa.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010014#include "hw/sysbus.h"
balroga171fe32007-04-30 01:48:07 +000015
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
53static 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
Andreas Färberfeea4362013-07-27 15:20:20 +020063#define TYPE_PXA2XX_TIMER "pxa2xx-timer"
64#define PXA2XX_TIMER(obj) \
65 OBJECT_CHECK(PXA2xxTimerInfo, (obj), TYPE_PXA2XX_TIMER)
66
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +010067typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
68
Paul Brookbc24a222009-05-10 01:44:56 +010069typedef struct {
balroga171fe32007-04-30 01:48:07 +000070 uint32_t value;
Andrzej Zaborowski5251d192011-03-03 14:24:25 +010071 qemu_irq irq;
balroga171fe32007-04-30 01:48:07 +000072 QEMUTimer *qtimer;
73 int num;
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +010074 PXA2xxTimerInfo *info;
Paul Brookbc24a222009-05-10 01:44:56 +010075} PXA2xxTimer0;
balroga171fe32007-04-30 01:48:07 +000076
Paul Brookbc24a222009-05-10 01:44:56 +010077typedef struct {
78 PXA2xxTimer0 tm;
balroga171fe32007-04-30 01:48:07 +000079 int32_t oldclock;
80 int32_t clock;
81 uint64_t lastload;
82 uint32_t freq;
83 uint32_t control;
Paul Brookbc24a222009-05-10 01:44:56 +010084} PXA2xxTimer4;
balroga171fe32007-04-30 01:48:07 +000085
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +010086struct PXA2xxTimerInfo {
Andreas Färberfeea4362013-07-27 15:20:20 +020087 SysBusDevice parent_obj;
88
Benoît Canetb755bde2011-10-30 14:50:16 +010089 MemoryRegion iomem;
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +010090 uint32_t flags;
91
balroga171fe32007-04-30 01:48:07 +000092 int32_t clock;
93 int32_t oldclock;
94 uint64_t lastload;
95 uint32_t freq;
Paul Brookbc24a222009-05-10 01:44:56 +010096 PXA2xxTimer0 timer[4];
balroga171fe32007-04-30 01:48:07 +000097 uint32_t events;
98 uint32_t irq_enabled;
99 uint32_t reset3;
balroga171fe32007-04-30 01:48:07 +0000100 uint32_t snapshot;
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100101
Dmitry Eremin-Solenikov4ff927c2011-03-04 03:40:59 +0300102 qemu_irq irq4;
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100103 PXA2xxTimer4 tm4[8];
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100104};
105
106#define PXA2XX_TIMER_HAVE_TM4 0
107
108static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
109{
110 return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
111}
balroga171fe32007-04-30 01:48:07 +0000112
113static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
114{
Dmitry Eremin-Solenikovd353eb42011-02-20 16:50:33 +0300115 PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
balroga171fe32007-04-30 01:48:07 +0000116 int i;
117 uint32_t now_vm;
118 uint64_t new_qemu;
119
120 now_vm = s->clock +
Juan Quintela6ee093c2009-09-10 03:04:26 +0200121 muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec());
balroga171fe32007-04-30 01:48:07 +0000122
123 for (i = 0; i < 4; i ++) {
124 new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
Juan Quintela6ee093c2009-09-10 03:04:26 +0200125 get_ticks_per_sec(), s->freq);
Alex Blighbc72ad62013-08-21 16:03:08 +0100126 timer_mod(s->timer[i].qtimer, new_qemu);
balroga171fe32007-04-30 01:48:07 +0000127 }
128}
129
130static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
131{
Dmitry Eremin-Solenikovd353eb42011-02-20 16:50:33 +0300132 PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
balroga171fe32007-04-30 01:48:07 +0000133 uint32_t now_vm;
134 uint64_t new_qemu;
135 static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
136 int counter;
137
138 if (s->tm4[n].control & (1 << 7))
139 counter = n;
140 else
141 counter = counters[n];
142
143 if (!s->tm4[counter].freq) {
Alex Blighbc72ad62013-08-21 16:03:08 +0100144 timer_del(s->tm4[n].tm.qtimer);
balroga171fe32007-04-30 01:48:07 +0000145 return;
146 }
147
148 now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
149 s->tm4[counter].lastload,
Juan Quintela6ee093c2009-09-10 03:04:26 +0200150 s->tm4[counter].freq, get_ticks_per_sec());
balroga171fe32007-04-30 01:48:07 +0000151
balrog3bdd58a2007-05-08 22:51:00 +0000152 new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
Juan Quintela6ee093c2009-09-10 03:04:26 +0200153 get_ticks_per_sec(), s->tm4[counter].freq);
Alex Blighbc72ad62013-08-21 16:03:08 +0100154 timer_mod(s->tm4[n].tm.qtimer, new_qemu);
balroga171fe32007-04-30 01:48:07 +0000155}
156
Avi Kivitya8170e52012-10-23 12:30:10 +0200157static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
Benoît Canetb755bde2011-10-30 14:50:16 +0100158 unsigned size)
balroga171fe32007-04-30 01:48:07 +0000159{
Dmitry Eremin-Solenikovd353eb42011-02-20 16:50:33 +0300160 PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
balroga171fe32007-04-30 01:48:07 +0000161 int tm = 0;
162
balroga171fe32007-04-30 01:48:07 +0000163 switch (offset) {
164 case OSMR3: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000165 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000166 case OSMR2: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000167 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000168 case OSMR1: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000169 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000170 case OSMR0:
171 return s->timer[tm].value;
172 case OSMR11: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000173 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000174 case OSMR10: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000175 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000176 case OSMR9: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000177 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000178 case OSMR8: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000179 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000180 case OSMR7: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000181 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000182 case OSMR6: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000183 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000184 case OSMR5: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000185 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000186 case OSMR4:
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100187 if (!pxa2xx_timer_has_tm4(s))
balroga171fe32007-04-30 01:48:07 +0000188 goto badreg;
balrog3bdd58a2007-05-08 22:51:00 +0000189 return s->tm4[tm].tm.value;
balroga171fe32007-04-30 01:48:07 +0000190 case OSCR:
Alex Blighbc72ad62013-08-21 16:03:08 +0100191 return s->clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
Juan Quintela6ee093c2009-09-10 03:04:26 +0200192 s->lastload, s->freq, get_ticks_per_sec());
balroga171fe32007-04-30 01:48:07 +0000193 case OSCR11: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000194 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000195 case OSCR10: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000196 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000197 case OSCR9: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000198 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000199 case OSCR8: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000200 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000201 case OSCR7: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000202 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000203 case OSCR6: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000204 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000205 case OSCR5: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000206 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000207 case OSCR4:
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100208 if (!pxa2xx_timer_has_tm4(s))
balroga171fe32007-04-30 01:48:07 +0000209 goto badreg;
210
211 if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
212 if (s->tm4[tm - 1].freq)
213 s->snapshot = s->tm4[tm - 1].clock + muldiv64(
Alex Blighbc72ad62013-08-21 16:03:08 +0100214 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
balroga171fe32007-04-30 01:48:07 +0000215 s->tm4[tm - 1].lastload,
Juan Quintela6ee093c2009-09-10 03:04:26 +0200216 s->tm4[tm - 1].freq, get_ticks_per_sec());
balroga171fe32007-04-30 01:48:07 +0000217 else
218 s->snapshot = s->tm4[tm - 1].clock;
219 }
220
221 if (!s->tm4[tm].freq)
222 return s->tm4[tm].clock;
Alex Blighbc72ad62013-08-21 16:03:08 +0100223 return s->tm4[tm].clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
Juan Quintela6ee093c2009-09-10 03:04:26 +0200224 s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec());
balroga171fe32007-04-30 01:48:07 +0000225 case OIER:
226 return s->irq_enabled;
227 case OSSR: /* Status register */
228 return s->events;
229 case OWER:
230 return s->reset3;
231 case OMCR11: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000232 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000233 case OMCR10: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000234 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000235 case OMCR9: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000236 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000237 case OMCR8: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000238 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000239 case OMCR7: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000240 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000241 case OMCR6: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000242 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000243 case OMCR5: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000244 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000245 case OMCR4:
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100246 if (!pxa2xx_timer_has_tm4(s))
balroga171fe32007-04-30 01:48:07 +0000247 goto badreg;
248 return s->tm4[tm].control;
249 case OSNR:
250 return s->snapshot;
251 default:
252 badreg:
Paul Brook2ac71172009-05-08 02:35:15 +0100253 hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
balroga171fe32007-04-30 01:48:07 +0000254 }
255
256 return 0;
257}
258
Avi Kivitya8170e52012-10-23 12:30:10 +0200259static void pxa2xx_timer_write(void *opaque, hwaddr offset,
Benoît Canetb755bde2011-10-30 14:50:16 +0100260 uint64_t value, unsigned size)
balroga171fe32007-04-30 01:48:07 +0000261{
262 int i, tm = 0;
Dmitry Eremin-Solenikovd353eb42011-02-20 16:50:33 +0300263 PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
balroga171fe32007-04-30 01:48:07 +0000264
balroga171fe32007-04-30 01:48:07 +0000265 switch (offset) {
266 case OSMR3: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000267 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000268 case OSMR2: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000269 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000270 case OSMR1: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000271 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000272 case OSMR0:
273 s->timer[tm].value = value;
Alex Blighbc72ad62013-08-21 16:03:08 +0100274 pxa2xx_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
balroga171fe32007-04-30 01:48:07 +0000275 break;
276 case OSMR11: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000277 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000278 case OSMR10: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000279 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000280 case OSMR9: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000281 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000282 case OSMR8: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000283 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000284 case OSMR7: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000285 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000286 case OSMR6: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000287 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000288 case OSMR5: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000289 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000290 case OSMR4:
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100291 if (!pxa2xx_timer_has_tm4(s))
balroga171fe32007-04-30 01:48:07 +0000292 goto badreg;
balrog3bdd58a2007-05-08 22:51:00 +0000293 s->tm4[tm].tm.value = value;
Alex Blighbc72ad62013-08-21 16:03:08 +0100294 pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
balroga171fe32007-04-30 01:48:07 +0000295 break;
296 case OSCR:
297 s->oldclock = s->clock;
Alex Blighbc72ad62013-08-21 16:03:08 +0100298 s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
balroga171fe32007-04-30 01:48:07 +0000299 s->clock = value;
300 pxa2xx_timer_update(s, s->lastload);
301 break;
302 case OSCR11: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000303 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000304 case OSCR10: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000305 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000306 case OSCR9: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000307 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000308 case OSCR8: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000309 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000310 case OSCR7: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000311 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000312 case OSCR6: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000313 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000314 case OSCR5: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000315 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000316 case OSCR4:
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100317 if (!pxa2xx_timer_has_tm4(s))
balroga171fe32007-04-30 01:48:07 +0000318 goto badreg;
319 s->tm4[tm].oldclock = s->tm4[tm].clock;
Alex Blighbc72ad62013-08-21 16:03:08 +0100320 s->tm4[tm].lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
balroga171fe32007-04-30 01:48:07 +0000321 s->tm4[tm].clock = value;
322 pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
323 break;
324 case OIER:
325 s->irq_enabled = value & 0xfff;
326 break;
327 case OSSR: /* Status register */
Andrzej Zaborowski8034ce72011-03-10 03:31:02 +0100328 value &= s->events;
balroga171fe32007-04-30 01:48:07 +0000329 s->events &= ~value;
Andrzej Zaborowski8034ce72011-03-10 03:31:02 +0100330 for (i = 0; i < 4; i ++, value >>= 1)
331 if (value & 1)
Andrzej Zaborowski5251d192011-03-03 14:24:25 +0100332 qemu_irq_lower(s->timer[i].irq);
Andrzej Zaborowski8034ce72011-03-10 03:31:02 +0100333 if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
334 qemu_irq_lower(s->irq4);
balroga171fe32007-04-30 01:48:07 +0000335 break;
336 case OWER: /* XXX: Reset on OSMR3 match? */
337 s->reset3 = value;
338 break;
339 case OMCR7: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000340 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000341 case OMCR6: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000342 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000343 case OMCR5: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000344 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000345 case OMCR4:
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100346 if (!pxa2xx_timer_has_tm4(s))
balroga171fe32007-04-30 01:48:07 +0000347 goto badreg;
348 s->tm4[tm].control = value & 0x0ff;
349 /* XXX Stop if running (shouldn't happen) */
350 if ((value & (1 << 7)) || tm == 0)
351 s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
352 else {
353 s->tm4[tm].freq = 0;
Alex Blighbc72ad62013-08-21 16:03:08 +0100354 pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
balroga171fe32007-04-30 01:48:07 +0000355 }
356 break;
357 case OMCR11: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000358 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000359 case OMCR10: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000360 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000361 case OMCR9: tm ++;
Peter Maydellde160172013-01-21 12:50:56 +0000362 /* fall through */
balroga171fe32007-04-30 01:48:07 +0000363 case OMCR8: tm += 4;
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100364 if (!pxa2xx_timer_has_tm4(s))
balroga171fe32007-04-30 01:48:07 +0000365 goto badreg;
366 s->tm4[tm].control = value & 0x3ff;
367 /* XXX Stop if running (shouldn't happen) */
368 if ((value & (1 << 7)) || !(tm & 1))
369 s->tm4[tm].freq =
370 pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)];
371 else {
372 s->tm4[tm].freq = 0;
Alex Blighbc72ad62013-08-21 16:03:08 +0100373 pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm);
balroga171fe32007-04-30 01:48:07 +0000374 }
375 break;
376 default:
377 badreg:
Paul Brook2ac71172009-05-08 02:35:15 +0100378 hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
balroga171fe32007-04-30 01:48:07 +0000379 }
380}
381
Benoît Canetb755bde2011-10-30 14:50:16 +0100382static const MemoryRegionOps pxa2xx_timer_ops = {
383 .read = pxa2xx_timer_read,
384 .write = pxa2xx_timer_write,
385 .endianness = DEVICE_NATIVE_ENDIAN,
balroga171fe32007-04-30 01:48:07 +0000386};
387
388static void pxa2xx_timer_tick(void *opaque)
389{
Paul Brookbc24a222009-05-10 01:44:56 +0100390 PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100391 PXA2xxTimerInfo *i = t->info;
balroga171fe32007-04-30 01:48:07 +0000392
393 if (i->irq_enabled & (1 << t->num)) {
balroga171fe32007-04-30 01:48:07 +0000394 i->events |= 1 << t->num;
Andrzej Zaborowski5251d192011-03-03 14:24:25 +0100395 qemu_irq_raise(t->irq);
balroga171fe32007-04-30 01:48:07 +0000396 }
397
398 if (t->num == 3)
399 if (i->reset3 & 1) {
400 i->reset3 = 0;
balrog3f582262007-05-23 21:47:51 +0000401 qemu_system_reset_request();
balroga171fe32007-04-30 01:48:07 +0000402 }
403}
404
405static void pxa2xx_timer_tick4(void *opaque)
406{
Paul Brookbc24a222009-05-10 01:44:56 +0100407 PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
Dmitry Eremin-Solenikovd353eb42011-02-20 16:50:33 +0300408 PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
balroga171fe32007-04-30 01:48:07 +0000409
balrog3bdd58a2007-05-08 22:51:00 +0000410 pxa2xx_timer_tick(&t->tm);
balroga171fe32007-04-30 01:48:07 +0000411 if (t->control & (1 << 3))
412 t->clock = 0;
413 if (t->control & (1 << 6))
Alex Blighbc72ad62013-08-21 16:03:08 +0100414 pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4);
Dmitry Eremin-Solenikov4ff927c2011-03-04 03:40:59 +0300415 if (i->events & 0xff0)
416 qemu_irq_raise(i->irq4);
balroga171fe32007-04-30 01:48:07 +0000417}
418
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100419static int pxa25x_timer_post_load(void *opaque, int version_id)
balrogaa941b92007-05-24 18:50:09 +0000420{
Dmitry Eremin-Solenikovd353eb42011-02-20 16:50:33 +0300421 PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
balrogaa941b92007-05-24 18:50:09 +0000422 int64_t now;
423 int i;
424
Alex Blighbc72ad62013-08-21 16:03:08 +0100425 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
balrogaa941b92007-05-24 18:50:09 +0000426 pxa2xx_timer_update(s, now);
427
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100428 if (pxa2xx_timer_has_tm4(s))
429 for (i = 0; i < 8; i ++)
balrogaa941b92007-05-24 18:50:09 +0000430 pxa2xx_timer_update4(s, now, i);
balrogaa941b92007-05-24 18:50:09 +0000431
432 return 0;
433}
434
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100435static int pxa2xx_timer_init(SysBusDevice *dev)
balroga171fe32007-04-30 01:48:07 +0000436{
Andreas Färberfeea4362013-07-27 15:20:20 +0200437 PXA2xxTimerInfo *s = PXA2XX_TIMER(dev);
balroga171fe32007-04-30 01:48:07 +0000438 int i;
balroga171fe32007-04-30 01:48:07 +0000439
balroga171fe32007-04-30 01:48:07 +0000440 s->irq_enabled = 0;
441 s->oldclock = 0;
442 s->clock = 0;
Alex Blighbc72ad62013-08-21 16:03:08 +0100443 s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
balroga171fe32007-04-30 01:48:07 +0000444 s->reset3 = 0;
balroga171fe32007-04-30 01:48:07 +0000445
446 for (i = 0; i < 4; i ++) {
447 s->timer[i].value = 0;
Andrzej Zaborowski5251d192011-03-03 14:24:25 +0100448 sysbus_init_irq(dev, &s->timer[i].irq);
balroga171fe32007-04-30 01:48:07 +0000449 s->timer[i].info = s;
450 s->timer[i].num = i;
Alex Blighbc72ad62013-08-21 16:03:08 +0100451 s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
balroga171fe32007-04-30 01:48:07 +0000452 pxa2xx_timer_tick, &s->timer[i]);
453 }
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100454 if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
Dmitry Eremin-Solenikov4ff927c2011-03-04 03:40:59 +0300455 sysbus_init_irq(dev, &s->irq4);
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100456
457 for (i = 0; i < 8; i ++) {
458 s->tm4[i].tm.value = 0;
459 s->tm4[i].tm.info = s;
460 s->tm4[i].tm.num = i + 4;
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100461 s->tm4[i].freq = 0;
462 s->tm4[i].control = 0x0;
Alex Blighbc72ad62013-08-21 16:03:08 +0100463 s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100464 pxa2xx_timer_tick4, &s->tm4[i]);
465 }
466 }
balroga171fe32007-04-30 01:48:07 +0000467
Paolo Bonzini853dca12013-06-06 21:25:08 -0400468 memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_timer_ops, s,
Benoît Canetb755bde2011-10-30 14:50:16 +0100469 "pxa2xx-timer", 0x00001000);
Avi Kivity750ecd42011-11-27 11:38:10 +0200470 sysbus_init_mmio(dev, &s->iomem);
balrogaa941b92007-05-24 18:50:09 +0000471
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100472 return 0;
balroga171fe32007-04-30 01:48:07 +0000473}
474
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100475static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
476 .name = "pxa2xx_timer0",
Andrzej Zaborowski8034ce72011-03-10 03:31:02 +0100477 .version_id = 2,
478 .minimum_version_id = 2,
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100479 .fields = (VMStateField[]) {
480 VMSTATE_UINT32(value, PXA2xxTimer0),
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100481 VMSTATE_END_OF_LIST(),
482 },
483};
484
485static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
486 .name = "pxa2xx_timer4",
487 .version_id = 1,
488 .minimum_version_id = 1,
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100489 .fields = (VMStateField[]) {
490 VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
491 vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
492 VMSTATE_INT32(oldclock, PXA2xxTimer4),
493 VMSTATE_INT32(clock, PXA2xxTimer4),
494 VMSTATE_UINT64(lastload, PXA2xxTimer4),
495 VMSTATE_UINT32(freq, PXA2xxTimer4),
496 VMSTATE_UINT32(control, PXA2xxTimer4),
497 VMSTATE_END_OF_LIST(),
498 },
499};
500
501static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
balroga171fe32007-04-30 01:48:07 +0000502{
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100503 return pxa2xx_timer_has_tm4(opaque);
balroga171fe32007-04-30 01:48:07 +0000504}
505
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100506static const VMStateDescription vmstate_pxa2xx_timer_regs = {
507 .name = "pxa2xx_timer",
508 .version_id = 1,
509 .minimum_version_id = 1,
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100510 .post_load = pxa25x_timer_post_load,
511 .fields = (VMStateField[]) {
512 VMSTATE_INT32(clock, PXA2xxTimerInfo),
513 VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
514 VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
515 VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
516 vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
517 VMSTATE_UINT32(events, PXA2xxTimerInfo),
518 VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
519 VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
520 VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
521 VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
522 pxa2xx_timer_has_tm4_test, 0,
523 vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
524 VMSTATE_END_OF_LIST(),
balroga171fe32007-04-30 01:48:07 +0000525 }
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100526};
527
Anthony Liguori999e12b2012-01-24 13:12:29 -0600528static Property pxa25x_timer_dev_properties[] = {
529 DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
530 DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
Andreas Färberfeea4362013-07-27 15:20:20 +0200531 PXA2XX_TIMER_HAVE_TM4, false),
Anthony Liguori999e12b2012-01-24 13:12:29 -0600532 DEFINE_PROP_END_OF_LIST(),
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100533};
534
Anthony Liguori999e12b2012-01-24 13:12:29 -0600535static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data)
536{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600537 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600538
Anthony Liguori39bffca2011-12-07 21:34:16 -0600539 dc->desc = "PXA25x timer";
Anthony Liguori39bffca2011-12-07 21:34:16 -0600540 dc->props = pxa25x_timer_dev_properties;
Anthony Liguori999e12b2012-01-24 13:12:29 -0600541}
542
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100543static const TypeInfo pxa25x_timer_dev_info = {
Anthony Liguori39bffca2011-12-07 21:34:16 -0600544 .name = "pxa25x-timer",
Andreas Färberfeea4362013-07-27 15:20:20 +0200545 .parent = TYPE_PXA2XX_TIMER,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600546 .instance_size = sizeof(PXA2xxTimerInfo),
547 .class_init = pxa25x_timer_dev_class_init,
Anthony Liguori999e12b2012-01-24 13:12:29 -0600548};
549
550static Property pxa27x_timer_dev_properties[] = {
551 DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
552 DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
Andreas Färberfeea4362013-07-27 15:20:20 +0200553 PXA2XX_TIMER_HAVE_TM4, true),
Anthony Liguori999e12b2012-01-24 13:12:29 -0600554 DEFINE_PROP_END_OF_LIST(),
555};
556
557static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
558{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600559 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600560
Anthony Liguori39bffca2011-12-07 21:34:16 -0600561 dc->desc = "PXA27x timer";
Anthony Liguori39bffca2011-12-07 21:34:16 -0600562 dc->props = pxa27x_timer_dev_properties;
Anthony Liguori999e12b2012-01-24 13:12:29 -0600563}
564
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100565static const TypeInfo pxa27x_timer_dev_info = {
Anthony Liguori39bffca2011-12-07 21:34:16 -0600566 .name = "pxa27x-timer",
Andreas Färberfeea4362013-07-27 15:20:20 +0200567 .parent = TYPE_PXA2XX_TIMER,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600568 .instance_size = sizeof(PXA2xxTimerInfo),
569 .class_init = pxa27x_timer_dev_class_init,
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100570};
571
Andreas Färberfeea4362013-07-27 15:20:20 +0200572static void pxa2xx_timer_class_init(ObjectClass *oc, void *data)
573{
574 DeviceClass *dc = DEVICE_CLASS(oc);
575 SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(oc);
576
577 sdc->init = pxa2xx_timer_init;
578 dc->vmsd = &vmstate_pxa2xx_timer_regs;
579}
580
581static const TypeInfo pxa2xx_timer_type_info = {
582 .name = TYPE_PXA2XX_TIMER,
583 .parent = TYPE_SYS_BUS_DEVICE,
584 .instance_size = sizeof(PXA2xxTimerInfo),
585 .abstract = true,
586 .class_init = pxa2xx_timer_class_init,
587};
588
Andreas Färber83f7d432012-02-09 15:20:55 +0100589static void pxa2xx_timer_register_types(void)
Dmitry Eremin-Solenikov797e9542011-03-03 14:14:44 +0100590{
Andreas Färberfeea4362013-07-27 15:20:20 +0200591 type_register_static(&pxa2xx_timer_type_info);
Anthony Liguori39bffca2011-12-07 21:34:16 -0600592 type_register_static(&pxa25x_timer_dev_info);
593 type_register_static(&pxa27x_timer_dev_info);
Andreas Färber83f7d432012-02-09 15:20:55 +0100594}
595
596type_init(pxa2xx_timer_register_types)