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