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 "sysemu/sysemu.h"
26#include "hw/sysbus.h"
27#include "trace.h"
28
29
30
31
32
33
34
35
36
37#define TYPE_SLAVIO_MISC "slavio_misc"
38#define SLAVIO_MISC(obj) OBJECT_CHECK(MiscState, (obj), TYPE_SLAVIO_MISC)
39
40typedef struct MiscState {
41 SysBusDevice parent_obj;
42
43 MemoryRegion cfg_iomem;
44 MemoryRegion diag_iomem;
45 MemoryRegion mdm_iomem;
46 MemoryRegion led_iomem;
47 MemoryRegion sysctrl_iomem;
48 MemoryRegion aux1_iomem;
49 MemoryRegion aux2_iomem;
50 qemu_irq irq;
51 qemu_irq fdc_tc;
52 uint32_t dummy;
53 uint8_t config;
54 uint8_t aux1, aux2;
55 uint8_t diag, mctrl;
56 uint8_t sysctrl;
57 uint16_t leds;
58} MiscState;
59
60#define TYPE_APC "apc"
61#define APC(obj) OBJECT_CHECK(APCState, (obj), TYPE_APC)
62
63typedef struct APCState {
64 SysBusDevice parent_obj;
65
66 MemoryRegion iomem;
67 qemu_irq cpu_halt;
68} APCState;
69
70#define MISC_SIZE 1
71#define SYSCTRL_SIZE 4
72
73#define AUX1_TC 0x02
74
75#define AUX2_PWROFF 0x01
76#define AUX2_PWRINTCLR 0x02
77#define AUX2_PWRFAIL 0x20
78
79#define CFG_PWRINTEN 0x08
80
81#define SYS_RESET 0x01
82#define SYS_RESETSTAT 0x02
83
84static void slavio_misc_update_irq(void *opaque)
85{
86 MiscState *s = opaque;
87
88 if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
89 trace_slavio_misc_update_irq_raise();
90 qemu_irq_raise(s->irq);
91 } else {
92 trace_slavio_misc_update_irq_lower();
93 qemu_irq_lower(s->irq);
94 }
95}
96
97static void slavio_misc_reset(DeviceState *d)
98{
99 MiscState *s = SLAVIO_MISC(d);
100
101
102 s->config = s->aux1 = s->aux2 = s->mctrl = 0;
103}
104
105static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
106{
107 MiscState *s = opaque;
108
109 trace_slavio_set_power_fail(power_failing, s->config);
110 if (power_failing && (s->config & CFG_PWRINTEN)) {
111 s->aux2 |= AUX2_PWRFAIL;
112 } else {
113 s->aux2 &= ~AUX2_PWRFAIL;
114 }
115 slavio_misc_update_irq(s);
116}
117
118static void slavio_cfg_mem_writeb(void *opaque, hwaddr addr,
119 uint64_t val, unsigned size)
120{
121 MiscState *s = opaque;
122
123 trace_slavio_cfg_mem_writeb(val & 0xff);
124 s->config = val & 0xff;
125 slavio_misc_update_irq(s);
126}
127
128static uint64_t slavio_cfg_mem_readb(void *opaque, hwaddr addr,
129 unsigned size)
130{
131 MiscState *s = opaque;
132 uint32_t ret = 0;
133
134 ret = s->config;
135 trace_slavio_cfg_mem_readb(ret);
136 return ret;
137}
138
139static const MemoryRegionOps slavio_cfg_mem_ops = {
140 .read = slavio_cfg_mem_readb,
141 .write = slavio_cfg_mem_writeb,
142 .endianness = DEVICE_NATIVE_ENDIAN,
143 .valid = {
144 .min_access_size = 1,
145 .max_access_size = 1,
146 },
147};
148
149static void slavio_diag_mem_writeb(void *opaque, hwaddr addr,
150 uint64_t val, unsigned size)
151{
152 MiscState *s = opaque;
153
154 trace_slavio_diag_mem_writeb(val & 0xff);
155 s->diag = val & 0xff;
156}
157
158static uint64_t slavio_diag_mem_readb(void *opaque, hwaddr addr,
159 unsigned size)
160{
161 MiscState *s = opaque;
162 uint32_t ret = 0;
163
164 ret = s->diag;
165 trace_slavio_diag_mem_readb(ret);
166 return ret;
167}
168
169static const MemoryRegionOps slavio_diag_mem_ops = {
170 .read = slavio_diag_mem_readb,
171 .write = slavio_diag_mem_writeb,
172 .endianness = DEVICE_NATIVE_ENDIAN,
173 .valid = {
174 .min_access_size = 1,
175 .max_access_size = 1,
176 },
177};
178
179static void slavio_mdm_mem_writeb(void *opaque, hwaddr addr,
180 uint64_t val, unsigned size)
181{
182 MiscState *s = opaque;
183
184 trace_slavio_mdm_mem_writeb(val & 0xff);
185 s->mctrl = val & 0xff;
186}
187
188static uint64_t slavio_mdm_mem_readb(void *opaque, hwaddr addr,
189 unsigned size)
190{
191 MiscState *s = opaque;
192 uint32_t ret = 0;
193
194 ret = s->mctrl;
195 trace_slavio_mdm_mem_readb(ret);
196 return ret;
197}
198
199static const MemoryRegionOps slavio_mdm_mem_ops = {
200 .read = slavio_mdm_mem_readb,
201 .write = slavio_mdm_mem_writeb,
202 .endianness = DEVICE_NATIVE_ENDIAN,
203 .valid = {
204 .min_access_size = 1,
205 .max_access_size = 1,
206 },
207};
208
209static void slavio_aux1_mem_writeb(void *opaque, hwaddr addr,
210 uint64_t val, unsigned size)
211{
212 MiscState *s = opaque;
213
214 trace_slavio_aux1_mem_writeb(val & 0xff);
215 if (val & AUX1_TC) {
216
217 if (s->fdc_tc) {
218 qemu_irq_raise(s->fdc_tc);
219 qemu_irq_lower(s->fdc_tc);
220 }
221 val &= ~AUX1_TC;
222 }
223 s->aux1 = val & 0xff;
224}
225
226static uint64_t slavio_aux1_mem_readb(void *opaque, hwaddr addr,
227 unsigned size)
228{
229 MiscState *s = opaque;
230 uint32_t ret = 0;
231
232 ret = s->aux1;
233 trace_slavio_aux1_mem_readb(ret);
234 return ret;
235}
236
237static const MemoryRegionOps slavio_aux1_mem_ops = {
238 .read = slavio_aux1_mem_readb,
239 .write = slavio_aux1_mem_writeb,
240 .endianness = DEVICE_NATIVE_ENDIAN,
241 .valid = {
242 .min_access_size = 1,
243 .max_access_size = 1,
244 },
245};
246
247static void slavio_aux2_mem_writeb(void *opaque, hwaddr addr,
248 uint64_t val, unsigned size)
249{
250 MiscState *s = opaque;
251
252 val &= AUX2_PWRINTCLR | AUX2_PWROFF;
253 trace_slavio_aux2_mem_writeb(val & 0xff);
254 val |= s->aux2 & AUX2_PWRFAIL;
255 if (val & AUX2_PWRINTCLR)
256 val &= AUX2_PWROFF;
257 s->aux2 = val;
258 if (val & AUX2_PWROFF)
259 qemu_system_shutdown_request();
260 slavio_misc_update_irq(s);
261}
262
263static uint64_t slavio_aux2_mem_readb(void *opaque, hwaddr addr,
264 unsigned size)
265{
266 MiscState *s = opaque;
267 uint32_t ret = 0;
268
269 ret = s->aux2;
270 trace_slavio_aux2_mem_readb(ret);
271 return ret;
272}
273
274static const MemoryRegionOps slavio_aux2_mem_ops = {
275 .read = slavio_aux2_mem_readb,
276 .write = slavio_aux2_mem_writeb,
277 .endianness = DEVICE_NATIVE_ENDIAN,
278 .valid = {
279 .min_access_size = 1,
280 .max_access_size = 1,
281 },
282};
283
284static void apc_mem_writeb(void *opaque, hwaddr addr,
285 uint64_t val, unsigned size)
286{
287 APCState *s = opaque;
288
289 trace_apc_mem_writeb(val & 0xff);
290 qemu_irq_raise(s->cpu_halt);
291}
292
293static uint64_t apc_mem_readb(void *opaque, hwaddr addr,
294 unsigned size)
295{
296 uint32_t ret = 0;
297
298 trace_apc_mem_readb(ret);
299 return ret;
300}
301
302static const MemoryRegionOps apc_mem_ops = {
303 .read = apc_mem_readb,
304 .write = apc_mem_writeb,
305 .endianness = DEVICE_NATIVE_ENDIAN,
306 .valid = {
307 .min_access_size = 1,
308 .max_access_size = 1,
309 }
310};
311
312static uint64_t slavio_sysctrl_mem_readl(void *opaque, hwaddr addr,
313 unsigned size)
314{
315 MiscState *s = opaque;
316 uint32_t ret = 0;
317
318 switch (addr) {
319 case 0:
320 ret = s->sysctrl;
321 break;
322 default:
323 break;
324 }
325 trace_slavio_sysctrl_mem_readl(ret);
326 return ret;
327}
328
329static void slavio_sysctrl_mem_writel(void *opaque, hwaddr addr,
330 uint64_t val, unsigned size)
331{
332 MiscState *s = opaque;
333
334 trace_slavio_sysctrl_mem_writel(val);
335 switch (addr) {
336 case 0:
337 if (val & SYS_RESET) {
338 s->sysctrl = SYS_RESETSTAT;
339 qemu_system_reset_request();
340 }
341 break;
342 default:
343 break;
344 }
345}
346
347static const MemoryRegionOps slavio_sysctrl_mem_ops = {
348 .read = slavio_sysctrl_mem_readl,
349 .write = slavio_sysctrl_mem_writel,
350 .endianness = DEVICE_NATIVE_ENDIAN,
351 .valid = {
352 .min_access_size = 4,
353 .max_access_size = 4,
354 },
355};
356
357static uint64_t slavio_led_mem_readw(void *opaque, hwaddr addr,
358 unsigned size)
359{
360 MiscState *s = opaque;
361 uint32_t ret = 0;
362
363 switch (addr) {
364 case 0:
365 ret = s->leds;
366 break;
367 default:
368 break;
369 }
370 trace_slavio_led_mem_readw(ret);
371 return ret;
372}
373
374static void slavio_led_mem_writew(void *opaque, hwaddr addr,
375 uint64_t val, unsigned size)
376{
377 MiscState *s = opaque;
378
379 trace_slavio_led_mem_writew(val & 0xffff);
380 switch (addr) {
381 case 0:
382 s->leds = val;
383 break;
384 default:
385 break;
386 }
387}
388
389static const MemoryRegionOps slavio_led_mem_ops = {
390 .read = slavio_led_mem_readw,
391 .write = slavio_led_mem_writew,
392 .endianness = DEVICE_NATIVE_ENDIAN,
393 .valid = {
394 .min_access_size = 2,
395 .max_access_size = 2,
396 },
397};
398
399static const VMStateDescription vmstate_misc = {
400 .name ="slavio_misc",
401 .version_id = 1,
402 .minimum_version_id = 1,
403 .minimum_version_id_old = 1,
404 .fields = (VMStateField []) {
405 VMSTATE_UINT32(dummy, MiscState),
406 VMSTATE_UINT8(config, MiscState),
407 VMSTATE_UINT8(aux1, MiscState),
408 VMSTATE_UINT8(aux2, MiscState),
409 VMSTATE_UINT8(diag, MiscState),
410 VMSTATE_UINT8(mctrl, MiscState),
411 VMSTATE_UINT8(sysctrl, MiscState),
412 VMSTATE_END_OF_LIST()
413 }
414};
415
416static int apc_init1(SysBusDevice *dev)
417{
418 APCState *s = APC(dev);
419
420 sysbus_init_irq(dev, &s->cpu_halt);
421
422
423 memory_region_init_io(&s->iomem, OBJECT(s), &apc_mem_ops, s,
424 "apc", MISC_SIZE);
425 sysbus_init_mmio(dev, &s->iomem);
426 return 0;
427}
428
429static int slavio_misc_init1(SysBusDevice *sbd)
430{
431 DeviceState *dev = DEVICE(sbd);
432 MiscState *s = SLAVIO_MISC(dev);
433
434 sysbus_init_irq(sbd, &s->irq);
435 sysbus_init_irq(sbd, &s->fdc_tc);
436
437
438
439 memory_region_init_io(&s->cfg_iomem, OBJECT(s), &slavio_cfg_mem_ops, s,
440 "configuration", MISC_SIZE);
441 sysbus_init_mmio(sbd, &s->cfg_iomem);
442
443
444 memory_region_init_io(&s->diag_iomem, OBJECT(s), &slavio_diag_mem_ops, s,
445 "diagnostic", MISC_SIZE);
446 sysbus_init_mmio(sbd, &s->diag_iomem);
447
448
449 memory_region_init_io(&s->mdm_iomem, OBJECT(s), &slavio_mdm_mem_ops, s,
450 "modem", MISC_SIZE);
451 sysbus_init_mmio(sbd, &s->mdm_iomem);
452
453
454
455 memory_region_init_io(&s->led_iomem, OBJECT(s), &slavio_led_mem_ops, s,
456 "leds", MISC_SIZE);
457 sysbus_init_mmio(sbd, &s->led_iomem);
458
459
460
461 memory_region_init_io(&s->sysctrl_iomem, OBJECT(s), &slavio_sysctrl_mem_ops, s,
462 "system-control", MISC_SIZE);
463 sysbus_init_mmio(sbd, &s->sysctrl_iomem);
464
465
466 memory_region_init_io(&s->aux1_iomem, OBJECT(s), &slavio_aux1_mem_ops, s,
467 "misc-system-functions", MISC_SIZE);
468 sysbus_init_mmio(sbd, &s->aux1_iomem);
469
470
471 memory_region_init_io(&s->aux2_iomem, OBJECT(s), &slavio_aux2_mem_ops, s,
472 "software-powerdown-control", MISC_SIZE);
473 sysbus_init_mmio(sbd, &s->aux2_iomem);
474
475 qdev_init_gpio_in(dev, slavio_set_power_fail, 1);
476
477 return 0;
478}
479
480static void slavio_misc_class_init(ObjectClass *klass, void *data)
481{
482 DeviceClass *dc = DEVICE_CLASS(klass);
483 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
484
485 k->init = slavio_misc_init1;
486 dc->reset = slavio_misc_reset;
487 dc->vmsd = &vmstate_misc;
488}
489
490static const TypeInfo slavio_misc_info = {
491 .name = TYPE_SLAVIO_MISC,
492 .parent = TYPE_SYS_BUS_DEVICE,
493 .instance_size = sizeof(MiscState),
494 .class_init = slavio_misc_class_init,
495};
496
497static void apc_class_init(ObjectClass *klass, void *data)
498{
499 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
500
501 k->init = apc_init1;
502}
503
504static const TypeInfo apc_info = {
505 .name = TYPE_APC,
506 .parent = TYPE_SYS_BUS_DEVICE,
507 .instance_size = sizeof(MiscState),
508 .class_init = apc_class_init,
509};
510
511static void slavio_misc_register_types(void)
512{
513 type_register_static(&slavio_misc_info);
514 type_register_static(&apc_info);
515}
516
517type_init(slavio_misc_register_types)
518