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