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