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, sysctrl; 48 } MiscState; 49 50 #define MISC_SIZE 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 MISC_DPRINTF("Raise IRQ\n"); 58 qemu_irq_raise(s->irq); 59 } else { 60 MISC_DPRINTF("Lower IRQ\n"); 61 qemu_irq_lower(s->irq); 62 } 63 } 64 65 static void slavio_misc_reset(void *opaque) 66 { 67 MiscState *s = opaque; 68 69 // Diagnostic and system control registers not cleared in reset 70 s->config = s->aux1 = s->aux2 = s->mctrl = 0; 71 } 72 73 void slavio_set_power_fail(void *opaque, int power_failing) 74 { 75 MiscState *s = opaque; 76 77 MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config); 78 if (power_failing && (s->config & 0x8)) { 79 s->aux2 |= 0x4; 80 } else { 81 s->aux2 &= ~0x4; 82 } 83 slavio_misc_update_irq(s); 84 } 85 86 static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) 87 { 88 MiscState *s = opaque; 89 90 switch (addr & 0xfff0000) { 91 case 0x1800000: 92 MISC_DPRINTF("Write config %2.2x\n", val & 0xff); 93 s->config = val & 0xff; 94 slavio_misc_update_irq(s); 95 break; 96 case 0x1900000: 97 MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff); 98 s->aux1 = val & 0xff; 99 break; 100 case 0x1910000: 101 val &= 0x3; 102 MISC_DPRINTF("Write aux2 %2.2x\n", val); 103 val |= s->aux2 & 0x4; 104 if (val & 0x2) // Clear Power Fail int 105 val &= 0x1; 106 s->aux2 = val; 107 if (val & 1) 108 qemu_system_shutdown_request(); 109 slavio_misc_update_irq(s); 110 break; 111 case 0x1a00000: 112 MISC_DPRINTF("Write diag %2.2x\n", val & 0xff); 113 s->diag = val & 0xff; 114 break; 115 case 0x1b00000: 116 MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff); 117 s->mctrl = val & 0xff; 118 break; 119 case 0x1f00000: 120 MISC_DPRINTF("Write system control %2.2x\n", val & 0xff); 121 if (val & 1) { 122 s->sysctrl = 0x2; 123 qemu_system_reset_request(); 124 } 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 0x1f00000: 160 MISC_DPRINTF("Read system control %2.2x\n", ret); 161 ret = s->sysctrl; 162 break; 163 case 0xa000000: 164 MISC_DPRINTF("Read power management %2.2x\n", ret); 165 break; 166 } 167 return ret; 168 } 169 170 static CPUReadMemoryFunc *slavio_misc_mem_read[3] = { 171 slavio_misc_mem_readb, 172 slavio_misc_mem_readb, 173 slavio_misc_mem_readb, 174 }; 175 176 static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = { 177 slavio_misc_mem_writeb, 178 slavio_misc_mem_writeb, 179 slavio_misc_mem_writeb, 180 }; 181 182 static void slavio_misc_save(QEMUFile *f, void *opaque) 183 { 184 MiscState *s = opaque; 185 int tmp; 186 187 tmp = 0; 188 qemu_put_be32s(f, &tmp); /* ignored, was IRQ. */ 189 qemu_put_8s(f, &s->config); 190 qemu_put_8s(f, &s->aux1); 191 qemu_put_8s(f, &s->aux2); 192 qemu_put_8s(f, &s->diag); 193 qemu_put_8s(f, &s->mctrl); 194 qemu_put_8s(f, &s->sysctrl); 195 } 196 197 static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) 198 { 199 MiscState *s = opaque; 200 int tmp; 201 202 if (version_id != 1) 203 return -EINVAL; 204 205 qemu_get_be32s(f, &tmp); 206 qemu_get_8s(f, &s->config); 207 qemu_get_8s(f, &s->aux1); 208 qemu_get_8s(f, &s->aux2); 209 qemu_get_8s(f, &s->diag); 210 qemu_get_8s(f, &s->mctrl); 211 qemu_get_8s(f, &s->sysctrl); 212 return 0; 213 } 214 215 void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base, 216 qemu_irq irq) 217 { 218 int slavio_misc_io_memory; 219 MiscState *s; 220 221 s = qemu_mallocz(sizeof(MiscState)); 222 if (!s) 223 return NULL; 224 225 slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s); 226 // Slavio control 227 cpu_register_physical_memory(base + 0x1800000, MISC_SIZE, 228 slavio_misc_io_memory); 229 // AUX 1 230 cpu_register_physical_memory(base + 0x1900000, MISC_SIZE, 231 slavio_misc_io_memory); 232 // AUX 2 233 cpu_register_physical_memory(base + 0x1910000, MISC_SIZE, 234 slavio_misc_io_memory); 235 // Diagnostics 236 cpu_register_physical_memory(base + 0x1a00000, MISC_SIZE, 237 slavio_misc_io_memory); 238 // Modem control 239 cpu_register_physical_memory(base + 0x1b00000, MISC_SIZE, 240 slavio_misc_io_memory); 241 // System control 242 cpu_register_physical_memory(base + 0x1f00000, MISC_SIZE, 243 slavio_misc_io_memory); 244 // Power management 245 cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory); 246 247 s->irq = irq; 248 249 register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s); 250 qemu_register_reset(slavio_misc_reset, s); 251 slavio_misc_reset(s); 252 return s; 253 } 254