ia64/xen-unstable

view tools/ioemu/hw/openpic.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 8e5fc5fe636c
children f7b43e5c42b9
line source
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"
37 //#define DEBUG_OPENPIC
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)
46 #define USE_MPCxxx /* Intel model is broken, for now */
48 #if defined (USE_INTEL_GW80314)
49 /* Intel GW80314 I/O Companion chip */
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
59 #define VID (0x00000000)
61 #define OPENPIC_LITTLE_ENDIAN 1
62 #define OPENPIC_BIG_ENDIAN 0
64 #elif defined(USE_MPCxxx)
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 */
77 enum {
78 IRQ_IPVP = 0,
79 IRQ_IDE,
80 };
82 #define OPENPIC_LITTLE_ENDIAN 1
83 #define OPENPIC_BIG_ENDIAN 0
85 #else
86 #error "Please select which OpenPic implementation is to be emulated"
87 #endif
89 #if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \
90 (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN)
91 #define OPENPIC_SWAP
92 #endif
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
106 #define BF_WIDTH(_bits_) \
107 (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
109 static inline void set_bit (uint32_t *field, int bit)
110 {
111 field[bit >> 5] |= 1 << (bit & 0x1F);
112 }
114 static inline void reset_bit (uint32_t *field, int bit)
115 {
116 field[bit >> 5] &= ~(1 << (bit & 0x1F));
117 }
119 static inline int test_bit (uint32_t *field, int bit)
120 {
121 return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
122 }
124 enum {
125 IRQ_EXTERNAL = 0x01,
126 IRQ_INTERNAL = 0x02,
127 IRQ_TIMER = 0x04,
128 IRQ_SPECIAL = 0x08,
129 } IRQ_src_type;
131 typedef struct IRQ_queue_t {
132 uint32_t queue[BF_WIDTH(MAX_IRQ)];
133 int next;
134 int priority;
135 } IRQ_queue_t;
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;
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)
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;
162 CPUState *env; /* Needed if we did SMP */
163 } IRQ_dst_t;
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 };
200 static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
201 {
202 set_bit(q->queue, n_IRQ);
203 }
205 static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
206 {
207 reset_bit(q->queue, n_IRQ);
208 }
210 static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
211 {
212 return test_bit(q->queue, n_IRQ);
213 }
215 static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
216 {
217 int next, i;
218 int priority;
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 }
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 }
243 return q->next;
244 }
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;
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");
268 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
269 }
270 }
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;
278 src = &opp->src[n_IRQ];
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 }
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 }
323 void openpic_set_irq(openpic_t *opp, int n_IRQ, int level)
324 {
325 IRQ_src_t *src;
327 src = &opp->src[n_IRQ];
328 DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
329 n_IRQ, level, src->ipvp);
330 if (test_bit(&src->ipvp, IPVP_SENSE)) {
331 /* level-sensitive irq */
332 src->pending = level;
333 if (!level)
334 reset_bit(&src->ipvp, IPVP_ACTIVITY);
335 } else {
336 /* edge-sensitive irq */
337 if (level)
338 src->pending = 1;
339 }
340 openpic_update_irq(opp, n_IRQ);
341 }
343 static void openpic_reset (openpic_t *opp)
344 {
345 int i;
347 opp->glbc = 0x80000000;
348 /* Initialise controler registers */
349 opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
350 opp->veni = VENI;
351 opp->spve = 0x000000FF;
352 opp->tifr = 0x003F7A00;
353 /* ? */
354 opp->micr = 0x00000000;
355 /* Initialise IRQ sources */
356 for (i = 0; i < MAX_IRQ; i++) {
357 opp->src[i].ipvp = 0xA0000000;
358 opp->src[i].ide = 0x00000000;
359 }
360 /* Initialise IRQ destinations */
361 for (i = 0; i < opp->nb_cpus; i++) {
362 opp->dst[i].pctp = 0x0000000F;
363 opp->dst[i].pcsr = 0x00000000;
364 memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
365 memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
366 }
367 /* Initialise timers */
368 for (i = 0; i < MAX_TMR; i++) {
369 opp->timers[i].ticc = 0x00000000;
370 opp->timers[i].tibc = 0x80000000;
371 }
372 /* Initialise doorbells */
373 #if MAX_DBL > 0
374 opp->dar = 0x00000000;
375 for (i = 0; i < MAX_DBL; i++) {
376 opp->doorbells[i].dmr = 0x00000000;
377 }
378 #endif
379 /* Initialise mailboxes */
380 #if MAX_MBX > 0
381 for (i = 0; i < MAX_MBX; i++) { /* ? */
382 opp->mailboxes[i].mbr = 0x00000000;
383 }
384 #endif
385 /* Go out of RESET state */
386 opp->glbc = 0x00000000;
387 }
389 static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
390 {
391 uint32_t retval;
393 switch (reg) {
394 case IRQ_IPVP:
395 retval = opp->src[n_IRQ].ipvp;
396 break;
397 case IRQ_IDE:
398 retval = opp->src[n_IRQ].ide;
399 break;
400 }
402 return retval;
403 }
405 static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
406 uint32_t reg, uint32_t val)
407 {
408 uint32_t tmp;
410 switch (reg) {
411 case IRQ_IPVP:
412 /* NOTE: not fully accurate for special IRQs, but simple and
413 sufficient */
414 /* ACTIVITY bit is read-only */
415 opp->src[n_IRQ].ipvp =
416 (opp->src[n_IRQ].ipvp & 0x40000000) |
417 (val & 0x800F00FF);
418 openpic_update_irq(opp, n_IRQ);
419 DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
420 n_IRQ, val, opp->src[n_IRQ].ipvp);
421 break;
422 case IRQ_IDE:
423 tmp = val & 0xC0000000;
424 tmp |= val & ((1 << MAX_CPU) - 1);
425 opp->src[n_IRQ].ide = tmp;
426 DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
427 break;
428 }
429 }
431 #if 0 // Code provision for Intel model
432 #if MAX_DBL > 0
433 static uint32_t read_doorbell_register (openpic_t *opp,
434 int n_dbl, uint32_t offset)
435 {
436 uint32_t retval;
438 switch (offset) {
439 case DBL_IPVP_OFFSET:
440 retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
441 break;
442 case DBL_IDE_OFFSET:
443 retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
444 break;
445 case DBL_DMR_OFFSET:
446 retval = opp->doorbells[n_dbl].dmr;
447 break;
448 }
450 return retval;
451 }
453 static void write_doorbell_register (penpic_t *opp, int n_dbl,
454 uint32_t offset, uint32_t value)
455 {
456 switch (offset) {
457 case DBL_IVPR_OFFSET:
458 write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
459 break;
460 case DBL_IDE_OFFSET:
461 write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
462 break;
463 case DBL_DMR_OFFSET:
464 opp->doorbells[n_dbl].dmr = value;
465 break;
466 }
467 }
468 #endif
470 #if MAX_MBX > 0
471 static uint32_t read_mailbox_register (openpic_t *opp,
472 int n_mbx, uint32_t offset)
473 {
474 uint32_t retval;
476 switch (offset) {
477 case MBX_MBR_OFFSET:
478 retval = opp->mailboxes[n_mbx].mbr;
479 break;
480 case MBX_IVPR_OFFSET:
481 retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
482 break;
483 case MBX_DMR_OFFSET:
484 retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
485 break;
486 }
488 return retval;
489 }
491 static void write_mailbox_register (openpic_t *opp, int n_mbx,
492 uint32_t address, uint32_t value)
493 {
494 switch (offset) {
495 case MBX_MBR_OFFSET:
496 opp->mailboxes[n_mbx].mbr = value;
497 break;
498 case MBX_IVPR_OFFSET:
499 write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
500 break;
501 case MBX_DMR_OFFSET:
502 write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
503 break;
504 }
505 }
506 #endif
507 #endif /* 0 : Code provision for Intel model */
509 static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
510 {
511 openpic_t *opp = opaque;
513 DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
514 if (addr & 0xF)
515 return;
516 #if defined OPENPIC_SWAP
517 val = bswap32(val);
518 #endif
519 addr &= 0xFF;
520 switch (addr) {
521 case 0x00: /* FREP */
522 break;
523 case 0x20: /* GLBC */
524 if (val & 0x80000000)
525 openpic_reset(opp);
526 opp->glbc = val & ~0x80000000;
527 break;
528 case 0x80: /* VENI */
529 break;
530 case 0x90: /* PINT */
531 /* XXX: Should be able to reset any CPU */
532 if (val & 1) {
533 DPRINTF("Reset CPU IRQ\n");
534 // cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET);
535 }
536 break;
537 #if MAX_IPI > 0
538 case 0xA0: /* IPI_IPVP */
539 case 0xB0:
540 case 0xC0:
541 case 0xD0:
542 {
543 int idx;
544 idx = (addr - 0xA0) >> 4;
545 write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
546 }
547 break;
548 #endif
549 case 0xE0: /* SPVE */
550 opp->spve = val & 0x000000FF;
551 break;
552 case 0xF0: /* TIFR */
553 opp->tifr = val;
554 break;
555 default:
556 break;
557 }
558 }
560 static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
561 {
562 openpic_t *opp = opaque;
563 uint32_t retval;
565 DPRINTF("%s: addr %08x\n", __func__, addr);
566 retval = 0xFFFFFFFF;
567 if (addr & 0xF)
568 return retval;
569 addr &= 0xFF;
570 switch (addr) {
571 case 0x00: /* FREP */
572 retval = opp->frep;
573 break;
574 case 0x20: /* GLBC */
575 retval = opp->glbc;
576 break;
577 case 0x80: /* VENI */
578 retval = opp->veni;
579 break;
580 case 0x90: /* PINT */
581 retval = 0x00000000;
582 break;
583 #if MAX_IPI > 0
584 case 0xA0: /* IPI_IPVP */
585 case 0xB0:
586 case 0xC0:
587 case 0xD0:
588 {
589 int idx;
590 idx = (addr - 0xA0) >> 4;
591 retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
592 }
593 break;
594 #endif
595 case 0xE0: /* SPVE */
596 retval = opp->spve;
597 break;
598 case 0xF0: /* TIFR */
599 retval = opp->tifr;
600 break;
601 default:
602 break;
603 }
604 DPRINTF("%s: => %08x\n", __func__, retval);
605 #if defined OPENPIC_SWAP
606 retval = bswap32(retval);
607 #endif
609 return retval;
610 }
612 static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
613 {
614 openpic_t *opp = opaque;
615 int idx;
617 DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
618 if (addr & 0xF)
619 return;
620 #if defined OPENPIC_SWAP
621 val = bswap32(val);
622 #endif
623 addr -= 0x1100;
624 addr &= 0xFFFF;
625 idx = (addr & 0xFFF0) >> 6;
626 addr = addr & 0x30;
627 switch (addr) {
628 case 0x00: /* TICC */
629 break;
630 case 0x10: /* TIBC */
631 if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
632 (val & 0x800000000) == 0 &&
633 (opp->timers[idx].tibc & 0x80000000) != 0)
634 opp->timers[idx].ticc &= ~0x80000000;
635 opp->timers[idx].tibc = val;
636 break;
637 case 0x20: /* TIVP */
638 write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val);
639 break;
640 case 0x30: /* TIDE */
641 write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val);
642 break;
643 }
644 }
646 static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
647 {
648 openpic_t *opp = opaque;
649 uint32_t retval;
650 int idx;
652 DPRINTF("%s: addr %08x\n", __func__, addr);
653 retval = 0xFFFFFFFF;
654 if (addr & 0xF)
655 return retval;
656 addr -= 0x1100;
657 addr &= 0xFFFF;
658 idx = (addr & 0xFFF0) >> 6;
659 addr = addr & 0x30;
660 switch (addr) {
661 case 0x00: /* TICC */
662 retval = opp->timers[idx].ticc;
663 break;
664 case 0x10: /* TIBC */
665 retval = opp->timers[idx].tibc;
666 break;
667 case 0x20: /* TIPV */
668 retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP);
669 break;
670 case 0x30: /* TIDE */
671 retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE);
672 break;
673 }
674 DPRINTF("%s: => %08x\n", __func__, retval);
675 #if defined OPENPIC_SWAP
676 retval = bswap32(retval);
677 #endif
679 return retval;
680 }
682 static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
683 {
684 openpic_t *opp = opaque;
685 int idx;
687 DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
688 if (addr & 0xF)
689 return;
690 #if defined OPENPIC_SWAP
691 val = tswap32(val);
692 #endif
693 addr = addr & 0xFFF0;
694 idx = addr >> 5;
695 if (addr & 0x10) {
696 /* EXDE / IFEDE / IEEDE */
697 write_IRQreg(opp, idx, IRQ_IDE, val);
698 } else {
699 /* EXVP / IFEVP / IEEVP */
700 write_IRQreg(opp, idx, IRQ_IPVP, val);
701 }
702 }
704 static uint32_t openpic_src_read (void *opaque, uint32_t addr)
705 {
706 openpic_t *opp = opaque;
707 uint32_t retval;
708 int idx;
710 DPRINTF("%s: addr %08x\n", __func__, addr);
711 retval = 0xFFFFFFFF;
712 if (addr & 0xF)
713 return retval;
714 addr = addr & 0xFFF0;
715 idx = addr >> 5;
716 if (addr & 0x10) {
717 /* EXDE / IFEDE / IEEDE */
718 retval = read_IRQreg(opp, idx, IRQ_IDE);
719 } else {
720 /* EXVP / IFEVP / IEEVP */
721 retval = read_IRQreg(opp, idx, IRQ_IPVP);
722 }
723 DPRINTF("%s: => %08x\n", __func__, retval);
724 #if defined OPENPIC_SWAP
725 retval = tswap32(retval);
726 #endif
728 return retval;
729 }
731 static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
732 {
733 openpic_t *opp = opaque;
734 IRQ_src_t *src;
735 IRQ_dst_t *dst;
736 int idx, n_IRQ;
738 DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
739 if (addr & 0xF)
740 return;
741 #if defined OPENPIC_SWAP
742 val = bswap32(val);
743 #endif
744 addr &= 0x1FFF0;
745 idx = addr / 0x1000;
746 dst = &opp->dst[idx];
747 addr &= 0xFF0;
748 switch (addr) {
749 #if MAX_IPI > 0
750 case 0x40: /* PIPD */
751 case 0x50:
752 case 0x60:
753 case 0x70:
754 idx = (addr - 0x40) >> 4;
755 write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val);
756 openpic_set_irq(opp, IRQ_IPI0 + idx, 1);
757 openpic_set_irq(opp, IRQ_IPI0 + idx, 0);
758 break;
759 #endif
760 case 0x80: /* PCTP */
761 dst->pctp = val & 0x0000000F;
762 break;
763 case 0x90: /* WHOAMI */
764 /* Read-only register */
765 break;
766 case 0xA0: /* PIAC */
767 /* Read-only register */
768 break;
769 case 0xB0: /* PEOI */
770 DPRINTF("PEOI\n");
771 n_IRQ = IRQ_get_next(opp, &dst->servicing);
772 IRQ_resetbit(&dst->servicing, n_IRQ);
773 dst->servicing.next = -1;
774 src = &opp->src[n_IRQ];
775 /* Set up next servicing IRQ */
776 IRQ_get_next(opp, &dst->servicing);
777 /* Check queued interrupts. */
778 n_IRQ = IRQ_get_next(opp, &dst->raised);
779 if (n_IRQ != -1) {
780 src = &opp->src[n_IRQ];
781 if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
782 DPRINTF("Raise CPU IRQ\n");
783 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
784 }
785 }
786 break;
787 default:
788 break;
789 }
790 }
792 static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
793 {
794 openpic_t *opp = opaque;
795 IRQ_src_t *src;
796 IRQ_dst_t *dst;
797 uint32_t retval;
798 int idx, n_IRQ;
800 DPRINTF("%s: addr %08x\n", __func__, addr);
801 retval = 0xFFFFFFFF;
802 if (addr & 0xF)
803 return retval;
804 addr &= 0x1FFF0;
805 idx = addr / 0x1000;
806 dst = &opp->dst[idx];
807 addr &= 0xFF0;
808 switch (addr) {
809 case 0x80: /* PCTP */
810 retval = dst->pctp;
811 break;
812 case 0x90: /* WHOAMI */
813 retval = idx;
814 break;
815 case 0xA0: /* PIAC */
816 n_IRQ = IRQ_get_next(opp, &dst->raised);
817 DPRINTF("PIAC: irq=%d\n", n_IRQ);
818 if (n_IRQ == -1) {
819 /* No more interrupt pending */
820 retval = opp->spve;
821 } else {
822 src = &opp->src[n_IRQ];
823 if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
824 !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
825 /* - Spurious level-sensitive IRQ
826 * - Priorities has been changed
827 * and the pending IRQ isn't allowed anymore
828 */
829 reset_bit(&src->ipvp, IPVP_ACTIVITY);
830 retval = IPVP_VECTOR(opp->spve);
831 } else {
832 /* IRQ enter servicing state */
833 IRQ_setbit(&dst->servicing, n_IRQ);
834 retval = IPVP_VECTOR(src->ipvp);
835 }
836 IRQ_resetbit(&dst->raised, n_IRQ);
837 dst->raised.next = -1;
838 if (!test_bit(&src->ipvp, IPVP_SENSE)) {
839 /* edge-sensitive IRQ */
840 reset_bit(&src->ipvp, IPVP_ACTIVITY);
841 src->pending = 0;
842 }
843 }
844 break;
845 case 0xB0: /* PEOI */
846 retval = 0;
847 break;
848 #if MAX_IPI > 0
849 case 0x40: /* IDE */
850 case 0x50:
851 idx = (addr - 0x40) >> 4;
852 retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE);
853 break;
854 #endif
855 default:
856 break;
857 }
858 DPRINTF("%s: => %08x\n", __func__, retval);
859 #if defined OPENPIC_SWAP
860 retval= bswap32(retval);
861 #endif
863 return retval;
864 }
866 static void openpic_buggy_write (void *opaque,
867 target_phys_addr_t addr, uint32_t val)
868 {
869 printf("Invalid OPENPIC write access !\n");
870 }
872 static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
873 {
874 printf("Invalid OPENPIC read access !\n");
876 return -1;
877 }
879 static void openpic_writel (void *opaque,
880 target_phys_addr_t addr, uint32_t val)
881 {
882 openpic_t *opp = opaque;
884 addr &= 0x3FFFF;
885 DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
886 if (addr < 0x1100) {
887 /* Global registers */
888 openpic_gbl_write(opp, addr, val);
889 } else if (addr < 0x10000) {
890 /* Timers registers */
891 openpic_timer_write(opp, addr, val);
892 } else if (addr < 0x20000) {
893 /* Source registers */
894 openpic_src_write(opp, addr, val);
895 } else {
896 /* CPU registers */
897 openpic_cpu_write(opp, addr, val);
898 }
899 }
901 static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
902 {
903 openpic_t *opp = opaque;
904 uint32_t retval;
906 addr &= 0x3FFFF;
907 DPRINTF("%s: offset %08x\n", __func__, (int)addr);
908 if (addr < 0x1100) {
909 /* Global registers */
910 retval = openpic_gbl_read(opp, addr);
911 } else if (addr < 0x10000) {
912 /* Timers registers */
913 retval = openpic_timer_read(opp, addr);
914 } else if (addr < 0x20000) {
915 /* Source registers */
916 retval = openpic_src_read(opp, addr);
917 } else {
918 /* CPU registers */
919 retval = openpic_cpu_read(opp, addr);
920 }
922 return retval;
923 }
925 static CPUWriteMemoryFunc *openpic_write[] = {
926 &openpic_buggy_write,
927 &openpic_buggy_write,
928 &openpic_writel,
929 };
931 static CPUReadMemoryFunc *openpic_read[] = {
932 &openpic_buggy_read,
933 &openpic_buggy_read,
934 &openpic_readl,
935 };
937 static void openpic_map(PCIDevice *pci_dev, int region_num,
938 uint32_t addr, uint32_t size, int type)
939 {
940 openpic_t *opp;
942 DPRINTF("Map OpenPIC\n");
943 opp = (openpic_t *)pci_dev;
944 /* Global registers */
945 DPRINTF("Register OPENPIC gbl %08x => %08x\n",
946 addr + 0x1000, addr + 0x1000 + 0x100);
947 /* Timer registers */
948 DPRINTF("Register OPENPIC timer %08x => %08x\n",
949 addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
950 /* Interrupt source registers */
951 DPRINTF("Register OPENPIC src %08x => %08x\n",
952 addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2));
953 /* Per CPU registers */
954 DPRINTF("Register OPENPIC dst %08x => %08x\n",
955 addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
956 cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
957 #if 0 // Don't implement ISU for now
958 opp_io_memory = cpu_register_io_memory(0, openpic_src_read,
959 openpic_src_write);
960 cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
961 opp_io_memory);
962 #endif
963 }
965 openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus)
966 {
967 openpic_t *opp;
968 uint8_t *pci_conf;
969 int i, m;
971 /* XXX: for now, only one CPU is supported */
972 if (nb_cpus != 1)
973 return NULL;
974 if (bus) {
975 opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
976 -1, NULL, NULL);
977 if (opp == NULL)
978 return NULL;
979 pci_conf = opp->pci_dev.config;
980 pci_conf[0x00] = 0x14; // IBM MPIC2
981 pci_conf[0x01] = 0x10;
982 pci_conf[0x02] = 0xFF;
983 pci_conf[0x03] = 0xFF;
984 pci_conf[0x0a] = 0x80; // PIC
985 pci_conf[0x0b] = 0x08;
986 pci_conf[0x0e] = 0x00; // header_type
987 pci_conf[0x3d] = 0x00; // no interrupt pin
989 /* Register I/O spaces */
990 pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
991 PCI_ADDRESS_SPACE_MEM, &openpic_map);
992 } else {
993 opp = qemu_mallocz(sizeof(openpic_t));
994 }
996 opp->mem_index = cpu_register_io_memory(0, openpic_read,
997 openpic_write, opp);
999 // isu_base &= 0xFFFC0000;
1000 opp->nb_cpus = nb_cpus;
1001 /* Set IRQ types */
1002 for (i = 0; i < EXT_IRQ; i++) {
1003 opp->src[i].type = IRQ_EXTERNAL;
1005 for (; i < IRQ_TIM0; i++) {
1006 opp->src[i].type = IRQ_SPECIAL;
1008 #if MAX_IPI > 0
1009 m = IRQ_IPI0;
1010 #else
1011 m = IRQ_DBL0;
1012 #endif
1013 for (; i < m; i++) {
1014 opp->src[i].type = IRQ_TIMER;
1016 for (; i < MAX_IRQ; i++) {
1017 opp->src[i].type = IRQ_INTERNAL;
1019 openpic_reset(opp);
1020 if (pmem_index)
1021 *pmem_index = opp->mem_index;
1022 return opp;