1 /* 2 * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors 3 * 4 * Copyright (c) 2007 Jocelyn Mayer 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "hw/intc/ppc-uic.h" 27 #include "hw/irq.h" 28 #include "hw/qdev-properties.h" 29 #include "migration/vmstate.h" 30 31 enum { 32 DCR_UICSR = 0x000, 33 DCR_UICSRS = 0x001, 34 DCR_UICER = 0x002, 35 DCR_UICCR = 0x003, 36 DCR_UICPR = 0x004, 37 DCR_UICTR = 0x005, 38 DCR_UICMSR = 0x006, 39 DCR_UICVR = 0x007, 40 DCR_UICVCR = 0x008, 41 DCR_UICMAX = 0x009, 42 }; 43 44 /*#define DEBUG_UIC*/ 45 46 #ifdef DEBUG_UIC 47 # define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__) 48 #else 49 # define LOG_UIC(...) do { } while (0) 50 #endif 51 52 static void ppcuic_trigger_irq(PPCUIC *uic) 53 { 54 uint32_t ir, cr; 55 int start, end, inc, i; 56 57 /* Trigger interrupt if any is pending */ 58 ir = uic->uicsr & uic->uicer & (~uic->uiccr); 59 cr = uic->uicsr & uic->uicer & uic->uiccr; 60 LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32 61 " uiccr %08" PRIx32 "\n" 62 " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n", 63 __func__, uic->uicsr, uic->uicer, uic->uiccr, 64 uic->uicsr & uic->uicer, ir, cr); 65 if (ir != 0x0000000) { 66 LOG_UIC("Raise UIC interrupt\n"); 67 qemu_irq_raise(uic->output_int); 68 } else { 69 LOG_UIC("Lower UIC interrupt\n"); 70 qemu_irq_lower(uic->output_int); 71 } 72 /* Trigger critical interrupt if any is pending and update vector */ 73 if (cr != 0x0000000) { 74 qemu_irq_raise(uic->output_cint); 75 if (uic->use_vectors) { 76 /* Compute critical IRQ vector */ 77 if (uic->uicvcr & 1) { 78 start = 31; 79 end = 0; 80 inc = -1; 81 } else { 82 start = 0; 83 end = 31; 84 inc = 1; 85 } 86 uic->uicvr = uic->uicvcr & 0xFFFFFFFC; 87 for (i = start; i <= end; i += inc) { 88 if (cr & (1 << i)) { 89 uic->uicvr += (i - start) * 512 * inc; 90 break; 91 } 92 } 93 } 94 LOG_UIC("Raise UIC critical interrupt - " 95 "vector %08" PRIx32 "\n", uic->uicvr); 96 } else { 97 LOG_UIC("Lower UIC critical interrupt\n"); 98 qemu_irq_lower(uic->output_cint); 99 uic->uicvr = 0x00000000; 100 } 101 } 102 103 static void ppcuic_set_irq(void *opaque, int irq_num, int level) 104 { 105 PPCUIC *uic = opaque; 106 uint32_t mask, sr; 107 108 mask = 1U << (31 - irq_num); 109 LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32 110 " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n", 111 __func__, irq_num, level, 112 uic->uicsr, mask, uic->uicsr & mask, level << irq_num); 113 if (irq_num < 0 || irq_num > 31) { 114 return; 115 } 116 sr = uic->uicsr; 117 118 /* Update status register */ 119 if (uic->uictr & mask) { 120 /* Edge sensitive interrupt */ 121 if (level == 1) { 122 uic->uicsr |= mask; 123 } 124 } else { 125 /* Level sensitive interrupt */ 126 if (level == 1) { 127 uic->uicsr |= mask; 128 uic->level |= mask; 129 } else { 130 uic->uicsr &= ~mask; 131 uic->level &= ~mask; 132 } 133 } 134 LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => " 135 "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr); 136 if (sr != uic->uicsr) { 137 ppcuic_trigger_irq(uic); 138 } 139 } 140 141 static uint32_t dcr_read_uic(void *opaque, int dcrn) 142 { 143 PPCUIC *uic = opaque; 144 uint32_t ret; 145 146 dcrn -= uic->dcr_base; 147 switch (dcrn) { 148 case DCR_UICSR: 149 case DCR_UICSRS: 150 ret = uic->uicsr; 151 break; 152 case DCR_UICER: 153 ret = uic->uicer; 154 break; 155 case DCR_UICCR: 156 ret = uic->uiccr; 157 break; 158 case DCR_UICPR: 159 ret = uic->uicpr; 160 break; 161 case DCR_UICTR: 162 ret = uic->uictr; 163 break; 164 case DCR_UICMSR: 165 ret = uic->uicsr & uic->uicer; 166 break; 167 case DCR_UICVR: 168 if (!uic->use_vectors) { 169 goto no_read; 170 } 171 ret = uic->uicvr; 172 break; 173 case DCR_UICVCR: 174 if (!uic->use_vectors) { 175 goto no_read; 176 } 177 ret = uic->uicvcr; 178 break; 179 default: 180 no_read: 181 ret = 0x00000000; 182 break; 183 } 184 185 return ret; 186 } 187 188 static void dcr_write_uic(void *opaque, int dcrn, uint32_t val) 189 { 190 PPCUIC *uic = opaque; 191 192 dcrn -= uic->dcr_base; 193 LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val); 194 switch (dcrn) { 195 case DCR_UICSR: 196 uic->uicsr &= ~val; 197 uic->uicsr |= uic->level; 198 ppcuic_trigger_irq(uic); 199 break; 200 case DCR_UICSRS: 201 uic->uicsr |= val; 202 ppcuic_trigger_irq(uic); 203 break; 204 case DCR_UICER: 205 uic->uicer = val; 206 ppcuic_trigger_irq(uic); 207 break; 208 case DCR_UICCR: 209 uic->uiccr = val; 210 ppcuic_trigger_irq(uic); 211 break; 212 case DCR_UICPR: 213 uic->uicpr = val; 214 break; 215 case DCR_UICTR: 216 uic->uictr = val; 217 ppcuic_trigger_irq(uic); 218 break; 219 case DCR_UICMSR: 220 break; 221 case DCR_UICVR: 222 break; 223 case DCR_UICVCR: 224 uic->uicvcr = val & 0xFFFFFFFD; 225 ppcuic_trigger_irq(uic); 226 break; 227 } 228 } 229 230 static void ppc_uic_reset(DeviceState *dev) 231 { 232 PPCUIC *uic = PPC_UIC(dev); 233 234 uic->uiccr = 0x00000000; 235 uic->uicer = 0x00000000; 236 uic->uicpr = 0x00000000; 237 uic->uicsr = 0x00000000; 238 uic->uictr = 0x00000000; 239 if (uic->use_vectors) { 240 uic->uicvcr = 0x00000000; 241 uic->uicvr = 0x0000000; 242 } 243 } 244 245 static void ppc_uic_realize(DeviceState *dev, Error **errp) 246 { 247 PPCUIC *uic = PPC_UIC(dev); 248 Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); 249 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 250 int i; 251 252 for (i = 0; i < DCR_UICMAX; i++) { 253 ppc4xx_dcr_register(dcr, uic->dcr_base + i, uic, 254 &dcr_read_uic, &dcr_write_uic); 255 } 256 257 sysbus_init_irq(sbd, &uic->output_int); 258 sysbus_init_irq(sbd, &uic->output_cint); 259 qdev_init_gpio_in(dev, ppcuic_set_irq, UIC_MAX_IRQ); 260 } 261 262 static Property ppc_uic_properties[] = { 263 DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0xc0), 264 DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true), 265 DEFINE_PROP_END_OF_LIST() 266 }; 267 268 static const VMStateDescription ppc_uic_vmstate = { 269 .name = "ppc-uic", 270 .version_id = 1, 271 .minimum_version_id = 1, 272 .fields = (VMStateField[]) { 273 VMSTATE_UINT32(level, PPCUIC), 274 VMSTATE_UINT32(uicsr, PPCUIC), 275 VMSTATE_UINT32(uicer, PPCUIC), 276 VMSTATE_UINT32(uiccr, PPCUIC), 277 VMSTATE_UINT32(uicpr, PPCUIC), 278 VMSTATE_UINT32(uictr, PPCUIC), 279 VMSTATE_UINT32(uicvcr, PPCUIC), 280 VMSTATE_UINT32(uicvr, PPCUIC), 281 VMSTATE_END_OF_LIST() 282 }, 283 }; 284 285 static void ppc_uic_class_init(ObjectClass *klass, void *data) 286 { 287 DeviceClass *dc = DEVICE_CLASS(klass); 288 289 dc->reset = ppc_uic_reset; 290 dc->realize = ppc_uic_realize; 291 dc->vmsd = &ppc_uic_vmstate; 292 device_class_set_props(dc, ppc_uic_properties); 293 } 294 295 static const TypeInfo ppc_uic_info = { 296 .name = TYPE_PPC_UIC, 297 .parent = TYPE_PPC4xx_DCR_DEVICE, 298 .instance_size = sizeof(PPCUIC), 299 .class_init = ppc_uic_class_init, 300 }; 301 302 static void ppc_uic_register_types(void) 303 { 304 type_register_static(&ppc_uic_info); 305 } 306 307 type_init(ppc_uic_register_types); 308