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