|
|
1.1 root 1: /*
2: * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
3: *
4: * Copyright (c) 2007 CodeSourcery.
5: *
1.1.1.6 root 6: * This code is licensed under the GPL
1.1 root 7: */
8: #include "hw.h"
9: #include "mcf.h"
10: #include "qemu-timer.h"
1.1.1.8 ! root 11: #include "ptimer.h"
1.1 root 12: #include "sysemu.h"
1.1.1.8 ! root 13: #include "exec-memory.h"
1.1 root 14:
15: /* General purpose timer module. */
16: typedef 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:
36: static 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:
44: static void m5206_timer_reset(m5206_timer_state *s)
45: {
46: s->tmr = 0;
47: s->trr = 0;
48: }
49:
50: static 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)
1.1.1.3 root 66: hw_error("m5206_timer: mode %d not implemented\n", mode);
1.1 root 67: if ((s->tmr & TMR_FRR) == 0)
1.1.1.3 root 68: hw_error("m5206_timer: free running mode not implemented\n");
1.1 root 69:
70: /* Assume 66MHz system clock. */
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:
78: static 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:
85: static 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:
103: static 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:
132: static m5206_timer_state *m5206_timer_init(qemu_irq irq)
133: {
134: m5206_timer_state *s;
135: QEMUBH *bh;
136:
1.1.1.7 root 137: s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state));
1.1 root 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: /* System Integration Module. */
146:
147: typedef struct {
1.1.1.8 ! root 148: CPUM68KState *env;
! 149: MemoryRegion iomem;
1.1 root 150: m5206_timer_state *timer[2];
151: void *uart[2];
152: uint8_t scr;
153: uint8_t icr[14];
154: uint16_t imr; /* 1 == interrupt is masked. */
155: uint16_t ipr;
156: uint8_t rsr;
157: uint8_t swivr;
158: uint8_t par;
159: /* Include the UART vector registers here. */
160: uint8_t uivr[2];
161: } m5206_mbar_state;
162:
163: /* Interrupt controller. */
164:
165: static 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:
193: static 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: /* Autovector. */
206: vector = 24 + level;
207: } else {
208: switch (irq) {
209: case 8: /* SWT */
210: vector = s->swivr;
211: break;
212: case 12: /* UART1 */
213: vector = s->uivr[0];
214: break;
215: case 13: /* UART2 */
216: vector = s->uivr[1];
217: break;
218: default:
219: /* Unknown vector. */
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->env, level, vector);
230: }
231:
232: static 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: /* System Integration Module. */
244:
245: static 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:
1.1.1.8 ! root 267: static uint64_t m5206_mbar_read(m5206_mbar_state *s,
! 268: uint64_t offset, unsigned size)
1.1 root 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) {
1.1.1.8 ! root 275: return mcf_uart_read(s->uart[0], offset - 0x140, size);
1.1 root 276: } else if (offset >= 0x180 && offset < 0x1a0) {
1.1.1.8 ! root 277: return mcf_uart_read(s->uart[1], offset - 0x180, size);
1.1 root 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: /* DRAM mask register. */
289: /* FIXME: currently hardcoded to 128Mb. */
290: {
291: uint32_t mask = ~0;
292: while (mask > ram_size)
293: mask >>= 1;
294: return mask & 0x0ffe0000;
295: }
296: case 0x5c: return 1; /* DRAM bank 1 empty. */
297: case 0xcb: return s->par;
298: case 0x170: return s->uivr[0];
299: case 0x1b0: return s->uivr[1];
300: }
1.1.1.3 root 301: hw_error("Bad MBAR read offset 0x%x", (int)offset);
1.1 root 302: return 0;
303: }
304:
305: static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
1.1.1.8 ! root 306: uint64_t value, unsigned size)
1.1 root 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) {
1.1.1.8 ! root 315: mcf_uart_write(s->uart[0], offset - 0x140, value, size);
1.1 root 316: return;
317: } else if (offset >= 0x180 && offset < 0x1a0) {
1.1.1.8 ! root 318: mcf_uart_write(s->uart[1], offset - 0x180, value, size);
1.1 root 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: /* TODO: implement watchdog. */
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: /* Not implemented: UART Output port bits. */
350: break;
351: case 0x1b0:
352: s->uivr[1] = value;
353: break;
354: default:
1.1.1.3 root 355: hw_error("Bad MBAR write offset 0x%x", (int)offset);
1.1 root 356: break;
357: }
358: }
359:
360: /* Internal peripherals use a variety of register widths.
361: This lookup table allows a single routine to handle all of them. */
362: static const int m5206_mbar_width[] =
363: {
364: /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
365: /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2,
366: /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4,
367: /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368: /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0,
369: /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
370: /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
371: /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
372: };
373:
374: static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset);
375: static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset);
376:
377: static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset)
378: {
379: m5206_mbar_state *s = (m5206_mbar_state *)opaque;
380: offset &= 0x3ff;
381: if (offset > 0x200) {
1.1.1.3 root 382: hw_error("Bad MBAR read offset 0x%x", (int)offset);
1.1 root 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: }
1.1.1.8 ! root 392: return m5206_mbar_read(s, offset, 1);
1.1 root 393: }
394:
395: static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset)
396: {
397: m5206_mbar_state *s = (m5206_mbar_state *)opaque;
398: int width;
399: offset &= 0x3ff;
400: if (offset > 0x200) {
1.1.1.3 root 401: hw_error("Bad MBAR read offset 0x%x", (int)offset);
1.1 root 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: }
1.1.1.8 ! root 416: return m5206_mbar_read(s, offset, 2);
1.1 root 417: }
418:
419: static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset)
420: {
421: m5206_mbar_state *s = (m5206_mbar_state *)opaque;
422: int width;
423: offset &= 0x3ff;
424: if (offset > 0x200) {
1.1.1.3 root 425: hw_error("Bad MBAR read offset 0x%x", (int)offset);
1.1 root 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: }
1.1.1.8 ! root 434: return m5206_mbar_read(s, offset, 4);
1.1 root 435: }
436:
437: static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
438: uint32_t value);
439: static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
440: uint32_t value);
441:
442: static void m5206_mbar_writeb(void *opaque, target_phys_addr_t 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) {
1.1.1.3 root 449: hw_error("Bad MBAR write offset 0x%x", (int)offset);
1.1 root 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: }
1.1.1.8 ! root 463: m5206_mbar_write(s, offset, value, 1);
1.1 root 464: }
465:
466: static void m5206_mbar_writew(void *opaque, target_phys_addr_t 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) {
1.1.1.3 root 473: hw_error("Bad MBAR write offset 0x%x", (int)offset);
1.1 root 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: }
1.1.1.8 ! root 491: m5206_mbar_write(s, offset, value, 2);
1.1 root 492: }
493:
494: static void m5206_mbar_writel(void *opaque, target_phys_addr_t 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) {
1.1.1.3 root 501: hw_error("Bad MBAR write offset 0x%x", (int)offset);
1.1 root 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: }
1.1.1.8 ! root 509: m5206_mbar_write(s, offset, value, 4);
1.1 root 510: }
511:
1.1.1.8 ! root 512: static 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,
1.1 root 526: };
527:
1.1.1.8 ! root 528: qemu_irq *mcf5206_init(MemoryRegion *sysmem, uint32_t base, CPUM68KState *env)
1.1 root 529: {
530: m5206_mbar_state *s;
531: qemu_irq *pic;
532:
1.1.1.7 root 533: s = (m5206_mbar_state *)g_malloc0(sizeof(m5206_mbar_state));
1.1.1.8 ! root 534:
! 535: memory_region_init_io(&s->iomem, &m5206_mbar_ops, s,
! 536: "mbar", 0x00001000);
! 537: memory_region_add_subregion(sysmem, base, &s->iomem);
1.1 root 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->env = env;
545:
546: m5206_mbar_reset(s);
547: return pic;
548: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.