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