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