1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include "sysbus.h"
26#include "hw.h"
27
28
29
30#define D(x)
31
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
39struct etrax_pic
40{
41 SysBusDevice busdev;
42 MemoryRegion mmio;
43 void *interrupt_vector;
44 qemu_irq parent_irq;
45 qemu_irq parent_nmi;
46 uint32_t regs[R_MAX];
47};
48
49static void pic_update(struct etrax_pic *fs)
50{
51 uint32_t vector = 0;
52 int i;
53
54 fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
55
56
57
58
59
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
66 if (mv > 1)
67 vector = 0x30;
68 break;
69 }
70 mv >>= 1;
71 }
72 }
73
74 if (fs->interrupt_vector) {
75
76 *(uint32_t*)(fs->interrupt_vector) = vector;
77 }
78 qemu_set_irq(fs->parent_irq, !!vector);
79}
80
81static uint64_t
82pic_read(void *opaque, hwaddr addr, unsigned int size)
83{
84 struct etrax_pic *fs = opaque;
85 uint32_t rval;
86
87 rval = fs->regs[addr >> 2];
88 D(printf("%s %x=%x\n", __func__, addr, rval));
89 return rval;
90}
91
92static void pic_write(void *opaque, hwaddr addr,
93 uint64_t value, unsigned int size)
94{
95 struct etrax_pic *fs = opaque;
96 D(printf("%s addr=%x val=%x\n", __func__, addr, value));
97
98 if (addr == R_RW_MASK) {
99 fs->regs[R_RW_MASK] = value;
100 pic_update(fs);
101 }
102}
103
104static 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 }
112};
113
114static void nmi_handler(void *opaque, int irq, int level)
115{
116 struct etrax_pic *fs = (void *)opaque;
117 uint32_t mask;
118
119 mask = 1 << irq;
120 if (level)
121 fs->regs[R_R_NMI] |= mask;
122 else
123 fs->regs[R_R_NMI] &= ~mask;
124
125 qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
126}
127
128static void irq_handler(void *opaque, int irq, int level)
129{
130 struct etrax_pic *fs = (void *)opaque;
131
132 if (irq >= 30)
133 return nmi_handler(opaque, irq, level);
134
135 irq -= 1;
136 fs->regs[R_R_VECT] &= ~(1 << irq);
137 fs->regs[R_R_VECT] |= (!!level << irq);
138 pic_update(fs);
139}
140
141static int etraxfs_pic_init(SysBusDevice *dev)
142{
143 struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
144
145 qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
146 sysbus_init_irq(dev, &s->parent_irq);
147 sysbus_init_irq(dev, &s->parent_nmi);
148
149 memory_region_init_io(&s->mmio, &pic_ops, s, "etraxfs-pic", R_MAX * 4);
150 sysbus_init_mmio(dev, &s->mmio);
151 return 0;
152}
153
154static 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{
161 DeviceClass *dc = DEVICE_CLASS(klass);
162 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
163
164 k->init = etraxfs_pic_init;
165 dc->props = etraxfs_pic_properties;
166}
167
168static 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,
173};
174
175static void etraxfs_pic_register_types(void)
176{
177 type_register_static(&etraxfs_pic_info);
178}
179
180type_init(etraxfs_pic_register_types)
181