xref: /openbmc/qemu/hw/timer/arm_timer.c (revision 7f709ce7)
1 /*
2  * ARM PrimeCell Timer modules.
3  *
4  * Copyright (c) 2005-2006 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licensed under the GPL.
8  */
9 
10 #include "qemu/osdep.h"
11 #include "hw/sysbus.h"
12 #include "qemu/timer.h"
13 #include "qemu-common.h"
14 #include "hw/qdev.h"
15 #include "hw/ptimer.h"
16 #include "qemu/main-loop.h"
17 #include "qemu/log.h"
18 
19 /* Common timer implementation.  */
20 
21 #define TIMER_CTRL_ONESHOT      (1 << 0)
22 #define TIMER_CTRL_32BIT        (1 << 1)
23 #define TIMER_CTRL_DIV1         (0 << 2)
24 #define TIMER_CTRL_DIV16        (1 << 2)
25 #define TIMER_CTRL_DIV256       (2 << 2)
26 #define TIMER_CTRL_IE           (1 << 5)
27 #define TIMER_CTRL_PERIODIC     (1 << 6)
28 #define TIMER_CTRL_ENABLE       (1 << 7)
29 
30 typedef struct {
31     ptimer_state *timer;
32     uint32_t control;
33     uint32_t limit;
34     int freq;
35     int int_level;
36     qemu_irq irq;
37 } arm_timer_state;
38 
39 /* Check all active timers, and schedule the next timer interrupt.  */
40 
41 static void arm_timer_update(arm_timer_state *s)
42 {
43     /* Update interrupts.  */
44     if (s->int_level && (s->control & TIMER_CTRL_IE)) {
45         qemu_irq_raise(s->irq);
46     } else {
47         qemu_irq_lower(s->irq);
48     }
49 }
50 
51 static uint32_t arm_timer_read(void *opaque, hwaddr offset)
52 {
53     arm_timer_state *s = (arm_timer_state *)opaque;
54 
55     switch (offset >> 2) {
56     case 0: /* TimerLoad */
57     case 6: /* TimerBGLoad */
58         return s->limit;
59     case 1: /* TimerValue */
60         return ptimer_get_count(s->timer);
61     case 2: /* TimerControl */
62         return s->control;
63     case 4: /* TimerRIS */
64         return s->int_level;
65     case 5: /* TimerMIS */
66         if ((s->control & TIMER_CTRL_IE) == 0)
67             return 0;
68         return s->int_level;
69     default:
70         qemu_log_mask(LOG_GUEST_ERROR,
71                       "%s: Bad offset %x\n", __func__, (int)offset);
72         return 0;
73     }
74 }
75 
76 /* Reset the timer limit after settings have changed.  */
77 static void arm_timer_recalibrate(arm_timer_state *s, int reload)
78 {
79     uint32_t limit;
80 
81     if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
82         /* Free running.  */
83         if (s->control & TIMER_CTRL_32BIT)
84             limit = 0xffffffff;
85         else
86             limit = 0xffff;
87     } else {
88           /* Periodic.  */
89           limit = s->limit;
90     }
91     ptimer_set_limit(s->timer, limit, reload);
92 }
93 
94 static void arm_timer_write(void *opaque, hwaddr offset,
95                             uint32_t value)
96 {
97     arm_timer_state *s = (arm_timer_state *)opaque;
98     int freq;
99 
100     switch (offset >> 2) {
101     case 0: /* TimerLoad */
102         s->limit = value;
103         arm_timer_recalibrate(s, 1);
104         break;
105     case 1: /* TimerValue */
106         /* ??? Linux seems to want to write to this readonly register.
107            Ignore it.  */
108         break;
109     case 2: /* TimerControl */
110         if (s->control & TIMER_CTRL_ENABLE) {
111             /* Pause the timer if it is running.  This may cause some
112                inaccuracy dure to rounding, but avoids a whole lot of other
113                messyness.  */
114             ptimer_stop(s->timer);
115         }
116         s->control = value;
117         freq = s->freq;
118         /* ??? Need to recalculate expiry time after changing divisor.  */
119         switch ((value >> 2) & 3) {
120         case 1: freq >>= 4; break;
121         case 2: freq >>= 8; break;
122         }
123         arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
124         ptimer_set_freq(s->timer, freq);
125         if (s->control & TIMER_CTRL_ENABLE) {
126             /* Restart the timer if still enabled.  */
127             ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
128         }
129         break;
130     case 3: /* TimerIntClr */
131         s->int_level = 0;
132         break;
133     case 6: /* TimerBGLoad */
134         s->limit = value;
135         arm_timer_recalibrate(s, 0);
136         break;
137     default:
138         qemu_log_mask(LOG_GUEST_ERROR,
139                       "%s: Bad offset %x\n", __func__, (int)offset);
140     }
141     arm_timer_update(s);
142 }
143 
144 static void arm_timer_tick(void *opaque)
145 {
146     arm_timer_state *s = (arm_timer_state *)opaque;
147     s->int_level = 1;
148     arm_timer_update(s);
149 }
150 
151 static const VMStateDescription vmstate_arm_timer = {
152     .name = "arm_timer",
153     .version_id = 1,
154     .minimum_version_id = 1,
155     .fields = (VMStateField[]) {
156         VMSTATE_UINT32(control, arm_timer_state),
157         VMSTATE_UINT32(limit, arm_timer_state),
158         VMSTATE_INT32(int_level, arm_timer_state),
159         VMSTATE_PTIMER(timer, arm_timer_state),
160         VMSTATE_END_OF_LIST()
161     }
162 };
163 
164 static arm_timer_state *arm_timer_init(uint32_t freq)
165 {
166     arm_timer_state *s;
167     QEMUBH *bh;
168 
169     s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
170     s->freq = freq;
171     s->control = TIMER_CTRL_IE;
172 
173     bh = qemu_bh_new(arm_timer_tick, s);
174     s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
175     vmstate_register(NULL, -1, &vmstate_arm_timer, s);
176     return s;
177 }
178 
179 /* ARM PrimeCell SP804 dual timer module.
180  * Docs at
181  * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
182 */
183 
184 #define TYPE_SP804 "sp804"
185 #define SP804(obj) OBJECT_CHECK(SP804State, (obj), TYPE_SP804)
186 
187 typedef struct SP804State {
188     SysBusDevice parent_obj;
189 
190     MemoryRegion iomem;
191     arm_timer_state *timer[2];
192     uint32_t freq0, freq1;
193     int level[2];
194     qemu_irq irq;
195 } SP804State;
196 
197 static const uint8_t sp804_ids[] = {
198     /* Timer ID */
199     0x04, 0x18, 0x14, 0,
200     /* PrimeCell ID */
201     0xd, 0xf0, 0x05, 0xb1
202 };
203 
204 /* Merge the IRQs from the two component devices.  */
205 static void sp804_set_irq(void *opaque, int irq, int level)
206 {
207     SP804State *s = (SP804State *)opaque;
208 
209     s->level[irq] = level;
210     qemu_set_irq(s->irq, s->level[0] || s->level[1]);
211 }
212 
213 static uint64_t sp804_read(void *opaque, hwaddr offset,
214                            unsigned size)
215 {
216     SP804State *s = (SP804State *)opaque;
217 
218     if (offset < 0x20) {
219         return arm_timer_read(s->timer[0], offset);
220     }
221     if (offset < 0x40) {
222         return arm_timer_read(s->timer[1], offset - 0x20);
223     }
224 
225     /* TimerPeriphID */
226     if (offset >= 0xfe0 && offset <= 0xffc) {
227         return sp804_ids[(offset - 0xfe0) >> 2];
228     }
229 
230     switch (offset) {
231     /* Integration Test control registers, which we won't support */
232     case 0xf00: /* TimerITCR */
233     case 0xf04: /* TimerITOP (strictly write only but..) */
234         qemu_log_mask(LOG_UNIMP,
235                       "%s: integration test registers unimplemented\n",
236                       __func__);
237         return 0;
238     }
239 
240     qemu_log_mask(LOG_GUEST_ERROR,
241                   "%s: Bad offset %x\n", __func__, (int)offset);
242     return 0;
243 }
244 
245 static void sp804_write(void *opaque, hwaddr offset,
246                         uint64_t value, unsigned size)
247 {
248     SP804State *s = (SP804State *)opaque;
249 
250     if (offset < 0x20) {
251         arm_timer_write(s->timer[0], offset, value);
252         return;
253     }
254 
255     if (offset < 0x40) {
256         arm_timer_write(s->timer[1], offset - 0x20, value);
257         return;
258     }
259 
260     /* Technically we could be writing to the Test Registers, but not likely */
261     qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
262                   __func__, (int)offset);
263 }
264 
265 static const MemoryRegionOps sp804_ops = {
266     .read = sp804_read,
267     .write = sp804_write,
268     .endianness = DEVICE_NATIVE_ENDIAN,
269 };
270 
271 static const VMStateDescription vmstate_sp804 = {
272     .name = "sp804",
273     .version_id = 1,
274     .minimum_version_id = 1,
275     .fields = (VMStateField[]) {
276         VMSTATE_INT32_ARRAY(level, SP804State, 2),
277         VMSTATE_END_OF_LIST()
278     }
279 };
280 
281 static void sp804_init(Object *obj)
282 {
283     SP804State *s = SP804(obj);
284     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
285 
286     sysbus_init_irq(sbd, &s->irq);
287     memory_region_init_io(&s->iomem, obj, &sp804_ops, s,
288                           "sp804", 0x1000);
289     sysbus_init_mmio(sbd, &s->iomem);
290 }
291 
292 static void sp804_realize(DeviceState *dev, Error **errp)
293 {
294     SP804State *s = SP804(dev);
295 
296     s->timer[0] = arm_timer_init(s->freq0);
297     s->timer[1] = arm_timer_init(s->freq1);
298     s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0);
299     s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1);
300 }
301 
302 /* Integrator/CP timer module.  */
303 
304 #define TYPE_INTEGRATOR_PIT "integrator_pit"
305 #define INTEGRATOR_PIT(obj) \
306     OBJECT_CHECK(icp_pit_state, (obj), TYPE_INTEGRATOR_PIT)
307 
308 typedef struct {
309     SysBusDevice parent_obj;
310 
311     MemoryRegion iomem;
312     arm_timer_state *timer[3];
313 } icp_pit_state;
314 
315 static uint64_t icp_pit_read(void *opaque, hwaddr offset,
316                              unsigned size)
317 {
318     icp_pit_state *s = (icp_pit_state *)opaque;
319     int n;
320 
321     /* ??? Don't know the PrimeCell ID for this device.  */
322     n = offset >> 8;
323     if (n > 2) {
324         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
325         return 0;
326     }
327 
328     return arm_timer_read(s->timer[n], offset & 0xff);
329 }
330 
331 static void icp_pit_write(void *opaque, hwaddr offset,
332                           uint64_t value, unsigned size)
333 {
334     icp_pit_state *s = (icp_pit_state *)opaque;
335     int n;
336 
337     n = offset >> 8;
338     if (n > 2) {
339         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
340         return;
341     }
342 
343     arm_timer_write(s->timer[n], offset & 0xff, value);
344 }
345 
346 static const MemoryRegionOps icp_pit_ops = {
347     .read = icp_pit_read,
348     .write = icp_pit_write,
349     .endianness = DEVICE_NATIVE_ENDIAN,
350 };
351 
352 static void icp_pit_init(Object *obj)
353 {
354     icp_pit_state *s = INTEGRATOR_PIT(obj);
355     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
356 
357     /* Timer 0 runs at the system clock speed (40MHz).  */
358     s->timer[0] = arm_timer_init(40000000);
359     /* The other two timers run at 1MHz.  */
360     s->timer[1] = arm_timer_init(1000000);
361     s->timer[2] = arm_timer_init(1000000);
362 
363     sysbus_init_irq(dev, &s->timer[0]->irq);
364     sysbus_init_irq(dev, &s->timer[1]->irq);
365     sysbus_init_irq(dev, &s->timer[2]->irq);
366 
367     memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s,
368                           "icp_pit", 0x1000);
369     sysbus_init_mmio(dev, &s->iomem);
370     /* This device has no state to save/restore.  The component timers will
371        save themselves.  */
372 }
373 
374 static const TypeInfo icp_pit_info = {
375     .name          = TYPE_INTEGRATOR_PIT,
376     .parent        = TYPE_SYS_BUS_DEVICE,
377     .instance_size = sizeof(icp_pit_state),
378     .instance_init = icp_pit_init,
379 };
380 
381 static Property sp804_properties[] = {
382     DEFINE_PROP_UINT32("freq0", SP804State, freq0, 1000000),
383     DEFINE_PROP_UINT32("freq1", SP804State, freq1, 1000000),
384     DEFINE_PROP_END_OF_LIST(),
385 };
386 
387 static void sp804_class_init(ObjectClass *klass, void *data)
388 {
389     DeviceClass *k = DEVICE_CLASS(klass);
390 
391     k->realize = sp804_realize;
392     k->props = sp804_properties;
393     k->vmsd = &vmstate_sp804;
394 }
395 
396 static const TypeInfo sp804_info = {
397     .name          = TYPE_SP804,
398     .parent        = TYPE_SYS_BUS_DEVICE,
399     .instance_size = sizeof(SP804State),
400     .instance_init = sp804_init,
401     .class_init    = sp804_class_init,
402 };
403 
404 static void arm_timer_register_types(void)
405 {
406     type_register_static(&icp_pit_info);
407     type_register_static(&sp804_info);
408 }
409 
410 type_init(arm_timer_register_types)
411