1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include "qemu/osdep.h"
23#include "hw/sysbus.h"
24#include "qemu/module.h"
25
26#define TYPE_MPC8XXX_GPIO "mpc8xxx_gpio"
27#define MPC8XXX_GPIO(obj) OBJECT_CHECK(MPC8XXXGPIOState, (obj), TYPE_MPC8XXX_GPIO)
28
29typedef struct MPC8XXXGPIOState {
30 SysBusDevice parent_obj;
31
32 MemoryRegion iomem;
33 qemu_irq irq;
34 qemu_irq out[32];
35
36 uint32_t dir;
37 uint32_t odr;
38 uint32_t dat;
39 uint32_t ier;
40 uint32_t imr;
41 uint32_t icr;
42} MPC8XXXGPIOState;
43
44static const VMStateDescription vmstate_mpc8xxx_gpio = {
45 .name = "mpc8xxx_gpio",
46 .version_id = 1,
47 .minimum_version_id = 1,
48 .fields = (VMStateField[]) {
49 VMSTATE_UINT32(dir, MPC8XXXGPIOState),
50 VMSTATE_UINT32(odr, MPC8XXXGPIOState),
51 VMSTATE_UINT32(dat, MPC8XXXGPIOState),
52 VMSTATE_UINT32(ier, MPC8XXXGPIOState),
53 VMSTATE_UINT32(imr, MPC8XXXGPIOState),
54 VMSTATE_UINT32(icr, MPC8XXXGPIOState),
55 VMSTATE_END_OF_LIST()
56 }
57};
58
59static void mpc8xxx_gpio_update(MPC8XXXGPIOState *s)
60{
61 qemu_set_irq(s->irq, !!(s->ier & s->imr));
62}
63
64static uint64_t mpc8xxx_gpio_read(void *opaque, hwaddr offset,
65 unsigned size)
66{
67 MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
68
69 if (size != 4) {
70
71 return 0;
72 }
73
74 switch (offset) {
75 case 0x0:
76 return s->dir;
77 case 0x4:
78 return s->odr;
79 case 0x8:
80 return s->dat;
81 case 0xC:
82 return s->ier;
83 case 0x10:
84 return s->imr;
85 case 0x14:
86 return s->icr;
87 default:
88 return 0;
89 }
90}
91
92static void mpc8xxx_write_data(MPC8XXXGPIOState *s, uint32_t new_data)
93{
94 uint32_t old_data = s->dat;
95 uint32_t diff = old_data ^ new_data;
96 int i;
97
98 for (i = 0; i < 32; i++) {
99 uint32_t mask = 0x80000000 >> i;
100 if (!(diff & mask)) {
101 continue;
102 }
103
104 if (s->dir & mask) {
105
106 qemu_set_irq(s->out[i], (new_data & mask) != 0);
107 }
108 }
109
110 s->dat = new_data;
111}
112
113static void mpc8xxx_gpio_write(void *opaque, hwaddr offset,
114 uint64_t value, unsigned size)
115{
116 MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
117
118 if (size != 4) {
119
120 return;
121 }
122
123 switch (offset) {
124 case 0x0:
125 s->dir = value;
126 break;
127 case 0x4:
128 s->odr = value;
129 break;
130 case 0x8:
131 mpc8xxx_write_data(s, value);
132 break;
133 case 0xC:
134 s->ier &= ~value;
135 break;
136 case 0x10:
137 s->imr = value;
138 break;
139 case 0x14:
140 s->icr = value;
141 break;
142 }
143
144 mpc8xxx_gpio_update(s);
145}
146
147static void mpc8xxx_gpio_reset(DeviceState *dev)
148{
149 MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev);
150
151 s->dir = 0;
152 s->odr = 0;
153 s->dat = 0;
154 s->ier = 0;
155 s->imr = 0;
156 s->icr = 0;
157}
158
159static void mpc8xxx_gpio_set_irq(void * opaque, int irq, int level)
160{
161 MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
162 uint32_t mask;
163
164 mask = 0x80000000 >> irq;
165 if ((s->dir & mask) == 0) {
166 uint32_t old_value = s->dat & mask;
167
168 s->dat &= ~mask;
169 if (level)
170 s->dat |= mask;
171
172 if (!(s->icr & irq) || (old_value && !level)) {
173 s->ier |= mask;
174 }
175
176 mpc8xxx_gpio_update(s);
177 }
178}
179
180static const MemoryRegionOps mpc8xxx_gpio_ops = {
181 .read = mpc8xxx_gpio_read,
182 .write = mpc8xxx_gpio_write,
183 .endianness = DEVICE_BIG_ENDIAN,
184};
185
186static void mpc8xxx_gpio_initfn(Object *obj)
187{
188 DeviceState *dev = DEVICE(obj);
189 MPC8XXXGPIOState *s = MPC8XXX_GPIO(obj);
190 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
191
192 memory_region_init_io(&s->iomem, obj, &mpc8xxx_gpio_ops,
193 s, "mpc8xxx_gpio", 0x1000);
194 sysbus_init_mmio(sbd, &s->iomem);
195 sysbus_init_irq(sbd, &s->irq);
196 qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32);
197 qdev_init_gpio_out(dev, s->out, 32);
198}
199
200static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data)
201{
202 DeviceClass *dc = DEVICE_CLASS(klass);
203
204 dc->vmsd = &vmstate_mpc8xxx_gpio;
205 dc->reset = mpc8xxx_gpio_reset;
206}
207
208static const TypeInfo mpc8xxx_gpio_info = {
209 .name = TYPE_MPC8XXX_GPIO,
210 .parent = TYPE_SYS_BUS_DEVICE,
211 .instance_size = sizeof(MPC8XXXGPIOState),
212 .instance_init = mpc8xxx_gpio_initfn,
213 .class_init = mpc8xxx_gpio_class_init,
214};
215
216static void mpc8xxx_gpio_register_types(void)
217{
218 type_register_static(&mpc8xxx_gpio_info);
219}
220
221type_init(mpc8xxx_gpio_register_types)
222