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