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