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 companion chip developer'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 "hw.h"
36: #include "ppc_mac.h"
37: #include "pci.h"
38: #include "openpic.h"
39:
40: //#define DEBUG_OPENPIC
41:
42: #ifdef DEBUG_OPENPIC
43: #define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
44: #else
45: #define DPRINTF(fmt, ...) do { } while (0)
46: #endif
47:
48: #define USE_MPCxxx /* Intel model is broken, for now */
49:
50: #if defined (USE_INTEL_GW80314)
51: /* Intel GW80314 I/O Companion chip */
52:
53: #define MAX_CPU 4
54: #define MAX_IRQ 32
55: #define MAX_DBL 4
56: #define MAX_MBX 4
57: #define MAX_TMR 4
58: #define VECTOR_BITS 8
59: #define MAX_IPI 0
60:
61: #define VID (0x00000000)
62:
63: #elif defined(USE_MPCxxx)
64:
65: #define MAX_CPU 2
66: #define MAX_IRQ 128
67: #define MAX_DBL 0
68: #define MAX_MBX 0
69: #define MAX_TMR 4
70: #define VECTOR_BITS 8
71: #define MAX_IPI 4
72: #define VID 0x03 /* MPIC version ID */
73: #define VENI 0x00000000 /* Vendor ID */
74:
75: enum {
76: IRQ_IPVP = 0,
77: IRQ_IDE,
78: };
79:
80: /* OpenPIC */
81: #define OPENPIC_MAX_CPU 2
82: #define OPENPIC_MAX_IRQ 64
83: #define OPENPIC_EXT_IRQ 48
84: #define OPENPIC_MAX_TMR MAX_TMR
85: #define OPENPIC_MAX_IPI MAX_IPI
86:
87: /* Interrupt definitions */
88: #define OPENPIC_IRQ_FE (OPENPIC_EXT_IRQ) /* Internal functional IRQ */
89: #define OPENPIC_IRQ_ERR (OPENPIC_EXT_IRQ + 1) /* Error IRQ */
90: #define OPENPIC_IRQ_TIM0 (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */
91: #if OPENPIC_MAX_IPI > 0
92: #define OPENPIC_IRQ_IPI0 (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */
93: #define OPENPIC_IRQ_DBL0 (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */
94: #else
95: #define OPENPIC_IRQ_DBL0 (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */
96: #define OPENPIC_IRQ_MBX0 (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */
97: #endif
98:
99: /* MPIC */
100: #define MPIC_MAX_CPU 1
101: #define MPIC_MAX_EXT 12
102: #define MPIC_MAX_INT 64
103: #define MPIC_MAX_MSG 4
104: #define MPIC_MAX_MSI 8
105: #define MPIC_MAX_TMR MAX_TMR
106: #define MPIC_MAX_IPI MAX_IPI
107: #define MPIC_MAX_IRQ (MPIC_MAX_EXT + MPIC_MAX_INT + MPIC_MAX_TMR + MPIC_MAX_MSG + MPIC_MAX_MSI + (MPIC_MAX_IPI * MPIC_MAX_CPU))
108:
109: /* Interrupt definitions */
110: #define MPIC_EXT_IRQ 0
111: #define MPIC_INT_IRQ (MPIC_EXT_IRQ + MPIC_MAX_EXT)
112: #define MPIC_TMR_IRQ (MPIC_INT_IRQ + MPIC_MAX_INT)
113: #define MPIC_MSG_IRQ (MPIC_TMR_IRQ + MPIC_MAX_TMR)
114: #define MPIC_MSI_IRQ (MPIC_MSG_IRQ + MPIC_MAX_MSG)
115: #define MPIC_IPI_IRQ (MPIC_MSI_IRQ + MPIC_MAX_MSI)
116:
117: #define MPIC_GLB_REG_START 0x0
118: #define MPIC_GLB_REG_SIZE 0x10F0
119: #define MPIC_TMR_REG_START 0x10F0
120: #define MPIC_TMR_REG_SIZE 0x220
121: #define MPIC_EXT_REG_START 0x10000
122: #define MPIC_EXT_REG_SIZE 0x180
123: #define MPIC_INT_REG_START 0x10200
124: #define MPIC_INT_REG_SIZE 0x800
125: #define MPIC_MSG_REG_START 0x11600
126: #define MPIC_MSG_REG_SIZE 0x100
127: #define MPIC_MSI_REG_START 0x11C00
128: #define MPIC_MSI_REG_SIZE 0x100
129: #define MPIC_CPU_REG_START 0x20000
130: #define MPIC_CPU_REG_SIZE 0x100
131:
132: enum mpic_ide_bits {
133: IDR_EP = 0,
134: IDR_CI0 = 1,
135: IDR_CI1 = 2,
136: IDR_P1 = 30,
137: IDR_P0 = 31,
138: };
139:
140: #else
141: #error "Please select which OpenPic implementation is to be emulated"
142: #endif
143:
144: #define BF_WIDTH(_bits_) \
145: (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
146:
147: static inline void set_bit (uint32_t *field, int bit)
148: {
149: field[bit >> 5] |= 1 << (bit & 0x1F);
150: }
151:
152: static inline void reset_bit (uint32_t *field, int bit)
153: {
154: field[bit >> 5] &= ~(1 << (bit & 0x1F));
155: }
156:
157: static inline int test_bit (uint32_t *field, int bit)
158: {
159: return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
160: }
161:
162: enum {
163: IRQ_EXTERNAL = 0x01,
164: IRQ_INTERNAL = 0x02,
165: IRQ_TIMER = 0x04,
166: IRQ_SPECIAL = 0x08,
167: };
168:
169: typedef struct IRQ_queue_t {
170: uint32_t queue[BF_WIDTH(MAX_IRQ)];
171: int next;
172: int priority;
173: } IRQ_queue_t;
174:
175: typedef struct IRQ_src_t {
176: uint32_t ipvp; /* IRQ vector/priority register */
177: uint32_t ide; /* IRQ destination register */
178: int type;
179: int last_cpu;
180: int pending; /* TRUE if IRQ is pending */
181: } IRQ_src_t;
182:
183: enum IPVP_bits {
184: IPVP_MASK = 31,
185: IPVP_ACTIVITY = 30,
186: IPVP_MODE = 29,
187: IPVP_POLARITY = 23,
188: IPVP_SENSE = 22,
189: };
190: #define IPVP_PRIORITY_MASK (0x1F << 16)
191: #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
192: #define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1)
193: #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK)
194:
195: typedef struct IRQ_dst_t {
196: uint32_t tfrr;
197: uint32_t pctp; /* CPU current task priority */
198: uint32_t pcsr; /* CPU sensitivity register */
199: IRQ_queue_t raised;
200: IRQ_queue_t servicing;
201: qemu_irq *irqs;
202: } IRQ_dst_t;
203:
204: typedef struct openpic_t {
205: PCIDevice pci_dev;
206: int mem_index;
207: /* Global registers */
208: uint32_t frep; /* Feature reporting register */
209: uint32_t glbc; /* Global configuration register */
210: uint32_t micr; /* MPIC interrupt configuration register */
211: uint32_t veni; /* Vendor identification register */
212: uint32_t pint; /* Processor initialization register */
213: uint32_t spve; /* Spurious vector register */
214: uint32_t tifr; /* Timer frequency reporting register */
215: /* Source registers */
216: IRQ_src_t src[MAX_IRQ];
217: /* Local registers per output pin */
218: IRQ_dst_t dst[MAX_CPU];
219: int nb_cpus;
220: /* Timer registers */
221: struct {
222: uint32_t ticc; /* Global timer current count register */
223: uint32_t tibc; /* Global timer base count register */
224: } timers[MAX_TMR];
225: #if MAX_DBL > 0
226: /* Doorbell registers */
227: uint32_t dar; /* Doorbell activate register */
228: struct {
229: uint32_t dmr; /* Doorbell messaging register */
230: } doorbells[MAX_DBL];
231: #endif
232: #if MAX_MBX > 0
233: /* Mailbox registers */
234: struct {
235: uint32_t mbr; /* Mailbox register */
236: } mailboxes[MAX_MAILBOXES];
237: #endif
238: /* IRQ out is used when in bypass mode (not implemented) */
239: qemu_irq irq_out;
240: int max_irq;
241: int irq_ipi0;
242: int irq_tim0;
243: int need_swap;
244: void (*reset) (void *);
245: void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *);
246: } openpic_t;
247:
248: static inline uint32_t openpic_swap32(openpic_t *opp, uint32_t val)
249: {
250: if (opp->need_swap)
251: return bswap32(val);
252:
253: return val;
254: }
255:
256: static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
257: {
258: set_bit(q->queue, n_IRQ);
259: }
260:
261: static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
262: {
263: reset_bit(q->queue, n_IRQ);
264: }
265:
266: static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
267: {
268: return test_bit(q->queue, n_IRQ);
269: }
270:
271: static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
272: {
273: int next, i;
274: int priority;
275:
276: next = -1;
277: priority = -1;
278: for (i = 0; i < opp->max_irq; i++) {
279: if (IRQ_testbit(q, i)) {
280: DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
281: i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
282: if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
283: next = i;
284: priority = IPVP_PRIORITY(opp->src[i].ipvp);
285: }
286: }
287: }
288: q->next = next;
289: q->priority = priority;
290: }
291:
292: static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
293: {
294: if (q->next == -1) {
295: /* XXX: optimize */
296: IRQ_check(opp, q);
297: }
298:
299: return q->next;
300: }
301:
302: static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
303: {
304: IRQ_dst_t *dst;
305: IRQ_src_t *src;
306: int priority;
307:
308: dst = &opp->dst[n_CPU];
309: src = &opp->src[n_IRQ];
310: priority = IPVP_PRIORITY(src->ipvp);
311: if (priority <= dst->pctp) {
312: /* Too low priority */
313: DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
314: __func__, n_IRQ, n_CPU);
315: return;
316: }
317: if (IRQ_testbit(&dst->raised, n_IRQ)) {
318: /* Interrupt miss */
319: DPRINTF("%s: IRQ %d was missed on CPU %d\n",
320: __func__, n_IRQ, n_CPU);
321: return;
322: }
323: set_bit(&src->ipvp, IPVP_ACTIVITY);
324: IRQ_setbit(&dst->raised, n_IRQ);
325: if (priority < dst->raised.priority) {
326: /* An higher priority IRQ is already raised */
327: DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
328: __func__, n_IRQ, dst->raised.next, n_CPU);
329: return;
330: }
331: IRQ_get_next(opp, &dst->raised);
332: if (IRQ_get_next(opp, &dst->servicing) != -1 &&
333: priority <= dst->servicing.priority) {
334: DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
335: __func__, n_IRQ, dst->servicing.next, n_CPU);
336: /* Already servicing a higher priority IRQ */
337: return;
338: }
339: DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
340: opp->irq_raise(opp, n_CPU, src);
341: }
342:
343: /* update pic state because registers for n_IRQ have changed value */
344: static void openpic_update_irq(openpic_t *opp, int n_IRQ)
345: {
346: IRQ_src_t *src;
347: int i;
348:
349: src = &opp->src[n_IRQ];
350:
351: if (!src->pending) {
352: /* no irq pending */
353: DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
354: return;
355: }
356: if (test_bit(&src->ipvp, IPVP_MASK)) {
357: /* Interrupt source is disabled */
358: DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
359: return;
360: }
361: if (IPVP_PRIORITY(src->ipvp) == 0) {
362: /* Priority set to zero */
363: DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
364: return;
365: }
366: if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
367: /* IRQ already active */
368: DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
369: return;
370: }
371: if (src->ide == 0x00000000) {
372: /* No target */
373: DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
374: return;
375: }
376:
377: if (src->ide == (1 << src->last_cpu)) {
378: /* Only one CPU is allowed to receive this IRQ */
379: IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
380: } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
381: /* Directed delivery mode */
382: for (i = 0; i < opp->nb_cpus; i++) {
383: if (test_bit(&src->ide, i))
384: IRQ_local_pipe(opp, i, n_IRQ);
385: }
386: } else {
387: /* Distributed delivery mode */
388: for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
389: if (i == opp->nb_cpus)
390: i = 0;
391: if (test_bit(&src->ide, i)) {
392: IRQ_local_pipe(opp, i, n_IRQ);
393: src->last_cpu = i;
394: break;
395: }
396: }
397: }
398: }
399:
400: static void openpic_set_irq(void *opaque, int n_IRQ, int level)
401: {
402: openpic_t *opp = opaque;
403: IRQ_src_t *src;
404:
405: src = &opp->src[n_IRQ];
406: DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
407: n_IRQ, level, src->ipvp);
408: if (test_bit(&src->ipvp, IPVP_SENSE)) {
409: /* level-sensitive irq */
410: src->pending = level;
411: if (!level)
412: reset_bit(&src->ipvp, IPVP_ACTIVITY);
413: } else {
414: /* edge-sensitive irq */
415: if (level)
416: src->pending = 1;
417: }
418: openpic_update_irq(opp, n_IRQ);
419: }
420:
421: static void openpic_reset (void *opaque)
422: {
423: openpic_t *opp = (openpic_t *)opaque;
424: int i;
425:
426: opp->glbc = 0x80000000;
427: /* Initialise controller registers */
428: opp->frep = ((OPENPIC_EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
429: opp->veni = VENI;
430: opp->pint = 0x00000000;
431: opp->spve = 0x000000FF;
432: opp->tifr = 0x003F7A00;
433: /* ? */
434: opp->micr = 0x00000000;
435: /* Initialise IRQ sources */
436: for (i = 0; i < opp->max_irq; i++) {
437: opp->src[i].ipvp = 0xA0000000;
438: opp->src[i].ide = 0x00000000;
439: }
440: /* Initialise IRQ destinations */
441: for (i = 0; i < MAX_CPU; i++) {
442: opp->dst[i].pctp = 0x0000000F;
443: opp->dst[i].pcsr = 0x00000000;
444: memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
445: memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
446: }
447: /* Initialise timers */
448: for (i = 0; i < MAX_TMR; i++) {
449: opp->timers[i].ticc = 0x00000000;
450: opp->timers[i].tibc = 0x80000000;
451: }
452: /* Initialise doorbells */
453: #if MAX_DBL > 0
454: opp->dar = 0x00000000;
455: for (i = 0; i < MAX_DBL; i++) {
456: opp->doorbells[i].dmr = 0x00000000;
457: }
458: #endif
459: /* Initialise mailboxes */
460: #if MAX_MBX > 0
461: for (i = 0; i < MAX_MBX; i++) { /* ? */
462: opp->mailboxes[i].mbr = 0x00000000;
463: }
464: #endif
465: /* Go out of RESET state */
466: opp->glbc = 0x00000000;
467: }
468:
469: static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
470: {
471: uint32_t retval;
472:
473: switch (reg) {
474: case IRQ_IPVP:
475: retval = opp->src[n_IRQ].ipvp;
476: break;
477: case IRQ_IDE:
478: retval = opp->src[n_IRQ].ide;
479: break;
480: }
481:
482: return retval;
483: }
484:
485: static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
486: uint32_t reg, uint32_t val)
487: {
488: uint32_t tmp;
489:
490: switch (reg) {
491: case IRQ_IPVP:
492: /* NOTE: not fully accurate for special IRQs, but simple and
493: sufficient */
494: /* ACTIVITY bit is read-only */
495: opp->src[n_IRQ].ipvp =
496: (opp->src[n_IRQ].ipvp & 0x40000000) |
497: (val & 0x800F00FF);
498: openpic_update_irq(opp, n_IRQ);
499: DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
500: n_IRQ, val, opp->src[n_IRQ].ipvp);
501: break;
502: case IRQ_IDE:
503: tmp = val & 0xC0000000;
504: tmp |= val & ((1 << MAX_CPU) - 1);
505: opp->src[n_IRQ].ide = tmp;
506: DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
507: break;
508: }
509: }
510:
511: #if 0 // Code provision for Intel model
512: #if MAX_DBL > 0
513: static uint32_t read_doorbell_register (openpic_t *opp,
514: int n_dbl, uint32_t offset)
515: {
516: uint32_t retval;
517:
518: switch (offset) {
519: case DBL_IPVP_OFFSET:
520: retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
521: break;
522: case DBL_IDE_OFFSET:
523: retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
524: break;
525: case DBL_DMR_OFFSET:
526: retval = opp->doorbells[n_dbl].dmr;
527: break;
528: }
529:
530: return retval;
531: }
532:
533: static void write_doorbell_register (penpic_t *opp, int n_dbl,
534: uint32_t offset, uint32_t value)
535: {
536: switch (offset) {
537: case DBL_IVPR_OFFSET:
538: write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
539: break;
540: case DBL_IDE_OFFSET:
541: write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
542: break;
543: case DBL_DMR_OFFSET:
544: opp->doorbells[n_dbl].dmr = value;
545: break;
546: }
547: }
548: #endif
549:
550: #if MAX_MBX > 0
551: static uint32_t read_mailbox_register (openpic_t *opp,
552: int n_mbx, uint32_t offset)
553: {
554: uint32_t retval;
555:
556: switch (offset) {
557: case MBX_MBR_OFFSET:
558: retval = opp->mailboxes[n_mbx].mbr;
559: break;
560: case MBX_IVPR_OFFSET:
561: retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
562: break;
563: case MBX_DMR_OFFSET:
564: retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
565: break;
566: }
567:
568: return retval;
569: }
570:
571: static void write_mailbox_register (openpic_t *opp, int n_mbx,
572: uint32_t address, uint32_t value)
573: {
574: switch (offset) {
575: case MBX_MBR_OFFSET:
576: opp->mailboxes[n_mbx].mbr = value;
577: break;
578: case MBX_IVPR_OFFSET:
579: write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
580: break;
581: case MBX_DMR_OFFSET:
582: write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
583: break;
584: }
585: }
586: #endif
587: #endif /* 0 : Code provision for Intel model */
588:
589: static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t val)
590: {
591: openpic_t *opp = opaque;
592: IRQ_dst_t *dst;
593: int idx;
594:
595: DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
596: if (addr & 0xF)
597: return;
598: #if defined TARGET_WORDS_BIGENDIAN
599: val = openpic_swap32(opp, val);
600: #endif
601: addr &= 0xFF;
602: switch (addr) {
603: case 0x00: /* FREP */
604: break;
605: case 0x20: /* GLBC */
606: if (val & 0x80000000 && opp->reset)
607: opp->reset(opp);
608: opp->glbc = val & ~0x80000000;
609: break;
610: case 0x80: /* VENI */
611: break;
612: case 0x90: /* PINT */
613: for (idx = 0; idx < opp->nb_cpus; idx++) {
614: if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
615: DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
616: dst = &opp->dst[idx];
617: qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
618: } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
619: DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
620: dst = &opp->dst[idx];
621: qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
622: }
623: }
624: opp->pint = val;
625: break;
626: #if MAX_IPI > 0
627: case 0xA0: /* IPI_IPVP */
628: case 0xB0:
629: case 0xC0:
630: case 0xD0:
631: {
632: int idx;
633: idx = (addr - 0xA0) >> 4;
634: write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP, val);
635: }
636: break;
637: #endif
638: case 0xE0: /* SPVE */
639: opp->spve = val & 0x000000FF;
640: break;
641: case 0xF0: /* TIFR */
642: opp->tifr = val;
643: break;
644: default:
645: break;
646: }
647: }
648:
649: static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
650: {
651: openpic_t *opp = opaque;
652: uint32_t retval;
653:
654: DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
655: retval = 0xFFFFFFFF;
656: if (addr & 0xF)
657: return retval;
658: addr &= 0xFF;
659: switch (addr) {
660: case 0x00: /* FREP */
661: retval = opp->frep;
662: break;
663: case 0x20: /* GLBC */
664: retval = opp->glbc;
665: break;
666: case 0x80: /* VENI */
667: retval = opp->veni;
668: break;
669: case 0x90: /* PINT */
670: retval = 0x00000000;
671: break;
672: #if MAX_IPI > 0
673: case 0xA0: /* IPI_IPVP */
674: case 0xB0:
675: case 0xC0:
676: case 0xD0:
677: {
678: int idx;
679: idx = (addr - 0xA0) >> 4;
680: retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP);
681: }
682: break;
683: #endif
684: case 0xE0: /* SPVE */
685: retval = opp->spve;
686: break;
687: case 0xF0: /* TIFR */
688: retval = opp->tifr;
689: break;
690: default:
691: break;
692: }
693: DPRINTF("%s: => %08x\n", __func__, retval);
694: #if defined TARGET_WORDS_BIGENDIAN
695: retval = openpic_swap32(opp, retval);
696: #endif
697:
698: return retval;
699: }
700:
701: static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
702: {
703: openpic_t *opp = opaque;
704: int idx;
705:
706: DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
707: if (addr & 0xF)
708: return;
709: #if defined TARGET_WORDS_BIGENDIAN
710: val = openpic_swap32(opp, val);
711: #endif
712: addr -= 0x1100;
713: addr &= 0xFFFF;
714: idx = (addr & 0xFFF0) >> 6;
715: addr = addr & 0x30;
716: switch (addr) {
717: case 0x00: /* TICC */
718: break;
719: case 0x10: /* TIBC */
720: if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
721: (val & 0x80000000) == 0 &&
722: (opp->timers[idx].tibc & 0x80000000) != 0)
723: opp->timers[idx].ticc &= ~0x80000000;
724: opp->timers[idx].tibc = val;
725: break;
726: case 0x20: /* TIVP */
727: write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP, val);
728: break;
729: case 0x30: /* TIDE */
730: write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE, val);
731: break;
732: }
733: }
734:
735: static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
736: {
737: openpic_t *opp = opaque;
738: uint32_t retval;
739: int idx;
740:
741: DPRINTF("%s: addr %08x\n", __func__, addr);
742: retval = 0xFFFFFFFF;
743: if (addr & 0xF)
744: return retval;
745: addr -= 0x1100;
746: addr &= 0xFFFF;
747: idx = (addr & 0xFFF0) >> 6;
748: addr = addr & 0x30;
749: switch (addr) {
750: case 0x00: /* TICC */
751: retval = opp->timers[idx].ticc;
752: break;
753: case 0x10: /* TIBC */
754: retval = opp->timers[idx].tibc;
755: break;
756: case 0x20: /* TIPV */
757: retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP);
758: break;
759: case 0x30: /* TIDE */
760: retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE);
761: break;
762: }
763: DPRINTF("%s: => %08x\n", __func__, retval);
764: #if defined TARGET_WORDS_BIGENDIAN
765: retval = openpic_swap32(opp, retval);
766: #endif
767:
768: return retval;
769: }
770:
771: static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
772: {
773: openpic_t *opp = opaque;
774: int idx;
775:
776: DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
777: if (addr & 0xF)
778: return;
779: #if defined TARGET_WORDS_BIGENDIAN
780: val = openpic_swap32(opp, val);
781: #endif
782: addr = addr & 0xFFF0;
783: idx = addr >> 5;
784: if (addr & 0x10) {
785: /* EXDE / IFEDE / IEEDE */
786: write_IRQreg(opp, idx, IRQ_IDE, val);
787: } else {
788: /* EXVP / IFEVP / IEEVP */
789: write_IRQreg(opp, idx, IRQ_IPVP, val);
790: }
791: }
792:
793: static uint32_t openpic_src_read (void *opaque, uint32_t addr)
794: {
795: openpic_t *opp = opaque;
796: uint32_t retval;
797: int idx;
798:
799: DPRINTF("%s: addr %08x\n", __func__, addr);
800: retval = 0xFFFFFFFF;
801: if (addr & 0xF)
802: return retval;
803: addr = addr & 0xFFF0;
804: idx = addr >> 5;
805: if (addr & 0x10) {
806: /* EXDE / IFEDE / IEEDE */
807: retval = read_IRQreg(opp, idx, IRQ_IDE);
808: } else {
809: /* EXVP / IFEVP / IEEVP */
810: retval = read_IRQreg(opp, idx, IRQ_IPVP);
811: }
812: DPRINTF("%s: => %08x\n", __func__, retval);
813: #if defined TARGET_WORDS_BIGENDIAN
814: retval = openpic_swap32(opp, retval);
815: #endif
816:
817: return retval;
818: }
819:
820: static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t val)
821: {
822: openpic_t *opp = opaque;
823: IRQ_src_t *src;
824: IRQ_dst_t *dst;
825: int idx, s_IRQ, n_IRQ;
826:
827: DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
828: if (addr & 0xF)
829: return;
830: #if defined TARGET_WORDS_BIGENDIAN
831: val = openpic_swap32(opp, val);
832: #endif
833: addr &= 0x1FFF0;
834: idx = addr / 0x1000;
835: dst = &opp->dst[idx];
836: addr &= 0xFF0;
837: switch (addr) {
838: #if MAX_IPI > 0
839: case 0x40: /* PIPD */
840: case 0x50:
841: case 0x60:
842: case 0x70:
843: idx = (addr - 0x40) >> 4;
844: write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE, val);
845: openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
846: openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
847: break;
848: #endif
849: case 0x80: /* PCTP */
850: dst->pctp = val & 0x0000000F;
851: break;
852: case 0x90: /* WHOAMI */
853: /* Read-only register */
854: break;
855: case 0xA0: /* PIAC */
856: /* Read-only register */
857: break;
858: case 0xB0: /* PEOI */
859: DPRINTF("PEOI\n");
860: s_IRQ = IRQ_get_next(opp, &dst->servicing);
861: IRQ_resetbit(&dst->servicing, s_IRQ);
862: dst->servicing.next = -1;
863: /* Set up next servicing IRQ */
864: s_IRQ = IRQ_get_next(opp, &dst->servicing);
865: /* Check queued interrupts. */
866: n_IRQ = IRQ_get_next(opp, &dst->raised);
867: src = &opp->src[n_IRQ];
868: if (n_IRQ != -1 &&
869: (s_IRQ == -1 ||
870: IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
871: DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
872: idx, n_IRQ);
873: opp->irq_raise(opp, idx, src);
874: }
875: break;
876: default:
877: break;
878: }
879: }
880:
881: static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr)
882: {
883: openpic_t *opp = opaque;
884: IRQ_src_t *src;
885: IRQ_dst_t *dst;
886: uint32_t retval;
887: int idx, n_IRQ;
888:
889: DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
890: retval = 0xFFFFFFFF;
891: if (addr & 0xF)
892: return retval;
893: addr &= 0x1FFF0;
894: idx = addr / 0x1000;
895: dst = &opp->dst[idx];
896: addr &= 0xFF0;
897: switch (addr) {
898: case 0x80: /* PCTP */
899: retval = dst->pctp;
900: break;
901: case 0x90: /* WHOAMI */
902: retval = idx;
903: break;
904: case 0xA0: /* PIAC */
905: DPRINTF("Lower OpenPIC INT output\n");
906: qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
907: n_IRQ = IRQ_get_next(opp, &dst->raised);
908: DPRINTF("PIAC: irq=%d\n", n_IRQ);
909: if (n_IRQ == -1) {
910: /* No more interrupt pending */
911: retval = IPVP_VECTOR(opp->spve);
912: } else {
913: src = &opp->src[n_IRQ];
914: if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
915: !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
916: /* - Spurious level-sensitive IRQ
917: * - Priorities has been changed
918: * and the pending IRQ isn't allowed anymore
919: */
920: reset_bit(&src->ipvp, IPVP_ACTIVITY);
921: retval = IPVP_VECTOR(opp->spve);
922: } else {
923: /* IRQ enter servicing state */
924: IRQ_setbit(&dst->servicing, n_IRQ);
925: retval = IPVP_VECTOR(src->ipvp);
926: }
927: IRQ_resetbit(&dst->raised, n_IRQ);
928: dst->raised.next = -1;
929: if (!test_bit(&src->ipvp, IPVP_SENSE)) {
930: /* edge-sensitive IRQ */
931: reset_bit(&src->ipvp, IPVP_ACTIVITY);
932: src->pending = 0;
933: }
934: }
935: break;
936: case 0xB0: /* PEOI */
937: retval = 0;
938: break;
939: #if MAX_IPI > 0
940: case 0x40: /* IDE */
941: case 0x50:
942: idx = (addr - 0x40) >> 4;
943: retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE);
944: break;
945: #endif
946: default:
947: break;
948: }
949: DPRINTF("%s: => %08x\n", __func__, retval);
950: #if defined TARGET_WORDS_BIGENDIAN
951: retval = openpic_swap32(opp, retval);
952: #endif
953:
954: return retval;
955: }
956:
957: static void openpic_buggy_write (void *opaque,
958: target_phys_addr_t addr, uint32_t val)
959: {
960: printf("Invalid OPENPIC write access !\n");
961: }
962:
963: static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
964: {
965: printf("Invalid OPENPIC read access !\n");
966:
967: return -1;
968: }
969:
970: static void openpic_writel (void *opaque,
971: target_phys_addr_t addr, uint32_t val)
972: {
973: openpic_t *opp = opaque;
974:
975: addr &= 0x3FFFF;
976: DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
977: if (addr < 0x1100) {
978: /* Global registers */
979: openpic_gbl_write(opp, addr, val);
980: } else if (addr < 0x10000) {
981: /* Timers registers */
982: openpic_timer_write(opp, addr, val);
983: } else if (addr < 0x20000) {
984: /* Source registers */
985: openpic_src_write(opp, addr, val);
986: } else {
987: /* CPU registers */
988: openpic_cpu_write(opp, addr, val);
989: }
990: }
991:
992: static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
993: {
994: openpic_t *opp = opaque;
995: uint32_t retval;
996:
997: addr &= 0x3FFFF;
998: DPRINTF("%s: offset %08x\n", __func__, (int)addr);
999: if (addr < 0x1100) {
1000: /* Global registers */
1001: retval = openpic_gbl_read(opp, addr);
1002: } else if (addr < 0x10000) {
1003: /* Timers registers */
1004: retval = openpic_timer_read(opp, addr);
1005: } else if (addr < 0x20000) {
1006: /* Source registers */
1007: retval = openpic_src_read(opp, addr);
1008: } else {
1009: /* CPU registers */
1010: retval = openpic_cpu_read(opp, addr);
1011: }
1012:
1013: return retval;
1014: }
1015:
1016: static CPUWriteMemoryFunc * const openpic_write[] = {
1017: &openpic_buggy_write,
1018: &openpic_buggy_write,
1019: &openpic_writel,
1020: };
1021:
1022: static CPUReadMemoryFunc * const openpic_read[] = {
1023: &openpic_buggy_read,
1024: &openpic_buggy_read,
1025: &openpic_readl,
1026: };
1027:
1028: static void openpic_map(PCIDevice *pci_dev, int region_num,
1029: pcibus_t addr, pcibus_t size, int type)
1030: {
1031: openpic_t *opp;
1032:
1033: DPRINTF("Map OpenPIC\n");
1034: opp = (openpic_t *)pci_dev;
1035: /* Global registers */
1036: DPRINTF("Register OPENPIC gbl %08x => %08x\n",
1037: addr + 0x1000, addr + 0x1000 + 0x100);
1038: /* Timer registers */
1039: DPRINTF("Register OPENPIC timer %08x => %08x\n",
1040: addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
1041: /* Interrupt source registers */
1042: DPRINTF("Register OPENPIC src %08x => %08x\n",
1043: addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2));
1044: /* Per CPU registers */
1045: DPRINTF("Register OPENPIC dst %08x => %08x\n",
1046: addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
1047: cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
1048: #if 0 // Don't implement ISU for now
1049: opp_io_memory = cpu_register_io_memory(openpic_src_read,
1050: openpic_src_write);
1051: cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
1052: opp_io_memory);
1053: #endif
1054: }
1055:
1056: static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
1057: {
1058: unsigned int i;
1059:
1060: for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
1061: qemu_put_be32s(f, &q->queue[i]);
1062:
1063: qemu_put_sbe32s(f, &q->next);
1064: qemu_put_sbe32s(f, &q->priority);
1065: }
1066:
1067: static void openpic_save(QEMUFile* f, void *opaque)
1068: {
1069: openpic_t *opp = (openpic_t *)opaque;
1070: unsigned int i;
1071:
1072: qemu_put_be32s(f, &opp->frep);
1073: qemu_put_be32s(f, &opp->glbc);
1074: qemu_put_be32s(f, &opp->micr);
1075: qemu_put_be32s(f, &opp->veni);
1076: qemu_put_be32s(f, &opp->pint);
1077: qemu_put_be32s(f, &opp->spve);
1078: qemu_put_be32s(f, &opp->tifr);
1079:
1080: for (i = 0; i < opp->max_irq; i++) {
1081: qemu_put_be32s(f, &opp->src[i].ipvp);
1082: qemu_put_be32s(f, &opp->src[i].ide);
1083: qemu_put_sbe32s(f, &opp->src[i].type);
1084: qemu_put_sbe32s(f, &opp->src[i].last_cpu);
1085: qemu_put_sbe32s(f, &opp->src[i].pending);
1086: }
1087:
1088: qemu_put_sbe32s(f, &opp->nb_cpus);
1089:
1090: for (i = 0; i < opp->nb_cpus; i++) {
1091: qemu_put_be32s(f, &opp->dst[i].tfrr);
1092: qemu_put_be32s(f, &opp->dst[i].pctp);
1093: qemu_put_be32s(f, &opp->dst[i].pcsr);
1094: openpic_save_IRQ_queue(f, &opp->dst[i].raised);
1095: openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
1096: }
1097:
1098: for (i = 0; i < MAX_TMR; i++) {
1099: qemu_put_be32s(f, &opp->timers[i].ticc);
1100: qemu_put_be32s(f, &opp->timers[i].tibc);
1101: }
1102:
1103: #if MAX_DBL > 0
1104: qemu_put_be32s(f, &opp->dar);
1105:
1106: for (i = 0; i < MAX_DBL; i++) {
1107: qemu_put_be32s(f, &opp->doorbells[i].dmr);
1108: }
1109: #endif
1110:
1111: #if MAX_MBX > 0
1112: for (i = 0; i < MAX_MAILBOXES; i++) {
1113: qemu_put_be32s(f, &opp->mailboxes[i].mbr);
1114: }
1115: #endif
1116:
1117: pci_device_save(&opp->pci_dev, f);
1118: }
1119:
1120: static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
1121: {
1122: unsigned int i;
1123:
1124: for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
1125: qemu_get_be32s(f, &q->queue[i]);
1126:
1127: qemu_get_sbe32s(f, &q->next);
1128: qemu_get_sbe32s(f, &q->priority);
1129: }
1130:
1131: static int openpic_load(QEMUFile* f, void *opaque, int version_id)
1132: {
1133: openpic_t *opp = (openpic_t *)opaque;
1134: unsigned int i;
1135:
1136: if (version_id != 1)
1137: return -EINVAL;
1138:
1139: qemu_get_be32s(f, &opp->frep);
1140: qemu_get_be32s(f, &opp->glbc);
1141: qemu_get_be32s(f, &opp->micr);
1142: qemu_get_be32s(f, &opp->veni);
1143: qemu_get_be32s(f, &opp->pint);
1144: qemu_get_be32s(f, &opp->spve);
1145: qemu_get_be32s(f, &opp->tifr);
1146:
1147: for (i = 0; i < opp->max_irq; i++) {
1148: qemu_get_be32s(f, &opp->src[i].ipvp);
1149: qemu_get_be32s(f, &opp->src[i].ide);
1150: qemu_get_sbe32s(f, &opp->src[i].type);
1151: qemu_get_sbe32s(f, &opp->src[i].last_cpu);
1152: qemu_get_sbe32s(f, &opp->src[i].pending);
1153: }
1154:
1155: qemu_get_sbe32s(f, &opp->nb_cpus);
1156:
1157: for (i = 0; i < opp->nb_cpus; i++) {
1158: qemu_get_be32s(f, &opp->dst[i].tfrr);
1159: qemu_get_be32s(f, &opp->dst[i].pctp);
1160: qemu_get_be32s(f, &opp->dst[i].pcsr);
1161: openpic_load_IRQ_queue(f, &opp->dst[i].raised);
1162: openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
1163: }
1164:
1165: for (i = 0; i < MAX_TMR; i++) {
1166: qemu_get_be32s(f, &opp->timers[i].ticc);
1167: qemu_get_be32s(f, &opp->timers[i].tibc);
1168: }
1169:
1170: #if MAX_DBL > 0
1171: qemu_get_be32s(f, &opp->dar);
1172:
1173: for (i = 0; i < MAX_DBL; i++) {
1174: qemu_get_be32s(f, &opp->doorbells[i].dmr);
1175: }
1176: #endif
1177:
1178: #if MAX_MBX > 0
1179: for (i = 0; i < MAX_MAILBOXES; i++) {
1180: qemu_get_be32s(f, &opp->mailboxes[i].mbr);
1181: }
1182: #endif
1183:
1184: return pci_device_load(&opp->pci_dev, f);
1185: }
1186:
1187: static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
1188: {
1189: qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1190: }
1191:
1192: qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
1193: qemu_irq **irqs, qemu_irq irq_out)
1194: {
1195: openpic_t *opp;
1196: uint8_t *pci_conf;
1197: int i, m;
1198:
1199: /* XXX: for now, only one CPU is supported */
1200: if (nb_cpus != 1)
1201: return NULL;
1202: if (bus) {
1203: opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
1204: -1, NULL, NULL);
1205: pci_conf = opp->pci_dev.config;
1206: pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
1207: pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
1208: pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
1209: pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
1210: pci_conf[0x3d] = 0x00; // no interrupt pin
1211:
1212: /* Register I/O spaces */
1213: pci_register_bar((PCIDevice *)opp, 0, 0x40000,
1214: PCI_BASE_ADDRESS_SPACE_MEMORY, &openpic_map);
1215: } else {
1216: opp = qemu_mallocz(sizeof(openpic_t));
1217: }
1218: opp->mem_index = cpu_register_io_memory(openpic_read,
1219: openpic_write, opp);
1220:
1221: // isu_base &= 0xFFFC0000;
1222: opp->nb_cpus = nb_cpus;
1223: opp->max_irq = OPENPIC_MAX_IRQ;
1224: opp->irq_ipi0 = OPENPIC_IRQ_IPI0;
1225: opp->irq_tim0 = OPENPIC_IRQ_TIM0;
1226: /* Set IRQ types */
1227: for (i = 0; i < OPENPIC_EXT_IRQ; i++) {
1228: opp->src[i].type = IRQ_EXTERNAL;
1229: }
1230: for (; i < OPENPIC_IRQ_TIM0; i++) {
1231: opp->src[i].type = IRQ_SPECIAL;
1232: }
1233: #if MAX_IPI > 0
1234: m = OPENPIC_IRQ_IPI0;
1235: #else
1236: m = OPENPIC_IRQ_DBL0;
1237: #endif
1238: for (; i < m; i++) {
1239: opp->src[i].type = IRQ_TIMER;
1240: }
1241: for (; i < OPENPIC_MAX_IRQ; i++) {
1242: opp->src[i].type = IRQ_INTERNAL;
1243: }
1244: for (i = 0; i < nb_cpus; i++)
1245: opp->dst[i].irqs = irqs[i];
1246: opp->irq_out = irq_out;
1247: opp->need_swap = 1;
1248:
1249: register_savevm("openpic", 0, 2, openpic_save, openpic_load, opp);
1250: qemu_register_reset(openpic_reset, opp);
1251:
1252: opp->irq_raise = openpic_irq_raise;
1253: opp->reset = openpic_reset;
1254:
1255: if (pmem_index)
1256: *pmem_index = opp->mem_index;
1257:
1258: return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
1259: }
1260:
1261: static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src)
1262: {
1263: int n_ci = IDR_CI0 - n_CPU;
1264:
1265: if(test_bit(&src->ide, n_ci)) {
1266: qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]);
1267: }
1268: else {
1269: qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1270: }
1271: }
1272:
1273: static void mpic_reset (void *opaque)
1274: {
1275: openpic_t *mpp = (openpic_t *)opaque;
1276: int i;
1277:
1278: mpp->glbc = 0x80000000;
1279: /* Initialise controller registers */
1280: mpp->frep = 0x004f0002;
1281: mpp->veni = VENI;
1282: mpp->pint = 0x00000000;
1283: mpp->spve = 0x0000FFFF;
1284: /* Initialise IRQ sources */
1285: for (i = 0; i < mpp->max_irq; i++) {
1286: mpp->src[i].ipvp = 0x80800000;
1287: mpp->src[i].ide = 0x00000001;
1288: }
1289: /* Initialise IRQ destinations */
1290: for (i = 0; i < MAX_CPU; i++) {
1291: mpp->dst[i].pctp = 0x0000000F;
1292: mpp->dst[i].tfrr = 0x00000000;
1293: memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t));
1294: mpp->dst[i].raised.next = -1;
1295: memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
1296: mpp->dst[i].servicing.next = -1;
1297: }
1298: /* Initialise timers */
1299: for (i = 0; i < MAX_TMR; i++) {
1300: mpp->timers[i].ticc = 0x00000000;
1301: mpp->timers[i].tibc = 0x80000000;
1302: }
1303: /* Go out of RESET state */
1304: mpp->glbc = 0x00000000;
1305: }
1306:
1307: static void mpic_timer_write (void *opaque, target_phys_addr_t addr, uint32_t val)
1308: {
1309: openpic_t *mpp = opaque;
1310: int idx, cpu;
1311:
1312: DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1313: if (addr & 0xF)
1314: return;
1315: addr &= 0xFFFF;
1316: cpu = addr >> 12;
1317: idx = (addr >> 6) & 0x3;
1318: switch (addr & 0x30) {
1319: case 0x00: /* gtccr */
1320: break;
1321: case 0x10: /* gtbcr */
1322: if ((mpp->timers[idx].ticc & 0x80000000) != 0 &&
1323: (val & 0x80000000) == 0 &&
1324: (mpp->timers[idx].tibc & 0x80000000) != 0)
1325: mpp->timers[idx].ticc &= ~0x80000000;
1326: mpp->timers[idx].tibc = val;
1327: break;
1328: case 0x20: /* GTIVPR */
1329: write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP, val);
1330: break;
1331: case 0x30: /* GTIDR & TFRR */
1332: if ((addr & 0xF0) == 0xF0)
1333: mpp->dst[cpu].tfrr = val;
1334: else
1335: write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE, val);
1336: break;
1337: }
1338: }
1339:
1340: static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr)
1341: {
1342: openpic_t *mpp = opaque;
1343: uint32_t retval;
1344: int idx, cpu;
1345:
1346: DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1347: retval = 0xFFFFFFFF;
1348: if (addr & 0xF)
1349: return retval;
1350: addr &= 0xFFFF;
1351: cpu = addr >> 12;
1352: idx = (addr >> 6) & 0x3;
1353: switch (addr & 0x30) {
1354: case 0x00: /* gtccr */
1355: retval = mpp->timers[idx].ticc;
1356: break;
1357: case 0x10: /* gtbcr */
1358: retval = mpp->timers[idx].tibc;
1359: break;
1360: case 0x20: /* TIPV */
1361: retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP);
1362: break;
1363: case 0x30: /* TIDR */
1364: if ((addr &0xF0) == 0XF0)
1365: retval = mpp->dst[cpu].tfrr;
1366: else
1367: retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE);
1368: break;
1369: }
1370: DPRINTF("%s: => %08x\n", __func__, retval);
1371:
1372: return retval;
1373: }
1374:
1375: static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr,
1376: uint32_t val)
1377: {
1378: openpic_t *mpp = opaque;
1379: int idx = MPIC_EXT_IRQ;
1380:
1381: DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1382: if (addr & 0xF)
1383: return;
1384:
1385: addr -= MPIC_EXT_REG_START & (TARGET_PAGE_SIZE - 1);
1386: if (addr < MPIC_EXT_REG_SIZE) {
1387: idx += (addr & 0xFFF0) >> 5;
1388: if (addr & 0x10) {
1389: /* EXDE / IFEDE / IEEDE */
1390: write_IRQreg(mpp, idx, IRQ_IDE, val);
1391: } else {
1392: /* EXVP / IFEVP / IEEVP */
1393: write_IRQreg(mpp, idx, IRQ_IPVP, val);
1394: }
1395: }
1396: }
1397:
1398: static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr)
1399: {
1400: openpic_t *mpp = opaque;
1401: uint32_t retval;
1402: int idx = MPIC_EXT_IRQ;
1403:
1404: DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1405: retval = 0xFFFFFFFF;
1406: if (addr & 0xF)
1407: return retval;
1408:
1409: addr -= MPIC_EXT_REG_START & (TARGET_PAGE_SIZE - 1);
1410: if (addr < MPIC_EXT_REG_SIZE) {
1411: idx += (addr & 0xFFF0) >> 5;
1412: if (addr & 0x10) {
1413: /* EXDE / IFEDE / IEEDE */
1414: retval = read_IRQreg(mpp, idx, IRQ_IDE);
1415: } else {
1416: /* EXVP / IFEVP / IEEVP */
1417: retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1418: }
1419: DPRINTF("%s: => %08x\n", __func__, retval);
1420: }
1421:
1422: return retval;
1423: }
1424:
1425: static void mpic_src_int_write (void *opaque, target_phys_addr_t addr,
1426: uint32_t val)
1427: {
1428: openpic_t *mpp = opaque;
1429: int idx = MPIC_INT_IRQ;
1430:
1431: DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1432: if (addr & 0xF)
1433: return;
1434:
1435: addr -= MPIC_INT_REG_START & (TARGET_PAGE_SIZE - 1);
1436: if (addr < MPIC_INT_REG_SIZE) {
1437: idx += (addr & 0xFFF0) >> 5;
1438: if (addr & 0x10) {
1439: /* EXDE / IFEDE / IEEDE */
1440: write_IRQreg(mpp, idx, IRQ_IDE, val);
1441: } else {
1442: /* EXVP / IFEVP / IEEVP */
1443: write_IRQreg(mpp, idx, IRQ_IPVP, val);
1444: }
1445: }
1446: }
1447:
1448: static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr)
1449: {
1450: openpic_t *mpp = opaque;
1451: uint32_t retval;
1452: int idx = MPIC_INT_IRQ;
1453:
1454: DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1455: retval = 0xFFFFFFFF;
1456: if (addr & 0xF)
1457: return retval;
1458:
1459: addr -= MPIC_INT_REG_START & (TARGET_PAGE_SIZE - 1);
1460: if (addr < MPIC_INT_REG_SIZE) {
1461: idx += (addr & 0xFFF0) >> 5;
1462: if (addr & 0x10) {
1463: /* EXDE / IFEDE / IEEDE */
1464: retval = read_IRQreg(mpp, idx, IRQ_IDE);
1465: } else {
1466: /* EXVP / IFEVP / IEEVP */
1467: retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1468: }
1469: DPRINTF("%s: => %08x\n", __func__, retval);
1470: }
1471:
1472: return retval;
1473: }
1474:
1475: static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr,
1476: uint32_t val)
1477: {
1478: openpic_t *mpp = opaque;
1479: int idx = MPIC_MSG_IRQ;
1480:
1481: DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1482: if (addr & 0xF)
1483: return;
1484:
1485: addr -= MPIC_MSG_REG_START & (TARGET_PAGE_SIZE - 1);
1486: if (addr < MPIC_MSG_REG_SIZE) {
1487: idx += (addr & 0xFFF0) >> 5;
1488: if (addr & 0x10) {
1489: /* EXDE / IFEDE / IEEDE */
1490: write_IRQreg(mpp, idx, IRQ_IDE, val);
1491: } else {
1492: /* EXVP / IFEVP / IEEVP */
1493: write_IRQreg(mpp, idx, IRQ_IPVP, val);
1494: }
1495: }
1496: }
1497:
1498: static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr)
1499: {
1500: openpic_t *mpp = opaque;
1501: uint32_t retval;
1502: int idx = MPIC_MSG_IRQ;
1503:
1504: DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1505: retval = 0xFFFFFFFF;
1506: if (addr & 0xF)
1507: return retval;
1508:
1509: addr -= MPIC_MSG_REG_START & (TARGET_PAGE_SIZE - 1);
1510: if (addr < MPIC_MSG_REG_SIZE) {
1511: idx += (addr & 0xFFF0) >> 5;
1512: if (addr & 0x10) {
1513: /* EXDE / IFEDE / IEEDE */
1514: retval = read_IRQreg(mpp, idx, IRQ_IDE);
1515: } else {
1516: /* EXVP / IFEVP / IEEVP */
1517: retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1518: }
1519: DPRINTF("%s: => %08x\n", __func__, retval);
1520: }
1521:
1522: return retval;
1523: }
1524:
1525: static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr,
1526: uint32_t val)
1527: {
1528: openpic_t *mpp = opaque;
1529: int idx = MPIC_MSI_IRQ;
1530:
1531: DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1532: if (addr & 0xF)
1533: return;
1534:
1535: addr -= MPIC_MSI_REG_START & (TARGET_PAGE_SIZE - 1);
1536: if (addr < MPIC_MSI_REG_SIZE) {
1537: idx += (addr & 0xFFF0) >> 5;
1538: if (addr & 0x10) {
1539: /* EXDE / IFEDE / IEEDE */
1540: write_IRQreg(mpp, idx, IRQ_IDE, val);
1541: } else {
1542: /* EXVP / IFEVP / IEEVP */
1543: write_IRQreg(mpp, idx, IRQ_IPVP, val);
1544: }
1545: }
1546: }
1547: static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr)
1548: {
1549: openpic_t *mpp = opaque;
1550: uint32_t retval;
1551: int idx = MPIC_MSI_IRQ;
1552:
1553: DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1554: retval = 0xFFFFFFFF;
1555: if (addr & 0xF)
1556: return retval;
1557:
1558: addr -= MPIC_MSI_REG_START & (TARGET_PAGE_SIZE - 1);
1559: if (addr < MPIC_MSI_REG_SIZE) {
1560: idx += (addr & 0xFFF0) >> 5;
1561: if (addr & 0x10) {
1562: /* EXDE / IFEDE / IEEDE */
1563: retval = read_IRQreg(mpp, idx, IRQ_IDE);
1564: } else {
1565: /* EXVP / IFEVP / IEEVP */
1566: retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1567: }
1568: DPRINTF("%s: => %08x\n", __func__, retval);
1569: }
1570:
1571: return retval;
1572: }
1573:
1574: static CPUWriteMemoryFunc * const mpic_glb_write[] = {
1575: &openpic_buggy_write,
1576: &openpic_buggy_write,
1577: &openpic_gbl_write,
1578: };
1579:
1580: static CPUReadMemoryFunc * const mpic_glb_read[] = {
1581: &openpic_buggy_read,
1582: &openpic_buggy_read,
1583: &openpic_gbl_read,
1584: };
1585:
1586: static CPUWriteMemoryFunc * const mpic_tmr_write[] = {
1587: &openpic_buggy_write,
1588: &openpic_buggy_write,
1589: &mpic_timer_write,
1590: };
1591:
1592: static CPUReadMemoryFunc * const mpic_tmr_read[] = {
1593: &openpic_buggy_read,
1594: &openpic_buggy_read,
1595: &mpic_timer_read,
1596: };
1597:
1598: static CPUWriteMemoryFunc * const mpic_cpu_write[] = {
1599: &openpic_buggy_write,
1600: &openpic_buggy_write,
1601: &openpic_cpu_write,
1602: };
1603:
1604: static CPUReadMemoryFunc * const mpic_cpu_read[] = {
1605: &openpic_buggy_read,
1606: &openpic_buggy_read,
1607: &openpic_cpu_read,
1608: };
1609:
1610: static CPUWriteMemoryFunc * const mpic_ext_write[] = {
1611: &openpic_buggy_write,
1612: &openpic_buggy_write,
1613: &mpic_src_ext_write,
1614: };
1615:
1616: static CPUReadMemoryFunc * const mpic_ext_read[] = {
1617: &openpic_buggy_read,
1618: &openpic_buggy_read,
1619: &mpic_src_ext_read,
1620: };
1621:
1622: static CPUWriteMemoryFunc * const mpic_int_write[] = {
1623: &openpic_buggy_write,
1624: &openpic_buggy_write,
1625: &mpic_src_int_write,
1626: };
1627:
1628: static CPUReadMemoryFunc * const mpic_int_read[] = {
1629: &openpic_buggy_read,
1630: &openpic_buggy_read,
1631: &mpic_src_int_read,
1632: };
1633:
1634: static CPUWriteMemoryFunc * const mpic_msg_write[] = {
1635: &openpic_buggy_write,
1636: &openpic_buggy_write,
1637: &mpic_src_msg_write,
1638: };
1639:
1640: static CPUReadMemoryFunc * const mpic_msg_read[] = {
1641: &openpic_buggy_read,
1642: &openpic_buggy_read,
1643: &mpic_src_msg_read,
1644: };
1645: static CPUWriteMemoryFunc * const mpic_msi_write[] = {
1646: &openpic_buggy_write,
1647: &openpic_buggy_write,
1648: &mpic_src_msi_write,
1649: };
1650:
1651: static CPUReadMemoryFunc * const mpic_msi_read[] = {
1652: &openpic_buggy_read,
1653: &openpic_buggy_read,
1654: &mpic_src_msi_read,
1655: };
1656:
1657: qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
1658: qemu_irq **irqs, qemu_irq irq_out)
1659: {
1660: openpic_t *mpp;
1661: int i;
1662: struct {
1663: CPUReadMemoryFunc * const *read;
1664: CPUWriteMemoryFunc * const *write;
1665: target_phys_addr_t start_addr;
1666: ram_addr_t size;
1667: } const list[] = {
1668: {mpic_glb_read, mpic_glb_write, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
1669: {mpic_tmr_read, mpic_tmr_write, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
1670: {mpic_ext_read, mpic_ext_write, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
1671: {mpic_int_read, mpic_int_write, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
1672: {mpic_msg_read, mpic_msg_write, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
1673: {mpic_msi_read, mpic_msi_write, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
1674: {mpic_cpu_read, mpic_cpu_write, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
1675: };
1676:
1677: /* XXX: for now, only one CPU is supported */
1678: if (nb_cpus != 1)
1679: return NULL;
1680:
1681: mpp = qemu_mallocz(sizeof(openpic_t));
1682:
1683: for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
1684: int mem_index;
1685:
1686: mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp);
1687: if (mem_index < 0) {
1688: goto free;
1689: }
1690: cpu_register_physical_memory(base + list[i].start_addr,
1691: list[i].size, mem_index);
1692: }
1693:
1694: mpp->nb_cpus = nb_cpus;
1695: mpp->max_irq = MPIC_MAX_IRQ;
1696: mpp->irq_ipi0 = MPIC_IPI_IRQ;
1697: mpp->irq_tim0 = MPIC_TMR_IRQ;
1698:
1699: for (i = 0; i < nb_cpus; i++)
1700: mpp->dst[i].irqs = irqs[i];
1701: mpp->irq_out = irq_out;
1702: mpp->need_swap = 0; /* MPIC has the same endian as target */
1703:
1704: mpp->irq_raise = mpic_irq_raise;
1705: mpp->reset = mpic_reset;
1706:
1707: register_savevm("mpic", 0, 2, openpic_save, openpic_load, mpp);
1708: qemu_register_reset(mpic_reset, mpp);
1709:
1710: return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
1711:
1712: free:
1713: qemu_free(mpp);
1714: return NULL;
1715: }
unix.superglobalmegacorp.com