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