]> git.proxmox.com Git - mirror_qemu.git/blame - hw/slavio_misc.c
slavio_misc: convert configuration to memory API
[mirror_qemu.git] / hw / slavio_misc.c
CommitLineData
3475187d
FB
1/*
2 * QEMU Sparc SLAVIO aux io port emulation
5fafdf24 3 *
3475187d 4 * Copyright (c) 2005 Fabrice Bellard
5fafdf24 5 *
3475187d
FB
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 */
2582cfa0 24
87ecb68b 25#include "sysemu.h"
2582cfa0 26#include "sysbus.h"
97bf4851 27#include "trace.h"
3475187d
FB
28
29/*
30 * This is the auxio port, chip control and system control part of
31 * chip STP2001 (Slave I/O), also produced as NCR89C105. See
32 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
33 *
34 * This also includes the PMC CPU idle controller.
35 */
36
3475187d 37typedef struct MiscState {
2582cfa0 38 SysBusDevice busdev;
dd703aae 39 MemoryRegion cfg_iomem;
d537cf6c 40 qemu_irq irq;
97bbb109 41 qemu_irq fdc_tc;
d37adb09 42 uint32_t dummy;
3475187d
FB
43 uint8_t config;
44 uint8_t aux1, aux2;
bfa30a38 45 uint8_t diag, mctrl;
d37adb09 46 uint8_t sysctrl;
6a3b9cc9 47 uint16_t leds;
3475187d
FB
48} MiscState;
49
2582cfa0
BS
50typedef struct APCState {
51 SysBusDevice busdev;
9c48dee6 52 MemoryRegion iomem;
2582cfa0
BS
53 qemu_irq cpu_halt;
54} APCState;
55
5aca8c3b 56#define MISC_SIZE 1
a8f48dcc 57#define SYSCTRL_SIZE 4
3475187d 58
2be17ebd
BS
59#define AUX1_TC 0x02
60
7debeb82
BS
61#define AUX2_PWROFF 0x01
62#define AUX2_PWRINTCLR 0x02
63#define AUX2_PWRFAIL 0x20
64
65#define CFG_PWRINTEN 0x08
66
67#define SYS_RESET 0x01
68#define SYS_RESETSTAT 0x02
69
3475187d
FB
70static void slavio_misc_update_irq(void *opaque)
71{
72 MiscState *s = opaque;
73
7debeb82 74 if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
97bf4851 75 trace_slavio_misc_update_irq_raise();
d537cf6c 76 qemu_irq_raise(s->irq);
3475187d 77 } else {
97bf4851 78 trace_slavio_misc_update_irq_lower();
d537cf6c 79 qemu_irq_lower(s->irq);
3475187d
FB
80 }
81}
82
1795057a 83static void slavio_misc_reset(DeviceState *d)
3475187d 84{
1795057a 85 MiscState *s = container_of(d, MiscState, busdev.qdev);
3475187d 86
4e3b1ea1 87 // Diagnostic and system control registers not cleared in reset
3475187d
FB
88 s->config = s->aux1 = s->aux2 = s->mctrl = 0;
89}
90
b2b6f6ec 91static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
3475187d
FB
92{
93 MiscState *s = opaque;
94
97bf4851 95 trace_slavio_set_power_fail(power_failing, s->config);
7debeb82
BS
96 if (power_failing && (s->config & CFG_PWRINTEN)) {
97 s->aux2 |= AUX2_PWRFAIL;
3475187d 98 } else {
7debeb82 99 s->aux2 &= ~AUX2_PWRFAIL;
3475187d
FB
100 }
101 slavio_misc_update_irq(s);
102}
103
c227f099 104static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
dd703aae 105 uint64_t val, unsigned size)
a8f48dcc
BS
106{
107 MiscState *s = opaque;
108
97bf4851 109 trace_slavio_cfg_mem_writeb(val & 0xff);
a8f48dcc
BS
110 s->config = val & 0xff;
111 slavio_misc_update_irq(s);
112}
113
dd703aae
BC
114static uint64_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr,
115 unsigned size)
a8f48dcc
BS
116{
117 MiscState *s = opaque;
118 uint32_t ret = 0;
119
120 ret = s->config;
97bf4851 121 trace_slavio_cfg_mem_readb(ret);
a8f48dcc
BS
122 return ret;
123}
124
dd703aae
BC
125static const MemoryRegionOps slavio_cfg_mem_ops = {
126 .read = slavio_cfg_mem_readb,
127 .write = slavio_cfg_mem_writeb,
128 .endianness = DEVICE_NATIVE_ENDIAN,
129 .valid = {
130 .min_access_size = 1,
131 .max_access_size = 1,
132 },
a8f48dcc
BS
133};
134
c227f099 135static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
bfa30a38 136 uint32_t val)
3475187d
FB
137{
138 MiscState *s = opaque;
139
97bf4851 140 trace_slavio_diag_mem_writeb(val & 0xff);
a8f48dcc 141 s->diag = val & 0xff;
3475187d
FB
142}
143
c227f099 144static uint32_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr)
3475187d
FB
145{
146 MiscState *s = opaque;
147 uint32_t ret = 0;
148
a8f48dcc 149 ret = s->diag;
97bf4851 150 trace_slavio_diag_mem_readb(ret);
a8f48dcc
BS
151 return ret;
152}
153
d60efc6b 154static CPUReadMemoryFunc * const slavio_diag_mem_read[3] = {
a8f48dcc
BS
155 slavio_diag_mem_readb,
156 NULL,
157 NULL,
158};
159
d60efc6b 160static CPUWriteMemoryFunc * const slavio_diag_mem_write[3] = {
a8f48dcc
BS
161 slavio_diag_mem_writeb,
162 NULL,
163 NULL,
164};
165
c227f099 166static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
a8f48dcc
BS
167 uint32_t val)
168{
169 MiscState *s = opaque;
170
97bf4851 171 trace_slavio_mdm_mem_writeb(val & 0xff);
a8f48dcc
BS
172 s->mctrl = val & 0xff;
173}
174
c227f099 175static uint32_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr)
a8f48dcc
BS
176{
177 MiscState *s = opaque;
178 uint32_t ret = 0;
179
180 ret = s->mctrl;
97bf4851 181 trace_slavio_mdm_mem_readb(ret);
3475187d
FB
182 return ret;
183}
184
d60efc6b 185static CPUReadMemoryFunc * const slavio_mdm_mem_read[3] = {
a8f48dcc 186 slavio_mdm_mem_readb,
7c560456
BS
187 NULL,
188 NULL,
3475187d
FB
189};
190
d60efc6b 191static CPUWriteMemoryFunc * const slavio_mdm_mem_write[3] = {
a8f48dcc 192 slavio_mdm_mem_writeb,
7c560456
BS
193 NULL,
194 NULL,
3475187d
FB
195};
196
c227f099 197static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
0019ad53
BS
198 uint32_t val)
199{
200 MiscState *s = opaque;
201
97bf4851 202 trace_slavio_aux1_mem_writeb(val & 0xff);
2be17ebd
BS
203 if (val & AUX1_TC) {
204 // Send a pulse to floppy terminal count line
205 if (s->fdc_tc) {
206 qemu_irq_raise(s->fdc_tc);
207 qemu_irq_lower(s->fdc_tc);
208 }
209 val &= ~AUX1_TC;
210 }
0019ad53
BS
211 s->aux1 = val & 0xff;
212}
213
c227f099 214static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr)
0019ad53
BS
215{
216 MiscState *s = opaque;
217 uint32_t ret = 0;
218
219 ret = s->aux1;
97bf4851 220 trace_slavio_aux1_mem_readb(ret);
0019ad53
BS
221 return ret;
222}
223
d60efc6b 224static CPUReadMemoryFunc * const slavio_aux1_mem_read[3] = {
0019ad53
BS
225 slavio_aux1_mem_readb,
226 NULL,
227 NULL,
228};
229
d60efc6b 230static CPUWriteMemoryFunc * const slavio_aux1_mem_write[3] = {
0019ad53
BS
231 slavio_aux1_mem_writeb,
232 NULL,
233 NULL,
234};
235
c227f099 236static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
0019ad53
BS
237 uint32_t val)
238{
239 MiscState *s = opaque;
240
241 val &= AUX2_PWRINTCLR | AUX2_PWROFF;
97bf4851 242 trace_slavio_aux2_mem_writeb(val & 0xff);
0019ad53
BS
243 val |= s->aux2 & AUX2_PWRFAIL;
244 if (val & AUX2_PWRINTCLR) // Clear Power Fail int
245 val &= AUX2_PWROFF;
246 s->aux2 = val;
247 if (val & AUX2_PWROFF)
248 qemu_system_shutdown_request();
249 slavio_misc_update_irq(s);
250}
251
c227f099 252static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr)
0019ad53
BS
253{
254 MiscState *s = opaque;
255 uint32_t ret = 0;
256
257 ret = s->aux2;
97bf4851 258 trace_slavio_aux2_mem_readb(ret);
0019ad53
BS
259 return ret;
260}
261
d60efc6b 262static CPUReadMemoryFunc * const slavio_aux2_mem_read[3] = {
0019ad53
BS
263 slavio_aux2_mem_readb,
264 NULL,
265 NULL,
266};
267
d60efc6b 268static CPUWriteMemoryFunc * const slavio_aux2_mem_write[3] = {
0019ad53
BS
269 slavio_aux2_mem_writeb,
270 NULL,
271 NULL,
272};
273
9c48dee6
BC
274static void apc_mem_writeb(void *opaque, target_phys_addr_t addr,
275 uint64_t val, unsigned size)
0019ad53 276{
2582cfa0 277 APCState *s = opaque;
0019ad53 278
97bf4851 279 trace_apc_mem_writeb(val & 0xff);
6d0c293d 280 qemu_irq_raise(s->cpu_halt);
0019ad53
BS
281}
282
9c48dee6
BC
283static uint64_t apc_mem_readb(void *opaque, target_phys_addr_t addr,
284 unsigned size)
0019ad53
BS
285{
286 uint32_t ret = 0;
287
97bf4851 288 trace_apc_mem_readb(ret);
0019ad53
BS
289 return ret;
290}
291
9c48dee6
BC
292static const MemoryRegionOps apc_mem_ops = {
293 .read = apc_mem_readb,
294 .write = apc_mem_writeb,
295 .endianness = DEVICE_NATIVE_ENDIAN,
296 .valid = {
297 .min_access_size = 1,
298 .max_access_size = 1,
299 }
0019ad53
BS
300};
301
c227f099 302static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
bfa30a38
BS
303{
304 MiscState *s = opaque;
a8f48dcc 305 uint32_t ret = 0;
bfa30a38 306
a8f48dcc 307 switch (addr) {
bfa30a38
BS
308 case 0:
309 ret = s->sysctrl;
310 break;
311 default:
312 break;
313 }
97bf4851 314 trace_slavio_sysctrl_mem_readl(ret);
bfa30a38
BS
315 return ret;
316}
317
c227f099 318static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
bfa30a38
BS
319 uint32_t val)
320{
321 MiscState *s = opaque;
bfa30a38 322
97bf4851 323 trace_slavio_sysctrl_mem_writel(val);
a8f48dcc 324 switch (addr) {
bfa30a38 325 case 0:
7debeb82
BS
326 if (val & SYS_RESET) {
327 s->sysctrl = SYS_RESETSTAT;
bfa30a38
BS
328 qemu_system_reset_request();
329 }
330 break;
331 default:
332 break;
333 }
334}
335
d60efc6b 336static CPUReadMemoryFunc * const slavio_sysctrl_mem_read[3] = {
7c560456
BS
337 NULL,
338 NULL,
bfa30a38
BS
339 slavio_sysctrl_mem_readl,
340};
341
d60efc6b 342static CPUWriteMemoryFunc * const slavio_sysctrl_mem_write[3] = {
7c560456
BS
343 NULL,
344 NULL,
bfa30a38
BS
345 slavio_sysctrl_mem_writel,
346};
347
c227f099 348static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
6a3b9cc9
BS
349{
350 MiscState *s = opaque;
a8f48dcc 351 uint32_t ret = 0;
6a3b9cc9 352
a8f48dcc 353 switch (addr) {
6a3b9cc9
BS
354 case 0:
355 ret = s->leds;
356 break;
357 default:
358 break;
359 }
97bf4851 360 trace_slavio_led_mem_readw(ret);
6a3b9cc9
BS
361 return ret;
362}
363
c227f099 364static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
6a3b9cc9
BS
365 uint32_t val)
366{
367 MiscState *s = opaque;
6a3b9cc9 368
97bf4851 369 trace_slavio_led_mem_readw(val & 0xffff);
a8f48dcc 370 switch (addr) {
6a3b9cc9 371 case 0:
d5296cb5 372 s->leds = val;
6a3b9cc9
BS
373 break;
374 default:
375 break;
376 }
377}
378
d60efc6b 379static CPUReadMemoryFunc * const slavio_led_mem_read[3] = {
7c560456
BS
380 NULL,
381 slavio_led_mem_readw,
382 NULL,
6a3b9cc9
BS
383};
384
d60efc6b 385static CPUWriteMemoryFunc * const slavio_led_mem_write[3] = {
7c560456
BS
386 NULL,
387 slavio_led_mem_writew,
388 NULL,
6a3b9cc9
BS
389};
390
d37adb09
BS
391static const VMStateDescription vmstate_misc = {
392 .name ="slavio_misc",
393 .version_id = 1,
394 .minimum_version_id = 1,
395 .minimum_version_id_old = 1,
396 .fields = (VMStateField []) {
397 VMSTATE_UINT32(dummy, MiscState),
398 VMSTATE_UINT8(config, MiscState),
399 VMSTATE_UINT8(aux1, MiscState),
400 VMSTATE_UINT8(aux2, MiscState),
401 VMSTATE_UINT8(diag, MiscState),
402 VMSTATE_UINT8(mctrl, MiscState),
403 VMSTATE_UINT8(sysctrl, MiscState),
404 VMSTATE_END_OF_LIST()
405 }
406};
3475187d 407
81a322d4 408static int apc_init1(SysBusDevice *dev)
2582cfa0
BS
409{
410 APCState *s = FROM_SYSBUS(APCState, dev);
3475187d 411
2582cfa0
BS
412 sysbus_init_irq(dev, &s->cpu_halt);
413
414 /* Power management (APC) XXX: not a Slavio device */
9c48dee6
BC
415 memory_region_init_io(&s->iomem, &apc_mem_ops, s,
416 "apc", MISC_SIZE);
417 sysbus_init_mmio_region(dev, &s->iomem);
81a322d4 418 return 0;
2582cfa0
BS
419}
420
81a322d4 421static int slavio_misc_init1(SysBusDevice *dev)
2582cfa0
BS
422{
423 MiscState *s = FROM_SYSBUS(MiscState, dev);
424 int io;
425
426 sysbus_init_irq(dev, &s->irq);
427 sysbus_init_irq(dev, &s->fdc_tc);
428
429 /* 8 bit registers */
430 /* Slavio control */
dd703aae
BC
431 memory_region_init_io(&s->cfg_iomem, &slavio_cfg_mem_ops, s,
432 "configuration", MISC_SIZE);
433 sysbus_init_mmio_region(dev, &s->cfg_iomem);
2582cfa0
BS
434
435 /* Diagnostics */
436 io = cpu_register_io_memory(slavio_diag_mem_read,
2507c12a
AG
437 slavio_diag_mem_write, s,
438 DEVICE_NATIVE_ENDIAN);
2582cfa0
BS
439 sysbus_init_mmio(dev, MISC_SIZE, io);
440
441 /* Modem control */
442 io = cpu_register_io_memory(slavio_mdm_mem_read,
2507c12a
AG
443 slavio_mdm_mem_write, s,
444 DEVICE_NATIVE_ENDIAN);
2582cfa0
BS
445 sysbus_init_mmio(dev, MISC_SIZE, io);
446
447 /* 16 bit registers */
448 /* ss600mp diag LEDs */
449 io = cpu_register_io_memory(slavio_led_mem_read,
2507c12a
AG
450 slavio_led_mem_write, s,
451 DEVICE_NATIVE_ENDIAN);
2582cfa0
BS
452 sysbus_init_mmio(dev, MISC_SIZE, io);
453
454 /* 32 bit registers */
455 /* System control */
456 io = cpu_register_io_memory(slavio_sysctrl_mem_read,
2507c12a
AG
457 slavio_sysctrl_mem_write, s,
458 DEVICE_NATIVE_ENDIAN);
2582cfa0
BS
459 sysbus_init_mmio(dev, SYSCTRL_SIZE, io);
460
461 /* AUX 1 (Misc System Functions) */
462 io = cpu_register_io_memory(slavio_aux1_mem_read,
2507c12a
AG
463 slavio_aux1_mem_write, s,
464 DEVICE_NATIVE_ENDIAN);
2582cfa0
BS
465 sysbus_init_mmio(dev, MISC_SIZE, io);
466
467 /* AUX 2 (Software Powerdown Control) */
468 io = cpu_register_io_memory(slavio_aux2_mem_read,
2507c12a
AG
469 slavio_aux2_mem_write, s,
470 DEVICE_NATIVE_ENDIAN);
2582cfa0
BS
471 sysbus_init_mmio(dev, MISC_SIZE, io);
472
b2b6f6ec
BS
473 qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
474
81a322d4 475 return 0;
2582cfa0 476}
0019ad53 477
2582cfa0
BS
478static SysBusDeviceInfo slavio_misc_info = {
479 .init = slavio_misc_init1,
480 .qdev.name = "slavio_misc",
481 .qdev.size = sizeof(MiscState),
1795057a
BS
482 .qdev.vmsd = &vmstate_misc,
483 .qdev.reset = slavio_misc_reset,
2582cfa0
BS
484};
485
486static SysBusDeviceInfo apc_info = {
487 .init = apc_init1,
488 .qdev.name = "apc",
489 .qdev.size = sizeof(MiscState),
2582cfa0
BS
490};
491
492static void slavio_misc_register_devices(void)
493{
494 sysbus_register_withprop(&slavio_misc_info);
495 sysbus_register_withprop(&apc_info);
3475187d 496}
2582cfa0
BS
497
498device_init(slavio_misc_register_devices)