|
|
1.1 root 1: /*
2: * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
3: *
4: * Copyright (c) 2007 CodeSourcery.
5: *
6: * This code is licenced under the GPL
7: */
8: #include "hw.h"
9: #include "mcf.h"
10: #include "qemu-timer.h"
11: #include "sysemu.h"
12:
13: /* General purpose timer module. */
14: typedef struct {
15: uint16_t tmr;
16: uint16_t trr;
17: uint16_t tcr;
18: uint16_t ter;
19: ptimer_state *timer;
20: qemu_irq irq;
21: int irq_state;
22: } m5206_timer_state;
23:
24: #define TMR_RST 0x01
25: #define TMR_CLK 0x06
26: #define TMR_FRR 0x08
27: #define TMR_ORI 0x10
28: #define TMR_OM 0x20
29: #define TMR_CE 0xc0
30:
31: #define TER_CAP 0x01
32: #define TER_REF 0x02
33:
34: static void m5206_timer_update(m5206_timer_state *s)
35: {
36: if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF))
37: qemu_irq_raise(s->irq);
38: else
39: qemu_irq_lower(s->irq);
40: }
41:
42: static void m5206_timer_reset(m5206_timer_state *s)
43: {
44: s->tmr = 0;
45: s->trr = 0;
46: }
47:
48: static void m5206_timer_recalibrate(m5206_timer_state *s)
49: {
50: int prescale;
51: int mode;
52:
53: ptimer_stop(s->timer);
54:
55: if ((s->tmr & TMR_RST) == 0)
56: return;
57:
58: prescale = (s->tmr >> 8) + 1;
59: mode = (s->tmr >> 1) & 3;
60: if (mode == 2)
61: prescale *= 16;
62:
63: if (mode == 3 || mode == 0)
64: cpu_abort(cpu_single_env,
65: "m5206_timer: mode %d not implemented\n", mode);
66: if ((s->tmr & TMR_FRR) == 0)
67: cpu_abort(cpu_single_env,
68: "m5206_timer: free running mode not implemented\n");
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:
137: s = (m5206_timer_state *)qemu_mallocz(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: /* System Integration Module. */
146:
147: typedef struct {
148: CPUState *env;
149: m5206_timer_state *timer[2];
150: void *uart[2];
151: uint8_t scr;
152: uint8_t icr[14];
153: uint16_t imr; /* 1 == interrupt is masked. */
154: uint16_t ipr;
155: uint8_t rsr;
156: uint8_t swivr;
157: uint8_t par;
158: /* Include the UART vector registers here. */
159: uint8_t uivr[2];
160: } m5206_mbar_state;
161:
162: /* Interrupt controller. */
163:
164: static int m5206_find_pending_irq(m5206_mbar_state *s)
165: {
166: int level;
167: int vector;
168: uint16_t active;
169: int i;
170:
171: level = 0;
172: vector = 0;
173: active = s->ipr & ~s->imr;
174: if (!active)
175: return 0;
176:
177: for (i = 1; i < 14; i++) {
178: if (active & (1 << i)) {
179: if ((s->icr[i] & 0x1f) > level) {
180: level = s->icr[i] & 0x1f;
181: vector = i;
182: }
183: }
184: }
185:
186: if (level < 4)
187: vector = 0;
188:
189: return vector;
190: }
191:
192: static void m5206_mbar_update(m5206_mbar_state *s)
193: {
194: int irq;
195: int vector;
196: int level;
197:
198: irq = m5206_find_pending_irq(s);
199: if (irq) {
200: int tmp;
201: tmp = s->icr[irq];
202: level = (tmp >> 2) & 7;
203: if (tmp & 0x80) {
204: /* Autovector. */
205: vector = 24 + level;
206: } else {
207: switch (irq) {
208: case 8: /* SWT */
209: vector = s->swivr;
210: break;
211: case 12: /* UART1 */
212: vector = s->uivr[0];
213: break;
214: case 13: /* UART2 */
215: vector = s->uivr[1];
216: break;
217: default:
218: /* Unknown vector. */
219: fprintf(stderr, "Unhandled vector for IRQ %d\n", irq);
220: vector = 0xf;
221: break;
222: }
223: }
224: } else {
225: level = 0;
226: vector = 0;
227: }
228: m68k_set_irq_level(s->env, level, vector);
229: }
230:
231: static void m5206_mbar_set_irq(void *opaque, int irq, int level)
232: {
233: m5206_mbar_state *s = (m5206_mbar_state *)opaque;
234: if (level) {
235: s->ipr |= 1 << irq;
236: } else {
237: s->ipr &= ~(1 << irq);
238: }
239: m5206_mbar_update(s);
240: }
241:
242: /* System Integration Module. */
243:
244: static void m5206_mbar_reset(m5206_mbar_state *s)
245: {
246: s->scr = 0xc0;
247: s->icr[1] = 0x04;
248: s->icr[2] = 0x08;
249: s->icr[3] = 0x0c;
250: s->icr[4] = 0x10;
251: s->icr[5] = 0x14;
252: s->icr[6] = 0x18;
253: s->icr[7] = 0x1c;
254: s->icr[8] = 0x1c;
255: s->icr[9] = 0x80;
256: s->icr[10] = 0x80;
257: s->icr[11] = 0x80;
258: s->icr[12] = 0x00;
259: s->icr[13] = 0x00;
260: s->imr = 0x3ffe;
261: s->rsr = 0x80;
262: s->swivr = 0x0f;
263: s->par = 0;
264: }
265:
266: static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset)
267: {
268: if (offset >= 0x100 && offset < 0x120) {
269: return m5206_timer_read(s->timer[0], offset - 0x100);
270: } else if (offset >= 0x120 && offset < 0x140) {
271: return m5206_timer_read(s->timer[1], offset - 0x120);
272: } else if (offset >= 0x140 && offset < 0x160) {
273: return mcf_uart_read(s->uart[0], offset - 0x140);
274: } else if (offset >= 0x180 && offset < 0x1a0) {
275: return mcf_uart_read(s->uart[1], offset - 0x180);
276: }
277: switch (offset) {
278: case 0x03: return s->scr;
279: case 0x14 ... 0x20: return s->icr[offset - 0x13];
280: case 0x36: return s->imr;
281: case 0x3a: return s->ipr;
282: case 0x40: return s->rsr;
283: case 0x41: return 0;
284: case 0x42: return s->swivr;
285: case 0x50:
286: /* DRAM mask register. */
287: /* FIXME: currently hardcoded to 128Mb. */
288: {
289: uint32_t mask = ~0;
290: while (mask > ram_size)
291: mask >>= 1;
292: return mask & 0x0ffe0000;
293: }
294: case 0x5c: return 1; /* DRAM bank 1 empty. */
295: case 0xcb: return s->par;
296: case 0x170: return s->uivr[0];
297: case 0x1b0: return s->uivr[1];
298: }
299: cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
300: return 0;
301: }
302:
303: static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
304: uint32_t value)
305: {
306: if (offset >= 0x100 && offset < 0x120) {
307: m5206_timer_write(s->timer[0], offset - 0x100, value);
308: return;
309: } else if (offset >= 0x120 && offset < 0x140) {
310: m5206_timer_write(s->timer[1], offset - 0x120, value);
311: return;
312: } else if (offset >= 0x140 && offset < 0x160) {
313: mcf_uart_write(s->uart[0], offset - 0x140, value);
314: return;
315: } else if (offset >= 0x180 && offset < 0x1a0) {
316: mcf_uart_write(s->uart[1], offset - 0x180, value);
317: return;
318: }
319: switch (offset) {
320: case 0x03:
321: s->scr = value;
322: break;
323: case 0x14 ... 0x20:
324: s->icr[offset - 0x13] = value;
325: m5206_mbar_update(s);
326: break;
327: case 0x36:
328: s->imr = value;
329: m5206_mbar_update(s);
330: break;
331: case 0x40:
332: s->rsr &= ~value;
333: break;
334: case 0x41:
335: /* TODO: implement watchdog. */
336: break;
337: case 0x42:
338: s->swivr = value;
339: break;
340: case 0xcb:
341: s->par = value;
342: break;
343: case 0x170:
344: s->uivr[0] = value;
345: break;
346: case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
347: /* Not implemented: UART Output port bits. */
348: break;
349: case 0x1b0:
350: s->uivr[1] = value;
351: break;
352: default:
353: cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
354: break;
355: }
356: }
357:
358: /* Internal peripherals use a variety of register widths.
359: This lookup table allows a single routine to handle all of them. */
360: static const int m5206_mbar_width[] =
361: {
362: /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
363: /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2,
364: /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4,
365: /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
366: /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0,
367: /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
368: /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
369: /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
370: };
371:
372: static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset);
373: static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset);
374:
375: static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset)
376: {
377: m5206_mbar_state *s = (m5206_mbar_state *)opaque;
378: offset &= 0x3ff;
379: if (offset > 0x200) {
380: cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
381: }
382: if (m5206_mbar_width[offset >> 2] > 1) {
383: uint16_t val;
384: val = m5206_mbar_readw(opaque, offset & ~1);
385: if ((offset & 1) == 0) {
386: val >>= 8;
387: }
388: return val & 0xff;
389: }
390: return m5206_mbar_read(s, offset);
391: }
392:
393: static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset)
394: {
395: m5206_mbar_state *s = (m5206_mbar_state *)opaque;
396: int width;
397: offset &= 0x3ff;
398: if (offset > 0x200) {
399: cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
400: }
401: width = m5206_mbar_width[offset >> 2];
402: if (width > 2) {
403: uint32_t val;
404: val = m5206_mbar_readl(opaque, offset & ~3);
405: if ((offset & 3) == 0)
406: val >>= 16;
407: return val & 0xffff;
408: } else if (width < 2) {
409: uint16_t val;
410: val = m5206_mbar_readb(opaque, offset) << 8;
411: val |= m5206_mbar_readb(opaque, offset + 1);
412: return val;
413: }
414: return m5206_mbar_read(s, offset);
415: }
416:
417: static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset)
418: {
419: m5206_mbar_state *s = (m5206_mbar_state *)opaque;
420: int width;
421: offset &= 0x3ff;
422: if (offset > 0x200) {
423: cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
424: }
425: width = m5206_mbar_width[offset >> 2];
426: if (width < 4) {
427: uint32_t val;
428: val = m5206_mbar_readw(opaque, offset) << 16;
429: val |= m5206_mbar_readw(opaque, offset + 2);
430: return val;
431: }
432: return m5206_mbar_read(s, offset);
433: }
434:
435: static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
436: uint32_t value);
437: static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
438: uint32_t value);
439:
440: static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset,
441: uint32_t value)
442: {
443: m5206_mbar_state *s = (m5206_mbar_state *)opaque;
444: int width;
445: offset &= 0x3ff;
446: if (offset > 0x200) {
447: cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
448: }
449: width = m5206_mbar_width[offset >> 2];
450: if (width > 1) {
451: uint32_t tmp;
452: tmp = m5206_mbar_readw(opaque, offset & ~1);
453: if (offset & 1) {
454: tmp = (tmp & 0xff00) | value;
455: } else {
456: tmp = (tmp & 0x00ff) | (value << 8);
457: }
458: m5206_mbar_writew(opaque, offset & ~1, tmp);
459: return;
460: }
461: m5206_mbar_write(s, offset, value);
462: }
463:
464: static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
465: uint32_t value)
466: {
467: m5206_mbar_state *s = (m5206_mbar_state *)opaque;
468: int width;
469: offset &= 0x3ff;
470: if (offset > 0x200) {
471: cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
472: }
473: width = m5206_mbar_width[offset >> 2];
474: if (width > 2) {
475: uint32_t tmp;
476: tmp = m5206_mbar_readl(opaque, offset & ~3);
477: if (offset & 3) {
478: tmp = (tmp & 0xffff0000) | value;
479: } else {
480: tmp = (tmp & 0x0000ffff) | (value << 16);
481: }
482: m5206_mbar_writel(opaque, offset & ~3, tmp);
483: return;
484: } else if (width < 2) {
485: m5206_mbar_writeb(opaque, offset, value >> 8);
486: m5206_mbar_writeb(opaque, offset + 1, value & 0xff);
487: return;
488: }
489: m5206_mbar_write(s, offset, value);
490: }
491:
492: static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
493: uint32_t value)
494: {
495: m5206_mbar_state *s = (m5206_mbar_state *)opaque;
496: int width;
497: offset &= 0x3ff;
498: if (offset > 0x200) {
499: cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
500: }
501: width = m5206_mbar_width[offset >> 2];
502: if (width < 4) {
503: m5206_mbar_writew(opaque, offset, value >> 16);
504: m5206_mbar_writew(opaque, offset + 2, value & 0xffff);
505: return;
506: }
507: m5206_mbar_write(s, offset, value);
508: }
509:
510: static CPUReadMemoryFunc *m5206_mbar_readfn[] = {
511: m5206_mbar_readb,
512: m5206_mbar_readw,
513: m5206_mbar_readl
514: };
515:
516: static CPUWriteMemoryFunc *m5206_mbar_writefn[] = {
517: m5206_mbar_writeb,
518: m5206_mbar_writew,
519: m5206_mbar_writel
520: };
521:
522: qemu_irq *mcf5206_init(uint32_t base, CPUState *env)
523: {
524: m5206_mbar_state *s;
525: qemu_irq *pic;
526: int iomemtype;
527:
528: s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state));
529: iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn,
530: m5206_mbar_writefn, s);
531: cpu_register_physical_memory(base, 0x00001000, iomemtype);
532:
533: pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
534: s->timer[0] = m5206_timer_init(pic[9]);
535: s->timer[1] = m5206_timer_init(pic[10]);
536: s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]);
537: s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]);
538: s->env = env;
539:
540: m5206_mbar_reset(s);
541: return pic;
542: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.