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