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