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 #ifdef TARGET_WORDS_BIGENDIAN 72 value = bswap32(value); 73 #endif 74 n = ((addr & 0xfff) - 0x10) >> 4; 75 PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value); 76 if (n >= 2) 77 return; 78 pic = &s->pics[n]; 79 switch(addr & 0xf) { 80 case 0x04: 81 pic->mask = value; 82 heathrow_pic_update(s); 83 break; 84 case 0x08: 85 /* do not reset level triggered IRQs */ 86 value &= ~pic->level_triggered; 87 pic->events &= ~value; 88 heathrow_pic_update(s); 89 break; 90 default: 91 break; 92 } 93 } 94 95 static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) 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 #ifdef TARGET_WORDS_BIGENDIAN 124 value = bswap32(value); 125 #endif 126 return value; 127 } 128 129 static CPUWriteMemoryFunc * const pic_write[] = { 130 &pic_writel, 131 &pic_writel, 132 &pic_writel, 133 }; 134 135 static CPUReadMemoryFunc * const pic_read[] = { 136 &pic_readl, 137 &pic_readl, 138 &pic_readl, 139 }; 140 141 142 static void heathrow_pic_set_irq(void *opaque, int num, int level) 143 { 144 HeathrowPICS *s = opaque; 145 HeathrowPIC *pic; 146 unsigned int irq_bit; 147 148 #if defined(DEBUG) 149 { 150 static int last_level[64]; 151 if (last_level[num] != level) { 152 PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level); 153 last_level[num] = level; 154 } 155 } 156 #endif 157 pic = &s->pics[1 - (num >> 5)]; 158 irq_bit = 1 << (num & 0x1f); 159 if (level) { 160 pic->events |= irq_bit & ~pic->level_triggered; 161 pic->levels |= irq_bit; 162 } else { 163 pic->levels &= ~irq_bit; 164 } 165 heathrow_pic_update(s); 166 } 167 168 static void heathrow_pic_save_one(QEMUFile *f, HeathrowPIC *s) 169 { 170 qemu_put_be32s(f, &s->events); 171 qemu_put_be32s(f, &s->mask); 172 qemu_put_be32s(f, &s->levels); 173 qemu_put_be32s(f, &s->level_triggered); 174 } 175 176 static void heathrow_pic_save(QEMUFile *f, void *opaque) 177 { 178 HeathrowPICS *s = (HeathrowPICS *)opaque; 179 180 heathrow_pic_save_one(f, &s->pics[0]); 181 heathrow_pic_save_one(f, &s->pics[1]); 182 } 183 184 static void heathrow_pic_load_one(QEMUFile *f, HeathrowPIC *s) 185 { 186 qemu_get_be32s(f, &s->events); 187 qemu_get_be32s(f, &s->mask); 188 qemu_get_be32s(f, &s->levels); 189 qemu_get_be32s(f, &s->level_triggered); 190 } 191 192 static int heathrow_pic_load(QEMUFile *f, void *opaque, int version_id) 193 { 194 HeathrowPICS *s = (HeathrowPICS *)opaque; 195 196 if (version_id != 1) 197 return -EINVAL; 198 199 heathrow_pic_load_one(f, &s->pics[0]); 200 heathrow_pic_load_one(f, &s->pics[1]); 201 202 return 0; 203 } 204 205 static void heathrow_pic_reset_one(HeathrowPIC *s) 206 { 207 memset(s, '\0', sizeof(HeathrowPIC)); 208 } 209 210 static void heathrow_pic_reset(void *opaque) 211 { 212 HeathrowPICS *s = opaque; 213 214 heathrow_pic_reset_one(&s->pics[0]); 215 heathrow_pic_reset_one(&s->pics[1]); 216 217 s->pics[0].level_triggered = 0; 218 s->pics[1].level_triggered = 0x1ff00000; 219 } 220 221 qemu_irq *heathrow_pic_init(int *pmem_index, 222 int nb_cpus, qemu_irq **irqs) 223 { 224 HeathrowPICS *s; 225 226 s = qemu_mallocz(sizeof(HeathrowPICS)); 227 /* only 1 CPU */ 228 s->irqs = irqs[0]; 229 *pmem_index = cpu_register_io_memory(pic_read, pic_write, s); 230 231 register_savevm("heathrow_pic", -1, 1, heathrow_pic_save, 232 heathrow_pic_load, s); 233 qemu_register_reset(heathrow_pic_reset, s); 234 heathrow_pic_reset(s); 235 return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64); 236 } 237