]> Git Repo - qemu.git/blob - hw/openpic.c
openpic: remove unused type variable
[qemu.git] / hw / openpic.c
1 /*
2  * OpenPIC emulation
3  *
4  * Copyright (c) 2004 Jocelyn Mayer
5  *               2011 Alexander Graf
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 /*
26  *
27  * Based on OpenPic implementations:
28  * - Intel GW80314 I/O companion chip developer's manual
29  * - Motorola MPC8245 & MPC8540 user manuals.
30  * - Motorola MCP750 (aka Raven) programmer manual.
31  * - Motorola Harrier programmer manuel
32  *
33  * Serial interrupts, as implemented in Raven chipset are not supported yet.
34  *
35  */
36 #include "hw.h"
37 #include "ppc_mac.h"
38 #include "pci.h"
39 #include "openpic.h"
40
41 //#define DEBUG_OPENPIC
42
43 #ifdef DEBUG_OPENPIC
44 #define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
45 #else
46 #define DPRINTF(fmt, ...) do { } while (0)
47 #endif
48
49 #define MAX_CPU     15
50 #define MAX_SRC     256
51 #define MAX_TMR     4
52 #define VECTOR_BITS 8
53 #define MAX_IPI     4
54 #define MAX_IRQ     (MAX_SRC + MAX_IPI + MAX_TMR)
55 #define VID         0x03 /* MPIC version ID */
56
57 enum {
58     IRQ_IPVP = 0,
59     IRQ_IDE,
60 };
61
62 /* OpenPIC */
63 #define OPENPIC_MAX_CPU      2
64 #define OPENPIC_MAX_IRQ     64
65 #define OPENPIC_EXT_IRQ     48
66 #define OPENPIC_MAX_TMR      MAX_TMR
67 #define OPENPIC_MAX_IPI      MAX_IPI
68
69 /* Interrupt definitions */
70 #define OPENPIC_IRQ_FE     (OPENPIC_EXT_IRQ)     /* Internal functional IRQ */
71 #define OPENPIC_IRQ_ERR    (OPENPIC_EXT_IRQ + 1) /* Error IRQ */
72 #define OPENPIC_IRQ_TIM0   (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */
73 #if OPENPIC_MAX_IPI > 0
74 #define OPENPIC_IRQ_IPI0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */
75 #define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */
76 #else
77 #define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */
78 #define OPENPIC_IRQ_MBX0   (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */
79 #endif
80
81 #define OPENPIC_GLB_REG_START        0x0
82 #define OPENPIC_GLB_REG_SIZE         0x10F0
83 #define OPENPIC_TMR_REG_START        0x10F0
84 #define OPENPIC_TMR_REG_SIZE         0x220
85 #define OPENPIC_SRC_REG_START        0x10000
86 #define OPENPIC_SRC_REG_SIZE         (MAX_SRC * 0x20)
87 #define OPENPIC_CPU_REG_START        0x20000
88 #define OPENPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
89
90 /* MPIC */
91 #define MPIC_MAX_CPU      1
92 #define MPIC_MAX_EXT     12
93 #define MPIC_MAX_INT     64
94 #define MPIC_MAX_IRQ     MAX_IRQ
95
96 /* Interrupt definitions */
97 /* IRQs, accessible through the IRQ region */
98 #define MPIC_EXT_IRQ      0x00
99 #define MPIC_INT_IRQ      0x10
100 #define MPIC_MSG_IRQ      0xb0
101 #define MPIC_MSI_IRQ      0xe0
102 /* These are available through separate regions, but
103    for simplicity's sake mapped into the same number space */
104 #define MPIC_TMR_IRQ      0x100
105 #define MPIC_IPI_IRQ      0x104
106
107 #define MPIC_GLB_REG_START        0x0
108 #define MPIC_GLB_REG_SIZE         0x10F0
109 #define MPIC_TMR_REG_START        0x10F0
110 #define MPIC_TMR_REG_SIZE         0x220
111 #define MPIC_SRC_REG_START        0x10000
112 #define MPIC_SRC_REG_SIZE         (MAX_SRC * 0x20)
113 #define MPIC_CPU_REG_START        0x20000
114 #define MPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
115
116 /*
117  * Block Revision Register1 (BRR1): QEMU does not fully emulate
118  * any version on MPIC. So to start with, set the IP version to 0.
119  *
120  * NOTE: This is Freescale MPIC specific register. Keep it here till
121  * this code is refactored for different variants of OPENPIC and MPIC.
122  */
123 #define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */
124 #define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */
125 #define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */
126
127 #define FREP_NIRQ_SHIFT   16
128 #define FREP_NCPU_SHIFT    8
129 #define FREP_VID_SHIFT     0
130
131 #define VID_REVISION_1_2   2
132
133 #define VENI_GENERIC      0x00000000 /* Generic Vendor ID */
134
135 enum mpic_ide_bits {
136     IDR_EP     = 31,
137     IDR_CI0     = 30,
138     IDR_CI1     = 29,
139     IDR_P1     = 1,
140     IDR_P0     = 0,
141 };
142
143 #define BF_WIDTH(_bits_) \
144 (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
145
146 static inline void set_bit (uint32_t *field, int bit)
147 {
148     field[bit >> 5] |= 1 << (bit & 0x1F);
149 }
150
151 static inline void reset_bit (uint32_t *field, int bit)
152 {
153     field[bit >> 5] &= ~(1 << (bit & 0x1F));
154 }
155
156 static inline int test_bit (uint32_t *field, int bit)
157 {
158     return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
159 }
160
161 static int get_current_cpu(void)
162 {
163   return cpu_single_env->cpu_index;
164 }
165
166 static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
167                                           int idx);
168 static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
169                                        uint32_t val, int idx);
170
171 typedef struct IRQ_queue_t {
172     uint32_t queue[BF_WIDTH(MAX_IRQ)];
173     int next;
174     int priority;
175 } IRQ_queue_t;
176
177 typedef struct IRQ_src_t {
178     uint32_t ipvp;  /* IRQ vector/priority register */
179     uint32_t ide;   /* IRQ destination register */
180     int last_cpu;
181     int pending;    /* TRUE if IRQ is pending */
182 } IRQ_src_t;
183
184 enum IPVP_bits {
185     IPVP_MASK     = 31,
186     IPVP_ACTIVITY = 30,
187     IPVP_MODE     = 29,
188     IPVP_POLARITY = 23,
189     IPVP_SENSE    = 22,
190 };
191 #define IPVP_PRIORITY_MASK     (0x1F << 16)
192 #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
193 #define IPVP_VECTOR_MASK       ((1 << VECTOR_BITS) - 1)
194 #define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)
195
196 typedef struct IRQ_dst_t {
197     uint32_t pctp; /* CPU current task priority */
198     uint32_t pcsr; /* CPU sensitivity register */
199     IRQ_queue_t raised;
200     IRQ_queue_t servicing;
201     qemu_irq *irqs;
202 } IRQ_dst_t;
203
204 typedef struct openpic_t {
205     PCIDevice pci_dev;
206     MemoryRegion mem;
207
208     /* Behavior control */
209     uint32_t flags;
210     uint32_t nb_irqs;
211     uint32_t vid;
212     uint32_t veni; /* Vendor identification register */
213     uint32_t spve_mask;
214     uint32_t tifr_reset;
215     uint32_t ipvp_reset;
216     uint32_t ide_reset;
217
218     /* Sub-regions */
219     MemoryRegion sub_io_mem[7];
220
221     /* Global registers */
222     uint32_t frep; /* Feature reporting register */
223     uint32_t glbc; /* Global configuration register  */
224     uint32_t pint; /* Processor initialization register */
225     uint32_t spve; /* Spurious vector register */
226     uint32_t tifr; /* Timer frequency reporting register */
227     /* Source registers */
228     IRQ_src_t src[MAX_IRQ];
229     /* Local registers per output pin */
230     IRQ_dst_t dst[MAX_CPU];
231     int nb_cpus;
232     /* Timer registers */
233     struct {
234         uint32_t ticc;  /* Global timer current count register */
235         uint32_t tibc;  /* Global timer base count register */
236     } timers[MAX_TMR];
237     /* IRQ out is used when in bypass mode (not implemented) */
238     qemu_irq irq_out;
239     int max_irq;
240     int irq_ipi0;
241     int irq_tim0;
242 } openpic_t;
243
244 static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src);
245
246 static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
247 {
248     set_bit(q->queue, n_IRQ);
249 }
250
251 static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
252 {
253     reset_bit(q->queue, n_IRQ);
254 }
255
256 static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
257 {
258     return test_bit(q->queue, n_IRQ);
259 }
260
261 static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
262 {
263     int next, i;
264     int priority;
265
266     next = -1;
267     priority = -1;
268     for (i = 0; i < opp->max_irq; i++) {
269         if (IRQ_testbit(q, i)) {
270             DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
271                     i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
272             if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
273                 next = i;
274                 priority = IPVP_PRIORITY(opp->src[i].ipvp);
275             }
276         }
277     }
278     q->next = next;
279     q->priority = priority;
280 }
281
282 static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
283 {
284     if (q->next == -1) {
285         /* XXX: optimize */
286         IRQ_check(opp, q);
287     }
288
289     return q->next;
290 }
291
292 static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
293 {
294     IRQ_dst_t *dst;
295     IRQ_src_t *src;
296     int priority;
297
298     dst = &opp->dst[n_CPU];
299     src = &opp->src[n_IRQ];
300     priority = IPVP_PRIORITY(src->ipvp);
301     if (priority <= dst->pctp) {
302         /* Too low priority */
303         DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
304                 __func__, n_IRQ, n_CPU);
305         return;
306     }
307     if (IRQ_testbit(&dst->raised, n_IRQ)) {
308         /* Interrupt miss */
309         DPRINTF("%s: IRQ %d was missed on CPU %d\n",
310                 __func__, n_IRQ, n_CPU);
311         return;
312     }
313     set_bit(&src->ipvp, IPVP_ACTIVITY);
314     IRQ_setbit(&dst->raised, n_IRQ);
315     if (priority < dst->raised.priority) {
316         /* An higher priority IRQ is already raised */
317         DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
318                 __func__, n_IRQ, dst->raised.next, n_CPU);
319         return;
320     }
321     IRQ_get_next(opp, &dst->raised);
322     if (IRQ_get_next(opp, &dst->servicing) != -1 &&
323         priority <= dst->servicing.priority) {
324         DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
325                 __func__, n_IRQ, dst->servicing.next, n_CPU);
326         /* Already servicing a higher priority IRQ */
327         return;
328     }
329     DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
330     openpic_irq_raise(opp, n_CPU, src);
331 }
332
333 /* update pic state because registers for n_IRQ have changed value */
334 static void openpic_update_irq(openpic_t *opp, int n_IRQ)
335 {
336     IRQ_src_t *src;
337     int i;
338
339     src = &opp->src[n_IRQ];
340
341     if (!src->pending) {
342         /* no irq pending */
343         DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
344         return;
345     }
346     if (test_bit(&src->ipvp, IPVP_MASK)) {
347         /* Interrupt source is disabled */
348         DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
349         return;
350     }
351     if (IPVP_PRIORITY(src->ipvp) == 0) {
352         /* Priority set to zero */
353         DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
354         return;
355     }
356     if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
357         /* IRQ already active */
358         DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
359         return;
360     }
361     if (src->ide == 0x00000000) {
362         /* No target */
363         DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
364         return;
365     }
366
367     if (src->ide == (1 << src->last_cpu)) {
368         /* Only one CPU is allowed to receive this IRQ */
369         IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
370     } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
371         /* Directed delivery mode */
372         for (i = 0; i < opp->nb_cpus; i++) {
373             if (test_bit(&src->ide, i))
374                 IRQ_local_pipe(opp, i, n_IRQ);
375         }
376     } else {
377         /* Distributed delivery mode */
378         for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
379             if (i == opp->nb_cpus)
380                 i = 0;
381             if (test_bit(&src->ide, i)) {
382                 IRQ_local_pipe(opp, i, n_IRQ);
383                 src->last_cpu = i;
384                 break;
385             }
386         }
387     }
388 }
389
390 static void openpic_set_irq(void *opaque, int n_IRQ, int level)
391 {
392     openpic_t *opp = opaque;
393     IRQ_src_t *src;
394
395     src = &opp->src[n_IRQ];
396     DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
397             n_IRQ, level, src->ipvp);
398     if (test_bit(&src->ipvp, IPVP_SENSE)) {
399         /* level-sensitive irq */
400         src->pending = level;
401         if (!level)
402             reset_bit(&src->ipvp, IPVP_ACTIVITY);
403     } else {
404         /* edge-sensitive irq */
405         if (level)
406             src->pending = 1;
407     }
408     openpic_update_irq(opp, n_IRQ);
409 }
410
411 static void openpic_reset (void *opaque)
412 {
413     openpic_t *opp = (openpic_t *)opaque;
414     int i;
415
416     opp->glbc = 0x80000000;
417     /* Initialise controller registers */
418     opp->frep = ((opp->nb_irqs -1) << FREP_NIRQ_SHIFT) |
419                 ((opp->nb_cpus -1) << FREP_NCPU_SHIFT) |
420                 (opp->vid << FREP_VID_SHIFT);
421
422     opp->pint = 0x00000000;
423     opp->spve = -1 & opp->spve_mask;
424     opp->tifr = opp->tifr_reset;
425     /* Initialise IRQ sources */
426     for (i = 0; i < opp->max_irq; i++) {
427         opp->src[i].ipvp = opp->ipvp_reset;
428         opp->src[i].ide  = opp->ide_reset;
429     }
430     /* Initialise IRQ destinations */
431     for (i = 0; i < MAX_CPU; i++) {
432         opp->dst[i].pctp      = 0x0000000F;
433         opp->dst[i].pcsr      = 0x00000000;
434         memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
435         opp->dst[i].raised.next = -1;
436         memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
437         opp->dst[i].servicing.next = -1;
438     }
439     /* Initialise timers */
440     for (i = 0; i < MAX_TMR; i++) {
441         opp->timers[i].ticc = 0x00000000;
442         opp->timers[i].tibc = 0x80000000;
443     }
444     /* Go out of RESET state */
445     opp->glbc = 0x00000000;
446 }
447
448 static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ)
449 {
450     return opp->src[n_IRQ].ide;
451 }
452
453 static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ)
454 {
455     return opp->src[n_IRQ].ipvp;
456 }
457
458 static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val)
459 {
460     uint32_t tmp;
461
462     tmp = val & 0xC0000000;
463     tmp |= val & ((1ULL << MAX_CPU) - 1);
464     opp->src[n_IRQ].ide = tmp;
465     DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
466 }
467
468 static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val)
469 {
470     /* NOTE: not fully accurate for special IRQs, but simple and sufficient */
471     /* ACTIVITY bit is read-only */
472     opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000)
473                          | (val & 0x800F00FF);
474     openpic_update_irq(opp, n_IRQ);
475     DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
476             opp->src[n_IRQ].ipvp);
477 }
478
479 static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
480                               unsigned len)
481 {
482     openpic_t *opp = opaque;
483     IRQ_dst_t *dst;
484     int idx;
485
486     DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
487     if (addr & 0xF)
488         return;
489     switch (addr) {
490     case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
491         break;
492     case 0x40:
493     case 0x50:
494     case 0x60:
495     case 0x70:
496     case 0x80:
497     case 0x90:
498     case 0xA0:
499     case 0xB0:
500         openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
501         break;
502     case 0x1000: /* FREP */
503         break;
504     case 0x1020: /* GLBC */
505         if (val & 0x80000000) {
506             openpic_reset(opp);
507         }
508         break;
509     case 0x1080: /* VENI */
510         break;
511     case 0x1090: /* PINT */
512         for (idx = 0; idx < opp->nb_cpus; idx++) {
513             if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
514                 DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
515                 dst = &opp->dst[idx];
516                 qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
517             } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
518                 DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
519                 dst = &opp->dst[idx];
520                 qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
521             }
522         }
523         opp->pint = val;
524         break;
525     case 0x10A0: /* IPI_IPVP */
526     case 0x10B0:
527     case 0x10C0:
528     case 0x10D0:
529         {
530             int idx;
531             idx = (addr - 0x10A0) >> 4;
532             write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val);
533         }
534         break;
535     case 0x10E0: /* SPVE */
536         opp->spve = val & opp->spve_mask;
537         break;
538     default:
539         break;
540     }
541 }
542
543 static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
544 {
545     openpic_t *opp = opaque;
546     uint32_t retval;
547
548     DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
549     retval = 0xFFFFFFFF;
550     if (addr & 0xF)
551         return retval;
552     switch (addr) {
553     case 0x1000: /* FREP */
554         retval = opp->frep;
555         break;
556     case 0x1020: /* GLBC */
557         retval = opp->glbc;
558         break;
559     case 0x1080: /* VENI */
560         retval = opp->veni;
561         break;
562     case 0x1090: /* PINT */
563         retval = 0x00000000;
564         break;
565     case 0x00: /* Block Revision Register1 (BRR1) */
566     case 0x40:
567     case 0x50:
568     case 0x60:
569     case 0x70:
570     case 0x80:
571     case 0x90:
572     case 0xA0:
573     case 0xB0:
574         retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
575         break;
576     case 0x10A0: /* IPI_IPVP */
577     case 0x10B0:
578     case 0x10C0:
579     case 0x10D0:
580         {
581             int idx;
582             idx = (addr - 0x10A0) >> 4;
583             retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx);
584         }
585         break;
586     case 0x10E0: /* SPVE */
587         retval = opp->spve;
588         break;
589     default:
590         break;
591     }
592     DPRINTF("%s: => %08x\n", __func__, retval);
593
594     return retval;
595 }
596
597 static void openpic_timer_write(void *opaque, hwaddr addr, uint64_t val,
598                                 unsigned len)
599 {
600     openpic_t *opp = opaque;
601     int idx;
602
603     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
604     if (addr & 0xF)
605         return;
606     idx = (addr >> 6) & 0x3;
607     addr = addr & 0x30;
608
609     if (addr == 0x0) {
610         /* TIFR (TFRR) */
611         opp->tifr = val;
612         return;
613     }
614     switch (addr & 0x30) {
615     case 0x00: /* TICC (GTCCR) */
616         break;
617     case 0x10: /* TIBC (GTBCR) */
618         if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
619             (val & 0x80000000) == 0 &&
620             (opp->timers[idx].tibc & 0x80000000) != 0)
621             opp->timers[idx].ticc &= ~0x80000000;
622         opp->timers[idx].tibc = val;
623         break;
624     case 0x20: /* TIVP (GTIVPR) */
625         write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val);
626         break;
627     case 0x30: /* TIDE (GTIDR) */
628         write_IRQreg_ide(opp, opp->irq_tim0 + idx, val);
629         break;
630     }
631 }
632
633 static uint64_t openpic_timer_read(void *opaque, hwaddr addr, unsigned len)
634 {
635     openpic_t *opp = opaque;
636     uint32_t retval = -1;
637     int idx;
638
639     DPRINTF("%s: addr %08x\n", __func__, addr);
640     if (addr & 0xF) {
641         goto out;
642     }
643     idx = (addr >> 6) & 0x3;
644     if (addr == 0x0) {
645         /* TIFR (TFRR) */
646         retval = opp->tifr;
647         goto out;
648     }
649     switch (addr & 0x30) {
650     case 0x00: /* TICC (GTCCR) */
651         retval = opp->timers[idx].ticc;
652         break;
653     case 0x10: /* TIBC (GTBCR) */
654         retval = opp->timers[idx].tibc;
655         break;
656     case 0x20: /* TIPV (TIPV) */
657         retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx);
658         break;
659     case 0x30: /* TIDE (TIDR) */
660         retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx);
661         break;
662     }
663
664 out:
665     DPRINTF("%s: => %08x\n", __func__, retval);
666
667     return retval;
668 }
669
670 static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
671                               unsigned len)
672 {
673     openpic_t *opp = opaque;
674     int idx;
675
676     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
677     if (addr & 0xF)
678         return;
679     addr = addr & 0xFFF0;
680     idx = addr >> 5;
681     if (addr & 0x10) {
682         /* EXDE / IFEDE / IEEDE */
683         write_IRQreg_ide(opp, idx, val);
684     } else {
685         /* EXVP / IFEVP / IEEVP */
686         write_IRQreg_ipvp(opp, idx, val);
687     }
688 }
689
690 static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
691 {
692     openpic_t *opp = opaque;
693     uint32_t retval;
694     int idx;
695
696     DPRINTF("%s: addr %08x\n", __func__, addr);
697     retval = 0xFFFFFFFF;
698     if (addr & 0xF)
699         return retval;
700     addr = addr & 0xFFF0;
701     idx = addr >> 5;
702     if (addr & 0x10) {
703         /* EXDE / IFEDE / IEEDE */
704         retval = read_IRQreg_ide(opp, idx);
705     } else {
706         /* EXVP / IFEVP / IEEVP */
707         retval = read_IRQreg_ipvp(opp, idx);
708     }
709     DPRINTF("%s: => %08x\n", __func__, retval);
710
711     return retval;
712 }
713
714 static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
715                                        uint32_t val, int idx)
716 {
717     openpic_t *opp = opaque;
718     IRQ_src_t *src;
719     IRQ_dst_t *dst;
720     int s_IRQ, n_IRQ;
721
722     DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx,
723             addr, val);
724     if (addr & 0xF)
725         return;
726     dst = &opp->dst[idx];
727     addr &= 0xFF0;
728     switch (addr) {
729     case 0x40: /* IPIDR */
730     case 0x50:
731     case 0x60:
732     case 0x70:
733         idx = (addr - 0x40) >> 4;
734         /* we use IDE as mask which CPUs to deliver the IPI to still. */
735         write_IRQreg_ide(opp, opp->irq_ipi0 + idx,
736                          opp->src[opp->irq_ipi0 + idx].ide | val);
737         openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
738         openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
739         break;
740     case 0x80: /* PCTP */
741         dst->pctp = val & 0x0000000F;
742         break;
743     case 0x90: /* WHOAMI */
744         /* Read-only register */
745         break;
746     case 0xA0: /* PIAC */
747         /* Read-only register */
748         break;
749     case 0xB0: /* PEOI */
750         DPRINTF("PEOI\n");
751         s_IRQ = IRQ_get_next(opp, &dst->servicing);
752         IRQ_resetbit(&dst->servicing, s_IRQ);
753         dst->servicing.next = -1;
754         /* Set up next servicing IRQ */
755         s_IRQ = IRQ_get_next(opp, &dst->servicing);
756         /* Check queued interrupts. */
757         n_IRQ = IRQ_get_next(opp, &dst->raised);
758         src = &opp->src[n_IRQ];
759         if (n_IRQ != -1 &&
760             (s_IRQ == -1 ||
761              IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
762             DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
763                     idx, n_IRQ);
764             openpic_irq_raise(opp, idx, src);
765         }
766         break;
767     default:
768         break;
769     }
770 }
771
772 static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val,
773                               unsigned len)
774 {
775     openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
776 }
777
778 static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
779                                           int idx)
780 {
781     openpic_t *opp = opaque;
782     IRQ_src_t *src;
783     IRQ_dst_t *dst;
784     uint32_t retval;
785     int n_IRQ;
786
787     DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr);
788     retval = 0xFFFFFFFF;
789     if (addr & 0xF)
790         return retval;
791     dst = &opp->dst[idx];
792     addr &= 0xFF0;
793     switch (addr) {
794     case 0x00: /* Block Revision Register1 (BRR1) */
795         retval = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN;
796         break;
797     case 0x80: /* PCTP */
798         retval = dst->pctp;
799         break;
800     case 0x90: /* WHOAMI */
801         retval = idx;
802         break;
803     case 0xA0: /* PIAC */
804         DPRINTF("Lower OpenPIC INT output\n");
805         qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
806         n_IRQ = IRQ_get_next(opp, &dst->raised);
807         DPRINTF("PIAC: irq=%d\n", n_IRQ);
808         if (n_IRQ == -1) {
809             /* No more interrupt pending */
810             retval = IPVP_VECTOR(opp->spve);
811         } else {
812             src = &opp->src[n_IRQ];
813             if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
814                 !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
815                 /* - Spurious level-sensitive IRQ
816                  * - Priorities has been changed
817                  *   and the pending IRQ isn't allowed anymore
818                  */
819                 reset_bit(&src->ipvp, IPVP_ACTIVITY);
820                 retval = IPVP_VECTOR(opp->spve);
821             } else {
822                 /* IRQ enter servicing state */
823                 IRQ_setbit(&dst->servicing, n_IRQ);
824                 retval = IPVP_VECTOR(src->ipvp);
825             }
826             IRQ_resetbit(&dst->raised, n_IRQ);
827             dst->raised.next = -1;
828             if (!test_bit(&src->ipvp, IPVP_SENSE)) {
829                 /* edge-sensitive IRQ */
830                 reset_bit(&src->ipvp, IPVP_ACTIVITY);
831                 src->pending = 0;
832             }
833
834             if ((n_IRQ >= opp->irq_ipi0) &&  (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) {
835                 src->ide &= ~(1 << idx);
836                 if (src->ide && !test_bit(&src->ipvp, IPVP_SENSE)) {
837                     /* trigger on CPUs that didn't know about it yet */
838                     openpic_set_irq(opp, n_IRQ, 1);
839                     openpic_set_irq(opp, n_IRQ, 0);
840                     /* if all CPUs knew about it, set active bit again */
841                     set_bit(&src->ipvp, IPVP_ACTIVITY);
842                 }
843             }
844         }
845         break;
846     case 0xB0: /* PEOI */
847         retval = 0;
848         break;
849     default:
850         break;
851     }
852     DPRINTF("%s: => %08x\n", __func__, retval);
853
854     return retval;
855 }
856
857 static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len)
858 {
859     return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
860 }
861
862 static const MemoryRegionOps openpic_glb_ops_le = {
863     .write = openpic_gbl_write,
864     .read  = openpic_gbl_read,
865     .endianness = DEVICE_LITTLE_ENDIAN,
866     .impl = {
867         .min_access_size = 4,
868         .max_access_size = 4,
869     },
870 };
871
872 static const MemoryRegionOps openpic_glb_ops_be = {
873     .write = openpic_gbl_write,
874     .read  = openpic_gbl_read,
875     .endianness = DEVICE_BIG_ENDIAN,
876     .impl = {
877         .min_access_size = 4,
878         .max_access_size = 4,
879     },
880 };
881
882 static const MemoryRegionOps openpic_tmr_ops_le = {
883     .write = openpic_timer_write,
884     .read  = openpic_timer_read,
885     .endianness = DEVICE_LITTLE_ENDIAN,
886     .impl = {
887         .min_access_size = 4,
888         .max_access_size = 4,
889     },
890 };
891
892 static const MemoryRegionOps openpic_tmr_ops_be = {
893     .write = openpic_timer_write,
894     .read  = openpic_timer_read,
895     .endianness = DEVICE_BIG_ENDIAN,
896     .impl = {
897         .min_access_size = 4,
898         .max_access_size = 4,
899     },
900 };
901
902 static const MemoryRegionOps openpic_cpu_ops_le = {
903     .write = openpic_cpu_write,
904     .read  = openpic_cpu_read,
905     .endianness = DEVICE_LITTLE_ENDIAN,
906     .impl = {
907         .min_access_size = 4,
908         .max_access_size = 4,
909     },
910 };
911
912 static const MemoryRegionOps openpic_cpu_ops_be = {
913     .write = openpic_cpu_write,
914     .read  = openpic_cpu_read,
915     .endianness = DEVICE_BIG_ENDIAN,
916     .impl = {
917         .min_access_size = 4,
918         .max_access_size = 4,
919     },
920 };
921
922 static const MemoryRegionOps openpic_src_ops_le = {
923     .write = openpic_src_write,
924     .read  = openpic_src_read,
925     .endianness = DEVICE_LITTLE_ENDIAN,
926     .impl = {
927         .min_access_size = 4,
928         .max_access_size = 4,
929     },
930 };
931
932 static const MemoryRegionOps openpic_src_ops_be = {
933     .write = openpic_src_write,
934     .read  = openpic_src_read,
935     .endianness = DEVICE_BIG_ENDIAN,
936     .impl = {
937         .min_access_size = 4,
938         .max_access_size = 4,
939     },
940 };
941
942 static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
943 {
944     unsigned int i;
945
946     for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
947         qemu_put_be32s(f, &q->queue[i]);
948
949     qemu_put_sbe32s(f, &q->next);
950     qemu_put_sbe32s(f, &q->priority);
951 }
952
953 static void openpic_save(QEMUFile* f, void *opaque)
954 {
955     openpic_t *opp = (openpic_t *)opaque;
956     unsigned int i;
957
958     qemu_put_be32s(f, &opp->glbc);
959     qemu_put_be32s(f, &opp->veni);
960     qemu_put_be32s(f, &opp->pint);
961     qemu_put_be32s(f, &opp->spve);
962     qemu_put_be32s(f, &opp->tifr);
963
964     for (i = 0; i < opp->max_irq; i++) {
965         qemu_put_be32s(f, &opp->src[i].ipvp);
966         qemu_put_be32s(f, &opp->src[i].ide);
967         qemu_put_sbe32s(f, &opp->src[i].last_cpu);
968         qemu_put_sbe32s(f, &opp->src[i].pending);
969     }
970
971     qemu_put_sbe32s(f, &opp->nb_cpus);
972
973     for (i = 0; i < opp->nb_cpus; i++) {
974         qemu_put_be32s(f, &opp->dst[i].pctp);
975         qemu_put_be32s(f, &opp->dst[i].pcsr);
976         openpic_save_IRQ_queue(f, &opp->dst[i].raised);
977         openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
978     }
979
980     for (i = 0; i < MAX_TMR; i++) {
981         qemu_put_be32s(f, &opp->timers[i].ticc);
982         qemu_put_be32s(f, &opp->timers[i].tibc);
983     }
984
985     pci_device_save(&opp->pci_dev, f);
986 }
987
988 static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
989 {
990     unsigned int i;
991
992     for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
993         qemu_get_be32s(f, &q->queue[i]);
994
995     qemu_get_sbe32s(f, &q->next);
996     qemu_get_sbe32s(f, &q->priority);
997 }
998
999 static int openpic_load(QEMUFile* f, void *opaque, int version_id)
1000 {
1001     openpic_t *opp = (openpic_t *)opaque;
1002     unsigned int i;
1003
1004     if (version_id != 1)
1005         return -EINVAL;
1006
1007     qemu_get_be32s(f, &opp->glbc);
1008     qemu_get_be32s(f, &opp->veni);
1009     qemu_get_be32s(f, &opp->pint);
1010     qemu_get_be32s(f, &opp->spve);
1011     qemu_get_be32s(f, &opp->tifr);
1012
1013     for (i = 0; i < opp->max_irq; i++) {
1014         qemu_get_be32s(f, &opp->src[i].ipvp);
1015         qemu_get_be32s(f, &opp->src[i].ide);
1016         qemu_get_sbe32s(f, &opp->src[i].last_cpu);
1017         qemu_get_sbe32s(f, &opp->src[i].pending);
1018     }
1019
1020     qemu_get_sbe32s(f, &opp->nb_cpus);
1021
1022     for (i = 0; i < opp->nb_cpus; i++) {
1023         qemu_get_be32s(f, &opp->dst[i].pctp);
1024         qemu_get_be32s(f, &opp->dst[i].pcsr);
1025         openpic_load_IRQ_queue(f, &opp->dst[i].raised);
1026         openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
1027     }
1028
1029     for (i = 0; i < MAX_TMR; i++) {
1030         qemu_get_be32s(f, &opp->timers[i].ticc);
1031         qemu_get_be32s(f, &opp->timers[i].tibc);
1032     }
1033
1034     return pci_device_load(&opp->pci_dev, f);
1035 }
1036
1037 static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
1038 {
1039     int n_ci = IDR_CI0 - n_CPU;
1040
1041     if ((opp->flags & OPENPIC_FLAG_IDE_CRIT) && test_bit(&src->ide, n_ci)) {
1042         qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]);
1043     } else {
1044         qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1045     }
1046 }
1047
1048 qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
1049                         qemu_irq **irqs, qemu_irq irq_out)
1050 {
1051     openpic_t *opp;
1052     int i;
1053     struct {
1054         const char             *name;
1055         MemoryRegionOps const  *ops;
1056         hwaddr      start_addr;
1057         ram_addr_t              size;
1058     } const list[] = {
1059         {"glb", &openpic_glb_ops_le, OPENPIC_GLB_REG_START,
1060                                      OPENPIC_GLB_REG_SIZE},
1061         {"tmr", &openpic_tmr_ops_le, OPENPIC_TMR_REG_START,
1062                                      OPENPIC_TMR_REG_SIZE},
1063         {"src", &openpic_src_ops_le, OPENPIC_SRC_REG_START,
1064                                      OPENPIC_SRC_REG_SIZE},
1065         {"cpu", &openpic_cpu_ops_le, OPENPIC_CPU_REG_START,
1066                                      OPENPIC_CPU_REG_SIZE},
1067     };
1068
1069     /* XXX: for now, only one CPU is supported */
1070     if (nb_cpus != 1)
1071         return NULL;
1072     opp = g_malloc0(sizeof(openpic_t));
1073
1074     memory_region_init(&opp->mem, "openpic", 0x40000);
1075
1076     for (i = 0; i < ARRAY_SIZE(list); i++) {
1077
1078         memory_region_init_io(&opp->sub_io_mem[i], list[i].ops, opp,
1079                               list[i].name, list[i].size);
1080
1081         memory_region_add_subregion(&opp->mem, list[i].start_addr,
1082                                     &opp->sub_io_mem[i]);
1083     }
1084
1085     //    isu_base &= 0xFFFC0000;
1086     opp->nb_cpus = nb_cpus;
1087     opp->nb_irqs = OPENPIC_EXT_IRQ;
1088     opp->vid = VID;
1089     opp->veni = VENI_GENERIC;
1090     opp->spve_mask = 0xFF;
1091     opp->tifr_reset = 0x003F7A00;
1092     opp->max_irq = OPENPIC_MAX_IRQ;
1093     opp->irq_ipi0 = OPENPIC_IRQ_IPI0;
1094     opp->irq_tim0 = OPENPIC_IRQ_TIM0;
1095
1096     for (i = 0; i < nb_cpus; i++)
1097         opp->dst[i].irqs = irqs[i];
1098     opp->irq_out = irq_out;
1099
1100     register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2,
1101                     openpic_save, openpic_load, opp);
1102     qemu_register_reset(openpic_reset, opp);
1103
1104     if (pmem)
1105         *pmem = &opp->mem;
1106
1107     return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
1108 }
1109
1110 qemu_irq *mpic_init (MemoryRegion *address_space, hwaddr base,
1111                      int nb_cpus, qemu_irq **irqs, qemu_irq irq_out)
1112 {
1113     openpic_t    *mpp;
1114     int           i;
1115     struct {
1116         const char             *name;
1117         MemoryRegionOps const  *ops;
1118         hwaddr      start_addr;
1119         ram_addr_t              size;
1120     } const list[] = {
1121         {"glb", &openpic_glb_ops_be, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
1122         {"tmr", &openpic_tmr_ops_be, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
1123         {"src", &openpic_src_ops_be, MPIC_SRC_REG_START, MPIC_SRC_REG_SIZE},
1124         {"cpu", &openpic_cpu_ops_be, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
1125     };
1126
1127     mpp = g_malloc0(sizeof(openpic_t));
1128
1129     memory_region_init(&mpp->mem, "mpic", 0x40000);
1130     memory_region_add_subregion(address_space, base, &mpp->mem);
1131
1132     for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
1133
1134         memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp,
1135                               list[i].name, list[i].size);
1136
1137         memory_region_add_subregion(&mpp->mem, list[i].start_addr,
1138                                     &mpp->sub_io_mem[i]);
1139     }
1140
1141     mpp->nb_cpus = nb_cpus;
1142     /* 12 external sources, 48 internal sources , 4 timer sources,
1143        4 IPI sources, 4 messaging sources, and 8 Shared MSI sources */
1144     mpp->nb_irqs = 80;
1145     mpp->vid = VID_REVISION_1_2;
1146     mpp->veni = VENI_GENERIC;
1147     mpp->spve_mask = 0xFFFF;
1148     mpp->tifr_reset = 0x00000000;
1149     mpp->ipvp_reset = 0x80000000;
1150     mpp->ide_reset = 0x00000001;
1151     mpp->max_irq = MPIC_MAX_IRQ;
1152     mpp->irq_ipi0 = MPIC_IPI_IRQ;
1153     mpp->irq_tim0 = MPIC_TMR_IRQ;
1154
1155     for (i = 0; i < nb_cpus; i++)
1156         mpp->dst[i].irqs = irqs[i];
1157     mpp->irq_out = irq_out;
1158
1159     /* Enable critical interrupt support */
1160     mpp->flags |= OPENPIC_FLAG_IDE_CRIT;
1161
1162     register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp);
1163     qemu_register_reset(openpic_reset, mpp);
1164
1165     return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
1166 }
This page took 0.089117 seconds and 4 git commands to generate.