Statistics
| Branch: | Revision:

root / hw / xilinx_intc.c @ a0f42610

History | View | Annotate | Download (4.7 kB)

1 17628bc6 Edgar E. Iglesias
/*
2 17628bc6 Edgar E. Iglesias
 * QEMU Xilinx OPB Interrupt Controller.
3 17628bc6 Edgar E. Iglesias
 *
4 17628bc6 Edgar E. Iglesias
 * Copyright (c) 2009 Edgar E. Iglesias.
5 17628bc6 Edgar E. Iglesias
 *
6 17628bc6 Edgar E. Iglesias
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 17628bc6 Edgar E. Iglesias
 * of this software and associated documentation files (the "Software"), to deal
8 17628bc6 Edgar E. Iglesias
 * in the Software without restriction, including without limitation the rights
9 17628bc6 Edgar E. Iglesias
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 17628bc6 Edgar E. Iglesias
 * copies of the Software, and to permit persons to whom the Software is
11 17628bc6 Edgar E. Iglesias
 * furnished to do so, subject to the following conditions:
12 17628bc6 Edgar E. Iglesias
 *
13 17628bc6 Edgar E. Iglesias
 * The above copyright notice and this permission notice shall be included in
14 17628bc6 Edgar E. Iglesias
 * all copies or substantial portions of the Software.
15 17628bc6 Edgar E. Iglesias
 *
16 17628bc6 Edgar E. Iglesias
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 17628bc6 Edgar E. Iglesias
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 17628bc6 Edgar E. Iglesias
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 17628bc6 Edgar E. Iglesias
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 17628bc6 Edgar E. Iglesias
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 17628bc6 Edgar E. Iglesias
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 17628bc6 Edgar E. Iglesias
 * THE SOFTWARE.
23 17628bc6 Edgar E. Iglesias
 */
24 17628bc6 Edgar E. Iglesias
25 17628bc6 Edgar E. Iglesias
#include "sysbus.h"
26 17628bc6 Edgar E. Iglesias
#include "hw.h"
27 17628bc6 Edgar E. Iglesias
28 17628bc6 Edgar E. Iglesias
#define D(x)
29 17628bc6 Edgar E. Iglesias
30 17628bc6 Edgar E. Iglesias
#define R_ISR       0
31 17628bc6 Edgar E. Iglesias
#define R_IPR       1
32 17628bc6 Edgar E. Iglesias
#define R_IER       2
33 17628bc6 Edgar E. Iglesias
#define R_IAR       3
34 17628bc6 Edgar E. Iglesias
#define R_SIE       4
35 17628bc6 Edgar E. Iglesias
#define R_CIE       5
36 17628bc6 Edgar E. Iglesias
#define R_IVR       6
37 17628bc6 Edgar E. Iglesias
#define R_MER       7
38 17628bc6 Edgar E. Iglesias
#define R_MAX       8
39 17628bc6 Edgar E. Iglesias
40 17628bc6 Edgar E. Iglesias
struct xlx_pic
41 17628bc6 Edgar E. Iglesias
{
42 17628bc6 Edgar E. Iglesias
    SysBusDevice busdev;
43 010f3f5f Edgar E. Iglesias
    MemoryRegion mmio;
44 17628bc6 Edgar E. Iglesias
    qemu_irq parent_irq;
45 17628bc6 Edgar E. Iglesias
46 17628bc6 Edgar E. Iglesias
    /* Configuration reg chosen at synthesis-time. QEMU populates
47 17628bc6 Edgar E. Iglesias
       the bits at board-setup.  */
48 17628bc6 Edgar E. Iglesias
    uint32_t c_kind_of_intr;
49 17628bc6 Edgar E. Iglesias
50 17628bc6 Edgar E. Iglesias
    /* Runtime control registers.  */
51 17628bc6 Edgar E. Iglesias
    uint32_t regs[R_MAX];
52 17628bc6 Edgar E. Iglesias
};
53 17628bc6 Edgar E. Iglesias
54 17628bc6 Edgar E. Iglesias
static void update_irq(struct xlx_pic *p)
55 17628bc6 Edgar E. Iglesias
{
56 17628bc6 Edgar E. Iglesias
    uint32_t i;
57 17628bc6 Edgar E. Iglesias
    /* Update the pending register.  */
58 17628bc6 Edgar E. Iglesias
    p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
59 17628bc6 Edgar E. Iglesias
60 17628bc6 Edgar E. Iglesias
    /* Update the vector register.  */
61 17628bc6 Edgar E. Iglesias
    for (i = 0; i < 32; i++) {
62 17628bc6 Edgar E. Iglesias
        if (p->regs[R_IPR] & (1 << i))
63 17628bc6 Edgar E. Iglesias
            break;
64 17628bc6 Edgar E. Iglesias
    }
65 17628bc6 Edgar E. Iglesias
    if (i == 32)
66 17628bc6 Edgar E. Iglesias
        i = ~0;
67 17628bc6 Edgar E. Iglesias
68 17628bc6 Edgar E. Iglesias
    p->regs[R_IVR] = i;
69 17628bc6 Edgar E. Iglesias
    if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) {
70 17628bc6 Edgar E. Iglesias
        qemu_irq_raise(p->parent_irq);
71 17628bc6 Edgar E. Iglesias
    } else {
72 17628bc6 Edgar E. Iglesias
        qemu_irq_lower(p->parent_irq);
73 17628bc6 Edgar E. Iglesias
    }
