xref: /qemu/hw/misc/slavio_misc.c (revision a01d6ef44622a2baf799a207809d090ca9882468)
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.h"
26 #include "sysbus.h"
27 
28 /* debug misc */
29 //#define DEBUG_MISC
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 #ifdef DEBUG_MISC
40 #define MISC_DPRINTF(fmt, ...)                                  \
41     do { printf("MISC: " fmt , ## __VA_ARGS__); } while (0)
42 #else
43 #define MISC_DPRINTF(fmt, ...)
44 #endif
45 
46 typedef struct MiscState {
47     SysBusDevice busdev;
48     qemu_irq irq;
49     uint32_t dummy;
50     uint8_t config;
51     uint8_t aux1, aux2;
52     uint8_t diag, mctrl;
53     uint8_t sysctrl;
54     uint16_t leds;
55     qemu_irq fdc_tc;
56 } MiscState;
57 
58 typedef struct APCState {
59     SysBusDevice busdev;
60     qemu_irq cpu_halt;
61 } APCState;
62 
63 #define MISC_SIZE 1
64 #define SYSCTRL_SIZE 4
65 
66 #define AUX1_TC        0x02
67 
68 #define AUX2_PWROFF    0x01
69 #define AUX2_PWRINTCLR 0x02
70 #define AUX2_PWRFAIL   0x20
71 
72 #define CFG_PWRINTEN   0x08
73 
74 #define SYS_RESET      0x01
75 #define SYS_RESETSTAT  0x02
76 
77 static void slavio_misc_update_irq(void *opaque)
78 {
79     MiscState *s = opaque;
80 
81     if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
82         MISC_DPRINTF("Raise IRQ\n");
83         qemu_irq_raise(s->irq);
84     } else {
85         MISC_DPRINTF("Lower IRQ\n");
86         qemu_irq_lower(s->irq);
87     }
88 }
89 
90 static void slavio_misc_reset(DeviceState *d)
91 {
92     MiscState *s = container_of(d, MiscState, busdev.qdev);
93 
94     // Diagnostic and system control registers not cleared in reset
95     s->config = s->aux1 = s->aux2 = s->mctrl = 0;
96 }
97 
98 static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
99 {
100     MiscState *s = opaque;
101 
102     MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
103     if (power_failing && (s->config & CFG_PWRINTEN)) {
104         s->aux2 |= AUX2_PWRFAIL;
105     } else {
106         s->aux2 &= ~AUX2_PWRFAIL;
107     }
108     slavio_misc_update_irq(s);
109 }
110 
111 static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
112                                   uint32_t val)
113 {
114     MiscState *s = opaque;
115 
116     MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
117     s->config = val & 0xff;
118     slavio_misc_update_irq(s);
119 }
120 
121 static uint32_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr)
122 {
123     MiscState *s = opaque;
124     uint32_t ret = 0;
125 
126     ret = s->config;
127     MISC_DPRINTF("Read config %2.2x\n", ret);
128     return ret;
129 }
130 
131 static CPUReadMemoryFunc * const slavio_cfg_mem_read[3] = {
132     slavio_cfg_mem_readb,
133     NULL,
134     NULL,
135 };
136 
137 static CPUWriteMemoryFunc * const slavio_cfg_mem_write[3] = {
138     slavio_cfg_mem_writeb,
139     NULL,
140     NULL,
141 };
142 
143 static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
144                                    uint32_t val)
145 {
146     MiscState *s = opaque;
147 
148     MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
149     s->diag = val & 0xff;
150 }
151 
152 static uint32_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr)
153 {
154     MiscState *s = opaque;
155     uint32_t ret = 0;
156 
157     ret = s->diag;
158     MISC_DPRINTF("Read diag %2.2x\n", ret);
159     return ret;
160 }
161 
162 static CPUReadMemoryFunc * const slavio_diag_mem_read[3] = {
163     slavio_diag_mem_readb,
164     NULL,
165     NULL,
166 };
167 
168 static CPUWriteMemoryFunc * const slavio_diag_mem_write[3] = {
169     slavio_diag_mem_writeb,
170     NULL,
171     NULL,
172 };
173 
174 static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
175                                   uint32_t val)
176 {
177     MiscState *s = opaque;
178 
179     MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
180     s->mctrl = val & 0xff;
181 }
182 
183 static uint32_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr)
184 {
185     MiscState *s = opaque;
186     uint32_t ret = 0;
187 
188     ret = s->mctrl;
189     MISC_DPRINTF("Read modem control %2.2x\n", ret);
190     return ret;
191 }
192 
193 static CPUReadMemoryFunc * const slavio_mdm_mem_read[3] = {
194     slavio_mdm_mem_readb,
195     NULL,
196     NULL,
197 };
198 
199 static CPUWriteMemoryFunc * const slavio_mdm_mem_write[3] = {
200     slavio_mdm_mem_writeb,
201     NULL,
202     NULL,
203 };
204 
205 static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
206                                    uint32_t val)
207 {
208     MiscState *s = opaque;
209 
210     MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
211     if (val & AUX1_TC) {
212         // Send a pulse to floppy terminal count line
213         if (s->fdc_tc) {
214             qemu_irq_raise(s->fdc_tc);
215             qemu_irq_lower(s->fdc_tc);
216         }
217         val &= ~AUX1_TC;
218     }
219     s->aux1 = val & 0xff;
220 }
221 
222 static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr)
223 {
224     MiscState *s = opaque;
225     uint32_t ret = 0;
226 
227     ret = s->aux1;
228     MISC_DPRINTF("Read aux1 %2.2x\n", ret);
229 
230     return ret;
231 }
232 
233 static CPUReadMemoryFunc * const slavio_aux1_mem_read[3] = {
234     slavio_aux1_mem_readb,
235     NULL,
236     NULL,
237 };
238 
239 static CPUWriteMemoryFunc * const slavio_aux1_mem_write[3] = {
240     slavio_aux1_mem_writeb,
241     NULL,
242     NULL,
243 };
244 
245 static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
246                                    uint32_t val)
247 {
248     MiscState *s = opaque;
249 
250     val &= AUX2_PWRINTCLR | AUX2_PWROFF;
251     MISC_DPRINTF("Write aux2 %2.2x\n", val);
252     val |= s->aux2 & AUX2_PWRFAIL;
253     if (val & AUX2_PWRINTCLR) // Clear Power Fail int
254         val &= AUX2_PWROFF;
255     s->aux2 = val;
256     if (val & AUX2_PWROFF)
257         qemu_system_shutdown_request();
258     slavio_misc_update_irq(s);
259 }
260 
261 static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr)
262 {
263     MiscState *s = opaque;
264     uint32_t ret = 0;
265 
266     ret = s->aux2;
267     MISC_DPRINTF("Read aux2 %2.2x\n", ret);
268 
269     return ret;
270 }
271 
272 static CPUReadMemoryFunc * const slavio_aux2_mem_read[3] = {
273     slavio_aux2_mem_readb,
274     NULL,
275     NULL,
276 };
277 
278 static CPUWriteMemoryFunc * const slavio_aux2_mem_write[3] = {
279     slavio_aux2_mem_writeb,
280     NULL,
281     NULL,
282 };
283 
284 static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
285 {
286     APCState *s = opaque;
287 
288     MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
289     qemu_irq_raise(s->cpu_halt);
290 }
291 
292 static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr)
293 {
294     uint32_t ret = 0;
295 
296     MISC_DPRINTF("Read power management %2.2x\n", ret);
297     return ret;
298 }
299 
300 static CPUReadMemoryFunc * const apc_mem_read[3] = {
301     apc_mem_readb,
302     NULL,
303     NULL,
304 };
305 
306 static CPUWriteMemoryFunc * const apc_mem_write[3] = {
307     apc_mem_writeb,
308     NULL,
309     NULL,
310 };
311 
312 static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
313 {
314     MiscState *s = opaque;
315     uint32_t ret = 0;
316 
317     switch (addr) {
318     case 0:
319         ret = s->sysctrl;
320         break;
321     default:
322         break;
323     }
324     MISC_DPRINTF("Read system control %08x\n", ret);
325     return ret;
326 }
327 
328 static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
329                                       uint32_t val)
330 {
331     MiscState *s = opaque;
332 
333     MISC_DPRINTF("Write system control %08x\n", val);
334     switch (addr) {
335     case 0:
336         if (val & SYS_RESET) {
337             s->sysctrl = SYS_RESETSTAT;
338             qemu_system_reset_request();
339         }
340         break;
341     default:
342         break;
343     }
344 }
345 
346 static CPUReadMemoryFunc * const slavio_sysctrl_mem_read[3] = {
347     NULL,
348     NULL,
349     slavio_sysctrl_mem_readl,
350 };
351 
352 static CPUWriteMemoryFunc * const slavio_sysctrl_mem_write[3] = {
353     NULL,
354     NULL,
355     slavio_sysctrl_mem_writel,
356 };
357 
358 static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
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     MISC_DPRINTF("Read diagnostic LED %04x\n", ret);
371     return ret;
372 }
373 
374 static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
375                                   uint32_t val)
376 {
377     MiscState *s = opaque;
378 
379     MISC_DPRINTF("Write diagnostic LED %04x\n", val & 0xffff);
380     switch (addr) {
381     case 0:
382         s->leds = val;
383         break;
384     default:
385         break;
386     }
387 }
388 
389 static CPUReadMemoryFunc * const slavio_led_mem_read[3] = {
390     NULL,
391     slavio_led_mem_readw,
392     NULL,
393 };
394 
395 static CPUWriteMemoryFunc * const slavio_led_mem_write[3] = {
396     NULL,
397     slavio_led_mem_writew,
398     NULL,
399 };
400 
401 static const VMStateDescription vmstate_misc = {
402     .name ="slavio_misc",
403     .version_id = 1,
404     .minimum_version_id = 1,
405     .minimum_version_id_old = 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 int apc_init1(SysBusDevice *dev)
419 {
420     APCState *s = FROM_SYSBUS(APCState, dev);
421     int io;
422 
423     sysbus_init_irq(dev, &s->cpu_halt);
424 
425     /* Power management (APC) XXX: not a Slavio device */
426     io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s);
427     sysbus_init_mmio(dev, MISC_SIZE, io);
428     return 0;
429 }
430 
431 static int slavio_misc_init1(SysBusDevice *dev)
432 {
433     MiscState *s = FROM_SYSBUS(MiscState, dev);
434     int io;
435 
436     sysbus_init_irq(dev, &s->irq);
437     sysbus_init_irq(dev, &s->fdc_tc);
438 
439     /* 8 bit registers */
440     /* Slavio control */
441     io = cpu_register_io_memory(slavio_cfg_mem_read,
442                                 slavio_cfg_mem_write, s);
443     sysbus_init_mmio(dev, MISC_SIZE, io);
444 
445     /* Diagnostics */
446     io = cpu_register_io_memory(slavio_diag_mem_read,
447                                 slavio_diag_mem_write, s);
448     sysbus_init_mmio(dev, MISC_SIZE, io);
449 
450     /* Modem control */
451     io = cpu_register_io_memory(slavio_mdm_mem_read,
452                                 slavio_mdm_mem_write, s);
453     sysbus_init_mmio(dev, MISC_SIZE, io);
454 
455     /* 16 bit registers */
456     /* ss600mp diag LEDs */
457     io = cpu_register_io_memory(slavio_led_mem_read,
458                                 slavio_led_mem_write, s);
459     sysbus_init_mmio(dev, MISC_SIZE, io);
460 
461     /* 32 bit registers */
462     /* System control */
463     io = cpu_register_io_memory(slavio_sysctrl_mem_read,
464                                 slavio_sysctrl_mem_write, s);
465     sysbus_init_mmio(dev, SYSCTRL_SIZE, io);
466 
467     /* AUX 1 (Misc System Functions) */
468     io = cpu_register_io_memory(slavio_aux1_mem_read,
469                                 slavio_aux1_mem_write, s);
470     sysbus_init_mmio(dev, MISC_SIZE, io);
471 
472     /* AUX 2 (Software Powerdown Control) */
473     io = cpu_register_io_memory(slavio_aux2_mem_read,
474                                 slavio_aux2_mem_write, s);
475     sysbus_init_mmio(dev, MISC_SIZE, io);
476 
477     qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
478 
479     return 0;
480 }
481 
482 static SysBusDeviceInfo slavio_misc_info = {
483     .init = slavio_misc_init1,
484     .qdev.name  = "slavio_misc",
485     .qdev.size  = sizeof(MiscState),
486     .qdev.vmsd  = &vmstate_misc,
487     .qdev.reset  = slavio_misc_reset,
488 };
489 
490 static SysBusDeviceInfo apc_info = {
491     .init = apc_init1,
492     .qdev.name  = "apc",
493     .qdev.size  = sizeof(MiscState),
494 };
495 
496 static void slavio_misc_register_devices(void)
497 {
498     sysbus_register_withprop(&slavio_misc_info);
499     sysbus_register_withprop(&apc_info);
500 }
501 
502 device_init(slavio_misc_register_devices)
503