xref: /qemu/hw/intc/heathrow_pic.c (revision 7a4e543d)
1 /*
2  * Heathrow PIC support (OldWorld PowerMac)
3  *
4  * Copyright (c) 2005-2007 Fabrice Bellard
5  * Copyright (c) 2007 Jocelyn Mayer
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 #include "qemu/osdep.h"
26 #include "hw/hw.h"
27 #include "hw/ppc/mac.h"
28 
29 /* debug PIC */
30 //#define DEBUG_PIC
31 
32 #ifdef DEBUG_PIC
33 #define PIC_DPRINTF(fmt, ...)                                   \
34     do { printf("PIC: " fmt , ## __VA_ARGS__); } while (0)
35 #else
36 #define PIC_DPRINTF(fmt, ...)
37 #endif
38 
39 typedef struct HeathrowPIC {
40     uint32_t events;
41     uint32_t mask;
42     uint32_t levels;
43     uint32_t level_triggered;
44 } HeathrowPIC;
45 
46 typedef struct HeathrowPICS {
47     MemoryRegion mem;
48     HeathrowPIC pics[2];
49     qemu_irq *irqs;
50 } HeathrowPICS;
51 
52 static inline int check_irq(HeathrowPIC *pic)
53 {
54     return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
55 }
56 
57 /* update the CPU irq state */
58 static void heathrow_pic_update(HeathrowPICS *s)
59 {
60     if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
61         qemu_irq_raise(s->irqs[0]);
62     } else {
63         qemu_irq_lower(s->irqs[0]);
64     }
65 }
66 
67 static void pic_write(void *opaque, hwaddr addr,
68                       uint64_t value, unsigned size)
69 {
70     HeathrowPICS *s = opaque;
71     HeathrowPIC *pic;
72     unsigned int n;
73 
74     n = ((addr & 0xfff) - 0x10) >> 4;
75     PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
76     if (n >= 2)
77         return;
78     pic = &s->pics[n];
79     switch(addr & 0xf) {
80     case 0x04:
81         pic->mask = value;
82         heathrow_pic_update(s);
83         break;
84     case 0x08:
85         /* do not reset level triggered IRQs */
86         value &= ~pic->level_triggered;
87         pic->events &= ~value;
88         heathrow_pic_update(s);
89         break;
90     default:
91         break;
92     }
93 }
94 
95 static uint64_t pic_read(void *opaque, hwaddr addr,
96                          unsigned size)
97 {
98     HeathrowPICS *s = opaque;
99     HeathrowPIC *pic;
100     unsigned int n;
101     uint32_t value;
102 
103     n = ((addr & 0xfff) - 0x10) >> 4;
104     if (n >= 2) {
105         value = 0;
106     } else {
107         pic = &s->pics[n];
108         switch(addr & 0xf) {
109         case 0x0:
110             value = pic->events;
111             break;
112         case 0x4:
113             value = pic->mask;
114             break;
115         case 0xc:
116             value = pic->levels;
117             break;
118         default:
119             value = 0;
120             break;
121         }
122     }
123     PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
124     return value;
125 }
126 
127 static const MemoryRegionOps heathrow_pic_ops = {
128     .read = pic_read,
129     .write = pic_write,
130     .endianness = DEVICE_LITTLE_ENDIAN,
131 };
132 
133 static void heathrow_pic_set_irq(void *opaque, int num, int level)
134 {
135     HeathrowPICS *s = opaque;
136     HeathrowPIC *pic;
137     unsigned int irq_bit;
138 
139 #if defined(DEBUG)
140     {
141         static int last_level[64];
142         if (last_level[num] != level) {
143             PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level);
144             last_level[num] = level;
145         }
146     }
147 #endif
148     pic = &s->pics[1 - (num >> 5)];
149     irq_bit = 1 << (num & 0x1f);
150     if (level) {
151         pic->events |= irq_bit & ~pic->level_triggered;
152         pic->levels |= irq_bit;
153     } else {
154         pic->levels &= ~irq_bit;
155     }
156     heathrow_pic_update(s);
157 }
158 
159 static const VMStateDescription vmstate_heathrow_pic_one = {
160     .name = "heathrow_pic_one",
161     .version_id = 0,
162     .minimum_version_id = 0,
163     .fields = (VMStateField[]) {
164         VMSTATE_UINT32(events, HeathrowPIC),
165         VMSTATE_UINT32(mask, HeathrowPIC),
166         VMSTATE_UINT32(levels, HeathrowPIC),
167         VMSTATE_UINT32(level_triggered, HeathrowPIC),
168         VMSTATE_END_OF_LIST()
169     }
170 };
171 
172 static const VMStateDescription vmstate_heathrow_pic = {
173     .name = "heathrow_pic",
174     .version_id = 1,
175     .minimum_version_id = 1,
176     .fields = (VMStateField[]) {
177         VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1,
178                              vmstate_heathrow_pic_one, HeathrowPIC),
179         VMSTATE_END_OF_LIST()
180     }
181 };
182 
183 static void heathrow_pic_reset_one(HeathrowPIC *s)
184 {
185     memset(s, '\0', sizeof(HeathrowPIC));
186 }
187 
188 static void heathrow_pic_reset(void *opaque)
189 {
190     HeathrowPICS *s = opaque;
191 
192     heathrow_pic_reset_one(&s->pics[0]);
193     heathrow_pic_reset_one(&s->pics[1]);
194 
195     s->pics[0].level_triggered = 0;
196     s->pics[1].level_triggered = 0x1ff00000;
197 }
198 
199 qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
200                             int nb_cpus, qemu_irq **irqs)
201 {
202     HeathrowPICS *s;
203 
204     s = g_malloc0(sizeof(HeathrowPICS));
205     /* only 1 CPU */
206     s->irqs = irqs[0];
207     memory_region_init_io(&s->mem, NULL, &heathrow_pic_ops, s,
208                           "heathrow-pic", 0x1000);
209     *pmem = &s->mem;
210 
211     vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
212     qemu_register_reset(heathrow_pic_reset, s);
213     return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
214 }
215