74 17628bc6 Edgar E. Iglesias
}
75 17628bc6 Edgar E. Iglesias
76 010f3f5f Edgar E. Iglesias
static uint64_t
77 010f3f5f Edgar E. Iglesias
pic_read(void *opaque, target_phys_addr_t addr, unsigned int size)
78 17628bc6 Edgar E. Iglesias
{
79 17628bc6 Edgar E. Iglesias
    struct xlx_pic *p = opaque;
80 17628bc6 Edgar E. Iglesias
    uint32_t r = 0;
81 17628bc6 Edgar E. Iglesias
82 17628bc6 Edgar E. Iglesias
    addr >>= 2;
83 17628bc6 Edgar E. Iglesias
    switch (addr)
84 17628bc6 Edgar E. Iglesias
    {
85 17628bc6 Edgar E. Iglesias
        default:
86 17628bc6 Edgar E. Iglesias
            if (addr < ARRAY_SIZE(p->regs))
87 17628bc6 Edgar E. Iglesias
                r = p->regs[addr];
88 17628bc6 Edgar E. Iglesias
            break;
89 17628bc6 Edgar E. Iglesias
90 17628bc6 Edgar E. Iglesias
    }
91 17628bc6 Edgar E. Iglesias
    D(printf("%s %x=%x\n", __func__, addr * 4, r));
92 17628bc6 Edgar E. Iglesias
    return r;
93 17628bc6 Edgar E. Iglesias
}
94 17628bc6 Edgar E. Iglesias
95 17628bc6 Edgar E. Iglesias
static void
96 010f3f5f Edgar E. Iglesias
pic_write(void *opaque, target_phys_addr_t addr,
97 010f3f5f Edgar E. Iglesias
          uint64_t val64, unsigned int size)
