xref: /openbmc/qemu/hw/misc/slavio_misc.c (revision b8877962)
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 SYSCTRL_SIZE 4
72 
73 #define AUX1_TC        0x02
74 
75 #define AUX2_PWROFF    0x01
76 #define AUX2_PWRINTCLR 0x02
77 #define AUX2_PWRFAIL   0x20
78 
79 #define CFG_PWRINTEN   0x08
80 
81 #define SYS_RESET      0x01
82 #define SYS_RESETSTAT  0x02
83 
84 static void slavio_misc_update_irq(void *opaque)
85 {
86     MiscState *s = opaque;
87 
88     if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
89         trace_slavio_misc_update_irq_raise();
90         qemu_irq_raise(s->irq);
91     } else {
92         trace_slavio_misc_update_irq_lower();
93         qemu_irq_lower(s->irq);
94     }
95 }
96 
97 static void slavio_misc_reset(DeviceState *d)
98 {
99     MiscState *s = SLAVIO_MISC(d);
100 
101     // Diagnostic and system control registers not cleared in reset
102     s->config = s->aux1 = s->aux2 = s->mctrl = 0;
103 }
104 
105 static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
106 {
107     MiscState *s = opaque;
108 
109     trace_slavio_set_power_fail(power_failing, s->config);
110     if (power_failing && (s->config & CFG_PWRINTEN)) {
111         s->aux2 |= AUX2_PWRFAIL;
112     } else {
113         s->aux2 &= ~AUX2_PWRFAIL;
114     }
115     slavio_misc_update_irq(s);
116 }
117 
118 static void slavio_cfg_mem_writeb(void *opaque, hwaddr addr,
119                                   uint64_t val, unsigned size)
120 {
121     MiscState *s = opaque;
122 
123     trace_slavio_cfg_mem_writeb(val & 0xff);
124     s->config = val & 0xff;
125     slavio_misc_update_irq(s);
126 }
127 
128 static uint64_t slavio_cfg_mem_readb(void *opaque, hwaddr addr,
129                                      unsigned size)
130 {
131     MiscState *s = opaque;
132     uint32_t ret = 0;
133 
134     ret = s->config;
135     trace_slavio_cfg_mem_readb(ret);
136     return ret;
137 }
138 
139 static const MemoryRegionOps slavio_cfg_mem_ops = {
140     .read = slavio_cfg_mem_readb,
141     .write = slavio_cfg_mem_writeb,
142     .endianness = DEVICE_NATIVE_ENDIAN,
143     .valid = {
144         .min_access_size = 1,
145         .max_access_size = 1,
146     },
147 };
148 
149 static void slavio_diag_mem_writeb(void *opaque, hwaddr addr,
150                                    uint64_t val, unsigned size)
151 {
152     MiscState *s = opaque;
153 
154     trace_slavio_diag_mem_writeb(val & 0xff);
155     s->diag = val & 0xff;
156 }
157 
158 static uint64_t slavio_diag_mem_readb(void *opaque, hwaddr addr,
159                                       unsigned size)
160 {
161     MiscState *s = opaque;
162     uint32_t ret = 0;
163 
164     ret = s->diag;
165     trace_slavio_diag_mem_readb(ret);
166     return ret;
167 }
168 
169 static const MemoryRegionOps slavio_diag_mem_ops = {
170     .read = slavio_diag_mem_readb,
171     .write = slavio_diag_mem_writeb,
172     .endianness = DEVICE_NATIVE_ENDIAN,
173     .valid = {
174         .min_access_size = 1,
175         .max_access_size = 1,
176     },
177 };
178 
179 static void slavio_mdm_mem_writeb(void *opaque, hwaddr addr,
180                                   uint64_t val, unsigned size)
181 {
182     MiscState *s = opaque;
183 
184     trace_slavio_mdm_mem_writeb(val & 0xff);
185     s->mctrl = val & 0xff;
186 }
187 
188 static uint64_t slavio_mdm_mem_readb(void *opaque, hwaddr addr,
189                                      unsigned size)
190 {
191     MiscState *s = opaque;
192     uint32_t ret = 0;
193 
194     ret = s->mctrl;
195     trace_slavio_mdm_mem_readb(ret);
196     return ret;
197 }
198 
199 static const MemoryRegionOps slavio_mdm_mem_ops = {
200     .read = slavio_mdm_mem_readb,
201     .write = slavio_mdm_mem_writeb,
202     .endianness = DEVICE_NATIVE_ENDIAN,
203     .valid = {
204         .min_access_size = 1,
205         .max_access_size = 1,
206     },
207 };
208 
209 static void slavio_aux1_mem_writeb(void *opaque, hwaddr addr,
210                                    uint64_t val, unsigned size)
211 {
212     MiscState *s = opaque;
213 
214     trace_slavio_aux1_mem_writeb(val & 0xff);
215     if (val & AUX1_TC) {
216         // Send a pulse to floppy terminal count line
217         if (s->fdc_tc) {
218             qemu_irq_raise(s->fdc_tc);
219             qemu_irq_lower(s->fdc_tc);
220         }
221         val &= ~AUX1_TC;
222     }
223     s->aux1 = val & 0xff;
224 }
225 
226 static uint64_t slavio_aux1_mem_readb(void *opaque, hwaddr addr,
227                                       unsigned size)
228 {
229     MiscState *s = opaque;
230     uint32_t ret = 0;
231 
232     ret = s->aux1;
233     trace_slavio_aux1_mem_readb(ret);
234     return ret;
235 }
236 
237 static const MemoryRegionOps slavio_aux1_mem_ops = {
238     .read = slavio_aux1_mem_readb,
239     .write = slavio_aux1_mem_writeb,
240     .endianness = DEVICE_NATIVE_ENDIAN,
241     .valid = {
242         .min_access_size = 1,
243         .max_access_size = 1,
244     },
245 };
246 
247 static void slavio_aux2_mem_writeb(void *opaque, hwaddr addr,
248                                    uint64_t val, unsigned size)
249 {
250     MiscState *s = opaque;
251 
252     val &= AUX2_PWRINTCLR | AUX2_PWROFF;
253     trace_slavio_aux2_mem_writeb(val & 0xff);
254     val |= s->aux2 & AUX2_PWRFAIL;
255     if (val & AUX2_PWRINTCLR) // Clear Power Fail int
256         val &= AUX2_PWROFF;
257     s->aux2 = val;
258     if (val & AUX2_PWROFF)
259         qemu_system_shutdown_request();
260     slavio_misc_update_irq(s);
261 }
262 
263 static uint64_t slavio_aux2_mem_readb(void *opaque, hwaddr addr,
264                                       unsigned size)
265 {
266     MiscState *s = opaque;
267     uint32_t ret = 0;
268 
269     ret = s->aux2;
270     trace_slavio_aux2_mem_readb(ret);
271     return ret;
272 }
273 
274 static const MemoryRegionOps slavio_aux2_mem_ops = {
275     .read = slavio_aux2_mem_readb,
276     .write = slavio_aux2_mem_writeb,
277     .endianness = DEVICE_NATIVE_ENDIAN,
278     .valid = {
279         .min_access_size = 1,
280         .max_access_size = 1,
281     },
282 };
283 
284 static void apc_mem_writeb(void *opaque, hwaddr addr,
285                            uint64_t val, unsigned size)
286 {
287     APCState *s = opaque;
288 
289     trace_apc_mem_writeb(val & 0xff);
290     qemu_irq_raise(s->cpu_halt);
291 }
292 
293 static uint64_t apc_mem_readb(void *opaque, hwaddr addr,
294                               unsigned size)
295 {
296     uint32_t ret = 0;
297 
298     trace_apc_mem_readb(ret);
299     return ret;
300 }
301 
302 static const MemoryRegionOps apc_mem_ops = {
303     .read = apc_mem_readb,
304     .write = apc_mem_writeb,
305     .endianness = DEVICE_NATIVE_ENDIAN,
306     .valid = {
307         .min_access_size = 1,
308         .max_access_size = 1,
309     }
310 };
311 
312 static uint64_t slavio_sysctrl_mem_readl(void *opaque, hwaddr addr,
313                                          unsigned size)
314 {
315     MiscState *s = opaque;
316     uint32_t ret = 0;
317 
318     switch (addr) {
319     case 0:
320         ret = s->sysctrl;
321         break;
322     default:
323         break;
324     }
325     trace_slavio_sysctrl_mem_readl(ret);
326     return ret;
327 }
328 
329 static void slavio_sysctrl_mem_writel(void *opaque, hwaddr addr,
330                                       uint64_t val, unsigned size)
331 {
332     MiscState *s = opaque;
333 
334     trace_slavio_sysctrl_mem_writel(val);
335     switch (addr) {
336     case 0:
337         if (val & SYS_RESET) {
338             s->sysctrl = SYS_RESETSTAT;
339             qemu_system_reset_request();
340         }
341         break;
342     default:
343         break;
344     }
345 }
346 
347 static const MemoryRegionOps slavio_sysctrl_mem_ops = {
348     .read = slavio_sysctrl_mem_readl,
349     .write = slavio_sysctrl_mem_writel,
350     .endianness = DEVICE_NATIVE_ENDIAN,
351     .valid = {
352         .min_access_size = 4,
353         .max_access_size = 4,
354     },
355 };
356 
357 static uint64_t slavio_led_mem_readw(void *opaque, hwaddr addr,
358                                      unsigned size)
359 {
360     MiscState *s = opaque;
361     uint32_t ret = 0;
362 
363     switch (addr) {
364     case 0:
365         ret = s->leds;
366         break;
367     default:
368         break;
369     }
370     trace_slavio_led_mem_readw(ret);
371     return ret;
372 }
373 
374 static void slavio_led_mem_writew(void *opaque, hwaddr addr,
375                                   uint64_t val, unsigned size)
376 {
377     MiscState *s = opaque;
378 
379     trace_slavio_led_mem_writew(val & 0xffff);
380     switch (addr) {
381     case 0:
382         s->leds = val;
383         break;
384     default:
385         break;
386     }
387 }
388 
389 static const MemoryRegionOps slavio_led_mem_ops = {
390     .read = slavio_led_mem_readw,
391     .write = slavio_led_mem_writew,
392     .endianness = DEVICE_NATIVE_ENDIAN,
393     .valid = {
394         .min_access_size = 2,
395         .max_access_size = 2,
396     },
397 };
398 
399 static const VMStateDescription vmstate_misc = {
400     .name ="slavio_misc",
401     .version_id = 1,
402     .minimum_version_id = 1,
403     .minimum_version_id_old = 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", MISC_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", MISC_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