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/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
20typedef 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
40static 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
48static void m5206_timer_reset(m5206_timer_state *s)
49{
50 s->tmr = 0;
51 s->trr = 0;
52}
53
54static 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
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);
88exit:
89 ptimer_transaction_commit(s->timer);
90}
91
92static 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
99static 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
117static 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
148static 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
160
161typedef 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;
169 uint16_t ipr;
170 uint8_t rsr;
171 uint8_t swivr;
172 uint8_t par;
173
174 uint8_t uivr[2];
175} m5206_mbar_state;
176
177
178
179static 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
207static 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
220 vector = 24 + level;
221 } else {
222 switch (irq) {
223 case 8:
224 vector = s->swivr;
225 break;
226 case 12:
227 vector = s->uivr[0];
228 break;
229 case 13:
230 vector = s->uivr[1];
231 break;
232 default:
233
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
247static 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
259
260static 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
282static 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
304
305 {
306 uint32_t mask = ~0;
307 while (mask > ram_size)
308 mask >>= 1;
309 return mask & 0x0ffe0000;
310 }
311 case 0x5c: return 1;
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
321static 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
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
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
378
379static const uint8_t m5206_mbar_width[] =
380{
381 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
382 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2,
383 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4,
384 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0,
386 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
387 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
388 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
389};
390
391static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset);
392static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset);
393
394static 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
414static 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
440static 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
460static void m5206_mbar_writew(void *opaque, hwaddr offset,
461 uint32_t value);
462static void m5206_mbar_writel(void *opaque, hwaddr offset,
463 uint32_t value);
464
465static 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
491static 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
521static 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
541static 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
555static 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
573static 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
581qemu_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