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.h" 26 #include "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 HeathrowPIC pics[2]; 47 qemu_irq *irqs; 48 } HeathrowPICS; 49 50 static inline int check_irq(HeathrowPIC *pic) 51 { 52 return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask; 53 } 54 55 /* update the CPU irq state */ 56 static void heathrow_pic_update(HeathrowPICS *s) 57 { 58 if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) { 59 qemu_irq_raise(s->irqs[0]); 60 } else { 61 qemu_irq_lower(s->irqs[0]); 62 } 63 } 64 65 static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) 66 { 67 HeathrowPICS *s = opaque; 68 HeathrowPIC *pic; 69 unsigned int n; 70 71 value = bswap32(value); 72 n = ((addr & 0xfff) - 0x10) >> 4; 73 PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value); 74 if (n >= 2) 75 return; 76 pic = &s->pics[n]; 77 switch(addr & 0xf) { 78 case 0x04: 79 pic->mask = value; 80 heathrow_pic_update(s); 81 break; 82 case 0x08: 83 /* do not reset level triggered IRQs */ 84 value &= ~pic->level_triggered; 85 pic->events &= ~value; 86 heathrow_pic_update(s); 87 break; 88 default: 89 break; 90 } 91 } 92 93 static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) 94 { 95 HeathrowPICS *s = opaque; 96 HeathrowPIC *pic; 97 unsigned int n; 98 uint32_t value; 99 100 n = ((addr & 0xfff) - 0x10) >> 4; 101 if (n >= 2) { 102 value = 0; 103 } else { 104 pic = &s->pics[n]; 105 switch(addr & 0xf) { 106 case 0x0: 107 value = pic->events; 108 break; 109 case 0x4: 110 value = pic->mask; 111 break; 112 case 0xc: 113 value = pic->levels; 114 break; 115 default: 116 value = 0; 117 break; 118 } 119 } 120 PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value); 121 value = bswap32(value); 122 return value; 123 } 124 125 static CPUWriteMemoryFunc * const pic_write[] = { 126 &pic_writel, 127 &pic_writel, 128 &pic_writel, 129 }; 130 131 static CPUReadMemoryFunc * const pic_read[] = { 132 &pic_readl, 133 &pic_readl, 134 &pic_readl, 135 }; 136 137 138 static void heathrow_pic_set_irq(void *opaque, int num, int level) 139 { 140 HeathrowPICS *s = opaque; 141 HeathrowPIC *pic; 142 unsigned int irq_bit; 143 144 #if defined(DEBUG) 145 { 146 static int last_level[64]; 147 if (last_level[num] != level) { 148 PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level); 149 last_level[num] = level; 150 } 151 } 152 #endif 153 pic = &s->pics[1 - (num >> 5)]; 154 irq_bit = 1 << (num & 0x1f); 155 if (level) { 156 pic->events |= irq_bit & ~pic->level_triggered; 157 pic->levels |= irq_bit; 158 } else { 159 pic->levels &= ~irq_bit; 160 } 161 heathrow_pic_update(s); 162 } 163 164 static void heathrow_pic_save_one(QEMUFile *f, HeathrowPIC *s) 165 { 166 qemu_put_be32s(f, &s->events); 167 qemu_put_be32s(f, &s->mask); 168 qemu_put_be32s(f, &s->levels); 169 qemu_put_be32s(f, &s->level_triggered); 170 } 171 172 static void heathrow_pic_save(QEMUFile *f, void *opaque) 173 { 174 HeathrowPICS *s = (HeathrowPICS *)opaque; 175 176 heathrow_pic_save_one(f, &s->pics[0]); 177 heathrow_pic_save_one(f, &s->pics[1]); 178 } 179 180 static void heathrow_pic_load_one(QEMUFile *f, HeathrowPIC *s) 181 { 182 qemu_get_be32s(f, &s->events); 183 qemu_get_be32s(f, &s->mask); 184 qemu_get_be32s(f, &s->levels); 185 qemu_get_be32s(f, &s->level_triggered); 186 } 187 188 static int heathrow_pic_load(QEMUFile *f, void *opaque, int version_id) 189 { 190 HeathrowPICS *s = (HeathrowPICS *)opaque; 191 192 if (version_id != 1) 193 return -EINVAL; 194 195 heathrow_pic_load_one(f, &s->pics[0]); 196 heathrow_pic_load_one(f, &s->pics[1]); 197 198 return 0; 199 } 200 201 static void heathrow_pic_reset_one(HeathrowPIC *s) 202 { 203 memset(s, '\0', sizeof(HeathrowPIC)); 204 } 205 206 static void heathrow_pic_reset(void *opaque) 207 { 208 HeathrowPICS *s = opaque; 209 210 heathrow_pic_reset_one(&s->pics[0]); 211 heathrow_pic_reset_one(&s->pics[1]); 212 213 s->pics[0].level_triggered = 0; 214 s->pics[1].level_triggered = 0x1ff00000; 215 } 216 217 qemu_irq *heathrow_pic_init(int *pmem_index, 218 int nb_cpus, qemu_irq **irqs) 219 { 220 HeathrowPICS *s; 221 222 s = qemu_mallocz(sizeof(HeathrowPICS)); 223 /* only 1 CPU */ 224 s->irqs = irqs[0]; 225 *pmem_index = cpu_register_io_memory(pic_read, pic_write, s, 226 DEVICE_NATIVE_ENDIAN); 227 228 register_savevm(NULL, "heathrow_pic", -1, 1, heathrow_pic_save, 229 heathrow_pic_load, s); 230 qemu_register_reset(heathrow_pic_reset, s); 231 return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64); 232 } 233