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