blob: 62a62a36af0a415c1dbc9b99d8fbb3d522ec20db [file] [log] [blame]
edgar_igle62b5b12008-03-14 01:04:24 +00001/*
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
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020025#include "sysbus.h"
edgar_igle62b5b12008-03-14 01:04:24 +000026#include "hw.h"
Paul Brook1ad21342009-05-19 16:17:58 +010027//#include "pc.h"
28//#include "etraxfs.h"
edgar_igle62b5b12008-03-14 01:04:24 +000029
30#define D(x)
31
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020032#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
Edgar E. Iglesias8d13fcc2009-05-05 12:38:39 +020038
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020039struct etrax_pic
edgar_igle62b5b12008-03-14 01:04:24 +000040{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020041 SysBusDevice busdev;
Edgar E. Iglesias5dd25f32011-08-11 13:47:44 +020042 MemoryRegion mmio;
Gerd Hoffmannddde0952009-08-03 17:35:24 +020043 void *interrupt_vector;
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020044 qemu_irq parent_irq;
45 qemu_irq parent_nmi;
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020046 uint32_t regs[R_MAX];
edgar_igle62b5b12008-03-14 01:04:24 +000047};
48
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020049static void pic_update(struct etrax_pic *fs)
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020050{
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020051 uint32_t vector = 0;
52 int i;
edgar_igl70ea2552009-01-07 13:30:41 +000053
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020054 fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
edgar_igl70ea2552009-01-07 13:30:41 +000055
Dong Xu Wang66a0a2c2011-11-29 16:52:39 +080056 /* The ETRAX interrupt controller signals interrupts to the core
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020057 through an interrupt request wire and an irq vector bus. If
58 multiple interrupts are simultaneously active it chooses vector
59 0x30 and lets the sw choose the priorities. */
60 if (fs->regs[R_R_MASKED_VECT]) {
61 uint32_t mv = fs->regs[R_R_MASKED_VECT];
62 for (i = 0; i < 31; i++) {
63 if (mv & 1) {
64 vector = 0x31 + i;
65 /* Check for multiple interrupts. */
66 if (mv > 1)
67 vector = 0x30;
68 break;
69 }
70 mv >>= 1;
71 }
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020072 }
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020073
74 if (fs->interrupt_vector) {
Gerd Hoffmannddde0952009-08-03 17:35:24 +020075 /* hack alert: ptr property */
76 *(uint32_t*)(fs->interrupt_vector) = vector;
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020077 }
78 qemu_set_irq(fs->parent_irq, !!vector);
edgar_igle62b5b12008-03-14 01:04:24 +000079}
80
Edgar E. Iglesias5dd25f32011-08-11 13:47:44 +020081static uint64_t
Avi Kivitya8170e52012-10-23 12:30:10 +020082pic_read(void *opaque, hwaddr addr, unsigned int size)
edgar_igle62b5b12008-03-14 01:04:24 +000083{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020084 struct etrax_pic *fs = opaque;
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020085 uint32_t rval;
edgar_igle62b5b12008-03-14 01:04:24 +000086
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020087 rval = fs->regs[addr >> 2];
88 D(printf("%s %x=%x\n", __func__, addr, rval));
89 return rval;
edgar_igle62b5b12008-03-14 01:04:24 +000090}
91
Avi Kivitya8170e52012-10-23 12:30:10 +020092static void pic_write(void *opaque, hwaddr addr,
Edgar E. Iglesias5dd25f32011-08-11 13:47:44 +020093 uint64_t value, unsigned int size)
edgar_igle62b5b12008-03-14 01:04:24 +000094{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020095 struct etrax_pic *fs = opaque;
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020096 D(printf("%s addr=%x val=%x\n", __func__, addr, value));
Edgar E. Iglesias8d13fcc2009-05-05 12:38:39 +020097
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020098 if (addr == R_RW_MASK) {
99 fs->regs[R_RW_MASK] = value;
100 pic_update(fs);
101 }
edgar_igle62b5b12008-03-14 01:04:24 +0000102}
103
Edgar E. Iglesias5dd25f32011-08-11 13:47:44 +0200104static const MemoryRegionOps pic_ops = {
105 .read = pic_read,
106 .write = pic_write,
107 .endianness = DEVICE_NATIVE_ENDIAN,
108 .valid = {
109 .min_access_size = 4,
110 .max_access_size = 4
111 }
edgar_igle62b5b12008-03-14 01:04:24 +0000112};
113
edgar_igl5ef98b42008-06-09 23:33:30 +0000114static void nmi_handler(void *opaque, int irq, int level)
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200115{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200116 struct etrax_pic *fs = (void *)opaque;
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200117 uint32_t mask;
edgar_igl5ef98b42008-06-09 23:33:30 +0000118
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200119 mask = 1 << irq;
120 if (level)
121 fs->regs[R_R_NMI] |= mask;
122 else
123 fs->regs[R_R_NMI] &= ~mask;
edgar_igl5ef98b42008-06-09 23:33:30 +0000124
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200125 qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
edgar_igl5ef98b42008-06-09 23:33:30 +0000126}
127
Edgar E. Iglesias73cfd292009-05-16 00:23:15 +0200128static void irq_handler(void *opaque, int irq, int level)
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200129{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200130 struct etrax_pic *fs = (void *)opaque;
Edgar E. Iglesias73cfd292009-05-16 00:23:15 +0200131
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200132 if (irq >= 30)
133 return nmi_handler(opaque, irq, level);
Edgar E. Iglesias73cfd292009-05-16 00:23:15 +0200134
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200135 irq -= 1;
136 fs->regs[R_R_VECT] &= ~(1 << irq);
137 fs->regs[R_R_VECT] |= (!!level << irq);
138 pic_update(fs);
edgar_igl5ef98b42008-06-09 23:33:30 +0000139}
140
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200141static int etraxfs_pic_init(SysBusDevice *dev)
edgar_igle62b5b12008-03-14 01:04:24 +0000142{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200143 struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
edgar_igle62b5b12008-03-14 01:04:24 +0000144
Paul Brook067a3dd2009-05-26 14:56:11 +0100145 qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200146 sysbus_init_irq(dev, &s->parent_irq);
147 sysbus_init_irq(dev, &s->parent_nmi);
edgar_igle62b5b12008-03-14 01:04:24 +0000148
Edgar E. Iglesias5dd25f32011-08-11 13:47:44 +0200149 memory_region_init_io(&s->mmio, &pic_ops, s, "etraxfs-pic", R_MAX * 4);
Avi Kivity750ecd42011-11-27 11:38:10 +0200150 sysbus_init_mmio(dev, &s->mmio);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200151 return 0;
edgar_igle62b5b12008-03-14 01:04:24 +0000152}
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200153
Anthony Liguori999e12b2012-01-24 13:12:29 -0600154static Property etraxfs_pic_properties[] = {
155 DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
156 DEFINE_PROP_END_OF_LIST(),
157};
158
159static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
160{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600161 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600162 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
163
164 k->init = etraxfs_pic_init;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600165 dc->props = etraxfs_pic_properties;
Anthony Liguori999e12b2012-01-24 13:12:29 -0600166}
167
Anthony Liguori39bffca2011-12-07 21:34:16 -0600168static TypeInfo etraxfs_pic_info = {
169 .name = "etraxfs,pic",
170 .parent = TYPE_SYS_BUS_DEVICE,
171 .instance_size = sizeof(struct etrax_pic),
172 .class_init = etraxfs_pic_class_init,
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200173};
174
Andreas Färber83f7d432012-02-09 15:20:55 +0100175static void etraxfs_pic_register_types(void)
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200176{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600177 type_register_static(&etraxfs_pic_info);
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200178}
179
Andreas Färber83f7d432012-02-09 15:20:55 +0100180type_init(etraxfs_pic_register_types)