|
|
1.1 root 1: /*
2: * OpenPIC emulation
3: *
4: * Copyright (c) 2004 Jocelyn Mayer
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
24: /*
25: *
26: * Based on OpenPic implementations:
27: * - Intel GW80314 I/O compagnion chip developper's manual
28: * - Motorola MPC8245 & MPC8540 user manuals.
29: * - Motorola MCP750 (aka Raven) programmer manual.
30: * - Motorola Harrier programmer manuel
31: *
32: * Serial interrupts, as implemented in Raven chipset are not supported yet.
33: *
34: */
35: #include "vl.h"
36:
37: //#define DEBUG_OPENPIC
38:
39: #ifdef DEBUG_OPENPIC
40: #define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
41: #else
42: #define DPRINTF(fmt, args...) do { } while (0)
43: #endif
44: #define ERROR(fmr, args...) do { printf("ERROR: " fmr , ##args); } while (0)
45:
46: #define USE_MPCxxx /* Intel model is broken, for now */
47:
48: #if defined (USE_INTEL_GW80314)
49: /* Intel GW80314 I/O Companion chip */
50:
51: #define MAX_CPU 4
52: #define MAX_IRQ 32
53: #define MAX_DBL 4
54: #define MAX_MBX 4
55: #define MAX_TMR 4
56: #define VECTOR_BITS 8
57: #define MAX_IPI 0
58:
59: #define VID (0x00000000)
60:
61: #define OPENPIC_LITTLE_ENDIAN 1
62: #define OPENPIC_BIG_ENDIAN 0
63:
64: #elif defined(USE_MPCxxx)
65:
66: #define MAX_CPU 2
67: #define MAX_IRQ 64
68: #define EXT_IRQ 48
69: #define MAX_DBL 0
70: #define MAX_MBX 0
71: #define MAX_TMR 4
72: #define VECTOR_BITS 8
73: #define MAX_IPI 4
74: #define VID 0x03 /* MPIC version ID */
75: #define VENI 0x00000000 /* Vendor ID */
76:
77: enum {
78: IRQ_IPVP = 0,
79: IRQ_IDE,
80: };
81:
82: #define OPENPIC_LITTLE_ENDIAN 1
83: #define OPENPIC_BIG_ENDIAN 0
84:
85: #else
86: #error "Please select which OpenPic implementation is to be emulated"
87: #endif
88:
89: #if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \
90: (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN)
91: #define OPENPIC_SWAP
92: #endif
93:
94: /* Interrupt definitions */
95: #define IRQ_FE (EXT_IRQ) /* Internal functional IRQ */
96: #define IRQ_ERR (EXT_IRQ + 1) /* Error IRQ */
97: #define IRQ_TIM0 (EXT_IRQ + 2) /* First timer IRQ */
98: #if MAX_IPI > 0
99: #define IRQ_IPI0 (IRQ_TIM0 + MAX_TMR) /* First IPI IRQ */
100: #define IRQ_DBL0 (IRQ_IPI0 + (MAX_CPU * MAX_IPI)) /* First doorbell IRQ */
101: #else
102: #define IRQ_DBL0 (IRQ_TIM0 + MAX_TMR) /* First doorbell IRQ */
103: #define IRQ_MBX0 (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */
104: #endif
105:
106: #define BF_WIDTH(_bits_) \
107: (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
108:
109: static inline void set_bit (uint32_t *field, int bit)
110: {
111: field[bit >> 5] |= 1 << (bit & 0x1F);
112: }
113:
114: static inline void reset_bit (uint32_t *field, int bit)
115: {
116: field[bit >> 5] &= ~(1 << (bit & 0x1F));
117: }
118:
119: static inline int test_bit (uint32_t *field, int bit)
120: {
121: return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
122: }
123:
124: enum {
125: IRQ_EXTERNAL = 0x01,
126: IRQ_INTERNAL = 0x02,
127: IRQ_TIMER = 0x04,
128: IRQ_SPECIAL = 0x08,
129: } IRQ_src_type;
130:
131: typedef struct IRQ_queue_t {
132: uint32_t queue[BF_WIDTH(MAX_IRQ)];
133: int next;
134: int priority;
135: } IRQ_queue_t;
136:
137: typedef struct IRQ_src_t {
138: uint32_t ipvp; /* IRQ vector/priority register */
139: uint32_t ide; /* IRQ destination register */
140: int type;
141: int last_cpu;
142: int pending; /* TRUE if IRQ is pending */
143: } IRQ_src_t;
144:
145: enum IPVP_bits {
146: IPVP_MASK = 31,
147: IPVP_ACTIVITY = 30,
148: IPVP_MODE = 29,
149: IPVP_POLARITY = 23,
150: IPVP_SENSE = 22,
151: };
152: #define IPVP_PRIORITY_MASK (0x1F << 16)
153: #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
154: #define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1)
155: #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK)
156:
157: typedef struct IRQ_dst_t {
158: uint32_t pctp; /* CPU current task priority */
159: uint32_t pcsr; /* CPU sensitivity register */
160: IRQ_queue_t raised;
161: IRQ_queue_t servicing;
1.1.1.2 ! root 162: CPUState *env;
1.1 root 163: } IRQ_dst_t;
164:
165: struct openpic_t {
166: PCIDevice pci_dev;
167: int mem_index;
168: /* Global registers */
169: uint32_t frep; /* Feature reporting register */
170: uint32_t glbc; /* Global configuration register */
171: uint32_t micr; /* MPIC interrupt configuration register */
172: uint32_t veni; /* Vendor identification register */
173: uint32_t spve; /* Spurious vector register */
174: uint32_t tifr; /* Timer frequency reporting register */
175: /* Source registers */
176: IRQ_src_t src[MAX_IRQ];
177: /* Local registers per output pin */
178: IRQ_dst_t dst[MAX_CPU];
179: int nb_cpus;
180: /* Timer registers */
181: struct {
182: uint32_t ticc; /* Global timer current count register */
183: uint32_t tibc; /* Global timer base count register */
184: } timers[MAX_TMR];
185: #if MAX_DBL > 0
186: /* Doorbell registers */
187: uint32_t dar; /* Doorbell activate register */
188: struct {
189: uint32_t dmr; /* Doorbell messaging register */
190: } doorbells[MAX_DBL];
191: #endif
192: #if MAX_MBX > 0
193: /* Mailbox registers */
194: struct {
195: uint32_t mbr; /* Mailbox register */
196: } mailboxes[MAX_MAILBOXES];
197: #endif
198: };
199:
200: static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
201: {
202: set_bit(q->queue, n_IRQ);
203: }
204:
205: static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
206: {
207: reset_bit(q->queue, n_IRQ);
208: }
209:
210: static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
211: {
212: return test_bit(q->queue, n_IRQ);
213: }
214:
215: static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
216: {
217: int next, i;
218: int priority;
219:
220: next = -1;
221: priority = -1;
222: for (i = 0; i < MAX_IRQ; i++) {
223: if (IRQ_testbit(q, i)) {
224: DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
225: i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
226: if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
227: next = i;
228: priority = IPVP_PRIORITY(opp->src[i].ipvp);
229: }
230: }
231: }
232: q->next = next;
233: q->priority = priority;
234: }
235:
236: static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
237: {
238: if (q->next == -1) {
239: /* XXX: optimize */
240: IRQ_check(opp, q);
241: }
242:
243: return q->next;
244: }
245:
246: static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
247: {
248: IRQ_dst_t *dst;
249: IRQ_src_t *src;
250: int priority;
251:
252: dst = &opp->dst[n_CPU];
253: src = &opp->src[n_IRQ];
254: priority = IPVP_PRIORITY(src->ipvp);
255: if (priority <= dst->pctp) {
256: /* Too low priority */
257: return;
258: }
259: if (IRQ_testbit(&dst->raised, n_IRQ)) {
260: /* Interrupt miss */
261: return;
262: }
263: set_bit(&src->ipvp, IPVP_ACTIVITY);
264: IRQ_setbit(&dst->raised, n_IRQ);
265: if (priority > dst->raised.priority) {
266: IRQ_get_next(opp, &dst->raised);
267: DPRINTF("Raise CPU IRQ\n");
1.1.1.2 ! root 268: cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
1.1 root 269: }
270: }
271:
272: /* update pic state because registers for n_IRQ have changed value */
273: static void openpic_update_irq(openpic_t *opp, int n_IRQ)
274: {
275: IRQ_src_t *src;
276: int i;
277:
278: src = &opp->src[n_IRQ];
279:
280: if (!src->pending) {
281: /* no irq pending */
282: return;
283: }
284: if (test_bit(&src->ipvp, IPVP_MASK)) {
285: /* Interrupt source is disabled */
286: return;
287: }
288: if (IPVP_PRIORITY(src->ipvp) == 0) {
289: /* Priority set to zero */
290: return;
291: }
292: if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
293: /* IRQ already active */
294: return;
295: }
296: if (src->ide == 0x00000000) {
297: /* No target */
298: return;
299: }
300:
301: if (!test_bit(&src->ipvp, IPVP_MODE) ||
302: src->ide == (1 << src->last_cpu)) {
303: /* Directed delivery mode */
304: for (i = 0; i < opp->nb_cpus; i++) {
305: if (test_bit(&src->ide, i))
306: IRQ_local_pipe(opp, i, n_IRQ);
307: }
308: } else {
309: /* Distributed delivery mode */
310: /* XXX: incorrect code */
311: for (i = src->last_cpu; i < src->last_cpu; i++) {
312: if (i == MAX_IRQ)
313: i = 0;
314: if (test_bit(&src->ide, i)) {
315: IRQ_local_pipe(opp, i, n_IRQ);
316: src->last_cpu = i;
317: break;
318: }
319: }
320: }
321: }
322:
323: void openpic_set_irq(void *opaque, int n_IRQ, int level)
324: {
325: openpic_t *opp = opaque;
326: IRQ_src_t *src;
327:
328: src = &opp->src[n_IRQ];
329: DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
330: n_IRQ, level, src->ipvp);
331: if (test_bit(&src->ipvp, IPVP_SENSE)) {
332: /* level-sensitive irq */
333: src->pending = level;
334: if (!level)
335: reset_bit(&src->ipvp, IPVP_ACTIVITY);
336: } else {
337: /* edge-sensitive irq */
338: if (level)
339: src->pending = 1;
340: }
341: openpic_update_irq(opp, n_IRQ);
342: }
343:
344: static void openpic_reset (openpic_t *opp)
345: {
346: int i;
347:
348: opp->glbc = 0x80000000;
349: /* Initialise controller registers */
350: opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
351: opp->veni = VENI;
352: opp->spve = 0x000000FF;
353: opp->tifr = 0x003F7A00;
354: /* ? */
355: opp->micr = 0x00000000;
356: /* Initialise IRQ sources */
357: for (i = 0; i < MAX_IRQ; i++) {
358: opp->src[i].ipvp = 0xA0000000;
359: opp->src[i].ide = 0x00000000;
360: }
361: /* Initialise IRQ destinations */
362: for (i = 0; i < opp->nb_cpus; i++) {
363: opp->dst[i].pctp = 0x0000000F;
364: opp->dst[i].pcsr = 0x00000000;
365: memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
366: memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
367: }
368: /* Initialise timers */
369: for (i = 0; i < MAX_TMR; i++) {
370: opp->timers[i].ticc = 0x00000000;
371: opp->timers[i].tibc = 0x80000000;
372: }
373: /* Initialise doorbells */
374: #if MAX_DBL > 0
375: opp->dar = 0x00000000;
376: for (i = 0; i < MAX_DBL; i++) {
377: opp->doorbells[i].dmr = 0x00000000;
378: }
379: #endif
380: /* Initialise mailboxes */
381: #if MAX_MBX > 0
382: for (i = 0; i < MAX_MBX; i++) { /* ? */
383: opp->mailboxes[i].mbr = 0x00000000;
384: }
385: #endif
386: /* Go out of RESET state */
387: opp->glbc = 0x00000000;
388: }
389:
390: static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
391: {
392: uint32_t retval;
393:
394: switch (reg) {
395: case IRQ_IPVP:
396: retval = opp->src[n_IRQ].ipvp;
397: break;
398: case IRQ_IDE:
399: retval = opp->src[n_IRQ].ide;
400: break;
401: }
402:
403: return retval;
404: }
405:
406: static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
407: uint32_t reg, uint32_t val)
408: {
409: uint32_t tmp;
410:
411: switch (reg) {
412: case IRQ_IPVP:
413: /* NOTE: not fully accurate for special IRQs, but simple and
414: sufficient */
415: /* ACTIVITY bit is read-only */
416: opp->src[n_IRQ].ipvp =
417: (opp->src[n_IRQ].ipvp & 0x40000000) |
418: (val & 0x800F00FF);
419: openpic_update_irq(opp, n_IRQ);
420: DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
421: n_IRQ, val, opp->src[n_IRQ].ipvp);
422: break;
423: case IRQ_IDE:
424: tmp = val & 0xC0000000;
425: tmp |= val & ((1 << MAX_CPU) - 1);
426: opp->src[n_IRQ].ide = tmp;
427: DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
428: break;
429: }
430: }
431:
432: #if 0 // Code provision for Intel model
433: #if MAX_DBL > 0
434: static uint32_t read_doorbell_register (openpic_t *opp,
435: int n_dbl, uint32_t offset)
436: {
437: uint32_t retval;
438:
439: switch (offset) {
440: case DBL_IPVP_OFFSET:
441: retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
442: break;
443: case DBL_IDE_OFFSET:
444: retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
445: break;
446: case DBL_DMR_OFFSET:
447: retval = opp->doorbells[n_dbl].dmr;
448: break;
449: }
450:
451: return retval;
452: }
453:
454: static void write_doorbell_register (penpic_t *opp, int n_dbl,
455: uint32_t offset, uint32_t value)
456: {
457: switch (offset) {
458: case DBL_IVPR_OFFSET:
459: write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
460: break;
461: case DBL_IDE_OFFSET:
462: write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
463: break;
464: case DBL_DMR_OFFSET:
465: opp->doorbells[n_dbl].dmr = value;
466: break;
467: }
468: }
469: #endif
470:
471: #if MAX_MBX > 0
472: static uint32_t read_mailbox_register (openpic_t *opp,
473: int n_mbx, uint32_t offset)
474: {
475: uint32_t retval;
476:
477: switch (offset) {
478: case MBX_MBR_OFFSET:
479: retval = opp->mailboxes[n_mbx].mbr;
480: break;
481: case MBX_IVPR_OFFSET:
482: retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
483: break;
484: case MBX_DMR_OFFSET:
485: retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
486: break;
487: }
488:
489: return retval;
490: }
491:
492: static void write_mailbox_register (openpic_t *opp, int n_mbx,
493: uint32_t address, uint32_t value)
494: {
495: switch (offset) {
496: case MBX_MBR_OFFSET:
497: opp->mailboxes[n_mbx].mbr = value;
498: break;
499: case MBX_IVPR_OFFSET:
500: write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
501: break;
502: case MBX_DMR_OFFSET:
503: write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
504: break;
505: }
506: }
507: #endif
508: #endif /* 0 : Code provision for Intel model */
509:
510: static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
511: {
512: openpic_t *opp = opaque;
513:
514: DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
515: if (addr & 0xF)
516: return;
517: #if defined OPENPIC_SWAP
518: val = bswap32(val);
519: #endif
520: addr &= 0xFF;
521: switch (addr) {
522: case 0x00: /* FREP */
523: break;
524: case 0x20: /* GLBC */
525: if (val & 0x80000000)
526: openpic_reset(opp);
527: opp->glbc = val & ~0x80000000;
528: break;
529: case 0x80: /* VENI */
530: break;
531: case 0x90: /* PINT */
532: /* XXX: Should be able to reset any CPU */
533: if (val & 1) {
534: DPRINTF("Reset CPU IRQ\n");
1.1.1.2 ! root 535: // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
1.1 root 536: }
537: break;
538: #if MAX_IPI > 0
539: case 0xA0: /* IPI_IPVP */
540: case 0xB0:
541: case 0xC0:
542: case 0xD0:
543: {
544: int idx;
545: idx = (addr - 0xA0) >> 4;
546: write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
547: }
548: break;
549: #endif
550: case 0xE0: /* SPVE */
551: opp->spve = val & 0x000000FF;
552: break;
553: case 0xF0: /* TIFR */
554: opp->tifr = val;
555: break;
556: default:
557: break;
558: }
559: }
560:
561: static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
562: {
563: openpic_t *opp = opaque;
564: uint32_t retval;
565:
566: DPRINTF("%s: addr %08x\n", __func__, addr);
567: retval = 0xFFFFFFFF;
568: if (addr & 0xF)
569: return retval;
570: addr &= 0xFF;
571: switch (addr) {
572: case 0x00: /* FREP */
573: retval = opp->frep;
574: break;
575: case 0x20: /* GLBC */
576: retval = opp->glbc;
577: break;
578: case 0x80: /* VENI */
579: retval = opp->veni;
580: break;
581: case 0x90: /* PINT */
582: retval = 0x00000000;
583: break;
584: #if MAX_IPI > 0
585: case 0xA0: /* IPI_IPVP */
586: case 0xB0:
587: case 0xC0:
588: case 0xD0:
589: {
590: int idx;
591: idx = (addr - 0xA0) >> 4;
592: retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
593: }
594: break;
595: #endif
596: case 0xE0: /* SPVE */
597: retval = opp->spve;
598: break;
599: case 0xF0: /* TIFR */
600: retval = opp->tifr;
601: break;
602: default:
603: break;
604: }
605: DPRINTF("%s: => %08x\n", __func__, retval);
606: #if defined OPENPIC_SWAP
607: retval = bswap32(retval);
608: #endif
609:
610: return retval;
611: }
612:
613: static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
614: {
615: openpic_t *opp = opaque;
616: int idx;
617:
618: DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
619: if (addr & 0xF)
620: return;
621: #if defined OPENPIC_SWAP
622: val = bswap32(val);
623: #endif
624: addr -= 0x1100;
625: addr &= 0xFFFF;
626: idx = (addr & 0xFFF0) >> 6;
627: addr = addr & 0x30;
628: switch (addr) {
629: case 0x00: /* TICC */
630: break;
631: case 0x10: /* TIBC */
632: if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
633: (val & 0x80000000) == 0 &&
634: (opp->timers[idx].tibc & 0x80000000) != 0)
635: opp->timers[idx].ticc &= ~0x80000000;
636: opp->timers[idx].tibc = val;
637: break;
638: case 0x20: /* TIVP */
639: write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val);
640: break;
641: case 0x30: /* TIDE */
642: write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val);
643: break;
644: }
645: }
646:
647: static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
648: {
649: openpic_t *opp = opaque;
650: uint32_t retval;
651: int idx;
652:
653: DPRINTF("%s: addr %08x\n", __func__, addr);
654: retval = 0xFFFFFFFF;
655: if (addr & 0xF)
656: return retval;
657: addr -= 0x1100;
658: addr &= 0xFFFF;
659: idx = (addr & 0xFFF0) >> 6;
660: addr = addr & 0x30;
661: switch (addr) {
662: case 0x00: /* TICC */
663: retval = opp->timers[idx].ticc;
664: break;
665: case 0x10: /* TIBC */
666: retval = opp->timers[idx].tibc;
667: break;
668: case 0x20: /* TIPV */
669: retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP);
670: break;
671: case 0x30: /* TIDE */
672: retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE);
673: break;
674: }
675: DPRINTF("%s: => %08x\n", __func__, retval);
676: #if defined OPENPIC_SWAP
677: retval = bswap32(retval);
678: #endif
679:
680: return retval;
681: }
682:
683: static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
684: {
685: openpic_t *opp = opaque;
686: int idx;
687:
688: DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
689: if (addr & 0xF)
690: return;
691: #if defined OPENPIC_SWAP
692: val = tswap32(val);
693: #endif
694: addr = addr & 0xFFF0;
695: idx = addr >> 5;
696: if (addr & 0x10) {
697: /* EXDE / IFEDE / IEEDE */
698: write_IRQreg(opp, idx, IRQ_IDE, val);
699: } else {
700: /* EXVP / IFEVP / IEEVP */
701: write_IRQreg(opp, idx, IRQ_IPVP, val);
702: }
703: }
704:
705: static uint32_t openpic_src_read (void *opaque, uint32_t addr)
706: {
707: openpic_t *opp = opaque;
708: uint32_t retval;
709: int idx;
710:
711: DPRINTF("%s: addr %08x\n", __func__, addr);
712: retval = 0xFFFFFFFF;
713: if (addr & 0xF)
714: return retval;
715: addr = addr & 0xFFF0;
716: idx = addr >> 5;
717: if (addr & 0x10) {
718: /* EXDE / IFEDE / IEEDE */
719: retval = read_IRQreg(opp, idx, IRQ_IDE);
720: } else {
721: /* EXVP / IFEVP / IEEVP */
722: retval = read_IRQreg(opp, idx, IRQ_IPVP);
723: }
724: DPRINTF("%s: => %08x\n", __func__, retval);
725: #if defined OPENPIC_SWAP
726: retval = tswap32(retval);
727: #endif
728:
729: return retval;
730: }
731:
732: static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
733: {
734: openpic_t *opp = opaque;
735: IRQ_src_t *src;
736: IRQ_dst_t *dst;
737: int idx, n_IRQ;
738:
739: DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
740: if (addr & 0xF)
741: return;
742: #if defined OPENPIC_SWAP
743: val = bswap32(val);
744: #endif
745: addr &= 0x1FFF0;
746: idx = addr / 0x1000;
747: dst = &opp->dst[idx];
748: addr &= 0xFF0;
749: switch (addr) {
750: #if MAX_IPI > 0
751: case 0x40: /* PIPD */
752: case 0x50:
753: case 0x60:
754: case 0x70:
755: idx = (addr - 0x40) >> 4;
756: write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val);
757: openpic_set_irq(opp, IRQ_IPI0 + idx, 1);
758: openpic_set_irq(opp, IRQ_IPI0 + idx, 0);
759: break;
760: #endif
761: case 0x80: /* PCTP */
762: dst->pctp = val & 0x0000000F;
763: break;
764: case 0x90: /* WHOAMI */
765: /* Read-only register */
766: break;
767: case 0xA0: /* PIAC */
768: /* Read-only register */
769: break;
770: case 0xB0: /* PEOI */
771: DPRINTF("PEOI\n");
772: n_IRQ = IRQ_get_next(opp, &dst->servicing);
773: IRQ_resetbit(&dst->servicing, n_IRQ);
774: dst->servicing.next = -1;
775: src = &opp->src[n_IRQ];
776: /* Set up next servicing IRQ */
777: IRQ_get_next(opp, &dst->servicing);
778: /* Check queued interrupts. */
779: n_IRQ = IRQ_get_next(opp, &dst->raised);
780: if (n_IRQ != -1) {
781: src = &opp->src[n_IRQ];
782: if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
783: DPRINTF("Raise CPU IRQ\n");
1.1.1.2 ! root 784: cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
1.1 root 785: }
786: }
787: break;
788: default:
789: break;
790: }
791: }
792:
793: static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
794: {
795: openpic_t *opp = opaque;
796: IRQ_src_t *src;
797: IRQ_dst_t *dst;
798: uint32_t retval;
799: int idx, n_IRQ;
800:
801: DPRINTF("%s: addr %08x\n", __func__, addr);
802: retval = 0xFFFFFFFF;
803: if (addr & 0xF)
804: return retval;
805: addr &= 0x1FFF0;
806: idx = addr / 0x1000;
807: dst = &opp->dst[idx];
808: addr &= 0xFF0;
809: switch (addr) {
810: case 0x80: /* PCTP */
811: retval = dst->pctp;
812: break;
813: case 0x90: /* WHOAMI */
814: retval = idx;
815: break;
816: case 0xA0: /* PIAC */
817: n_IRQ = IRQ_get_next(opp, &dst->raised);
818: DPRINTF("PIAC: irq=%d\n", n_IRQ);
819: if (n_IRQ == -1) {
820: /* No more interrupt pending */
821: retval = opp->spve;
822: } else {
823: src = &opp->src[n_IRQ];
824: if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
825: !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
826: /* - Spurious level-sensitive IRQ
827: * - Priorities has been changed
828: * and the pending IRQ isn't allowed anymore
829: */
830: reset_bit(&src->ipvp, IPVP_ACTIVITY);
831: retval = IPVP_VECTOR(opp->spve);
832: } else {
833: /* IRQ enter servicing state */
834: IRQ_setbit(&dst->servicing, n_IRQ);
835: retval = IPVP_VECTOR(src->ipvp);
836: }
837: IRQ_resetbit(&dst->raised, n_IRQ);
838: dst->raised.next = -1;
839: if (!test_bit(&src->ipvp, IPVP_SENSE)) {
840: /* edge-sensitive IRQ */
841: reset_bit(&src->ipvp, IPVP_ACTIVITY);
842: src->pending = 0;
843: }
844: }
845: break;
846: case 0xB0: /* PEOI */
847: retval = 0;
848: break;
849: #if MAX_IPI > 0
850: case 0x40: /* IDE */
851: case 0x50:
852: idx = (addr - 0x40) >> 4;
853: retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE);
854: break;
855: #endif
856: default:
857: break;
858: }
859: DPRINTF("%s: => %08x\n", __func__, retval);
860: #if defined OPENPIC_SWAP
861: retval= bswap32(retval);
862: #endif
863:
864: return retval;
865: }
866:
867: static void openpic_buggy_write (void *opaque,
868: target_phys_addr_t addr, uint32_t val)
869: {
870: printf("Invalid OPENPIC write access !\n");
871: }
872:
873: static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
874: {
875: printf("Invalid OPENPIC read access !\n");
876:
877: return -1;
878: }
879:
880: static void openpic_writel (void *opaque,
881: target_phys_addr_t addr, uint32_t val)
882: {
883: openpic_t *opp = opaque;
884:
885: addr &= 0x3FFFF;
886: DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
887: if (addr < 0x1100) {
888: /* Global registers */
889: openpic_gbl_write(opp, addr, val);
890: } else if (addr < 0x10000) {
891: /* Timers registers */
892: openpic_timer_write(opp, addr, val);
893: } else if (addr < 0x20000) {
894: /* Source registers */
895: openpic_src_write(opp, addr, val);
896: } else {
897: /* CPU registers */
898: openpic_cpu_write(opp, addr, val);
899: }
900: }
901:
902: static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
903: {
904: openpic_t *opp = opaque;
905: uint32_t retval;
906:
907: addr &= 0x3FFFF;
908: DPRINTF("%s: offset %08x\n", __func__, (int)addr);
909: if (addr < 0x1100) {
910: /* Global registers */
911: retval = openpic_gbl_read(opp, addr);
912: } else if (addr < 0x10000) {
913: /* Timers registers */
914: retval = openpic_timer_read(opp, addr);
915: } else if (addr < 0x20000) {
916: /* Source registers */
917: retval = openpic_src_read(opp, addr);
918: } else {
919: /* CPU registers */
920: retval = openpic_cpu_read(opp, addr);
921: }
922:
923: return retval;
924: }
925:
926: static CPUWriteMemoryFunc *openpic_write[] = {
927: &openpic_buggy_write,
928: &openpic_buggy_write,
929: &openpic_writel,
930: };
931:
932: static CPUReadMemoryFunc *openpic_read[] = {
933: &openpic_buggy_read,
934: &openpic_buggy_read,
935: &openpic_readl,
936: };
937:
938: static void openpic_map(PCIDevice *pci_dev, int region_num,
939: uint32_t addr, uint32_t size, int type)
940: {
941: openpic_t *opp;
942:
943: DPRINTF("Map OpenPIC\n");
944: opp = (openpic_t *)pci_dev;
945: /* Global registers */
946: DPRINTF("Register OPENPIC gbl %08x => %08x\n",
947: addr + 0x1000, addr + 0x1000 + 0x100);
948: /* Timer registers */
949: DPRINTF("Register OPENPIC timer %08x => %08x\n",
950: addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
951: /* Interrupt source registers */
952: DPRINTF("Register OPENPIC src %08x => %08x\n",
953: addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2));
954: /* Per CPU registers */
955: DPRINTF("Register OPENPIC dst %08x => %08x\n",
956: addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
957: cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
958: #if 0 // Don't implement ISU for now
959: opp_io_memory = cpu_register_io_memory(0, openpic_src_read,
960: openpic_src_write);
961: cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
962: opp_io_memory);
963: #endif
964: }
965:
1.1.1.2 ! root 966: openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
! 967: CPUPPCState **envp)
1.1 root 968: {
969: openpic_t *opp;
970: uint8_t *pci_conf;
971: int i, m;
972:
973: /* XXX: for now, only one CPU is supported */
974: if (nb_cpus != 1)
975: return NULL;
976: if (bus) {
977: opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
978: -1, NULL, NULL);
979: if (opp == NULL)
980: return NULL;
981: pci_conf = opp->pci_dev.config;
982: pci_conf[0x00] = 0x14; // IBM MPIC2
983: pci_conf[0x01] = 0x10;
984: pci_conf[0x02] = 0xFF;
985: pci_conf[0x03] = 0xFF;
986: pci_conf[0x0a] = 0x80; // PIC
987: pci_conf[0x0b] = 0x08;
988: pci_conf[0x0e] = 0x00; // header_type
989: pci_conf[0x3d] = 0x00; // no interrupt pin
990:
991: /* Register I/O spaces */
992: pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
993: PCI_ADDRESS_SPACE_MEM, &openpic_map);
994: } else {
995: opp = qemu_mallocz(sizeof(openpic_t));
996: }
997:
998: opp->mem_index = cpu_register_io_memory(0, openpic_read,
999: openpic_write, opp);
1000:
1001: // isu_base &= 0xFFFC0000;
1002: opp->nb_cpus = nb_cpus;
1003: /* Set IRQ types */
1004: for (i = 0; i < EXT_IRQ; i++) {
1005: opp->src[i].type = IRQ_EXTERNAL;
1006: }
1007: for (; i < IRQ_TIM0; i++) {
1008: opp->src[i].type = IRQ_SPECIAL;
1009: }
1010: #if MAX_IPI > 0
1011: m = IRQ_IPI0;
1012: #else
1013: m = IRQ_DBL0;
1014: #endif
1015: for (; i < m; i++) {
1016: opp->src[i].type = IRQ_TIMER;
1017: }
1018: for (; i < MAX_IRQ; i++) {
1019: opp->src[i].type = IRQ_INTERNAL;
1020: }
1.1.1.2 ! root 1021: for (i = 0; i < nb_cpus; i++)
! 1022: opp->dst[i].env = envp[i];
1.1 root 1023: openpic_reset(opp);
1024: if (pmem_index)
1025: *pmem_index = opp->mem_index;
1026: return opp;
1027: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.