|
|
1.1 ! root 1: /* ! 2: * QEMU Xilinx OPB Interrupt Controller. ! 3: * ! 4: * Copyright (c) 2009 Edgar E. Iglesias. ! 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 "sysbus.h" ! 26: #include "hw.h" ! 27: ! 28: #define D(x) ! 29: ! 30: #define R_ISR 0 ! 31: #define R_IPR 1 ! 32: #define R_IER 2 ! 33: #define R_IAR 3 ! 34: #define R_SIE 4 ! 35: #define R_CIE 5 ! 36: #define R_IVR 6 ! 37: #define R_MER 7 ! 38: #define R_MAX 8 ! 39: ! 40: struct xlx_pic ! 41: { ! 42: SysBusDevice busdev; ! 43: qemu_irq parent_irq; ! 44: ! 45: /* Configuration reg chosen at synthesis-time. QEMU populates ! 46: the bits at board-setup. */ ! 47: uint32_t c_kind_of_intr; ! 48: ! 49: /* Runtime control registers. */ ! 50: uint32_t regs[R_MAX]; ! 51: }; ! 52: ! 53: static void update_irq(struct xlx_pic *p) ! 54: { ! 55: uint32_t i; ! 56: /* Update the pending register. */ ! 57: p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER]; ! 58: ! 59: /* Update the vector register. */ ! 60: for (i = 0; i < 32; i++) { ! 61: if (p->regs[R_IPR] & (1 << i)) ! 62: break; ! 63: } ! 64: if (i == 32) ! 65: i = ~0; ! 66: ! 67: p->regs[R_IVR] = i; ! 68: if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) { ! 69: qemu_irq_raise(p->parent_irq); ! 70: } else { ! 71: qemu_irq_lower(p->parent_irq); ! 72: } ! 73: } ! 74: ! 75: static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) ! 76: { ! 77: struct xlx_pic *p = opaque; ! 78: uint32_t r = 0; ! 79: ! 80: addr >>= 2; ! 81: switch (addr) ! 82: { ! 83: default: ! 84: if (addr < ARRAY_SIZE(p->regs)) ! 85: r = p->regs[addr]; ! 86: break; ! 87: ! 88: } ! 89: D(printf("%s %x=%x\n", __func__, addr * 4, r)); ! 90: return r; ! 91: } ! 92: ! 93: static void ! 94: pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) ! 95: { ! 96: struct xlx_pic *p = opaque; ! 97: ! 98: addr >>= 2; ! 99: D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); ! 100: switch (addr) ! 101: { ! 102: case R_IAR: ! 103: p->regs[R_ISR] &= ~value; /* ACK. */ ! 104: break; ! 105: case R_SIE: ! 106: p->regs[R_IER] |= value; /* Atomic set ie. */ ! 107: break; ! 108: case R_CIE: ! 109: p->regs[R_IER] &= ~value; /* Atomic clear ie. */ ! 110: break; ! 111: default: ! 112: if (addr < ARRAY_SIZE(p->regs)) ! 113: p->regs[addr] = value; ! 114: break; ! 115: } ! 116: update_irq(p); ! 117: } ! 118: ! 119: static CPUReadMemoryFunc *pic_read[] = { ! 120: NULL, NULL, ! 121: &pic_readl, ! 122: }; ! 123: ! 124: static CPUWriteMemoryFunc *pic_write[] = { ! 125: NULL, NULL, ! 126: &pic_writel, ! 127: }; ! 128: ! 129: static void irq_handler(void *opaque, int irq, int level) ! 130: { ! 131: struct xlx_pic *p = opaque; ! 132: ! 133: if (!(p->regs[R_MER] & 2)) { ! 134: qemu_irq_lower(p->parent_irq); ! 135: return; ! 136: } ! 137: ! 138: /* Update source flops. Don't clear unless level triggered. ! 139: Edge triggered interrupts only go away when explicitely acked to ! 140: the interrupt controller. */ ! 141: if (!(p->c_kind_of_intr & (1 << irq)) || level) { ! 142: p->regs[R_ISR] &= ~(1 << irq); ! 143: p->regs[R_ISR] |= (level << irq); ! 144: } ! 145: update_irq(p); ! 146: } ! 147: ! 148: static void xilinx_intc_init(SysBusDevice *dev) ! 149: { ! 150: struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev); ! 151: int pic_regs; ! 152: ! 153: qdev_init_gpio_in(&dev->qdev, irq_handler, 32); ! 154: sysbus_init_irq(dev, &p->parent_irq); ! 155: ! 156: pic_regs = cpu_register_io_memory(pic_read, pic_write, p); ! 157: sysbus_init_mmio(dev, R_MAX * 4, pic_regs); ! 158: } ! 159: ! 160: static SysBusDeviceInfo xilinx_intc_info = { ! 161: .init = xilinx_intc_init, ! 162: .qdev.name = "xilinx,intc", ! 163: .qdev.size = sizeof(struct xlx_pic), ! 164: .qdev.props = (Property[]) { ! 165: { ! 166: .name = "kind-of-intr", ! 167: .info = &qdev_prop_uint32, ! 168: .offset = offsetof(struct xlx_pic, c_kind_of_intr), ! 169: }, ! 170: {/* end of list */} ! 171: } ! 172: }; ! 173: ! 174: static void xilinx_intc_register(void) ! 175: { ! 176: sysbus_register_withprop(&xilinx_intc_info); ! 177: } ! 178: ! 179: device_init(xilinx_intc_register)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.