blob: b2c4859949846a500dc7260538b149a71a6a9d1c [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;
Gerd Hoffmannddde0952009-08-03 17:35:24 +020042 void *interrupt_vector;
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020043 qemu_irq parent_irq;
44 qemu_irq parent_nmi;
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020045 uint32_t regs[R_MAX];
edgar_igle62b5b12008-03-14 01:04:24 +000046};
47
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020048static void pic_update(struct etrax_pic *fs)
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020049{
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020050 uint32_t vector = 0;
51 int i;
edgar_igl70ea2552009-01-07 13:30:41 +000052
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020053 fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
edgar_igl70ea2552009-01-07 13:30:41 +000054
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020055 /* 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 }
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020071 }
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020072
73 if (fs->interrupt_vector) {
Gerd Hoffmannddde0952009-08-03 17:35:24 +020074 /* hack alert: ptr property */
75 *(uint32_t*)(fs->interrupt_vector) = vector;
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020076 }
77 qemu_set_irq(fs->parent_irq, !!vector);
edgar_igle62b5b12008-03-14 01:04:24 +000078}
79
Anthony Liguoric227f092009-10-01 16:12:16 -050080static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
edgar_igle62b5b12008-03-14 01:04:24 +000081{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020082 struct etrax_pic *fs = opaque;
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020083 uint32_t rval;
edgar_igle62b5b12008-03-14 01:04:24 +000084
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020085 rval = fs->regs[addr >> 2];
86 D(printf("%s %x=%x\n", __func__, addr, rval));
87 return rval;
edgar_igle62b5b12008-03-14 01:04:24 +000088}
89
90static void
Anthony Liguoric227f092009-10-01 16:12:16 -050091pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
edgar_igle62b5b12008-03-14 01:04:24 +000092{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +020093 struct etrax_pic *fs = opaque;
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020094 D(printf("%s addr=%x val=%x\n", __func__, addr, value));
Edgar E. Iglesias8d13fcc2009-05-05 12:38:39 +020095
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +020096 if (addr == R_RW_MASK) {
97 fs->regs[R_RW_MASK] = value;
98 pic_update(fs);
99 }
edgar_igle62b5b12008-03-14 01:04:24 +0000100}
101
Blue Swirld60efc62009-08-25 18:29:31 +0000102static CPUReadMemoryFunc * const pic_read[] = {
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200103 NULL, NULL,
104 &pic_readl,
edgar_igle62b5b12008-03-14 01:04:24 +0000105};
106
Blue Swirld60efc62009-08-25 18:29:31 +0000107static CPUWriteMemoryFunc * const pic_write[] = {
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200108 NULL, NULL,
109 &pic_writel,
edgar_igle62b5b12008-03-14 01:04:24 +0000110};
111
edgar_igl5ef98b42008-06-09 23:33:30 +0000112static void nmi_handler(void *opaque, int irq, int level)
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200113{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200114 struct etrax_pic *fs = (void *)opaque;
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200115 uint32_t mask;
edgar_igl5ef98b42008-06-09 23:33:30 +0000116
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200117 mask = 1 << irq;
118 if (level)
119 fs->regs[R_R_NMI] |= mask;
120 else
121 fs->regs[R_R_NMI] &= ~mask;
edgar_igl5ef98b42008-06-09 23:33:30 +0000122
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200123 qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
edgar_igl5ef98b42008-06-09 23:33:30 +0000124}
125
Edgar E. Iglesias73cfd292009-05-16 00:23:15 +0200126static void irq_handler(void *opaque, int irq, int level)
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200127{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200128 struct etrax_pic *fs = (void *)opaque;
Edgar E. Iglesias73cfd292009-05-16 00:23:15 +0200129
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200130 if (irq >= 30)
131 return nmi_handler(opaque, irq, level);
Edgar E. Iglesias73cfd292009-05-16 00:23:15 +0200132
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200133 irq -= 1;
134 fs->regs[R_R_VECT] &= ~(1 << irq);
135 fs->regs[R_R_VECT] |= (!!level << irq);
136 pic_update(fs);
edgar_igl5ef98b42008-06-09 23:33:30 +0000137}
138
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200139static int etraxfs_pic_init(SysBusDevice *dev)
edgar_igle62b5b12008-03-14 01:04:24 +0000140{
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200141 struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
Edgar E. Iglesias979d98c2009-05-16 12:28:33 +0200142 int intr_vect_regs;
edgar_igle62b5b12008-03-14 01:04:24 +0000143
Paul Brook067a3dd2009-05-26 14:56:11 +0100144 qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200145 sysbus_init_irq(dev, &s->parent_irq);
146 sysbus_init_irq(dev, &s->parent_nmi);
edgar_igle62b5b12008-03-14 01:04:24 +0000147
Avi Kivity1eed09c2009-06-14 11:38:51 +0300148 intr_vect_regs = cpu_register_io_memory(pic_read, pic_write, s);
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200149 sysbus_init_mmio(dev, R_MAX * 4, intr_vect_regs);
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200150 return 0;
edgar_igle62b5b12008-03-14 01:04:24 +0000151}
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200152
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200153static SysBusDeviceInfo etraxfs_pic_info = {
154 .init = etraxfs_pic_init,
155 .qdev.name = "etraxfs,pic",
156 .qdev.size = sizeof(struct etrax_pic),
157 .qdev.props = (Property[]) {
Gerd Hoffmannddde0952009-08-03 17:35:24 +0200158 DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
159 DEFINE_PROP_END_OF_LIST(),
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200160 }
161};
162
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200163static void etraxfs_pic_register(void)
164{
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200165 sysbus_register_withprop(&etraxfs_pic_info);
Edgar E. Iglesiasfd6dc902009-05-18 22:24:22 +0200166}
167
168device_init(etraxfs_pic_register)