xref: /openbmc/qemu/hw/m68k/mcf5206.c (revision 7cc25f6c)
1 /*
2  * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
3  *
4  * Copyright (c) 2007 CodeSourcery.
5  *
6  * This code is licensed under the GPL
7  */
8 
9 #include "qemu/osdep.h"
10 #include "qemu/error-report.h"
11 #include "qemu/log.h"
12 #include "cpu.h"
13 #include "hw/boards.h"
14 #include "hw/irq.h"
15 #include "hw/m68k/mcf.h"
16 #include "qemu/timer.h"
17 #include "hw/ptimer.h"
18 #include "sysemu/sysemu.h"
19 #include "hw/sysbus.h"
20 
21 /* General purpose timer module.  */
22 typedef struct {
23     uint16_t tmr;
24     uint16_t trr;
25     uint16_t tcr;
26     uint16_t ter;
27     ptimer_state *timer;
28     qemu_irq irq;
29     int irq_state;
30 } m5206_timer_state;
31 
32 #define TMR_RST 0x01
33 #define TMR_CLK 0x06
34 #define TMR_FRR 0x08
35 #define TMR_ORI 0x10
36 #define TMR_OM  0x20
37 #define TMR_CE  0xc0
38 
39 #define TER_CAP 0x01
40 #define TER_REF 0x02
41 
42 static void m5206_timer_update(m5206_timer_state *s)
43 {
44     if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF))
45         qemu_irq_raise(s->irq);
46     else
47         qemu_irq_lower(s->irq);
48 }
49 
50 static void m5206_timer_reset(m5206_timer_state *s)
51 {
52     s->tmr = 0;
53     s->trr = 0;
54 }
55 
56 static void m5206_timer_recalibrate(m5206_timer_state *s)
57 {
58     int prescale;
59     int mode;
60 
61     ptimer_transaction_begin(s->timer);
62     ptimer_stop(s->timer);
63 
64     if ((s->tmr & TMR_RST) == 0) {
65         goto exit;
66     }
67 
68     prescale = (s->tmr >> 8) + 1;
69     mode = (s->tmr >> 1) & 3;
70     if (mode == 2)
71         prescale *= 16;
72 
73     if (mode == 3 || mode == 0) {
74         qemu_log_mask(LOG_UNIMP, "m5206_timer: mode %d not implemented\n",
75                       mode);
76         goto exit;
77     }
78     if ((s->tmr & TMR_FRR) == 0) {
79         qemu_log_mask(LOG_UNIMP,
80                       "m5206_timer: free running mode not implemented\n");
81         goto exit;
82     }
83 
84     /* Assume 66MHz system clock.  */
85     ptimer_set_freq(s->timer, 66000000 / prescale);
86 
87     ptimer_set_limit(s->timer, s->trr, 0);
88 
89     ptimer_run(s->timer, 0);
90 exit:
91     ptimer_transaction_commit(s->timer);
92 }
93 
94 static void m5206_timer_trigger(void *opaque)
95 {
96     m5206_timer_state *s = (m5206_timer_state *)opaque;
97     s->ter |= TER_REF;
98     m5206_timer_update(s);
99 }
100 
101 static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr)
102 {
103     switch (addr) {
104     case 0:
105         return s->tmr;
106     case 4:
107         return s->trr;
108     case 8:
109         return s->tcr;
110     case 0xc:
111         return s->trr - ptimer_get_count(s->timer);
112     case 0x11:
113         return s->ter;
114     default:
115         return 0;
116     }
117 }
118 
119 static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
120 {
121     switch (addr) {
122     case 0:
123         if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) {
124             m5206_timer_reset(s);
125         }
126         s->tmr = val;
127         m5206_timer_recalibrate(s);
128         break;
129     case 4:
130         s->trr = val;
131         m5206_timer_recalibrate(s);
132         break;
133     case 8:
134         s->tcr = val;
135         break;
136     case 0xc:
137         ptimer_transaction_begin(s->timer);
138         ptimer_set_count(s->timer, val);
139         ptimer_transaction_commit(s->timer);
140         break;
141     case 0x11:
142         s->ter &= ~val;
143         break;
144     default:
145         break;
146     }
147     m5206_timer_update(s);
148 }
149 
150 static m5206_timer_state *m5206_timer_init(qemu_irq irq)
151 {
152     m5206_timer_state *s;
153 
154     s = g_new0(m5206_timer_state, 1);
155     s->timer = ptimer_init(m5206_timer_trigger, s, PTIMER_POLICY_DEFAULT);
156     s->irq = irq;
157     m5206_timer_reset(s);
158     return s;
159 }
160 
161 /* System Integration Module.  */
162 
163 typedef struct {
164     SysBusDevice parent_obj;
165 
166     M68kCPU *cpu;
167     MemoryRegion iomem;
168     qemu_irq *pic;
169     m5206_timer_state *timer[2];
170     void *uart[2];
171     uint8_t scr;
172     uint8_t icr[14];
173     uint16_t imr; /* 1 == interrupt is masked.  */
174     uint16_t ipr;
175     uint8_t rsr;
176     uint8_t swivr;
177     uint8_t par;
178     /* Include the UART vector registers here.  */
179     uint8_t uivr[2];
180 } m5206_mbar_state;
181 
182 #define MCF5206_MBAR(obj) OBJECT_CHECK(m5206_mbar_state, (obj), TYPE_MCF5206_MBAR)
183 
184 /* Interrupt controller.  */
185 
186 static int m5206_find_pending_irq(m5206_mbar_state *s)
187 {
188     int level;
189     int vector;
190     uint16_t active;
191     int i;
192 
193     level = 0;
194     vector = 0;
195     active = s->ipr & ~s->imr;
196     if (!active)
197         return 0;
198 
199     for (i = 1; i < 14; i++) {
200         if (active & (1 << i)) {
201             if ((s->icr[i] & 0x1f) > level) {
202                 level = s->icr[i] & 0x1f;
203                 vector = i;
204             }
205         }
206     }
207 
208     if (level < 4)
209         vector = 0;
210 
211     return vector;
212 }
213 
214 static void m5206_mbar_update(m5206_mbar_state *s)
215 {
216     int irq;
217     int vector;
218     int level;
219 
220     irq = m5206_find_pending_irq(s);
221     if (irq) {
222         int tmp;
223         tmp = s->icr[irq];
224         level = (tmp >> 2) & 7;
225         if (tmp & 0x80) {
226             /* Autovector.  */
227             vector = 24 + level;
228         } else {
229             switch (irq) {
230             case 8: /* SWT */
231                 vector = s->swivr;
232                 break;
233             case 12: /* UART1 */
234                 vector = s->uivr[0];
235                 break;
236             case 13: /* UART2 */
237                 vector = s->uivr[1];
238                 break;
239             default:
240                 /* Unknown vector.  */
241                 qemu_log_mask(LOG_UNIMP, "%s: Unhandled vector for IRQ %d\n",
242                               __func__, irq);
243                 vector = 0xf;
244                 break;
245             }
246         }
247     } else {
248         level = 0;
249         vector = 0;
250     }
251     m68k_set_irq_level(s->cpu, level, vector);
252 }
253 
254 static void m5206_mbar_set_irq(void *opaque, int irq, int level)
255 {
256     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
257     if (level) {
258         s->ipr |= 1 << irq;
259     } else {
260         s->ipr &= ~(1 << irq);
261     }
262     m5206_mbar_update(s);
263 }
264 
265 /* System Integration Module.  */
266 
267 static void m5206_mbar_reset(DeviceState *dev)
268 {
269     m5206_mbar_state *s = MCF5206_MBAR(dev);
270 
271     s->scr = 0xc0;
272     s->icr[1] = 0x04;
273     s->icr[2] = 0x08;
274     s->icr[3] = 0x0c;
275     s->icr[4] = 0x10;
276     s->icr[5] = 0x14;
277     s->icr[6] = 0x18;
278     s->icr[7] = 0x1c;
279     s->icr[8] = 0x1c;
280     s->icr[9] = 0x80;
281     s->icr[10] = 0x80;
282     s->icr[11] = 0x80;
283     s->icr[12] = 0x00;
284     s->icr[13] = 0x00;
285     s->imr = 0x3ffe;
286     s->rsr = 0x80;
287     s->swivr = 0x0f;
288     s->par = 0;
289 }
290 
291 static uint64_t m5206_mbar_read(m5206_mbar_state *s,
292                                 uint16_t offset, unsigned size)
293 {
294     if (offset >= 0x100 && offset < 0x120) {
295         return m5206_timer_read(s->timer[0], offset - 0x100);
296     } else if (offset >= 0x120 && offset < 0x140) {
297         return m5206_timer_read(s->timer[1], offset - 0x120);
298     } else if (offset >= 0x140 && offset < 0x160) {
299         return mcf_uart_read(s->uart[0], offset - 0x140, size);
300     } else if (offset >= 0x180 && offset < 0x1a0) {
301         return mcf_uart_read(s->uart[1], offset - 0x180, size);
302     }
303     switch (offset) {
304     case 0x03: return s->scr;
305     case 0x14 ... 0x20: return s->icr[offset - 0x13];
306     case 0x36: return s->imr;
307     case 0x3a: return s->ipr;
308     case 0x40: return s->rsr;
309     case 0x41: return 0;
310     case 0x42: return s->swivr;
311     case 0x50:
312         /* DRAM mask register.  */
313         /* FIXME: currently hardcoded to 128Mb.  */
314         {
315             uint32_t mask = ~0;
316             while (mask > current_machine->ram_size) {
317                 mask >>= 1;
318             }
319             return mask & 0x0ffe0000;
320         }
321     case 0x5c: return 1; /* DRAM bank 1 empty.  */
322     case 0xcb: return s->par;
323     case 0x170: return s->uivr[0];
324     case 0x1b0: return s->uivr[1];
325     }
326     qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad MBAR offset 0x%"PRIx16"\n",
327                   __func__, offset);
328     return 0;
329 }
330 
331 static void m5206_mbar_write(m5206_mbar_state *s, uint16_t offset,
332                              uint64_t value, unsigned size)
333 {
334     if (offset >= 0x100 && offset < 0x120) {
335         m5206_timer_write(s->timer[0], offset - 0x100, value);
336         return;
337     } else if (offset >= 0x120 && offset < 0x140) {
338         m5206_timer_write(s->timer[1], offset - 0x120, value);
339         return;
340     } else if (offset >= 0x140 && offset < 0x160) {
341         mcf_uart_write(s->uart[0], offset - 0x140, value, size);
342         return;
343     } else if (offset >= 0x180 && offset < 0x1a0) {
344         mcf_uart_write(s->uart[1], offset - 0x180, value, size);
345         return;
346     }
347     switch (offset) {
348     case 0x03:
349         s->scr = value;
350         break;
351     case 0x14 ... 0x20:
352         s->icr[offset - 0x13] = value;
353         m5206_mbar_update(s);
354         break;
355     case 0x36:
356         s->imr = value;
357         m5206_mbar_update(s);
358         break;
359     case 0x40:
360         s->rsr &= ~value;
361         break;
362     case 0x41:
363         /* TODO: implement watchdog.  */
364         break;
365     case 0x42:
366         s->swivr = value;
367         break;
368     case 0xcb:
369         s->par = value;
370         break;
371     case 0x170:
372         s->uivr[0] = value;
373         break;
374     case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
375         /* Not implemented: UART Output port bits.  */
376         break;
377     case 0x1b0:
378         s->uivr[1] = value;
379         break;
380     default:
381         qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad MBAR offset 0x%"PRIx16"\n",
382                       __func__, offset);
383         break;
384     }
385 }
386 
387 /* Internal peripherals use a variety of register widths.
388    This lookup table allows a single routine to handle all of them.  */
389 static const uint8_t m5206_mbar_width[] =
390 {
391   /* 000-040 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  2, 2, 2, 2,
392   /* 040-080 */ 1, 2, 2, 2,  4, 1, 2, 4,  1, 2, 4, 2,  2, 4, 2, 2,
393   /* 080-0c0 */ 4, 2, 2, 4,  2, 2, 4, 2,  2, 4, 2, 2,  4, 2, 2, 4,
394   /* 0c0-100 */ 2, 2, 1, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
395   /* 100-140 */ 2, 2, 2, 2,  1, 0, 0, 0,  2, 2, 2, 2,  1, 0, 0, 0,
396   /* 140-180 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
397   /* 180-1c0 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
398   /* 1c0-200 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
399 };
400 
401 static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset);
402 static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset);
403 
404 static uint32_t m5206_mbar_readb(void *opaque, hwaddr offset)
405 {
406     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
407     offset &= 0x3ff;
408     if (offset >= 0x200) {
409         qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR read offset 0x%" HWADDR_PRIX,
410                       offset);
411         return 0;
412     }
413     if (m5206_mbar_width[offset >> 2] > 1) {
414         uint16_t val;
415         val = m5206_mbar_readw(opaque, offset & ~1);
416         if ((offset & 1) == 0) {
417             val >>= 8;
418         }
419         return val & 0xff;
420     }
421     return m5206_mbar_read(s, offset, 1);
422 }
423 
424 static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset)
425 {
426     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
427     int width;
428     offset &= 0x3ff;
429     if (offset >= 0x200) {
430         qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR read offset 0x%" HWADDR_PRIX,
431                       offset);
432         return 0;
433     }
434     width = m5206_mbar_width[offset >> 2];
435     if (width > 2) {
436         uint32_t val;
437         val = m5206_mbar_readl(opaque, offset & ~3);
438         if ((offset & 3) == 0)
439             val >>= 16;
440         return val & 0xffff;
441     } else if (width < 2) {
442         uint16_t val;
443         val = m5206_mbar_readb(opaque, offset) << 8;
444         val |= m5206_mbar_readb(opaque, offset + 1);
445         return val;
446     }
447     return m5206_mbar_read(s, offset, 2);
448 }
449 
450 static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset)
451 {
452     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
453     int width;
454     offset &= 0x3ff;
455     if (offset >= 0x200) {
456         qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR read offset 0x%" HWADDR_PRIX,
457                       offset);
458         return 0;
459     }
460     width = m5206_mbar_width[offset >> 2];
461     if (width < 4) {
462         uint32_t val;
463         val = m5206_mbar_readw(opaque, offset) << 16;
464         val |= m5206_mbar_readw(opaque, offset + 2);
465         return val;
466     }
467     return m5206_mbar_read(s, offset, 4);
468 }
469 
470 static void m5206_mbar_writew(void *opaque, hwaddr offset,
471                               uint32_t value);
472 static void m5206_mbar_writel(void *opaque, hwaddr offset,
473                               uint32_t value);
474 
475 static void m5206_mbar_writeb(void *opaque, hwaddr offset,
476                               uint32_t value)
477 {
478     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
479     int width;
480     offset &= 0x3ff;
481     if (offset >= 0x200) {
482         qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR write offset 0x%" HWADDR_PRIX,
483                       offset);
484         return;
485     }
486     width = m5206_mbar_width[offset >> 2];
487     if (width > 1) {
488         uint32_t tmp;
489         tmp = m5206_mbar_readw(opaque, offset & ~1);
490         if (offset & 1) {
491             tmp = (tmp & 0xff00) | value;
492         } else {
493             tmp = (tmp & 0x00ff) | (value << 8);
494         }
495         m5206_mbar_writew(opaque, offset & ~1, tmp);
496         return;
497     }
498     m5206_mbar_write(s, offset, value, 1);
499 }
500 
501 static void m5206_mbar_writew(void *opaque, hwaddr offset,
502                               uint32_t value)
503 {
504     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
505     int width;
506     offset &= 0x3ff;
507     if (offset >= 0x200) {
508         qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR write offset 0x%" HWADDR_PRIX,
509                       offset);
510         return;
511     }
512     width = m5206_mbar_width[offset >> 2];
513     if (width > 2) {
514         uint32_t tmp;
515         tmp = m5206_mbar_readl(opaque, offset & ~3);
516         if (offset & 3) {
517             tmp = (tmp & 0xffff0000) | value;
518         } else {
519             tmp = (tmp & 0x0000ffff) | (value << 16);
520         }
521         m5206_mbar_writel(opaque, offset & ~3, tmp);
522         return;
523     } else if (width < 2) {
524         m5206_mbar_writeb(opaque, offset, value >> 8);
525         m5206_mbar_writeb(opaque, offset + 1, value & 0xff);
526         return;
527     }
528     m5206_mbar_write(s, offset, value, 2);
529 }
530 
531 static void m5206_mbar_writel(void *opaque, hwaddr offset,
532                               uint32_t value)
533 {
534     m5206_mbar_state *s = (m5206_mbar_state *)opaque;
535     int width;
536     offset &= 0x3ff;
537     if (offset >= 0x200) {
538         qemu_log_mask(LOG_GUEST_ERROR, "Bad MBAR write offset 0x%" HWADDR_PRIX,
539                       offset);
540         return;
541     }
542     width = m5206_mbar_width[offset >> 2];
543     if (width < 4) {
544         m5206_mbar_writew(opaque, offset, value >> 16);
545         m5206_mbar_writew(opaque, offset + 2, value & 0xffff);
546         return;
547     }
548     m5206_mbar_write(s, offset, value, 4);
549 }
550 
551 static uint64_t m5206_mbar_readfn(void *opaque, hwaddr addr, unsigned size)
552 {
553     switch (size) {
554     case 1:
555         return m5206_mbar_readb(opaque, addr);
556     case 2:
557         return m5206_mbar_readw(opaque, addr);
558     case 4:
559         return m5206_mbar_readl(opaque, addr);
560     default:
561         g_assert_not_reached();
562     }
563 }
564 
565 static void m5206_mbar_writefn(void *opaque, hwaddr addr,
566                                uint64_t value, unsigned size)
567 {
568     switch (size) {
569     case 1:
570         m5206_mbar_writeb(opaque, addr, value);
571         break;
572     case 2:
573         m5206_mbar_writew(opaque, addr, value);
574         break;
575     case 4:
576         m5206_mbar_writel(opaque, addr, value);
577         break;
578     default:
579         g_assert_not_reached();
580     }
581 }
582 
583 static const MemoryRegionOps m5206_mbar_ops = {
584     .read = m5206_mbar_readfn,
585     .write = m5206_mbar_writefn,
586     .valid.min_access_size = 1,
587     .valid.max_access_size = 4,
588     .endianness = DEVICE_NATIVE_ENDIAN,
589 };
590 
591 static void mcf5206_mbar_realize(DeviceState *dev, Error **errp)
592 {
593     m5206_mbar_state *s = MCF5206_MBAR(dev);
594 
595     memory_region_init_io(&s->iomem, NULL, &m5206_mbar_ops, s,
596                           "mbar", 0x00001000);
597     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
598 
599     s->pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
600     s->timer[0] = m5206_timer_init(s->pic[9]);
601     s->timer[1] = m5206_timer_init(s->pic[10]);
602     s->uart[0] = mcf_uart_init(s->pic[12], serial_hd(0));
603     s->uart[1] = mcf_uart_init(s->pic[13], serial_hd(1));
604     s->cpu = M68K_CPU(qemu_get_cpu(0));
605 }
606 
607 static void mcf5206_mbar_class_init(ObjectClass *oc, void *data)
608 {
609     DeviceClass *dc = DEVICE_CLASS(oc);
610 
611     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
612     dc->desc = "MCF5206 system integration module";
613     dc->realize = mcf5206_mbar_realize;
614     dc->reset = m5206_mbar_reset;
615 }
616 
617 static const TypeInfo mcf5206_mbar_info = {
618     .name          = TYPE_MCF5206_MBAR,
619     .parent        = TYPE_SYS_BUS_DEVICE,
620     .instance_size = sizeof(m5206_mbar_state),
621     .class_init    = mcf5206_mbar_class_init,
622 };
623 
624 static void mcf5206_mbar_register_types(void)
625 {
626     type_register_static(&mcf5206_mbar_info);
627 }
628 
629 type_init(mcf5206_mbar_register_types)
630