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