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