|
|
1.1 root 1: /*
2: * QEMU Sparc SLAVIO aux io port emulation
1.1.1.4 root 3: *
1.1 root 4: * Copyright (c) 2005 Fabrice Bellard
1.1.1.4 root 5: *
1.1 root 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: */
1.1.1.6 ! root 24:
1.1.1.4 root 25: #include "sun4m.h"
26: #include "sysemu.h"
1.1.1.6 ! root 27: #include "sysbus.h"
1.1.1.4 root 28:
1.1 root 29: /* debug misc */
30: //#define DEBUG_MISC
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: #ifdef DEBUG_MISC
1.1.1.6 ! root 41: #define MISC_DPRINTF(fmt, ...) \
! 42: do { printf("MISC: " fmt , ## __VA_ARGS__); } while (0)
1.1 root 43: #else
1.1.1.6 ! root 44: #define MISC_DPRINTF(fmt, ...)
1.1 root 45: #endif
46:
47: typedef struct MiscState {
1.1.1.6 ! root 48: SysBusDevice busdev;
1.1.1.4 root 49: qemu_irq irq;
1.1 root 50: uint8_t config;
51: uint8_t aux1, aux2;
1.1.1.4 root 52: uint8_t diag, mctrl;
53: uint32_t sysctrl;
54: uint16_t leds;
1.1.1.5 root 55: qemu_irq fdc_tc;
1.1 root 56: } MiscState;
57:
1.1.1.6 ! root 58: typedef struct APCState {
! 59: SysBusDevice busdev;
! 60: qemu_irq cpu_halt;
! 61: } APCState;
! 62:
1.1.1.4 root 63: #define MISC_SIZE 1
1.1.1.5 root 64: #define SYSCTRL_SIZE 4
1.1.1.4 root 65:
66: #define MISC_LEDS 0x01600000
67: #define MISC_CFG 0x01800000
68: #define MISC_DIAG 0x01a00000
69: #define MISC_MDM 0x01b00000
70: #define MISC_SYS 0x01f00000
71:
1.1.1.5 root 72: #define AUX1_TC 0x02
73:
1.1.1.4 root 74: #define AUX2_PWROFF 0x01
75: #define AUX2_PWRINTCLR 0x02
76: #define AUX2_PWRFAIL 0x20
77:
78: #define CFG_PWRINTEN 0x08
79:
80: #define SYS_RESET 0x01
81: #define SYS_RESETSTAT 0x02
1.1 root 82:
83: static void slavio_misc_update_irq(void *opaque)
84: {
85: MiscState *s = opaque;
86:
1.1.1.4 root 87: if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
88: MISC_DPRINTF("Raise IRQ\n");
89: qemu_irq_raise(s->irq);
1.1 root 90: } else {
1.1.1.4 root 91: MISC_DPRINTF("Lower IRQ\n");
92: qemu_irq_lower(s->irq);
1.1 root 93: }
94: }
95:
96: static void slavio_misc_reset(void *opaque)
97: {
98: MiscState *s = opaque;
99:
1.1.1.2 root 100: // Diagnostic and system control registers not cleared in reset
1.1 root 101: s->config = s->aux1 = s->aux2 = s->mctrl = 0;
102: }
103:
104: void slavio_set_power_fail(void *opaque, int power_failing)
105: {
106: MiscState *s = opaque;
107:
108: MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
1.1.1.4 root 109: if (power_failing && (s->config & CFG_PWRINTEN)) {
110: s->aux2 |= AUX2_PWRFAIL;
1.1 root 111: } else {
1.1.1.4 root 112: s->aux2 &= ~AUX2_PWRFAIL;
1.1 root 113: }
114: slavio_misc_update_irq(s);
115: }
116:
1.1.1.5 root 117: static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
118: uint32_t val)
119: {
120: MiscState *s = opaque;
121:
122: MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
123: s->config = val & 0xff;
124: slavio_misc_update_irq(s);
125: }
126:
127: static uint32_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr)
128: {
129: MiscState *s = opaque;
130: uint32_t ret = 0;
131:
132: ret = s->config;
133: MISC_DPRINTF("Read config %2.2x\n", ret);
134: return ret;
135: }
136:
137: static CPUReadMemoryFunc *slavio_cfg_mem_read[3] = {
138: slavio_cfg_mem_readb,
139: NULL,
140: NULL,
141: };
142:
143: static CPUWriteMemoryFunc *slavio_cfg_mem_write[3] = {
144: slavio_cfg_mem_writeb,
145: NULL,
146: NULL,
147: };
148:
149: static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
1.1.1.4 root 150: uint32_t val)
1.1 root 151: {
152: MiscState *s = opaque;
153:
1.1.1.5 root 154: MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
155: s->diag = val & 0xff;
1.1 root 156: }
157:
1.1.1.5 root 158: static uint32_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr)
1.1 root 159: {
160: MiscState *s = opaque;
161: uint32_t ret = 0;
162:
1.1.1.5 root 163: ret = s->diag;
164: MISC_DPRINTF("Read diag %2.2x\n", ret);
165: return ret;
166: }
167:
168: static CPUReadMemoryFunc *slavio_diag_mem_read[3] = {
169: slavio_diag_mem_readb,
170: NULL,
171: NULL,
172: };
173:
174: static CPUWriteMemoryFunc *slavio_diag_mem_write[3] = {
175: slavio_diag_mem_writeb,
176: NULL,
177: NULL,
178: };
179:
180: static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
181: uint32_t val)
182: {
183: MiscState *s = opaque;
184:
185: MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
186: s->mctrl = val & 0xff;
187: }
188:
189: static uint32_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr)
190: {
191: MiscState *s = opaque;
192: uint32_t ret = 0;
193:
194: ret = s->mctrl;
195: MISC_DPRINTF("Read modem control %2.2x\n", ret);
196: return ret;
197: }
198:
199: static CPUReadMemoryFunc *slavio_mdm_mem_read[3] = {
200: slavio_mdm_mem_readb,
201: NULL,
202: NULL,
203: };
204:
205: static CPUWriteMemoryFunc *slavio_mdm_mem_write[3] = {
206: slavio_mdm_mem_writeb,
207: NULL,
208: NULL,
209: };
210:
211: static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
212: uint32_t val)
213: {
214: MiscState *s = opaque;
215:
216: MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
217: if (val & AUX1_TC) {
218: // Send a pulse to floppy terminal count line
219: if (s->fdc_tc) {
220: qemu_irq_raise(s->fdc_tc);
221: qemu_irq_lower(s->fdc_tc);
1.1.1.4 root 222: }
1.1.1.5 root 223: val &= ~AUX1_TC;
1.1 root 224: }
1.1.1.5 root 225: s->aux1 = val & 0xff;
226: }
227:
228: static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr)
229: {
230: MiscState *s = opaque;
231: uint32_t ret = 0;
232:
233: ret = s->aux1;
234: MISC_DPRINTF("Read aux1 %2.2x\n", ret);
235:
1.1 root 236: return ret;
237: }
238:
1.1.1.5 root 239: static CPUReadMemoryFunc *slavio_aux1_mem_read[3] = {
240: slavio_aux1_mem_readb,
241: NULL,
242: NULL,
243: };
244:
245: static CPUWriteMemoryFunc *slavio_aux1_mem_write[3] = {
246: slavio_aux1_mem_writeb,
1.1.1.4 root 247: NULL,
248: NULL,
1.1 root 249: };
250:
1.1.1.5 root 251: static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
252: uint32_t val)
253: {
254: MiscState *s = opaque;
255:
256: val &= AUX2_PWRINTCLR | AUX2_PWROFF;
257: MISC_DPRINTF("Write aux2 %2.2x\n", val);
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();
264: slavio_misc_update_irq(s);
265: }
266:
267: static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr)
268: {
269: MiscState *s = opaque;
270: uint32_t ret = 0;
271:
272: ret = s->aux2;
273: MISC_DPRINTF("Read aux2 %2.2x\n", ret);
274:
275: return ret;
276: }
277:
278: static CPUReadMemoryFunc *slavio_aux2_mem_read[3] = {
279: slavio_aux2_mem_readb,
280: NULL,
281: NULL,
282: };
283:
284: static CPUWriteMemoryFunc *slavio_aux2_mem_write[3] = {
285: slavio_aux2_mem_writeb,
286: NULL,
287: NULL,
288: };
289:
290: static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
291: {
1.1.1.6 ! root 292: APCState *s = opaque;
1.1.1.5 root 293:
294: MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
295: qemu_irq_raise(s->cpu_halt);
296: }
297:
298: static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr)
299: {
300: uint32_t ret = 0;
301:
302: MISC_DPRINTF("Read power management %2.2x\n", ret);
303: return ret;
304: }
305:
306: static CPUReadMemoryFunc *apc_mem_read[3] = {
307: apc_mem_readb,
308: NULL,
309: NULL,
310: };
311:
312: static CPUWriteMemoryFunc *apc_mem_write[3] = {
313: apc_mem_writeb,
1.1.1.4 root 314: NULL,
315: NULL,
316: };
317:
318: static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
319: {
320: MiscState *s = opaque;
1.1.1.5 root 321: uint32_t ret = 0;
1.1.1.4 root 322:
1.1.1.5 root 323: switch (addr) {
1.1.1.4 root 324: case 0:
325: ret = s->sysctrl;
326: break;
327: default:
328: break;
329: }
1.1.1.5 root 330: MISC_DPRINTF("Read system control %08x\n", ret);
1.1.1.4 root 331: return ret;
332: }
333:
334: static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
335: uint32_t val)
336: {
337: MiscState *s = opaque;
338:
1.1.1.5 root 339: MISC_DPRINTF("Write system control %08x\n", val);
340: switch (addr) {
1.1.1.4 root 341: case 0:
342: if (val & SYS_RESET) {
343: s->sysctrl = SYS_RESETSTAT;
344: qemu_system_reset_request();
345: }
346: break;
347: default:
348: break;
349: }
350: }
351:
352: static CPUReadMemoryFunc *slavio_sysctrl_mem_read[3] = {
353: NULL,
354: NULL,
355: slavio_sysctrl_mem_readl,
356: };
357:
358: static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = {
359: NULL,
360: NULL,
361: slavio_sysctrl_mem_writel,
362: };
363:
364: static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
365: {
366: MiscState *s = opaque;
1.1.1.5 root 367: uint32_t ret = 0;
1.1.1.4 root 368:
1.1.1.5 root 369: switch (addr) {
1.1.1.4 root 370: case 0:
371: ret = s->leds;
372: break;
373: default:
374: break;
375: }
1.1.1.5 root 376: MISC_DPRINTF("Read diagnostic LED %04x\n", ret);
1.1.1.4 root 377: return ret;
378: }
379:
380: static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
381: uint32_t val)
382: {
383: MiscState *s = opaque;
384:
1.1.1.5 root 385: MISC_DPRINTF("Write diagnostic LED %04x\n", val & 0xffff);
386: switch (addr) {
1.1.1.4 root 387: case 0:
388: s->leds = val;
389: break;
390: default:
391: break;
392: }
393: }
394:
395: static CPUReadMemoryFunc *slavio_led_mem_read[3] = {
396: NULL,
397: slavio_led_mem_readw,
398: NULL,
399: };
400:
401: static CPUWriteMemoryFunc *slavio_led_mem_write[3] = {
402: NULL,
403: slavio_led_mem_writew,
404: NULL,
1.1 root 405: };
406:
407: static void slavio_misc_save(QEMUFile *f, void *opaque)
408: {
409: MiscState *s = opaque;
1.1.1.5 root 410: uint32_t tmp = 0;
1.1.1.4 root 411: uint8_t tmp8;
1.1 root 412:
1.1.1.4 root 413: qemu_put_be32s(f, &tmp); /* ignored, was IRQ. */
1.1 root 414: qemu_put_8s(f, &s->config);
415: qemu_put_8s(f, &s->aux1);
416: qemu_put_8s(f, &s->aux2);
417: qemu_put_8s(f, &s->diag);
418: qemu_put_8s(f, &s->mctrl);
1.1.1.4 root 419: tmp8 = s->sysctrl & 0xff;
420: qemu_put_8s(f, &tmp8);
1.1 root 421: }
422:
423: static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
424: {
425: MiscState *s = opaque;
1.1.1.5 root 426: uint32_t tmp;
1.1.1.4 root 427: uint8_t tmp8;
1.1 root 428:
429: if (version_id != 1)
430: return -EINVAL;
431:
1.1.1.4 root 432: qemu_get_be32s(f, &tmp);
1.1 root 433: qemu_get_8s(f, &s->config);
434: qemu_get_8s(f, &s->aux1);
435: qemu_get_8s(f, &s->aux2);
436: qemu_get_8s(f, &s->diag);
437: qemu_get_8s(f, &s->mctrl);
1.1.1.4 root 438: qemu_get_8s(f, &tmp8);
439: s->sysctrl = (uint32_t)tmp8;
1.1 root 440: return 0;
441: }
442:
1.1.1.6 ! root 443: void *slavio_misc_init(target_phys_addr_t base,
1.1.1.5 root 444: target_phys_addr_t aux1_base,
445: target_phys_addr_t aux2_base, qemu_irq irq,
1.1.1.6 ! root 446: qemu_irq fdc_tc)
1.1 root 447: {
1.1.1.6 ! root 448: DeviceState *dev;
! 449: SysBusDevice *s;
! 450: MiscState *d;
! 451:
! 452: dev = qdev_create(NULL, "slavio_misc");
! 453: qdev_init(dev);
! 454: s = sysbus_from_qdev(dev);
1.1.1.5 root 455: if (base) {
456: /* 8 bit registers */
1.1.1.6 ! root 457: /* Slavio control */
! 458: sysbus_mmio_map(s, 0, base + MISC_CFG);
! 459: /* Diagnostics */
! 460: sysbus_mmio_map(s, 1, base + MISC_DIAG);
! 461: /* Modem control */
! 462: sysbus_mmio_map(s, 2, base + MISC_MDM);
1.1.1.5 root 463: /* 16 bit registers */
464: /* ss600mp diag LEDs */
1.1.1.6 ! root 465: sysbus_mmio_map(s, 3, base + MISC_LEDS);
1.1.1.5 root 466: /* 32 bit registers */
1.1.1.6 ! root 467: /* System control */
! 468: sysbus_mmio_map(s, 4, base + MISC_SYS);
1.1.1.5 root 469: }
470: if (aux1_base) {
1.1.1.6 ! root 471: /* AUX 1 (Misc System Functions) */
! 472: sysbus_mmio_map(s, 5, aux1_base);
1.1.1.5 root 473: }
474: if (aux2_base) {
1.1.1.6 ! root 475: /* AUX 2 (Software Powerdown Control) */
! 476: sysbus_mmio_map(s, 6, aux2_base);
1.1.1.5 root 477: }
1.1.1.6 ! root 478: sysbus_connect_irq(s, 0, irq);
! 479: sysbus_connect_irq(s, 1, fdc_tc);
1.1.1.5 root 480:
1.1.1.6 ! root 481: d = FROM_SYSBUS(MiscState, s);
! 482:
! 483: return d;
! 484: }
! 485:
! 486: static void apc_init1(SysBusDevice *dev)
! 487: {
! 488: APCState *s = FROM_SYSBUS(APCState, dev);
! 489: int io;
1.1 root 490:
1.1.1.6 ! root 491: sysbus_init_irq(dev, &s->cpu_halt);
1.1 root 492:
1.1.1.6 ! root 493: /* Power management (APC) XXX: not a Slavio device */
! 494: io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s);
! 495: sysbus_init_mmio(dev, MISC_SIZE, io);
! 496: }
! 497:
! 498: void apc_init(target_phys_addr_t power_base, qemu_irq cpu_halt)
! 499: {
! 500: DeviceState *dev;
! 501: SysBusDevice *s;
! 502:
! 503: dev = qdev_create(NULL, "apc");
! 504: qdev_init(dev);
! 505: s = sysbus_from_qdev(dev);
! 506: /* Power management (APC) XXX: not a Slavio device */
! 507: sysbus_mmio_map(s, 0, power_base);
! 508: sysbus_connect_irq(s, 0, cpu_halt);
! 509: }
! 510:
! 511: static void slavio_misc_init1(SysBusDevice *dev)
! 512: {
! 513: MiscState *s = FROM_SYSBUS(MiscState, dev);
! 514: int io;
! 515:
! 516: sysbus_init_irq(dev, &s->irq);
! 517: sysbus_init_irq(dev, &s->fdc_tc);
! 518:
! 519: /* 8 bit registers */
! 520: /* Slavio control */
! 521: io = cpu_register_io_memory(slavio_cfg_mem_read,
! 522: slavio_cfg_mem_write, s);
! 523: sysbus_init_mmio(dev, MISC_SIZE, io);
! 524:
! 525: /* Diagnostics */
! 526: io = cpu_register_io_memory(slavio_diag_mem_read,
! 527: slavio_diag_mem_write, s);
! 528: sysbus_init_mmio(dev, MISC_SIZE, io);
! 529:
! 530: /* Modem control */
! 531: io = cpu_register_io_memory(slavio_mdm_mem_read,
! 532: slavio_mdm_mem_write, s);
! 533: sysbus_init_mmio(dev, MISC_SIZE, io);
! 534:
! 535: /* 16 bit registers */
! 536: /* ss600mp diag LEDs */
! 537: io = cpu_register_io_memory(slavio_led_mem_read,
! 538: slavio_led_mem_write, s);
! 539: sysbus_init_mmio(dev, MISC_SIZE, io);
! 540:
! 541: /* 32 bit registers */
! 542: /* System control */
! 543: io = cpu_register_io_memory(slavio_sysctrl_mem_read,
! 544: slavio_sysctrl_mem_write, s);
! 545: sysbus_init_mmio(dev, SYSCTRL_SIZE, io);
! 546:
! 547: /* AUX 1 (Misc System Functions) */
! 548: io = cpu_register_io_memory(slavio_aux1_mem_read,
! 549: slavio_aux1_mem_write, s);
! 550: sysbus_init_mmio(dev, MISC_SIZE, io);
! 551:
! 552: /* AUX 2 (Software Powerdown Control) */
! 553: io = cpu_register_io_memory(slavio_aux2_mem_read,
! 554: slavio_aux2_mem_write, s);
! 555: sysbus_init_mmio(dev, MISC_SIZE, io);
! 556:
! 557: register_savevm("slavio_misc", -1, 1, slavio_misc_save, slavio_misc_load,
1.1.1.4 root 558: s);
1.1 root 559: qemu_register_reset(slavio_misc_reset, s);
560: slavio_misc_reset(s);
1.1.1.6 ! root 561: }
! 562:
! 563: static SysBusDeviceInfo slavio_misc_info = {
! 564: .init = slavio_misc_init1,
! 565: .qdev.name = "slavio_misc",
! 566: .qdev.size = sizeof(MiscState),
! 567: };
1.1.1.5 root 568:
1.1.1.6 ! root 569: static SysBusDeviceInfo apc_info = {
! 570: .init = apc_init1,
! 571: .qdev.name = "apc",
! 572: .qdev.size = sizeof(MiscState),
! 573: };
! 574:
! 575: static void slavio_misc_register_devices(void)
! 576: {
! 577: sysbus_register_withprop(&slavio_misc_info);
! 578: sysbus_register_withprop(&apc_info);
1.1 root 579: }
1.1.1.6 ! root 580:
! 581: device_init(slavio_misc_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.