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