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