|
|
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;
47: uint8_t diag, mctrl;
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:
67: // Diagnostic register not cleared in reset
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);
119: if (val & 1)
120: qemu_system_reset_request();
121: break;
122: case 0xa000000:
123: MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
124: #if 0
125: // XXX: halting CPU does not work
126: raise_exception(EXCP_HLT);
127: cpu_loop_exit();
128: #endif
129: break;
130: }
131: }
132:
133: static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
134: {
135: MiscState *s = opaque;
136: uint32_t ret = 0;
137:
138: switch (addr & 0xfff0000) {
139: case 0x1800000:
140: ret = s->config;
141: MISC_DPRINTF("Read config %2.2x\n", ret);
142: break;
143: case 0x1900000:
144: ret = s->aux1;
145: MISC_DPRINTF("Read aux1 %2.2x\n", ret);
146: break;
147: case 0x1910000:
148: ret = s->aux2;
149: MISC_DPRINTF("Read aux2 %2.2x\n", ret);
150: break;
151: case 0x1a00000:
152: ret = s->diag;
153: MISC_DPRINTF("Read diag %2.2x\n", ret);
154: break;
155: case 0x1b00000:
156: ret = s->mctrl;
157: MISC_DPRINTF("Read modem control %2.2x\n", ret);
158: break;
159: case 0x1f00000:
160: MISC_DPRINTF("Read system control %2.2x\n", ret);
161: break;
162: case 0xa000000:
163: MISC_DPRINTF("Read power management %2.2x\n", ret);
164: break;
165: }
166: return ret;
167: }
168:
169: static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
170: slavio_misc_mem_readb,
171: slavio_misc_mem_readb,
172: slavio_misc_mem_readb,
173: };
174:
175: static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
176: slavio_misc_mem_writeb,
177: slavio_misc_mem_writeb,
178: slavio_misc_mem_writeb,
179: };
180:
181: static void slavio_misc_save(QEMUFile *f, void *opaque)
182: {
183: MiscState *s = opaque;
184:
185: qemu_put_be32s(f, &s->irq);
186: qemu_put_8s(f, &s->config);
187: qemu_put_8s(f, &s->aux1);
188: qemu_put_8s(f, &s->aux2);
189: qemu_put_8s(f, &s->diag);
190: qemu_put_8s(f, &s->mctrl);
191: }
192:
193: static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
194: {
195: MiscState *s = opaque;
196:
197: if (version_id != 1)
198: return -EINVAL;
199:
200: qemu_get_be32s(f, &s->irq);
201: qemu_get_8s(f, &s->config);
202: qemu_get_8s(f, &s->aux1);
203: qemu_get_8s(f, &s->aux2);
204: qemu_get_8s(f, &s->diag);
205: qemu_get_8s(f, &s->mctrl);
206: return 0;
207: }
208:
209: void *slavio_misc_init(uint32_t base, int irq)
210: {
211: int slavio_misc_io_memory;
212: MiscState *s;
213:
214: s = qemu_mallocz(sizeof(MiscState));
215: if (!s)
216: return NULL;
217:
218: slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s);
219: // Slavio control
220: cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory);
221: // AUX 1
222: cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory);
223: // AUX 2
224: cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory);
225: // Diagnostics
226: cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory);
227: // Modem control
228: cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory);
229: // System control
230: cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory);
231: // Power management
232: cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory);
233:
234: s->irq = irq;
235:
236: register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s);
237: qemu_register_reset(slavio_misc_reset, s);
238: slavio_misc_reset(s);
239: return s;
240: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.