1
2
3
4
5
6
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
22typedef 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
42static 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
50static void m5206_timer_reset(m5206_timer_state *s)
51{
52 s->tmr = 0;
53 s->trr = 0;
54}
55
56static 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
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);
90exit:
91 ptimer_transaction_commit(s->timer);
92}
93
94static 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
101static 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
119static 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
150static 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_LEGACY);
156 s->irq = irq;
157 m5206_timer_reset(s);
158 return s;
159}
160
161
162
163typedef 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;
174 uint16_t ipr;
175 uint8_t rsr;
176 uint8_t swivr;
177 uint8_t par;
178
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
185
186static 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
214static 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
227 vector = 24 + level;
228 } else {
229 switch (irq) {
230 case 8:
231 vector = s->swivr;
232 break;
233 case 12:
234 vector = s->uivr[0];
235 break;
236 case 13:
237 vector = s->uivr[1];
238 break;
239 default:
240
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
254static 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
266
267static 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
291static 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
313
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;
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
331static 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
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
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
388
389static const uint8_t m5206_mbar_width[] =
390{
391 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
392 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2,
393 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4,
394 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
395 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0,
396 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
397 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
398 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
399};
400
401static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset);
402static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset);
403
404static 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
424static 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
450static 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
470static void m5206_mbar_writew(void *opaque, hwaddr offset,
471 uint32_t value);
472static void m5206_mbar_writel(void *opaque, hwaddr offset,
473 uint32_t value);
474
475static 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
501static 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
531static 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
551static 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
565static 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
583static 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
591static 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
607static 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
617static 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
624static void mcf5206_mbar_register_types(void)
625{
626 type_register_static(&mcf5206_mbar_info);
627}
628
629type_init(mcf5206_mbar_register_types)
630