Add PowerPC power-management state check callback.
[qemu] / hw / mcf5206.c
1 /*
2  * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
3  *
4  * Copyright (c) 2007 CodeSourcery.
5  *
6  * This code is licenced under the GPL
7  */
8 #include "vl.h"
9
10 /* General purpose timer module.  */
11 typedef struct {
12     uint16_t tmr;
13     uint16_t trr;
14     uint16_t tcr;
15     uint16_t ter;
16     ptimer_state *timer;
17     qemu_irq irq;
18     int irq_state;
19 } m5206_timer_state;
20
21 #define TMR_RST 0x01
22 #define TMR_CLK 0x06
23 #define TMR_FRR 0x08
24 #define TMR_ORI 0x10
25 #define TMR_OM  0x20
26 #define TMR_CE  0xc0
27
28 #define TER_CAP 0x01
29 #define TER_REF 0x02
30
31 static void m5206_timer_update(m5206_timer_state *s)
32 {
33     if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF))
34         qemu_irq_raise(s->irq);
35     else
36         qemu_irq_lower(s->irq);
37 }
38
39 static void m5206_timer_reset(m5206_timer_state *s)
40 {
41     s->tmr = 0;
42     s->trr = 0;
43 }
44
45 static void m5206_timer_recalibrate(m5206_timer_state *s)
46 {
47     int prescale;
48     int mode;
49
50     ptimer_stop(s->timer);
51
52     if ((s->tmr & TMR_RST) == 0)
53         return;
54
55     prescale = (s->tmr >> 8) + 1;
56     mode = (s->tmr >> 1) & 3;
57     if (mode == 2)
58         prescale *= 16;
59
60     if (mode == 3 || mode == 0)
61         cpu_abort(cpu_single_env,
62                   "m5206_timer: mode %d not implemented\n", mode);
63     if ((s->tmr & TMR_FRR) == 0)
64         cpu_abort(cpu_single_env,
65                   "m5206_timer: free running mode not implemented\n");
66
67     /* Assume 66MHz system clock.  */
68     ptimer_set_freq(s->timer, 66000000 / prescale);
69
70     ptimer_set_limit(s->timer, s->trr, 0);
71
72     ptimer_run(s->timer, 0);
73 }
74
75 static void m5206_timer_trigger(void *opaque)
76 {
77     m5206_timer_state *s = (m5206_timer_state *)opaque;
78     s->ter |= TER_REF;
79     m5206_timer_update(s);
80 }
81
82 static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr)
83 {
84     switch (addr) {
85     case 0:
86         return s->tmr;
87     case 4:
88         return s->trr;
89     case 8:
90         return s->tcr;
91     case 0xc:
92         return s->trr - ptimer_get_count(s->timer);
93     case 0x11:
94         return s->ter;
95     default:
96         return 0;
97     }
98 }
99
100 static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
101 {
102     switch (addr) {
103     case 0:
104         if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) {
105             m5206_timer_reset(s);
106         }
107         s->tmr = val;
108         m5206_timer_recalibrate(s);
109         break;
110     case 4:
111         s->trr = val;
112         m5206_timer_recalibrate(s);
113         break;
114     case 8:
115         s->tcr = val;
116         break;
117     case 0xc:
118         ptimer_set_count(s->timer, val);
119         break;
120     case 0x11:
121         s->ter &= ~val;
122         break;
123     default:
124         break;
125     }
126     m5206_timer_update(s);
127 }
128
129 static m5206_timer_state *m5206_timer_init(qemu_irq irq)
130 {
131     m5206_timer_state *s;
132     QEMUBH *bh;
133
134     s = (m5206_timer_state *)qemu_mallocz(sizeof(m5206_timer_state));
135     bh = qemu_bh_new(m5206_timer_trigger, s);
136     s->timer = ptimer_init(bh);
137     s->irq = irq;
138     m5206_timer_reset(s);
139     return s;
140 }
141
142 /* System Integration Module.  */
143
144 typedef struct {
145     CPUState *env;
146     m5206_timer_state *timer[2];
147     void *uart[2];
148     uint8_t scr;
149     uint8_t icr[14];
150     uint16_t imr; /* 1 == interrupt is masked.  */
151     uint16_t ipr;
152     uint8_t rsr;
153     uint8_t swivr;
154     uint8_t par;
155     /* Include the UART vector registers here.  */
156     uint8_t uivr[2];
157 } m5206_mbar_state;
158
159 /* Interrupt controller.  */
160
161 static int m5206_find_pending_irq(m5206_mbar_state *s)
162 {
163     int level;
164     int vector;
165     uint16_t active;
166     int i;
167
168     level = 0;
169     vector = 0;
170     active = s->ipr & ~s->imr;
171     if (!active)
172         return 0;
173
174     for (i = 1; i < 14; i++) {
175         if (active & (1 << i)) {
176             if ((s->icr[i] & 0x1f) > level) {
177                 level = s->icr[i] & 0x1f;
178                 vector = i;
179             }
180         }
181     }
182
183     if (level < 4)
184         vector = 0;
185
186     return vector;
187 }
188
189 static void m5206_mbar_update(m5206_mbar_state *s)
190 {
191     int irq;
192     int vector;
193     int level;
194
195     irq = m5206_find_pending_irq(s);
196     if (irq) {
197         int tmp;
198         tmp = s->icr[irq];
199         level = (tmp >> 2) & 7;
200         if (tmp & 0x80) {
201             /* Autovector.  */
202             vector = 24 + level;
203         } else {
204             switch (irq) {
205             case 8: /* SWT */
206                 vector = s->swivr;
207                 break;
208             case 12: /* UART1 */
209                 vector = s->uivr[0];
210                 break;
211             case 13: /* UART2 */
212                 vector = s->uivr[1];
213                 break;
214             default:
215                 /* Unknown vector.  */
216                 fprintf(stderr, "Unhandled vector for IRQ %d\n", irq);
217                 vector = 0xf;
218                 break;
219             }
220         }
221     } else {
222         level = 0;
223         vector = 0;
224     }
225     m68k_set_irq_level(s->env, level, vector);
226 }
227
228 static void m5206_mbar_set_irq(void *opaque, int irq, int level)
229 {
230     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
231     if (level) {
232         s->ipr |= 1 << irq;
233     } else {
234         s->ipr &= ~(1 << irq);
235     }
236     m5206_mbar_update(s);
237 }
238
239 /* System Integration Module.  */
240
241 static void m5206_mbar_reset(m5206_mbar_state *s)
242 {
243     s->scr = 0xc0;
244     s->icr[1] = 0x04;
245     s->icr[2] = 0x08;
246     s->icr[3] = 0x0c;
247     s->icr[4] = 0x10;
248     s->icr[5] = 0x14;
249     s->icr[6] = 0x18;
250     s->icr[7] = 0x1c;
251     s->icr[8] = 0x1c;
252     s->icr[9] = 0x80;
253     s->icr[10] = 0x80;
254     s->icr[11] = 0x80;
255     s->icr[12] = 0x00;
256     s->icr[13] = 0x00;
257     s->imr = 0x3ffe;
258     s->rsr = 0x80;
259     s->swivr = 0x0f;
260     s->par = 0;
261 }
262
263 static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset)
264 {
265     if (offset >= 0x100 && offset < 0x120) {
266         return m5206_timer_read(s->timer[0], offset - 0x100);
267     } else if (offset >= 0x120 && offset < 0x140) {
268         return m5206_timer_read(s->timer[1], offset - 0x120);
269     } else if (offset >= 0x140 && offset < 0x160) {
270         return mcf_uart_read(s->uart[0], offset - 0x140);
271     } else if (offset >= 0x180 && offset < 0x1a0) {
272         return mcf_uart_read(s->uart[1], offset - 0x180);
273     }
274     switch (offset) {
275     case 0x03: return s->scr;
276     case 0x14 ... 0x20: return s->icr[offset - 0x13];
277     case 0x36: return s->imr;
278     case 0x3a: return s->ipr;
279     case 0x40: return s->rsr;
280     case 0x41: return 0;
281     case 0x42: return s->swivr;
282     case 0x50:
283         /* DRAM mask register.  */
284         /* FIXME: currently hardcoded to 128Mb.  */
285         {
286             uint32_t mask = ~0;
287             while (mask > ram_size)
288                 mask >>= 1;
289             return mask & 0x0ffe0000;
290         }
291     case 0x5c: return 1; /* DRAM bank 1 empty.  */
292     case 0xcb: return s->par;
293     case 0x170: return s->uivr[0];
294     case 0x1b0: return s->uivr[1];
295     }
296     cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
297     return 0;
298 }
299
300 static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
301                              uint32_t value)
302 {
303     if (offset >= 0x100 && offset < 0x120) {
304         m5206_timer_write(s->timer[0], offset - 0x100, value);
305         return;
306     } else if (offset >= 0x120 && offset < 0x140) {
307         m5206_timer_write(s->timer[1], offset - 0x120, value);
308         return;
309     } else if (offset >= 0x140 && offset < 0x160) {
310         mcf_uart_write(s->uart[0], offset - 0x140, value);
311         return;
312     } else if (offset >= 0x180 && offset < 0x1a0) {
313         mcf_uart_write(s->uart[1], offset - 0x180, value);
314         return;
315     }
316     switch (offset) {
317     case 0x03:
318         s->scr = value;
319         break;
320     case 0x14 ... 0x20:
321         s->icr[offset - 0x13] = value;
322         m5206_mbar_update(s);
323         break;
324     case 0x36:
325         s->imr = value;
326         m5206_mbar_update(s);
327         break;
328     case 0x40:
329         s->rsr &= ~value;
330         break;
331     case 0x41:
332         /* TODO: implement watchdog.  */
333         break;
334     case 0x42:
335         s->swivr = value;
336         break;
337     case 0xcb:
338         s->par = value;
339         break;
340     case 0x170:
341         s->uivr[0] = value;
342         break;
343     case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
344         /* Not implemented: UART Output port bits.  */
345         break;
346     case 0x1b0:
347         s->uivr[1] = value;
348         break;
349     default:
350         cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
351         break;
352     }
353 }
354
355 /* Internal peripherals use a variety of register widths.
356    This lookup table allows a single routine to handle all of them.  */
357 static const int m5206_mbar_width[] =
358 {
359   /* 000-040 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  2, 2, 2, 2,
360   /* 040-080 */ 1, 2, 2, 2,  4, 1, 2, 4,  1, 2, 4, 2,  2, 4, 2, 2,
361   /* 080-0c0 */ 4, 2, 2, 4,  2, 2, 4, 2,  2, 4, 2, 2,  4, 2, 2, 4,
362   /* 0c0-100 */ 2, 2, 1, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
363   /* 100-140 */ 2, 2, 2, 2,  1, 0, 0, 0,  2, 2, 2, 2,  1, 0, 0, 0,
364   /* 140-180 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
365   /* 180-1c0 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
366   /* 1c0-200 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
367 };
368
369 static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset);
370 static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset);
371
372 static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset)
373 {
374     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
375     offset &= 0x3ff;
376     if (offset > 0x200) {
377         cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
378     }
379     if (m5206_mbar_width[offset >> 2] > 1) {
380         uint16_t val;
381         val = m5206_mbar_readw(opaque, offset & ~1);
382         if ((offset & 1) == 0) {
383             val >>= 8;
384         }
385         return val & 0xff;
386     }
387     return m5206_mbar_read(s, offset);
388 }
389
390 static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset)
391 {
392     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
393     int width;
394     offset &= 0x3ff;
395     if (offset > 0x200) {
396         cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
397     }
398     width = m5206_mbar_width[offset >> 2];
399     if (width > 2) {
400         uint32_t val;
401         val = m5206_mbar_readl(opaque, offset & ~3);
402         if ((offset & 3) == 0)
403             val >>= 16;
404         return val & 0xffff;
405     } else if (width < 2) {
406         uint16_t val;
407         val = m5206_mbar_readb(opaque, offset) << 8;
408         val |= m5206_mbar_readb(opaque, offset + 1);
409         return val;
410     }
411     return m5206_mbar_read(s, offset);
412 }
413
414 static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset)
415 {
416     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
417     int width;
418     offset &= 0x3ff;
419     if (offset > 0x200) {
420         cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
421     }
422     width = m5206_mbar_width[offset >> 2];
423     if (width < 4) {
424         uint32_t val;
425         val = m5206_mbar_readw(opaque, offset) << 16;
426         val |= m5206_mbar_readw(opaque, offset + 2);
427         return val;
428     }
429     return m5206_mbar_read(s, offset);
430 }
431
432 static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
433                               uint32_t value);
434 static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
435                               uint32_t value);
436
437 static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset,
438                               uint32_t value)
439 {
440     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
441     int width;
442     offset &= 0x3ff;
443     if (offset > 0x200) {
444         cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
445     }
446     width = m5206_mbar_width[offset >> 2];
447     if (width > 1) {
448         uint32_t tmp;
449         tmp = m5206_mbar_readw(opaque, offset & ~1);
450         if (offset & 1) {
451             tmp = (tmp & 0xff00) | value;
452         } else {
453             tmp = (tmp & 0x00ff) | (value << 8);
454         }
455         m5206_mbar_writew(opaque, offset & ~1, tmp);
456         return;
457     }
458     m5206_mbar_write(s, offset, value);
459 }
460
461 static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
462                               uint32_t value)
463 {
464     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
465     int width;
466     offset &= 0x3ff;
467     if (offset > 0x200) {
468         cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
469     }
470     width = m5206_mbar_width[offset >> 2];
471     if (width > 2) {
472         uint32_t tmp;
473         tmp = m5206_mbar_readl(opaque, offset & ~3);
474         if (offset & 3) {
475             tmp = (tmp & 0xffff0000) | value;
476         } else {
477             tmp = (tmp & 0x0000ffff) | (value << 16);
478         }
479         m5206_mbar_writel(opaque, offset & ~3, tmp);
480         return;
481     } else if (width < 2) {
482         m5206_mbar_writeb(opaque, offset, value >> 8);
483         m5206_mbar_writeb(opaque, offset + 1, value & 0xff);
484         return;
485     }
486     m5206_mbar_write(s, offset, value);
487 }
488
489 static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
490                               uint32_t value)
491 {
492     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
493     int width;
494     offset &= 0x3ff;
495     if (offset > 0x200) {
496         cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
497     }
498     width = m5206_mbar_width[offset >> 2];
499     if (width < 4) {
500         m5206_mbar_writew(opaque, offset, value >> 16);
501         m5206_mbar_writew(opaque, offset + 2, value & 0xffff);
502         return;
503     }
504     m5206_mbar_write(s, offset, value);
505 }
506
507 static CPUReadMemoryFunc *m5206_mbar_readfn[] = {
508    m5206_mbar_readb,
509    m5206_mbar_readw,
510    m5206_mbar_readl
511 };
512
513 static CPUWriteMemoryFunc *m5206_mbar_writefn[] = {
514    m5206_mbar_writeb,
515    m5206_mbar_writew,
516    m5206_mbar_writel
517 };
518
519 qemu_irq *mcf5206_init(uint32_t base, CPUState *env)
520 {
521     m5206_mbar_state *s;
522     qemu_irq *pic;
523     int iomemtype;
524
525     s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state));
526     iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn,
527                                        m5206_mbar_writefn, s);
528     cpu_register_physical_memory(base, 0x00001000, iomemtype);
529
530     pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
531     s->timer[0] = m5206_timer_init(pic[9]);
532     s->timer[1] = m5206_timer_init(pic[10]);
533     s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]);
534     s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]);
535     s->env = env;
536
537     m5206_mbar_reset(s);
538     return pic;
539 }
540