|
|
1.1 root 1: /*
2: * QEMU ETRAX Interrupt Controller.
3: *
4: * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
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:
1.1.1.2 ! root 25: #include "sysbus.h"
1.1 root 26: #include "hw.h"
1.1.1.2 ! root 27: //#include "pc.h"
! 28: //#include "etraxfs.h"
1.1 root 29:
30: #define D(x)
31:
1.1.1.2 ! root 32: #define R_RW_MASK 0
! 33: #define R_R_VECT 1
! 34: #define R_R_MASKED_VECT 2
! 35: #define R_R_NMI 3
! 36: #define R_R_GURU 4
! 37: #define R_MAX 5
! 38:
! 39: struct etrax_pic
! 40: {
! 41: SysBusDevice busdev;
! 42: uint32_t *interrupt_vector;
! 43: qemu_irq parent_irq;
! 44: qemu_irq parent_nmi;
! 45: uint32_t regs[R_MAX];
1.1 root 46: };
47:
1.1.1.2 ! root 48: static void pic_update(struct etrax_pic *fs)
! 49: {
! 50: uint32_t vector = 0;
! 51: int i;
! 52:
! 53: fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
! 54:
! 55: /* The ETRAX interrupt controller signals interrupts to teh core
! 56: through an interrupt request wire and an irq vector bus. If
! 57: multiple interrupts are simultaneously active it chooses vector
! 58: 0x30 and lets the sw choose the priorities. */
! 59: if (fs->regs[R_R_MASKED_VECT]) {
! 60: uint32_t mv = fs->regs[R_R_MASKED_VECT];
! 61: for (i = 0; i < 31; i++) {
! 62: if (mv & 1) {
! 63: vector = 0x31 + i;
! 64: /* Check for multiple interrupts. */
! 65: if (mv > 1)
! 66: vector = 0x30;
! 67: break;
! 68: }
! 69: mv >>= 1;
! 70: }
! 71: }
! 72:
! 73: if (fs->interrupt_vector) {
! 74: *fs->interrupt_vector = vector;
! 75: }
! 76: qemu_set_irq(fs->parent_irq, !!vector);
1.1 root 77: }
78:
79: static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
80: {
1.1.1.2 ! root 81: struct etrax_pic *fs = opaque;
! 82: uint32_t rval;
1.1 root 83:
1.1.1.2 ! root 84: rval = fs->regs[addr >> 2];
! 85: D(printf("%s %x=%x\n", __func__, addr, rval));
! 86: return rval;
1.1 root 87: }
88:
89: static void
90: pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
91: {
1.1.1.2 ! root 92: struct etrax_pic *fs = opaque;
! 93: D(printf("%s addr=%x val=%x\n", __func__, addr, value));
! 94:
! 95: if (addr == R_RW_MASK) {
! 96: fs->regs[R_RW_MASK] = value;
! 97: pic_update(fs);
! 98: }
1.1 root 99: }
100:
101: static CPUReadMemoryFunc *pic_read[] = {
1.1.1.2 ! root 102: NULL, NULL,
! 103: &pic_readl,
1.1 root 104: };
105:
106: static CPUWriteMemoryFunc *pic_write[] = {
1.1.1.2 ! root 107: NULL, NULL,
! 108: &pic_writel,
1.1 root 109: };
110:
1.1.1.2 ! root 111: static void nmi_handler(void *opaque, int irq, int level)
! 112: {
! 113: struct etrax_pic *fs = (void *)opaque;
! 114: uint32_t mask;
! 115:
! 116: mask = 1 << irq;
! 117: if (level)
! 118: fs->regs[R_R_NMI] |= mask;
! 119: else
! 120: fs->regs[R_R_NMI] &= ~mask;
1.1 root 121:
1.1.1.2 ! root 122: qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
1.1 root 123: }
124:
125: static void irq_handler(void *opaque, int irq, int level)
1.1.1.2 ! root 126: {
! 127: struct etrax_pic *fs = (void *)opaque;
1.1 root 128:
1.1.1.2 ! root 129: if (irq >= 30)
! 130: return nmi_handler(opaque, irq, level);
1.1 root 131:
1.1.1.2 ! root 132: irq -= 1;
! 133: fs->regs[R_R_VECT] &= ~(1 << irq);
! 134: fs->regs[R_R_VECT] |= (!!level << irq);
! 135: pic_update(fs);
! 136: }
! 137:
! 138: static void etraxfs_pic_init(SysBusDevice *dev)
! 139: {
! 140: struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
! 141: int intr_vect_regs;
! 142:
! 143: qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
! 144: sysbus_init_irq(dev, &s->parent_irq);
! 145: sysbus_init_irq(dev, &s->parent_nmi);
! 146:
! 147: intr_vect_regs = cpu_register_io_memory(pic_read, pic_write, s);
! 148: sysbus_init_mmio(dev, R_MAX * 4, intr_vect_regs);
! 149: }
! 150:
! 151: static SysBusDeviceInfo etraxfs_pic_info = {
! 152: .init = etraxfs_pic_init,
! 153: .qdev.name = "etraxfs,pic",
! 154: .qdev.size = sizeof(struct etrax_pic),
! 155: .qdev.props = (Property[]) {
! 156: {
! 157: .name = "interrupt_vector",
! 158: .info = &qdev_prop_ptr,
! 159: .offset = offsetof(struct etrax_pic, interrupt_vector),
! 160: },
! 161: {/* end of list */}
! 162: }
! 163: };
1.1 root 164:
1.1.1.2 ! root 165: static void etraxfs_pic_register(void)
1.1 root 166: {
1.1.1.2 ! root 167: sysbus_register_withprop(&etraxfs_pic_info);
1.1 root 168: }
1.1.1.2 ! root 169:
! 170: device_init(etraxfs_pic_register)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.