98 17628bc6 Edgar E. Iglesias
{
99 17628bc6 Edgar E. Iglesias
    struct xlx_pic *p = opaque;
100 010f3f5f Edgar E. Iglesias
    uint32_t value = val64;
101 17628bc6 Edgar E. Iglesias
102 17628bc6 Edgar E. Iglesias
    addr >>= 2;
103 17628bc6 Edgar E. Iglesias
    D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
104 17628bc6 Edgar E. Iglesias
    switch (addr) 
105 17628bc6 Edgar E. Iglesias
    {
106 17628bc6 Edgar E. Iglesias
        case R_IAR:
107 17628bc6 Edgar E. Iglesias
            p->regs[R_ISR] &= ~value; /* ACK.  */
108 17628bc6 Edgar E. Iglesias
            break;
109 17628bc6 Edgar E. Iglesias
        case R_SIE:
110 17628bc6 Edgar E. Iglesias
            p->regs[R_IER] |= value;  /* Atomic set ie.  */
111 17628bc6 Edgar E. Iglesias
            break;
112 17628bc6 Edgar E. Iglesias
        case R_CIE:
113 17628bc6 Edgar E. Iglesias
            p->regs[R_IER] &= ~value; /* Atomic clear ie.  */
114 17628bc6 Edgar E. Iglesias
            break;
115 17628bc6 Edgar E. Iglesias
        default:
116 17628bc6 Edgar E. Iglesias
            if (addr < ARRAY_SIZE(p->regs))
117 17628bc6 Edgar E. Iglesias
                p->regs[addr] = value;
118 17628bc6 Edgar E. Iglesias
            break;
119 17628bc6 Edgar E. Iglesias
    }
120 17628bc6 Edgar E. Iglesias
    update_irq(p);
121 17628bc6 Edgar E. Iglesias
}
122 17628bc6 Edgar E. Iglesias
123 010f3f5f Edgar E. Iglesias
static const MemoryRegionOps pic_ops = {
124 010f3f5f Edgar E. Iglesias
    .read = pic_read,
125 010f3f5f Edgar E. Iglesias
    .write = pic_write,
126 010f3f5f Edgar E. Iglesias
    .endianness = DEVICE_NATIVE_ENDIAN,
127 010f3f5f Edgar E. Iglesias
    .valid = {
128 010f3f5f Edgar E. Iglesias
        .min_access_size = 4,
129 010f3f5f Edgar E. Iglesias
        .max_access_size = 4
130 010f3f5f Edgar E. Iglesias
    }
131 17628bc6 Edgar E. Iglesias
};
132 17628bc6 Edgar E. Iglesias
133 17628bc6 Edgar E. Iglesias
static void irq_handler(void *opaque, int irq, int level)
134 17628bc6 Edgar E. Iglesias
{
135 17628bc6 Edgar E. Iglesias
    struct xlx_pic *p = opaque;
136 17628bc6 Edgar E. Iglesias
137 17628bc6 Edgar E. Iglesias
    if (!(p->regs[R_MER] & 2)) {
138 17628bc6 Edgar E. Iglesias
        qemu_irq_lower(p->parent_irq);
139 17628bc6 Edgar E. Iglesias
        return;
140 17628bc6 Edgar E. Iglesias
    }
141 17628bc6 Edgar E. Iglesias
142 17628bc6 Edgar E. Iglesias
    /* Update source flops. Don't clear unless level triggered.
143 17628bc6 Edgar E. Iglesias
       Edge triggered interrupts only go away when explicitely acked to
144 17628bc6 Edgar E. Iglesias
       the interrupt controller.  */
145 17628bc6 Edgar E. Iglesias
    if (!(p->c_kind_of_intr & (1 << irq)) || level) {
146 17628bc6 Edgar E. Iglesias
        p->regs[R_ISR] &= ~(1 << irq);
147 17628bc6 Edgar E. Iglesias
        p->regs[R_ISR] |= (level << irq);
148 17628bc6 Edgar E. Iglesias
    }
149 17628bc6 Edgar E. Iglesias
    update_irq(p);
150 17628bc6 Edgar E. Iglesias
}
151 17628bc6 Edgar E. Iglesias
152 81a322d4 Gerd Hoffmann
static int xilinx_intc_init(SysBusDevice *dev)
153 17628bc6 Edgar E. Iglesias
{
154 17628bc6 Edgar E. Iglesias
    struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev);
155 17628bc6 Edgar E. Iglesias
156 17628bc6 Edgar E. Iglesias
    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
157 17628bc6 Edgar E. Iglesias
    sysbus_init_irq(dev, &p->parent_irq);
158 17628bc6 Edgar E. Iglesias
159 010f3f5f Edgar E. Iglesias
    memory_region_init_io(&p->mmio, &pic_ops, p, "xilinx-pic", R_MAX * 4);
160 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &p->mmio);
161 81a322d4 Gerd Hoffmann
    return 0;
162 17628bc6 Edgar E. Iglesias
}
163 17628bc6 Edgar E. Iglesias
164 ee6847d1 Gerd Hoffmann
static SysBusDeviceInfo xilinx_intc_info = {
165 ee6847d1 Gerd Hoffmann
    .init = xilinx_intc_init,
166 ee6847d1 Gerd Hoffmann
    .qdev.name  = "xilinx,intc",
167 ee6847d1 Gerd Hoffmann
    .qdev.size  = sizeof(struct xlx_pic),
168 ee6847d1 Gerd Hoffmann
    .qdev.props = (Property[]) {
169 8017dc26 Gerd Hoffmann
        DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
170 8017dc26 Gerd Hoffmann
        DEFINE_PROP_END_OF_LIST(),
171 ee6847d1 Gerd Hoffmann
    }
172 ee6847d1 Gerd Hoffmann
};
173 ee6847d1 Gerd Hoffmann
174 17628bc6 Edgar E. Iglesias
static void xilinx_intc_register(void)
175 17628bc6 Edgar E. Iglesias
{
176 ee6847d1 Gerd Hoffmann
    sysbus_register_withprop(&xilinx_intc_info);
177 17628bc6 Edgar E. Iglesias
}
178 17628bc6 Edgar E. Iglesias
179 17628bc6 Edgar E. Iglesias
device_init(xilinx_intc_register)