Break up vl.h.
[qemu] / hw / arm_timer.c
1 /*
2  * ARM PrimeCell Timer modules.
3  *
4  * Copyright (c) 2005-2006 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licenced under the GPL.
8  */
9
10 #include "hw.h"
11 #include "arm-misc.h"
12 #include "qemu-timer.h"
13
14 /* Common timer implementation.  */
15
16 #define TIMER_CTRL_ONESHOT      (1 << 0)
17 #define TIMER_CTRL_32BIT        (1 << 1)
18 #define TIMER_CTRL_DIV1         (0 << 2)
19 #define TIMER_CTRL_DIV16        (1 << 2)
20 #define TIMER_CTRL_DIV256       (2 << 2)
21 #define TIMER_CTRL_IE           (1 << 5)
22 #define TIMER_CTRL_PERIODIC     (1 << 6)
23 #define TIMER_CTRL_ENABLE       (1 << 7)
24
25 typedef struct {
26     ptimer_state *timer;
27     uint32_t control;
28     uint32_t limit;
29     int freq;
30     int int_level;
31     qemu_irq irq;
32 } arm_timer_state;
33
34 /* Check all active timers, and schedule the next timer interrupt.  */
35
36 static void arm_timer_update(arm_timer_state *s)
37 {
38     /* Update interrupts.  */
39     if (s->int_level && (s->control & TIMER_CTRL_IE)) {
40         qemu_irq_raise(s->irq);
41     } else {
42         qemu_irq_lower(s->irq);
43     }
44 }
45
46 uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
47 {
48     arm_timer_state *s = (arm_timer_state *)opaque;
49
50     switch (offset >> 2) {
51     case 0: /* TimerLoad */
52     case 6: /* TimerBGLoad */
53         return s->limit;
54     case 1: /* TimerValue */
55         return ptimer_get_count(s->timer);
56     case 2: /* TimerControl */
57         return s->control;
58     case 4: /* TimerRIS */
59         return s->int_level;
60     case 5: /* TimerMIS */
61         if ((s->control & TIMER_CTRL_IE) == 0)
62             return 0;
63         return s->int_level;
64     default:
65         cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n",
66                    (int)offset);
67         return 0;
68     }
69 }
70
71 /* Reset the timer limit after settings have changed.  */
72 static void arm_timer_recalibrate(arm_timer_state *s, int reload)
73 {
74     uint32_t limit;
75
76     if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
77         /* Free running.  */
78         if (s->control & TIMER_CTRL_32BIT)
79             limit = 0xffffffff;
80         else
81             limit = 0xffff;
82     } else {
83           /* Periodic.  */
84           limit = s->limit;
85     }
86     ptimer_set_limit(s->timer, limit, reload);
87 }
88
89 static void arm_timer_write(void *opaque, target_phys_addr_t offset,
90                             uint32_t value)
91 {
92     arm_timer_state *s = (arm_timer_state *)opaque;
93     int freq;
94
95     switch (offset >> 2) {
96     case 0: /* TimerLoad */
97         s->limit = value;
98         arm_timer_recalibrate(s, 1);
99         break;
100     case 1: /* TimerValue */
101         /* ??? Linux seems to want to write to this readonly register.
102            Ignore it.  */
103         break;
104     case 2: /* TimerControl */
105         if (s->control & TIMER_CTRL_ENABLE) {
106             /* Pause the timer if it is running.  This may cause some
107                inaccuracy dure to rounding, but avoids a whole lot of other
108                messyness.  */
109             ptimer_stop(s->timer);
110         }
111         s->control = value;
112         freq = s->freq;
113         /* ??? Need to recalculate expiry time after changing divisor.  */
114         switch ((value >> 2) & 3) {
115         case 1: freq >>= 4; break;
116         case 2: freq >>= 8; break;
117         }
118         arm_timer_recalibrate(s, 0);
119         ptimer_set_freq(s->timer, freq);
120         if (s->control & TIMER_CTRL_ENABLE) {
121             /* Restart the timer if still enabled.  */
122             ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
123         }
124         break;
125     case 3: /* TimerIntClr */
126         s->int_level = 0;
127         break;
128     case 6: /* TimerBGLoad */
129         s->limit = value;
130         arm_timer_recalibrate(s, 0);
131         break;
132     default:
133         cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n",
134                    (int)offset);
135     }
136     arm_timer_update(s);
137 }
138
139 static void arm_timer_tick(void *opaque)
140 {
141     arm_timer_state *s = (arm_timer_state *)opaque;
142     s->int_level = 1;
143     arm_timer_update(s);
144 }
145
146 static void *arm_timer_init(uint32_t freq, qemu_irq irq)
147 {
148     arm_timer_state *s;
149     QEMUBH *bh;
150
151     s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
152     s->irq = irq;
153     s->freq = freq;
154     s->control = TIMER_CTRL_IE;
155
156     bh = qemu_bh_new(arm_timer_tick, s);
157     s->timer = ptimer_init(bh);
158     /* ??? Save/restore.  */
159     return s;
160 }
161
162 /* ARM PrimeCell SP804 dual timer module.
163    Docs for this device don't seem to be publicly available.  This
164    implementation is based on guesswork, the linux kernel sources and the
165    Integrator/CP timer modules.  */
166
167 typedef struct {
168     void *timer[2];
169     int level[2];
170     uint32_t base;
171     qemu_irq irq;
172 } sp804_state;
173
174 /* Merge the IRQs from the two component devices.  */
175 static void sp804_set_irq(void *opaque, int irq, int level)
176 {
177     sp804_state *s = (sp804_state *)opaque;
178
179     s->level[irq] = level;
180     qemu_set_irq(s->irq, s->level[0] || s->level[1]);
181 }
182
183 static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
184 {
185     sp804_state *s = (sp804_state *)opaque;
186
187     /* ??? Don't know the PrimeCell ID for this device.  */
188     offset -= s->base;
189     if (offset < 0x20) {
190         return arm_timer_read(s->timer[0], offset);
191     } else {
192         return arm_timer_read(s->timer[1], offset - 0x20);
193     }
194 }
195
196 static void sp804_write(void *opaque, target_phys_addr_t offset,
197                         uint32_t value)
198 {
199     sp804_state *s = (sp804_state *)opaque;
200
201     offset -= s->base;
202     if (offset < 0x20) {
203         arm_timer_write(s->timer[0], offset, value);
204     } else {
205         arm_timer_write(s->timer[1], offset - 0x20, value);
206     }
207 }
208
209 static CPUReadMemoryFunc *sp804_readfn[] = {
210    sp804_read,
211    sp804_read,
212    sp804_read
213 };
214
215 static CPUWriteMemoryFunc *sp804_writefn[] = {
216    sp804_write,
217    sp804_write,
218    sp804_write
219 };
220
221 void sp804_init(uint32_t base, qemu_irq irq)
222 {
223     int iomemtype;
224     sp804_state *s;
225     qemu_irq *qi;
226
227     s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
228     qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
229     s->base = base;
230     s->irq = irq;
231     /* ??? The timers are actually configurable between 32kHz and 1MHz, but
232        we don't implement that.  */
233     s->timer[0] = arm_timer_init(1000000, qi[0]);
234     s->timer[1] = arm_timer_init(1000000, qi[1]);
235     iomemtype = cpu_register_io_memory(0, sp804_readfn,
236                                        sp804_writefn, s);
237     cpu_register_physical_memory(base, 0x00001000, iomemtype);
238     /* ??? Save/restore.  */
239 }
240
241
242 /* Integrator/CP timer module.  */
243
244 typedef struct {
245     void *timer[3];
246     uint32_t base;
247 } icp_pit_state;
248
249 static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
250 {
251     icp_pit_state *s = (icp_pit_state *)opaque;
252     int n;
253
254     /* ??? Don't know the PrimeCell ID for this device.  */
255     offset -= s->base;
256     n = offset >> 8;
257     if (n > 3)
258         cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n);
259
260     return arm_timer_read(s->timer[n], offset & 0xff);
261 }
262
263 static void icp_pit_write(void *opaque, target_phys_addr_t offset,
264                           uint32_t value)
265 {
266     icp_pit_state *s = (icp_pit_state *)opaque;
267     int n;
268
269     offset -= s->base;
270     n = offset >> 8;
271     if (n > 3)
272         cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n);
273
274     arm_timer_write(s->timer[n], offset & 0xff, value);
275 }
276
277
278 static CPUReadMemoryFunc *icp_pit_readfn[] = {
279    icp_pit_read,
280    icp_pit_read,
281    icp_pit_read
282 };
283
284 static CPUWriteMemoryFunc *icp_pit_writefn[] = {
285    icp_pit_write,
286    icp_pit_write,
287    icp_pit_write
288 };
289
290 void icp_pit_init(uint32_t base, qemu_irq *pic, int irq)
291 {
292     int iomemtype;
293     icp_pit_state *s;
294
295     s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
296     s->base = base;
297     /* Timer 0 runs at the system clock speed (40MHz).  */
298     s->timer[0] = arm_timer_init(40000000, pic[irq]);
299     /* The other two timers run at 1MHz.  */
300     s->timer[1] = arm_timer_init(1000000, pic[irq + 1]);
301     s->timer[2] = arm_timer_init(1000000, pic[irq + 2]);
302
303     iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
304                                        icp_pit_writefn, s);
305     cpu_register_physical_memory(base, 0x00001000, iomemtype);
306     /* ??? Save/restore.  */
307 }
308