xref: /qemu/hw/misc/slavio_misc.c (revision 6a3b9cc9c5c52808435402a0b422e67f2ea9875c)
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 }
368