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