]> git.proxmox.com Git - qemu.git/blob - hw/slavio_misc.c
Add SPARCserver 600MP emulation (original patch by Robert Reif)
[qemu.git] / hw / slavio_misc.c
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 qemu_irq irq;
45 uint8_t config;
46 uint8_t aux1, aux2;
47 uint8_t diag, mctrl;
48 uint32_t sysctrl;
49 uint16_t leds;
50 } MiscState;
51
52 #define MISC_SIZE 1
53 #define SYSCTRL_MAXADDR 3
54 #define SYSCTRL_SIZE (SYSCTRL_MAXADDR + 1)
55 #define LED_MAXADDR 2
56 #define LED_SIZE (LED_MAXADDR + 1)
57
58 static void slavio_misc_update_irq(void *opaque)
59 {
60 MiscState *s = opaque;
61
62 if ((s->aux2 & 0x4) && (s->config & 0x8)) {
63 MISC_DPRINTF("Raise IRQ\n");
64 qemu_irq_raise(s->irq);
65 } else {
66 MISC_DPRINTF("Lower IRQ\n");
67 qemu_irq_lower(s->irq);
68 }
69 }
70
71 static void slavio_misc_reset(void *opaque)
72 {
73 MiscState *s = opaque;
74
75 // Diagnostic and system control registers not cleared in reset
76 s->config = s->aux1 = s->aux2 = s->mctrl = 0;
77 }
78
79 void slavio_set_power_fail(void *opaque, int power_failing)
80 {
81 MiscState *s = opaque;
82
83 MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
84 if (power_failing && (s->config & 0x8)) {
85 s->aux2 |= 0x4;
86 } else {
87 s->aux2 &= ~0x4;
88 }
89 slavio_misc_update_irq(s);
90 }
91
92 static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr,
93 uint32_t val)
94 {
95 MiscState *s = opaque;
96
97 switch (addr & 0xfff0000) {
98 case 0x1800000:
99 MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
100 s->config = val & 0xff;
101 slavio_misc_update_irq(s);
102 break;
103 case 0x1900000:
104 MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
105 s->aux1 = val & 0xff;
106 break;
107 case 0x1910000:
108 val &= 0x3;
109 MISC_DPRINTF("Write aux2 %2.2x\n", val);
110 val |= s->aux2 & 0x4;
111 if (val & 0x2) // Clear Power Fail int
112 val &= 0x1;
113 s->aux2 = val;
114 if (val & 1)
115 qemu_system_shutdown_request();
116 slavio_misc_update_irq(s);
117 break;
118 case 0x1a00000:
119 MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
120 s->diag = val & 0xff;
121 break;
122 case 0x1b00000:
123 MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
124 s->mctrl = val & 0xff;
125 break;
126 case 0xa000000:
127 MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
128 cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
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 0xa000000:
160 MISC_DPRINTF("Read power management %2.2x\n", ret);
161 break;
162 }
163 return ret;
164 }
165
166 static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
167 slavio_misc_mem_readb,
168 slavio_misc_mem_readb,
169 slavio_misc_mem_readb,
170 };
171
172 static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
173 slavio_misc_mem_writeb,
174 slavio_misc_mem_writeb,
175 slavio_misc_mem_writeb,
176 };
177
178 static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
179 {
180 MiscState *s = opaque;
181 uint32_t ret = 0, saddr;
182
183 saddr = addr & SYSCTRL_MAXADDR;
184 switch (saddr) {
185 case 0:
186 ret = s->sysctrl;
187 break;
188 default:
189 break;
190 }
191 MISC_DPRINTF("Read system control reg 0x" TARGET_FMT_plx " = %x\n", addr,
192 ret);
193 return ret;
194 }
195
196 static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
197 uint32_t val)
198 {
199 MiscState *s = opaque;
200 uint32_t saddr;
201
202 saddr = addr & SYSCTRL_MAXADDR;
203 MISC_DPRINTF("Write system control reg 0x" TARGET_FMT_plx " = %x\n", addr,
204 val);
205 switch (saddr) {
206 case 0:
207 if (val & 1) {
208 s->sysctrl = 0x2;
209 qemu_system_reset_request();
210 }
211 break;
212 default:
213 break;
214 }
215 }
216
217 static CPUReadMemoryFunc *slavio_sysctrl_mem_read[3] = {
218 slavio_sysctrl_mem_readl,
219 slavio_sysctrl_mem_readl,
220 slavio_sysctrl_mem_readl,
221 };
222
223 static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = {
224 slavio_sysctrl_mem_writel,
225 slavio_sysctrl_mem_writel,
226 slavio_sysctrl_mem_writel,
227 };
228
229 static uint32_t slavio_led_mem_reads(void *opaque, target_phys_addr_t addr)
230 {
231 MiscState *s = opaque;
232 uint32_t ret = 0, saddr;
233
234 saddr = addr & LED_MAXADDR;
235 switch (saddr) {
236 case 0:
237 ret = s->leds;
238 break;
239 default:
240 break;
241 }
242 MISC_DPRINTF("Read diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr,
243 ret);
244 return ret;
245 }
246
247 static void slavio_led_mem_writes(void *opaque, target_phys_addr_t addr,
248 uint32_t val)
249 {
250 MiscState *s = opaque;
251 uint32_t saddr;
252
253 saddr = addr & LED_MAXADDR;
254 MISC_DPRINTF("Write diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr,
255 val);
256 switch (saddr) {
257 case 0:
258 s->sysctrl = val;
259 break;
260 default:
261 break;
262 }
263 }
264
265 static CPUReadMemoryFunc *slavio_led_mem_read[3] = {
266 slavio_led_mem_reads,
267 slavio_led_mem_reads,
268 slavio_led_mem_reads,
269 };
270
271 static CPUWriteMemoryFunc *slavio_led_mem_write[3] = {
272 slavio_led_mem_writes,
273 slavio_led_mem_writes,
274 slavio_led_mem_writes,
275 };
276
277 static void slavio_misc_save(QEMUFile *f, void *opaque)
278 {
279 MiscState *s = opaque;
280 int tmp;
281 uint8_t tmp8;
282
283 tmp = 0;
284 qemu_put_be32s(f, &tmp); /* ignored, was IRQ. */
285 qemu_put_8s(f, &s->config);
286 qemu_put_8s(f, &s->aux1);
287 qemu_put_8s(f, &s->aux2);
288 qemu_put_8s(f, &s->diag);
289 qemu_put_8s(f, &s->mctrl);
290 tmp8 = s->sysctrl & 0xff;
291 qemu_put_8s(f, &tmp8);
292 }
293
294 static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
295 {
296 MiscState *s = opaque;
297 int tmp;
298 uint8_t tmp8;
299
300 if (version_id != 1)
301 return -EINVAL;
302
303 qemu_get_be32s(f, &tmp);
304 qemu_get_8s(f, &s->config);
305 qemu_get_8s(f, &s->aux1);
306 qemu_get_8s(f, &s->aux2);
307 qemu_get_8s(f, &s->diag);
308 qemu_get_8s(f, &s->mctrl);
309 qemu_get_8s(f, &tmp8);
310 s->sysctrl = (uint32_t)tmp8;
311 return 0;
312 }
313
314 void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base,
315 qemu_irq irq)
316 {
317 int slavio_misc_io_memory;
318 MiscState *s;
319
320 s = qemu_mallocz(sizeof(MiscState));
321 if (!s)
322 return NULL;
323
324 /* 8 bit registers */
325 slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read,
326 slavio_misc_mem_write, s);
327 // Slavio control
328 cpu_register_physical_memory(base + 0x1800000, MISC_SIZE,
329 slavio_misc_io_memory);
330 // AUX 1
331 cpu_register_physical_memory(base + 0x1900000, MISC_SIZE,
332 slavio_misc_io_memory);
333 // AUX 2
334 cpu_register_physical_memory(base + 0x1910000, MISC_SIZE,
335 slavio_misc_io_memory);
336 // Diagnostics
337 cpu_register_physical_memory(base + 0x1a00000, MISC_SIZE,
338 slavio_misc_io_memory);
339 // Modem control
340 cpu_register_physical_memory(base + 0x1b00000, MISC_SIZE,
341 slavio_misc_io_memory);
342 // Power management
343 cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory);
344
345 /* 16 bit registers */
346 slavio_misc_io_memory = cpu_register_io_memory(0, slavio_led_mem_read,
347 slavio_led_mem_write, s);
348 /* ss600mp diag LEDs */
349 cpu_register_physical_memory(base + 0x1600000, MISC_SIZE,
350 slavio_misc_io_memory);
351
352 /* 32 bit registers */
353 slavio_misc_io_memory = cpu_register_io_memory(0, slavio_sysctrl_mem_read,
354 slavio_sysctrl_mem_write,
355 s);
356 // System control
357 cpu_register_physical_memory(base + 0x1f00000, SYSCTRL_SIZE,
358 slavio_misc_io_memory);
359
360 s->irq = irq;
361
362 register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load,
363 s);
364 qemu_register_reset(slavio_misc_reset, s);
365 slavio_misc_reset(s);
366 return s;
367 }