target-ppc: create a helper function to allow more flexible RAM allocation for PPC 4xx
[qemu/qemu-JZ.git] / hw / openpic.c
blobdef20eb4c866e52ca2de04064d376766b825f5e5
1 /*
2 * OpenPIC emulation
4 * Copyright (c) 2004 Jocelyn Mayer
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
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
32 * Serial interrupts, as implemented in Raven chipset are not supported yet.
35 #include "hw.h"
36 #include "ppc_mac.h"
37 #include "pci.h"
39 //#define DEBUG_OPENPIC
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)
48 #define USE_MPCxxx /* Intel model is broken, for now */
50 #if defined (USE_INTEL_GW80314)
51 /* Intel GW80314 I/O Companion chip */
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
61 #define VID (0x00000000)
63 #define OPENPIC_LITTLE_ENDIAN 1
64 #define OPENPIC_BIG_ENDIAN 0
66 #elif defined(USE_MPCxxx)
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 */
79 enum {
80 IRQ_IPVP = 0,
81 IRQ_IDE,
84 #define OPENPIC_LITTLE_ENDIAN 1
85 #define OPENPIC_BIG_ENDIAN 0
87 #else
88 #error "Please select which OpenPic implementation is to be emulated"
89 #endif
91 #if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \
92 (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN)
93 #define OPENPIC_SWAP
94 #endif
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
108 #define BF_WIDTH(_bits_) \
109 (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
111 static inline void set_bit (uint32_t *field, int bit)
113 field[bit >> 5] |= 1 << (bit & 0x1F);
116 static inline void reset_bit (uint32_t *field, int bit)
118 field[bit >> 5] &= ~(1 << (bit & 0x1F));
121 static inline int test_bit (uint32_t *field, int bit)
123 return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
126 enum {
127 IRQ_EXTERNAL = 0x01,
128 IRQ_INTERNAL = 0x02,
129 IRQ_TIMER = 0x04,
130 IRQ_SPECIAL = 0x08,
133 typedef struct IRQ_queue_t {
134 uint32_t queue[BF_WIDTH(MAX_IRQ)];
135 int next;
136 int priority;
137 } IRQ_queue_t;
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;
147 enum IPVP_bits {
148 IPVP_MASK = 31,
149 IPVP_ACTIVITY = 30,
150 IPVP_MODE = 29,
151 IPVP_POLARITY = 23,
152 IPVP_SENSE = 22,
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)
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;
164 qemu_irq *irqs;
165 } IRQ_dst_t;
167 typedef struct openpic_t {
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 */
175 uint32_t pint; /* Processor initialization register */
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
201 /* IRQ out is used when in bypass mode (not implemented) */
202 qemu_irq irq_out;
203 } openpic_t;
205 static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
207 set_bit(q->queue, n_IRQ);
210 static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
212 reset_bit(q->queue, n_IRQ);
215 static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
217 return test_bit(q->queue, n_IRQ);
220 static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
222 int next, i;
223 int priority;
225 next = -1;
226 priority = -1;
227 for (i = 0; i < MAX_IRQ; i++) {
228 if (IRQ_testbit(q, i)) {
229 DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
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);
237 q->next = next;
238 q->priority = priority;
241 static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
243 if (q->next == -1) {
244 /* XXX: optimize */
245 IRQ_check(opp, q);
248 return q->next;
251 static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
253 IRQ_dst_t *dst;
254 IRQ_src_t *src;
255 int priority;
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 */
262 DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
263 __func__, n_IRQ, n_CPU);
264 return;
266 if (IRQ_testbit(&dst->raised, n_IRQ)) {
267 /* Interrupt miss */
268 DPRINTF("%s: IRQ %d was missed on CPU %d\n",
269 __func__, n_IRQ, n_CPU);
270 return;
272 set_bit(&src->ipvp, IPVP_ACTIVITY);
273 IRQ_setbit(&dst->raised, n_IRQ);
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;
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;
288 DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
289 qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
292 /* update pic state because registers for n_IRQ have changed value */
293 static void openpic_update_irq(openpic_t *opp, int n_IRQ)
295 IRQ_src_t *src;
296 int i;
298 src = &opp->src[n_IRQ];
300 if (!src->pending) {
301 /* no irq pending */
302 DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
303 return;
305 if (test_bit(&src->ipvp, IPVP_MASK)) {
306 /* Interrupt source is disabled */
307 DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
308 return;
310 if (IPVP_PRIORITY(src->ipvp) == 0) {
311 /* Priority set to zero */
312 DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
313 return;
315 if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
316 /* IRQ already active */
317 DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
318 return;
320 if (src->ide == 0x00000000) {
321 /* No target */
322 DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
323 return;
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)) {
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);
335 } else {
336 /* Distributed delivery mode */
337 for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
338 if (i == opp->nb_cpus)
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;
349 static void openpic_set_irq(void *opaque, int n_IRQ, int level)
351 openpic_t *opp = opaque;
352 IRQ_src_t *src;
354 src = &opp->src[n_IRQ];
355 DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
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;
367 openpic_update_irq(opp, n_IRQ);
370 static void openpic_reset (openpic_t *opp)
372 int i;
374 opp->glbc = 0x80000000;
375 /* Initialise controller registers */
376 opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
377 opp->veni = VENI;
378 opp->pint = 0x00000000;
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;
388 /* Initialise IRQ destinations */
389 for (i = 0; i < MAX_CPU; i++) {
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));
395 /* Initialise timers */
396 for (i = 0; i < MAX_TMR; i++) {
397 opp->timers[i].ticc = 0x00000000;
398 opp->timers[i].tibc = 0x80000000;
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;
406 #endif
407 /* Initialise mailboxes */
408 #if MAX_MBX > 0
409 for (i = 0; i < MAX_MBX; i++) { /* ? */
410 opp->mailboxes[i].mbr = 0x00000000;
412 #endif
413 /* Go out of RESET state */
414 opp->glbc = 0x00000000;
417 static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
419 uint32_t retval;
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;
430 return retval;
433 static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
434 uint32_t reg, uint32_t val)
436 uint32_t tmp;
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 */
443 opp->src[n_IRQ].ipvp =
444 (opp->src[n_IRQ].ipvp & 0x40000000) |
445 (val & 0x800F00FF);
446 openpic_update_irq(opp, n_IRQ);
447 DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
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;
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)
464 uint32_t retval;
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;
478 return retval;
481 static void write_doorbell_register (penpic_t *opp, int n_dbl,
482 uint32_t offset, uint32_t value)
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;
496 #endif
498 #if MAX_MBX > 0
499 static uint32_t read_mailbox_register (openpic_t *opp,
500 int n_mbx, uint32_t offset)
502 uint32_t retval;
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;
516 return retval;
519 static void write_mailbox_register (openpic_t *opp, int n_mbx,
520 uint32_t address, uint32_t value)
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;
534 #endif
535 #endif /* 0 : Code provision for Intel model */
537 static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
539 openpic_t *opp = opaque;
540 IRQ_dst_t *dst;
541 int idx;
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 */
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]);
572 opp->pint = val;
573 break;
574 #if MAX_IPI > 0
575 case 0xA0: /* IPI_IPVP */
576 case 0xB0:
577 case 0xC0:
578 case 0xD0:
580 int idx;
581 idx = (addr - 0xA0) >> 4;
582 write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
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;
597 static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
599 openpic_t *opp = opaque;
600 uint32_t retval;
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:
626 int idx;
627 idx = (addr - 0xA0) >> 4;
628 retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
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;
641 DPRINTF("%s: => %08x\n", __func__, retval);
642 #if defined OPENPIC_SWAP
643 retval = bswap32(retval);
644 #endif
646 return retval;
649 static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
651 openpic_t *opp = opaque;
652 int idx;
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;
683 static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
685 openpic_t *opp = opaque;
686 uint32_t retval;
687 int idx;
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;
711 DPRINTF("%s: => %08x\n", __func__, retval);
712 #if defined OPENPIC_SWAP
713 retval = bswap32(retval);
714 #endif
716 return retval;
719 static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
721 openpic_t *opp = opaque;
722 int idx;
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);
741 static uint32_t openpic_src_read (void *opaque, uint32_t addr)
743 openpic_t *opp = opaque;
744 uint32_t retval;
745 int idx;
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);
760 DPRINTF("%s: => %08x\n", __func__, retval);
761 #if defined OPENPIC_SWAP
762 retval = tswap32(retval);
763 #endif
765 return retval;
768 static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
770 openpic_t *opp = opaque;
771 IRQ_src_t *src;
772 IRQ_dst_t *dst;
773 int idx, s_IRQ, n_IRQ;
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");
808 s_IRQ = IRQ_get_next(opp, &dst->servicing);
809 IRQ_resetbit(&dst->servicing, s_IRQ);
810 dst->servicing.next = -1;
811 /* Set up next servicing IRQ */
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]);
823 break;
824 default:
825 break;
829 static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
831 openpic_t *opp = opaque;
832 IRQ_src_t *src;
833 IRQ_dst_t *dst;
834 uint32_t retval;
835 int idx, n_IRQ;
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 */
853 DPRINTF("Lower OpenPIC INT output\n");
854 qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
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 */
859 retval = IPVP_VECTOR(opp->spve);
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
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);
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;
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;
897 DPRINTF("%s: => %08x\n", __func__, retval);
898 #if defined OPENPIC_SWAP
899 retval= bswap32(retval);
900 #endif
902 return retval;
905 static void openpic_buggy_write (void *opaque,
906 target_phys_addr_t addr, uint32_t val)
908 printf("Invalid OPENPIC write access !\n");
911 static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
913 printf("Invalid OPENPIC read access !\n");
915 return -1;
918 static void openpic_writel (void *opaque,
919 target_phys_addr_t addr, uint32_t val)
921 openpic_t *opp = opaque;
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);
940 static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
942 openpic_t *opp = opaque;
943 uint32_t retval;
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);
961 return retval;
964 static CPUWriteMemoryFunc *openpic_write[] = {
965 &openpic_buggy_write,
966 &openpic_buggy_write,
967 &openpic_writel,
970 static CPUReadMemoryFunc *openpic_read[] = {
971 &openpic_buggy_read,
972 &openpic_buggy_read,
973 &openpic_readl,
976 static void openpic_map(PCIDevice *pci_dev, int region_num,
977 uint32_t addr, uint32_t size, int type)
979 openpic_t *opp;
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
1004 qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
1005 qemu_irq **irqs, qemu_irq irq_out)
1007 openpic_t *opp;
1008 uint8_t *pci_conf;
1009 int i, m;
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
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));
1035 opp->mem_index = cpu_register_io_memory(0, openpic_read,
1036 openpic_write, opp);
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;
1044 for (; i < IRQ_TIM0; i++) {
1045 opp->src[i].type = IRQ_SPECIAL;
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;
1055 for (; i < MAX_IRQ; i++) {
1056 opp->src[i].type = IRQ_INTERNAL;
1058 for (i = 0; i < nb_cpus; i++)
1059 opp->dst[i].irqs = irqs[i];
1060 opp->irq_out = irq_out;
1061 openpic_reset(opp);
1062 if (pmem_index)
1063 *pmem_index = opp->mem_index;
1065 return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);