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