|
|
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.4 ! root 24: #include "hw.h"
! 25: #include "sun4m.h"
! 26: #include "sysemu.h"
! 27:
1.1 root 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, args...) \
41: do { printf("MISC: " fmt , ##args); } while (0)
42: #else
43: #define MISC_DPRINTF(fmt, args...)
44: #endif
45:
46: typedef struct MiscState {
1.1.1.4 ! root 47: qemu_irq irq;
1.1 root 48: uint8_t config;
49: uint8_t aux1, aux2;
1.1.1.4 ! root 50: uint8_t diag, mctrl;
! 51: uint32_t sysctrl;
! 52: uint16_t leds;
! 53: target_phys_addr_t power_base;
1.1 root 54: } MiscState;
55:
1.1.1.4 ! root 56: #define MISC_SIZE 1
! 57: #define SYSCTRL_MAXADDR 3
! 58: #define SYSCTRL_SIZE (SYSCTRL_MAXADDR + 1)
! 59: #define LED_MAXADDR 1
! 60: #define LED_SIZE (LED_MAXADDR + 1)
! 61:
! 62: #define MISC_MASK 0x0fff0000
! 63: #define MISC_LEDS 0x01600000
! 64: #define MISC_CFG 0x01800000
! 65: #define MISC_AUX1 0x01900000
! 66: #define MISC_AUX2 0x01910000
! 67: #define MISC_DIAG 0x01a00000
! 68: #define MISC_MDM 0x01b00000
! 69: #define MISC_SYS 0x01f00000
! 70:
! 71: #define AUX2_PWROFF 0x01
! 72: #define AUX2_PWRINTCLR 0x02
! 73: #define AUX2_PWRFAIL 0x20
! 74:
! 75: #define CFG_PWRINTEN 0x08
! 76:
! 77: #define SYS_RESET 0x01
! 78: #define SYS_RESETSTAT 0x02
1.1 root 79:
80: static void slavio_misc_update_irq(void *opaque)
81: {
82: MiscState *s = opaque;
83:
1.1.1.4 ! root 84: if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
! 85: MISC_DPRINTF("Raise IRQ\n");
! 86: qemu_irq_raise(s->irq);
1.1 root 87: } else {
1.1.1.4 ! root 88: MISC_DPRINTF("Lower IRQ\n");
! 89: qemu_irq_lower(s->irq);
1.1 root 90: }
91: }
92:
93: static void slavio_misc_reset(void *opaque)
94: {
95: MiscState *s = opaque;
96:
1.1.1.2 root 97: // Diagnostic and system control registers not cleared in reset
1.1 root 98: s->config = s->aux1 = s->aux2 = s->mctrl = 0;
99: }
100:
101: void slavio_set_power_fail(void *opaque, int power_failing)
102: {
103: MiscState *s = opaque;
104:
105: MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
1.1.1.4 ! root 106: if (power_failing && (s->config & CFG_PWRINTEN)) {
! 107: s->aux2 |= AUX2_PWRFAIL;
1.1 root 108: } else {
1.1.1.4 ! root 109: s->aux2 &= ~AUX2_PWRFAIL;
1.1 root 110: }
111: slavio_misc_update_irq(s);
112: }
113:
1.1.1.4 ! root 114: static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr,
! 115: uint32_t val)
1.1 root 116: {
117: MiscState *s = opaque;
118:
1.1.1.4 ! root 119: switch (addr & MISC_MASK) {
! 120: case MISC_CFG:
! 121: MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
! 122: s->config = val & 0xff;
! 123: slavio_misc_update_irq(s);
! 124: break;
! 125: case MISC_AUX1:
! 126: MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
! 127: s->aux1 = val & 0xff;
! 128: break;
! 129: case MISC_AUX2:
! 130: val &= AUX2_PWRINTCLR | AUX2_PWROFF;
! 131: MISC_DPRINTF("Write aux2 %2.2x\n", val);
! 132: val |= s->aux2 & AUX2_PWRFAIL;
! 133: if (val & AUX2_PWRINTCLR) // Clear Power Fail int
! 134: val &= AUX2_PWROFF;
! 135: s->aux2 = val;
! 136: if (val & AUX2_PWROFF)
! 137: qemu_system_shutdown_request();
! 138: slavio_misc_update_irq(s);
! 139: break;
! 140: case MISC_DIAG:
! 141: MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
! 142: s->diag = val & 0xff;
! 143: break;
! 144: case MISC_MDM:
! 145: MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
! 146: s->mctrl = val & 0xff;
! 147: break;
! 148: default:
! 149: if (addr == s->power_base) {
! 150: MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
! 151: cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
! 152: }
! 153: break;
1.1 root 154: }
155: }
156:
157: static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
158: {
159: MiscState *s = opaque;
160: uint32_t ret = 0;
161:
1.1.1.4 ! root 162: switch (addr & MISC_MASK) {
! 163: case MISC_CFG:
! 164: ret = s->config;
! 165: MISC_DPRINTF("Read config %2.2x\n", ret);
! 166: break;
! 167: case MISC_AUX1:
! 168: ret = s->aux1;
! 169: MISC_DPRINTF("Read aux1 %2.2x\n", ret);
! 170: break;
! 171: case MISC_AUX2:
! 172: ret = s->aux2;
! 173: MISC_DPRINTF("Read aux2 %2.2x\n", ret);
! 174: break;
! 175: case MISC_DIAG:
! 176: ret = s->diag;
! 177: MISC_DPRINTF("Read diag %2.2x\n", ret);
! 178: break;
! 179: case MISC_MDM:
! 180: ret = s->mctrl;
! 181: MISC_DPRINTF("Read modem control %2.2x\n", ret);
! 182: break;
! 183: default:
! 184: if (addr == s->power_base) {
! 185: MISC_DPRINTF("Read power management %2.2x\n", ret);
! 186: }
! 187: break;
1.1 root 188: }
189: return ret;
190: }
191:
192: static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
193: slavio_misc_mem_readb,
1.1.1.4 ! root 194: NULL,
! 195: NULL,
1.1 root 196: };
197:
198: static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
199: slavio_misc_mem_writeb,
1.1.1.4 ! root 200: NULL,
! 201: NULL,
! 202: };
! 203:
! 204: static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
! 205: {
! 206: MiscState *s = opaque;
! 207: uint32_t ret = 0, saddr;
! 208:
! 209: saddr = addr & SYSCTRL_MAXADDR;
! 210: switch (saddr) {
! 211: case 0:
! 212: ret = s->sysctrl;
! 213: break;
! 214: default:
! 215: break;
! 216: }
! 217: MISC_DPRINTF("Read system control reg 0x" TARGET_FMT_plx " = %x\n", addr,
! 218: ret);
! 219: return ret;
! 220: }
! 221:
! 222: static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
! 223: uint32_t val)
! 224: {
! 225: MiscState *s = opaque;
! 226: uint32_t saddr;
! 227:
! 228: saddr = addr & SYSCTRL_MAXADDR;
! 229: MISC_DPRINTF("Write system control reg 0x" TARGET_FMT_plx " = %x\n", addr,
! 230: val);
! 231: switch (saddr) {
! 232: case 0:
! 233: if (val & SYS_RESET) {
! 234: s->sysctrl = SYS_RESETSTAT;
! 235: qemu_system_reset_request();
! 236: }
! 237: break;
! 238: default:
! 239: break;
! 240: }
! 241: }
! 242:
! 243: static CPUReadMemoryFunc *slavio_sysctrl_mem_read[3] = {
! 244: NULL,
! 245: NULL,
! 246: slavio_sysctrl_mem_readl,
! 247: };
! 248:
! 249: static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = {
! 250: NULL,
! 251: NULL,
! 252: slavio_sysctrl_mem_writel,
! 253: };
! 254:
! 255: static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
! 256: {
! 257: MiscState *s = opaque;
! 258: uint32_t ret = 0, saddr;
! 259:
! 260: saddr = addr & LED_MAXADDR;
! 261: switch (saddr) {
! 262: case 0:
! 263: ret = s->leds;
! 264: break;
! 265: default:
! 266: break;
! 267: }
! 268: MISC_DPRINTF("Read diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr,
! 269: ret);
! 270: return ret;
! 271: }
! 272:
! 273: static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
! 274: uint32_t val)
! 275: {
! 276: MiscState *s = opaque;
! 277: uint32_t saddr;
! 278:
! 279: saddr = addr & LED_MAXADDR;
! 280: MISC_DPRINTF("Write diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr,
! 281: val);
! 282: switch (saddr) {
! 283: case 0:
! 284: s->leds = val;
! 285: break;
! 286: default:
! 287: break;
! 288: }
! 289: }
! 290:
! 291: static CPUReadMemoryFunc *slavio_led_mem_read[3] = {
! 292: NULL,
! 293: slavio_led_mem_readw,
! 294: NULL,
! 295: };
! 296:
! 297: static CPUWriteMemoryFunc *slavio_led_mem_write[3] = {
! 298: NULL,
! 299: slavio_led_mem_writew,
! 300: NULL,
1.1 root 301: };
302:
303: static void slavio_misc_save(QEMUFile *f, void *opaque)
304: {
305: MiscState *s = opaque;
1.1.1.4 ! root 306: int tmp;
! 307: uint8_t tmp8;
1.1 root 308:
1.1.1.4 ! root 309: tmp = 0;
! 310: qemu_put_be32s(f, &tmp); /* ignored, was IRQ. */
1.1 root 311: qemu_put_8s(f, &s->config);
312: qemu_put_8s(f, &s->aux1);
313: qemu_put_8s(f, &s->aux2);
314: qemu_put_8s(f, &s->diag);
315: qemu_put_8s(f, &s->mctrl);
1.1.1.4 ! root 316: tmp8 = s->sysctrl & 0xff;
! 317: qemu_put_8s(f, &tmp8);
1.1 root 318: }
319:
320: static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
321: {
322: MiscState *s = opaque;
1.1.1.4 ! root 323: int tmp;
! 324: uint8_t tmp8;
1.1 root 325:
326: if (version_id != 1)
327: return -EINVAL;
328:
1.1.1.4 ! root 329: qemu_get_be32s(f, &tmp);
1.1 root 330: qemu_get_8s(f, &s->config);
331: qemu_get_8s(f, &s->aux1);
332: qemu_get_8s(f, &s->aux2);
333: qemu_get_8s(f, &s->diag);
334: qemu_get_8s(f, &s->mctrl);
1.1.1.4 ! root 335: qemu_get_8s(f, &tmp8);
! 336: s->sysctrl = (uint32_t)tmp8;
1.1 root 337: return 0;
338: }
339:
1.1.1.4 ! root 340: void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base,
! 341: qemu_irq irq)
1.1 root 342: {
343: int slavio_misc_io_memory;
344: MiscState *s;
345:
346: s = qemu_mallocz(sizeof(MiscState));
347: if (!s)
348: return NULL;
349:
1.1.1.4 ! root 350: /* 8 bit registers */
! 351: slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read,
! 352: slavio_misc_mem_write, s);
1.1 root 353: // Slavio control
1.1.1.4 ! root 354: cpu_register_physical_memory(base + MISC_CFG, MISC_SIZE,
! 355: slavio_misc_io_memory);
1.1 root 356: // AUX 1
1.1.1.4 ! root 357: cpu_register_physical_memory(base + MISC_AUX1, MISC_SIZE,
! 358: slavio_misc_io_memory);
1.1 root 359: // AUX 2
1.1.1.4 ! root 360: cpu_register_physical_memory(base + MISC_AUX2, MISC_SIZE,
! 361: slavio_misc_io_memory);
1.1 root 362: // Diagnostics
1.1.1.4 ! root 363: cpu_register_physical_memory(base + MISC_DIAG, MISC_SIZE,
! 364: slavio_misc_io_memory);
1.1 root 365: // Modem control
1.1.1.4 ! root 366: cpu_register_physical_memory(base + MISC_MDM, MISC_SIZE,
! 367: slavio_misc_io_memory);
1.1 root 368: // Power management
1.1.1.4 ! root 369: cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory);
! 370: s->power_base = power_base;
! 371:
! 372: /* 16 bit registers */
! 373: slavio_misc_io_memory = cpu_register_io_memory(0, slavio_led_mem_read,
! 374: slavio_led_mem_write, s);
! 375: /* ss600mp diag LEDs */
! 376: cpu_register_physical_memory(base + MISC_LEDS, MISC_SIZE,
! 377: slavio_misc_io_memory);
! 378:
! 379: /* 32 bit registers */
! 380: slavio_misc_io_memory = cpu_register_io_memory(0, slavio_sysctrl_mem_read,
! 381: slavio_sysctrl_mem_write,
! 382: s);
! 383: // System control
! 384: cpu_register_physical_memory(base + MISC_SYS, SYSCTRL_SIZE,
! 385: slavio_misc_io_memory);
1.1 root 386:
387: s->irq = irq;
388:
1.1.1.4 ! root 389: register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load,
! 390: s);
1.1 root 391: qemu_register_reset(slavio_misc_reset, s);
392: slavio_misc_reset(s);
393: return s;
394: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.