xref: /openbmc/qemu/hw/intc/heathrow_pic.c (revision 086df4f30a8f33e7b696c79b6f5cd2c94afbf98f)
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 #include "hw/intc/heathrow_pic.h"
29 
30 /* debug PIC */
31 //#define DEBUG_PIC
32 
33 #ifdef DEBUG_PIC
34 #define PIC_DPRINTF(fmt, ...)                                   \
35     do { printf("PIC: " fmt , ## __VA_ARGS__); } while (0)
36 #else
37 #define PIC_DPRINTF(fmt, ...)
38 #endif
39 
40 static inline int heathrow_check_irq(HeathrowPICState *pic)
41 {
42     return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
43 }
44 
45 /* update the CPU irq state */
46 static void heathrow_update_irq(HeathrowState *s)
47 {
48     if (heathrow_check_irq(&s->pics[0]) ||
49             heathrow_check_irq(&s->pics[1])) {
50         qemu_irq_raise(s->irqs[0]);
51     } else {
52         qemu_irq_lower(s->irqs[0]);
53     }
54 }
55 
56 static void heathrow_write(void *opaque, hwaddr addr,
57                            uint64_t value, unsigned size)
58 {
59     HeathrowState *s = opaque;
60     HeathrowPICState *pic;
61     unsigned int n;
62 
63     n = ((addr & 0xfff) - 0x10) >> 4;
64     PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
65     if (n >= 2)
66         return;
67     pic = &s->pics[n];
68     switch(addr & 0xf) {
69     case 0x04:
70         pic->mask = value;
71         heathrow_update_irq(s);
72         break;
73     case 0x08:
74         /* do not reset level triggered IRQs */
75         value &= ~pic->level_triggered;
76         pic->events &= ~value;
77         heathrow_update_irq(s);
78         break;
79     default:
80         break;
81     }
82 }
83 
84 static uint64_t heathrow_read(void *opaque, hwaddr addr,
85                               unsigned size)
86 {
87     HeathrowState *s = opaque;
88     HeathrowPICState *pic;
89     unsigned int n;
90     uint32_t value;
91 
92     n = ((addr & 0xfff) - 0x10) >> 4;
93     if (n >= 2) {
94         value = 0;
95     } else {
96         pic = &s->pics[n];
97         switch(addr & 0xf) {
98         case 0x0:
99             value = pic->events;
100             break;
101         case 0x4:
102             value = pic->mask;
103             break;
104         case 0xc:
105             value = pic->levels;
106             break;
107         default:
108             value = 0;
109             break;
110         }
111     }
112     PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
113     return value;
114 }
115 
116 static const MemoryRegionOps heathrow_ops = {
117     .read = heathrow_read,
118     .write = heathrow_write,
119     .endianness = DEVICE_LITTLE_ENDIAN,
120 };
121 
122 static void heathrow_set_irq(void *opaque, int num, int level)
123 {
124     HeathrowState *s = opaque;
125     HeathrowPICState *pic;
126     unsigned int irq_bit;
127 
128 #if defined(DEBUG)
129     {
130         static int last_level[64];
131         if (last_level[num] != level) {
132             PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level);
133             last_level[num] = level;
134         }
135     }
136 #endif
137     pic = &s->pics[1 - (num >> 5)];
138     irq_bit = 1 << (num & 0x1f);
139     if (level) {
140         pic->events |= irq_bit & ~pic->level_triggered;
141         pic->levels |= irq_bit;
142     } else {
143         pic->levels &= ~irq_bit;
144     }
145     heathrow_update_irq(s);
146 }
147 
148 static const VMStateDescription vmstate_heathrow_pic_one = {
149     .name = "heathrow_pic_one",
150     .version_id = 0,
151     .minimum_version_id = 0,
152     .fields = (VMStateField[]) {
153         VMSTATE_UINT32(events, HeathrowPICState),
154         VMSTATE_UINT32(mask, HeathrowPICState),
155         VMSTATE_UINT32(levels, HeathrowPICState),
156         VMSTATE_UINT32(level_triggered, HeathrowPICState),
157         VMSTATE_END_OF_LIST()
158     }
159 };
160 
161 static const VMStateDescription vmstate_heathrow = {
162     .name = "heathrow_pic",
163     .version_id = 1,
164     .minimum_version_id = 1,
165     .fields = (VMStateField[]) {
166         VMSTATE_STRUCT_ARRAY(pics, HeathrowState, 2, 1,
167                              vmstate_heathrow_pic_one, HeathrowPICState),
168         VMSTATE_END_OF_LIST()
169     }
170 };
171 
172 static void heathrow_reset(DeviceState *d)
173 {
174     HeathrowState *s = HEATHROW(d);
175 
176     s->pics[0].level_triggered = 0;
177     s->pics[1].level_triggered = 0x1ff00000;
178 }
179 
180 static void heathrow_init(Object *obj)
181 {
182     HeathrowState *s = HEATHROW(obj);
183 
184     memory_region_init_io(&s->mem, OBJECT(s), &heathrow_ops, s,
185                           "heathrow-pic", 0x1000);
186 }
187 
188 qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
189                             int nb_cpus, qemu_irq **irqs)
190 {
191     DeviceState *d;
192     HeathrowState *s;
193 
194     d = qdev_create(NULL, TYPE_HEATHROW);
195     qdev_init_nofail(d);
196 
197     s = HEATHROW(d);
198     /* only 1 CPU */
199     s->irqs = irqs[0];
200 
201     *pmem = &s->mem;
202 
203     return qemu_allocate_irqs(heathrow_set_irq, s, HEATHROW_NUM_IRQS);
204 }
205 
206 static void heathrow_class_init(ObjectClass *oc, void *data)
207 {
208     DeviceClass *dc = DEVICE_CLASS(oc);
209 
210     dc->reset = heathrow_reset;
211     dc->vmsd = &vmstate_heathrow;
212     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
213 }
214 
215 static const TypeInfo heathrow_type_info = {
216     .name = TYPE_HEATHROW,
217     .parent = TYPE_SYS_BUS_DEVICE,
218     .instance_size = sizeof(HeathrowState),
219     .instance_init = heathrow_init,
220     .class_init = heathrow_class_init,
221 };
222 
223 static void heathrow_register_types(void)
224 {
225     type_register_static(&heathrow_type_info);
226 }
227 
228 type_init(heathrow_register_types)
229