|
|
1.1 root 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: #include "vl.h"
25: /* debug misc */
26: //#define DEBUG_MISC
27:
28: /*
29: * This is the auxio port, chip control and system control part of
30: * chip STP2001 (Slave I/O), also produced as NCR89C105. See
31: * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
32: *
33: * This also includes the PMC CPU idle controller.
34: */
35:
36: #ifdef DEBUG_MISC
37: #define MISC_DPRINTF(fmt, args...) \
38: do { printf("MISC: " fmt , ##args); } while (0)
39: #else
40: #define MISC_DPRINTF(fmt, args...)
41: #endif
42:
43: typedef struct MiscState {
44: int irq;
45: uint8_t config;
46: uint8_t aux1, aux2;
1.1.1.2 ! root 47: uint8_t diag, mctrl, sysctrl;
1.1 root 48: } MiscState;
49:
50: #define MISC_MAXADDR 1
51:
52: static void slavio_misc_update_irq(void *opaque)
53: {
54: MiscState *s = opaque;
55:
56: if ((s->aux2 & 0x4) && (s->config & 0x8)) {
57: pic_set_irq(s->irq, 1);
58: } else {
59: pic_set_irq(s->irq, 0);
60: }
61: }
62:
63: static void slavio_misc_reset(void *opaque)
64: {
65: MiscState *s = opaque;
66:
1.1.1.2 ! root 67: // Diagnostic and system control registers not cleared in reset
1.1 root 68: s->config = s->aux1 = s->aux2 = s->mctrl = 0;
69: }
70:
71: void slavio_set_power_fail(void *opaque, int power_failing)
72: {
73: MiscState *s = opaque;
74:
75: MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
76: if (power_failing && (s->config & 0x8)) {
77: s->aux2 |= 0x4;
78: } else {
79: s->aux2 &= ~0x4;
80: }
81: slavio_misc_update_irq(s);
82: }
83:
84: static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
85: {
86: MiscState *s = opaque;
87:
88: switch (addr & 0xfff0000) {
89: case 0x1800000:
90: MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
91: s->config = val & 0xff;
92: slavio_misc_update_irq(s);
93: break;
94: case 0x1900000:
95: MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
96: s->aux1 = val & 0xff;
97: break;
98: case 0x1910000:
99: val &= 0x3;
100: MISC_DPRINTF("Write aux2 %2.2x\n", val);
101: val |= s->aux2 & 0x4;
102: if (val & 0x2) // Clear Power Fail int
103: val &= 0x1;
104: s->aux2 = val;
105: if (val & 1)
106: qemu_system_shutdown_request();
107: slavio_misc_update_irq(s);
108: break;
109: case 0x1a00000:
110: MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
111: s->diag = val & 0xff;
112: break;
113: case 0x1b00000:
114: MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
115: s->mctrl = val & 0xff;
116: break;
117: case 0x1f00000:
118: MISC_DPRINTF("Write system control %2.2x\n", val & 0xff);
1.1.1.2 ! root 119: if (val & 1) {
! 120: s->sysctrl = 0x2;
1.1 root 121: qemu_system_reset_request();
1.1.1.2 ! root 122: }
1.1 root 123: break;
124: case 0xa000000:
125: MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
126: #if 0
1.1.1.2 ! root 127: // XXX almost works
! 128: cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
1.1 root 129: #endif
130: break;
131: }
132: }
133:
134: static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
135: {
136: MiscState *s = opaque;
137: uint32_t ret = 0;
138:
139: switch (addr & 0xfff0000) {
140: case 0x1800000:
141: ret = s->config;
142: MISC_DPRINTF("Read config %2.2x\n", ret);
143: break;
144: case 0x1900000:
145: ret = s->aux1;
146: MISC_DPRINTF("Read aux1 %2.2x\n", ret);
147: break;
148: case 0x1910000:
149: ret = s->aux2;
150: MISC_DPRINTF("Read aux2 %2.2x\n", ret);
151: break;
152: case 0x1a00000:
153: ret = s->diag;
154: MISC_DPRINTF("Read diag %2.2x\n", ret);
155: break;
156: case 0x1b00000:
157: ret = s->mctrl;
158: MISC_DPRINTF("Read modem control %2.2x\n", ret);
159: break;
160: case 0x1f00000:
161: MISC_DPRINTF("Read system control %2.2x\n", ret);
1.1.1.2 ! root 162: ret = s->sysctrl;
1.1 root 163: break;
164: case 0xa000000:
165: MISC_DPRINTF("Read power management %2.2x\n", ret);
166: break;
167: }
168: return ret;
169: }
170:
171: static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
172: slavio_misc_mem_readb,
173: slavio_misc_mem_readb,
174: slavio_misc_mem_readb,
175: };
176:
177: static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
178: slavio_misc_mem_writeb,
179: slavio_misc_mem_writeb,
180: slavio_misc_mem_writeb,
181: };
182:
183: static void slavio_misc_save(QEMUFile *f, void *opaque)
184: {
185: MiscState *s = opaque;
186:
187: qemu_put_be32s(f, &s->irq);
188: qemu_put_8s(f, &s->config);
189: qemu_put_8s(f, &s->aux1);
190: qemu_put_8s(f, &s->aux2);
191: qemu_put_8s(f, &s->diag);
192: qemu_put_8s(f, &s->mctrl);
1.1.1.2 ! root 193: qemu_put_8s(f, &s->sysctrl);
1.1 root 194: }
195:
196: static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
197: {
198: MiscState *s = opaque;
199:
200: if (version_id != 1)
201: return -EINVAL;
202:
203: qemu_get_be32s(f, &s->irq);
204: qemu_get_8s(f, &s->config);
205: qemu_get_8s(f, &s->aux1);
206: qemu_get_8s(f, &s->aux2);
207: qemu_get_8s(f, &s->diag);
208: qemu_get_8s(f, &s->mctrl);
1.1.1.2 ! root 209: qemu_get_8s(f, &s->sysctrl);
1.1 root 210: return 0;
211: }
212:
213: void *slavio_misc_init(uint32_t base, int irq)
214: {
215: int slavio_misc_io_memory;
216: MiscState *s;
217:
218: s = qemu_mallocz(sizeof(MiscState));
219: if (!s)
220: return NULL;
221:
222: slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s);
223: // Slavio control
224: cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory);
225: // AUX 1
226: cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory);
227: // AUX 2
228: cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory);
229: // Diagnostics
230: cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory);
231: // Modem control
232: cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory);
233: // System control
234: cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory);
235: // Power management
236: cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory);
237:
238: s->irq = irq;
239:
240: register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s);
241: qemu_register_reset(slavio_misc_reset, s);
242: slavio_misc_reset(s);
243: return s;
244: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.