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