]> git.proxmox.com Git - mirror_qemu.git/blame - hw/syborg_interrupt.c
fmopl: Fix spelling in code and comments
[mirror_qemu.git] / hw / syborg_interrupt.c
CommitLineData
4af39611
PB
1/*
2 * Syborg interrupt controller.
3 *
4 * Copyright (c) 2008 CodeSourcery
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
25#include "sysbus.h"
26#include "syborg.h"
27
28//#define DEBUG_SYBORG_INT
29
30#ifdef DEBUG_SYBORG_INT
31#define DPRINTF(fmt, ...) \
32do { printf("syborg_int: " fmt , ## __VA_ARGS__); } while (0)
33#define BADF(fmt, ...) \
34do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__); \
35 exit(1);} while (0)
36#else
37#define DPRINTF(fmt, ...) do {} while(0)
38#define BADF(fmt, ...) \
39do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__);} while (0)
40#endif
41enum {
42 INT_ID = 0,
43 INT_STATUS = 1, /* number of pending interrupts */
44 INT_CURRENT = 2, /* next interrupt to be serviced */
45 INT_DISABLE_ALL = 3,
46 INT_DISABLE = 4,
47 INT_ENABLE = 5,
48 INT_TOTAL = 6
49};
50
51typedef struct {
52 unsigned level:1;
53 unsigned enabled:1;
54} syborg_int_flags;
55
56typedef struct {
57 SysBusDevice busdev;
9cc60076 58 MemoryRegion iomem;
4af39611 59 int pending_count;
ee6847d1 60 uint32_t num_irqs;
4af39611
PB
61 syborg_int_flags *flags;
62 qemu_irq parent_irq;
63} SyborgIntState;
64
65static void syborg_int_update(SyborgIntState *s)
66{
67 DPRINTF("pending %d\n", s->pending_count);
68 qemu_set_irq(s->parent_irq, s->pending_count > 0);
69}
70
71static void syborg_int_set_irq(void *opaque, int irq, int level)
72{
73 SyborgIntState *s = (SyborgIntState *)opaque;
74
75 if (s->flags[irq].level == level)
76 return;
77
78 s->flags[irq].level = level;
79 if (s->flags[irq].enabled) {
80 if (level)
81 s->pending_count++;
82 else
83 s->pending_count--;
84 syborg_int_update(s);
85 }
86}
87
9cc60076
BC
88static uint64_t syborg_int_read(void *opaque, target_phys_addr_t offset,
89 unsigned size)
4af39611
PB
90{
91 SyborgIntState *s = (SyborgIntState *)opaque;
92 int i;
93
94 offset &= 0xfff;
95 switch (offset >> 2) {
96 case INT_ID:
97 return SYBORG_ID_INT;
98 case INT_STATUS:
99 DPRINTF("read status=%d\n", s->pending_count);
100 return s->pending_count;
101
102 case INT_CURRENT:
103 for (i = 0; i < s->num_irqs; i++) {
104 if (s->flags[i].level & s->flags[i].enabled) {
105 DPRINTF("read current=%d\n", i);
106 return i;
107 }
108 }
109 DPRINTF("read current=none\n");
110 return 0xffffffffu;
111
112 default:
113 cpu_abort(cpu_single_env, "syborg_int_read: Bad offset %x\n",
114 (int)offset);
115 return 0;
116 }
117}
118
9cc60076
BC
119static void syborg_int_write(void *opaque, target_phys_addr_t offset,
120 uint64_t value, unsigned size)
4af39611
PB
121{
122 SyborgIntState *s = (SyborgIntState *)opaque;
123 int i;
124 offset &= 0xfff;
125
126 DPRINTF("syborg_int_write offset=%d val=%d\n", (int)offset, (int)value);
127 switch (offset >> 2) {
128 case INT_DISABLE_ALL:
129 s->pending_count = 0;
130 for (i = 0; i < s->num_irqs; i++)
131 s->flags[i].enabled = 0;
132 break;
133
134 case INT_DISABLE:
135 if (value >= s->num_irqs)
136 break;
137 if (s->flags[value].enabled) {
138 if (s->flags[value].enabled)
139 s->pending_count--;
140 s->flags[value].enabled = 0;
141 }
142 break;
143
144 case INT_ENABLE:
145 if (value >= s->num_irqs)
146 break;
147 if (!(s->flags[value].enabled)) {
148 if(s->flags[value].level)
149 s->pending_count++;
150 s->flags[value].enabled = 1;
151 }
152 break;
153
154 default:
155 cpu_abort(cpu_single_env, "syborg_int_write: Bad offset %x\n",
156 (int)offset);
157 return;
158 }
159 syborg_int_update(s);
160}
161
9cc60076
BC
162static const MemoryRegionOps syborg_int_ops = {
163 .read = syborg_int_read,
164 .write = syborg_int_write,
165 .endianness = DEVICE_NATIVE_ENDIAN,
4af39611
PB
166};
167
168static void syborg_int_save(QEMUFile *f, void *opaque)
169{
170 SyborgIntState *s = (SyborgIntState *)opaque;
171 int i;
172
173 qemu_put_be32(f, s->num_irqs);
174 qemu_put_be32(f, s->pending_count);
175 for (i = 0; i < s->num_irqs; i++) {
176 qemu_put_be32(f, s->flags[i].enabled
177 | ((unsigned)s->flags[i].level << 1));
178 }
179}
180
181static int syborg_int_load(QEMUFile *f, void *opaque, int version_id)
182{
183 SyborgIntState *s = (SyborgIntState *)opaque;
184 uint32_t val;
185 int i;
186
187 if (version_id != 1)
188 return -EINVAL;
189
190 val = qemu_get_be32(f);
191 if (val != s->num_irqs)
192 return -EINVAL;
193 s->pending_count = qemu_get_be32(f);
194 for (i = 0; i < s->num_irqs; i++) {
195 val = qemu_get_be32(f);
196 s->flags[i].enabled = val & 1;
197 s->flags[i].level = (val >> 1) & 1;
198 }
199 return 0;
200}
201
81a322d4 202static int syborg_int_init(SysBusDevice *dev)
4af39611
PB
203{
204 SyborgIntState *s = FROM_SYSBUS(SyborgIntState, dev);
4af39611
PB
205
206 sysbus_init_irq(dev, &s->parent_irq);
067a3ddc 207 qdev_init_gpio_in(&dev->qdev, syborg_int_set_irq, s->num_irqs);
9cc60076
BC
208 memory_region_init_io(&s->iomem, &syborg_int_ops, s,
209 "interrupt", 0x1000);
750ecd44 210 sysbus_init_mmio(dev, &s->iomem);
7267c094 211 s->flags = g_malloc0(s->num_irqs * sizeof(syborg_int_flags));
4af39611 212
0be71e32
AW
213 register_savevm(&dev->qdev, "syborg_int", -1, 1, syborg_int_save,
214 syborg_int_load, s);
81a322d4 215 return 0;
4af39611
PB
216}
217
ee6847d1
GH
218static SysBusDeviceInfo syborg_int_info = {
219 .init = syborg_int_init,
220 .qdev.name = "syborg,interrupt",
221 .qdev.size = sizeof(SyborgIntState),
222 .qdev.props = (Property[]) {
3c2aed8b
GH
223 DEFINE_PROP_UINT32("num-interrupts", SyborgIntState, num_irqs, 64),
224 DEFINE_PROP_END_OF_LIST(),
ee6847d1
GH
225 }
226};
227
4af39611
PB
228static void syborg_interrupt_register_devices(void)
229{
ee6847d1 230 sysbus_register_withprop(&syborg_int_info);
4af39611
PB
231}
232
233device_init(syborg_interrupt_register_devices)