Statistics
| Branch: | Revision:

root / hw / slavio_misc.c @ ee6847d1

History | View | Annotate | Download (14 kB)

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

    
25
#include "sun4m.h"
26
#include "sysemu.h"
27
#include "sysbus.h"
28

    
29
/* debug misc */
30
//#define DEBUG_MISC
31

    
32
/*
33
 * This is the auxio port, chip control and system control part of
34
 * chip STP2001 (Slave I/O), also produced as NCR89C105. See
35
 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
36
 *
37
 * This also includes the PMC CPU idle controller.
38
 */
39

    
40
#ifdef DEBUG_MISC
41
#define MISC_DPRINTF(fmt, ...)                                  \
42
    do { printf("MISC: " fmt , ## __VA_ARGS__); } while (0)
43
#else
44
#define MISC_DPRINTF(fmt, ...)
45
#endif
46

    
47
typedef struct MiscState {
48
    SysBusDevice busdev;
49
    qemu_irq irq;
50
    uint8_t config;
51
    uint8_t aux1, aux2;
52
    uint8_t diag, mctrl;
53
    uint32_t sysctrl;
54
    uint16_t leds;
55
    qemu_irq fdc_tc;
56
} MiscState;
57

    
58
typedef struct APCState {
59
    SysBusDevice busdev;
60
    qemu_irq cpu_halt;
61
} APCState;
62

    
63
#define MISC_SIZE 1
64
#define SYSCTRL_SIZE 4
65

    
66
#define MISC_LEDS 0x01600000
67
#define MISC_CFG  0x01800000
68
#define MISC_DIAG 0x01a00000
69
#define MISC_MDM  0x01b00000
70
#define MISC_SYS  0x01f00000
71

    
72
#define AUX1_TC        0x02
73

    
74
#define AUX2_PWROFF    0x01
75
#define AUX2_PWRINTCLR 0x02
76
#define AUX2_PWRFAIL   0x20
77

    
78
#define CFG_PWRINTEN   0x08
79

    
80
#define SYS_RESET      0x01
81
#define SYS_RESETSTAT  0x02
82

    
83
static void slavio_misc_update_irq(void *opaque)
84
{
85
    MiscState *s = opaque;
86

    
87
    if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
88
        MISC_DPRINTF("Raise IRQ\n");
89
        qemu_irq_raise(s->irq);
90
    } else {
91
        MISC_DPRINTF("Lower IRQ\n");
92
        qemu_irq_lower(s->irq);
93
    }
94
}
95

    
96
static void slavio_misc_reset(void *opaque)
97
{
98
    MiscState *s = opaque;
99

    
100
    // Diagnostic and system control registers not cleared in reset
101
    s->config = s->aux1 = s->aux2 = s->mctrl = 0;
102
}
103

    
104
void slavio_set_power_fail(void *opaque, int power_failing)
105
{
106
    MiscState *s = opaque;
107

    
108
    MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
109
    if (power_failing && (s->config & CFG_PWRINTEN)) {
110
        s->aux2 |= AUX2_PWRFAIL;
111
    } else {
112
        s->aux2 &= ~AUX2_PWRFAIL;
113
    }
114
    slavio_misc_update_irq(s);
115
}
116

    
117
static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
118
                                  uint32_t val)
119
{
120
    MiscState *s = opaque;
121

    
122
    MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
123
    s->config = val & 0xff;
124
    slavio_misc_update_irq(s);
125
}
126

    
127
static uint32_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr)
128
{
129
    MiscState *s = opaque;
130
    uint32_t ret = 0;
131

    
132
    ret = s->config;
133
    MISC_DPRINTF("Read config %2.2x\n", ret);
134
    return ret;
135
}
136

    
137
static CPUReadMemoryFunc *slavio_cfg_mem_read[3] = {
138
    slavio_cfg_mem_readb,
139
    NULL,
140
    NULL,
141
};
142

    
143
static CPUWriteMemoryFunc *slavio_cfg_mem_write[3] = {
144
    slavio_cfg_mem_writeb,
145
    NULL,
146
    NULL,
147
};
148

    
149
static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
150
                                   uint32_t val)
151
{
152
    MiscState *s = opaque;
153

    
154
    MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
155
    s->diag = val & 0xff;
156
}
157

    
158
static uint32_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr)
159
{
160
    MiscState *s = opaque;
161
    uint32_t ret = 0;
162

    
163
    ret = s->diag;
164
    MISC_DPRINTF("Read diag %2.2x\n", ret);
165
    return ret;
166
}
167

    
168
static CPUReadMemoryFunc *slavio_diag_mem_read[3] = {
169
    slavio_diag_mem_readb,
170
    NULL,
171
    NULL,
172
};
173

    
174
static CPUWriteMemoryFunc *slavio_diag_mem_write[3] = {
175
    slavio_diag_mem_writeb,
176
    NULL,
177
    NULL,
178
};
179

    
180
static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
181
                                  uint32_t val)
182
{
183
    MiscState *s = opaque;
184

    
185
    MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
186
    s->mctrl = val & 0xff;
187
}
188

    
189
static uint32_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr)
190
{
191
    MiscState *s = opaque;
192
    uint32_t ret = 0;
193

    
194
    ret = s->mctrl;
195
    MISC_DPRINTF("Read modem control %2.2x\n", ret);
196
    return ret;
197
}
198

    
199
static CPUReadMemoryFunc *slavio_mdm_mem_read[3] = {
200
    slavio_mdm_mem_readb,
201
    NULL,
202
    NULL,
203
};
204

    
205
static CPUWriteMemoryFunc *slavio_mdm_mem_write[3] = {
206
    slavio_mdm_mem_writeb,
207
    NULL,
208
    NULL,
209
};
210

    
211
static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
212
                                   uint32_t val)
213
{
214
    MiscState *s = opaque;
215

    
216
    MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
217
    if (val & AUX1_TC) {
218
        // Send a pulse to floppy terminal count line
219
        if (s->fdc_tc) {
220
            qemu_irq_raise(s->fdc_tc);
221
            qemu_irq_lower(s->fdc_tc);
222
        }
223
        val &= ~AUX1_TC;
224
    }
225
    s->aux1 = val & 0xff;
226
}
227

    
228
static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr)
229
{
230
    MiscState *s = opaque;
231
    uint32_t ret = 0;
232

    
233
    ret = s->aux1;
234
    MISC_DPRINTF("Read aux1 %2.2x\n", ret);
235

    
236
    return ret;
237
}
238

    
239
static CPUReadMemoryFunc *slavio_aux1_mem_read[3] = {
240
    slavio_aux1_mem_readb,
241
    NULL,
242
    NULL,
243
};
244

    
245
static CPUWriteMemoryFunc *slavio_aux1_mem_write[3] = {
246
    slavio_aux1_mem_writeb,
247
    NULL,
248
    NULL,
249
};
250

    
251
static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
252
                                   uint32_t val)
253
{
254
    MiscState *s = opaque;
255

    
256
    val &= AUX2_PWRINTCLR | AUX2_PWROFF;
257
    MISC_DPRINTF("Write aux2 %2.2x\n", val);
258
    val |= s->aux2 & AUX2_PWRFAIL;
259
    if (val & AUX2_PWRINTCLR) // Clear Power Fail int
260
        val &= AUX2_PWROFF;
261
    s->aux2 = val;
262
    if (val & AUX2_PWROFF)
263
        qemu_system_shutdown_request();
264
    slavio_misc_update_irq(s);
265
}
266

    
267
static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr)
268
{
269
    MiscState *s = opaque;
270
    uint32_t ret = 0;
271

    
272
    ret = s->aux2;
273
    MISC_DPRINTF("Read aux2 %2.2x\n", ret);
274

    
275
    return ret;
276
}
277

    
278
static CPUReadMemoryFunc *slavio_aux2_mem_read[3] = {
279
    slavio_aux2_mem_readb,
280
    NULL,
281
    NULL,
282
};
283

    
284
static CPUWriteMemoryFunc *slavio_aux2_mem_write[3] = {
285
    slavio_aux2_mem_writeb,
286
    NULL,
287
    NULL,
288
};
289

    
290
static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
291
{
292
    APCState *s = opaque;
293

    
294
    MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
295
    qemu_irq_raise(s->cpu_halt);
296
}
297

    
298
static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr)
299
{
300
    uint32_t ret = 0;
301

    
302
    MISC_DPRINTF("Read power management %2.2x\n", ret);
303
    return ret;
304
}
305

    
306
static CPUReadMemoryFunc *apc_mem_read[3] = {
307
    apc_mem_readb,
308
    NULL,
309
    NULL,
310
};
311

    
312
static CPUWriteMemoryFunc *apc_mem_write[3] = {
313
    apc_mem_writeb,
314
    NULL,
315
    NULL,
316
};
317

    
318
static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
319
{
320
    MiscState *s = opaque;
321
    uint32_t ret = 0;
322

    
323
    switch (addr) {
324
    case 0:
325
        ret = s->sysctrl;
326
        break;
327
    default:
328
        break;
329
    }
330
    MISC_DPRINTF("Read system control %08x\n", ret);
331
    return ret;
332
}
333

    
334
static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
335
                                      uint32_t val)
336
{
337
    MiscState *s = opaque;
338

    
339
    MISC_DPRINTF("Write system control %08x\n", val);
340
    switch (addr) {
341
    case 0:
342
        if (val & SYS_RESET) {
343
            s->sysctrl = SYS_RESETSTAT;
344
            qemu_system_reset_request();
345
        }
346
        break;
347
    default:
348
        break;
349
    }
350
}
351

    
352
static CPUReadMemoryFunc *slavio_sysctrl_mem_read[3] = {
353
    NULL,
354
    NULL,
355
    slavio_sysctrl_mem_readl,
356
};
357

    
358
static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = {
359
    NULL,
360
    NULL,
361
    slavio_sysctrl_mem_writel,
362
};
363

    
364
static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
365
{
366
    MiscState *s = opaque;
367
    uint32_t ret = 0;
368

    
369
    switch (addr) {
370
    case 0:
371
        ret = s->leds;
372
        break;
373
    default:
374
        break;
375
    }
376
    MISC_DPRINTF("Read diagnostic LED %04x\n", ret);
377
    return ret;
378
}
379

    
380
static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
381
                                  uint32_t val)
382
{
383
    MiscState *s = opaque;
384

    
385
    MISC_DPRINTF("Write diagnostic LED %04x\n", val & 0xffff);
386
    switch (addr) {
387
    case 0:
388
        s->leds = val;
389
        break;
390
    default:
391
        break;
392
    }
393
}
394

    
395
static CPUReadMemoryFunc *slavio_led_mem_read[3] = {
396
    NULL,
397
    slavio_led_mem_readw,
398
    NULL,
399
};
400

    
401
static CPUWriteMemoryFunc *slavio_led_mem_write[3] = {
402
    NULL,
403
    slavio_led_mem_writew,
404
    NULL,
405
};
406

    
407
static void slavio_misc_save(QEMUFile *f, void *opaque)
408
{
409
    MiscState *s = opaque;
410
    uint32_t tmp = 0;
411
    uint8_t tmp8;
412

    
413
    qemu_put_be32s(f, &tmp); /* ignored, was IRQ.  */
414
    qemu_put_8s(f, &s->config);
415
    qemu_put_8s(f, &s->aux1);
416
    qemu_put_8s(f, &s->aux2);
417
    qemu_put_8s(f, &s->diag);
418
    qemu_put_8s(f, &s->mctrl);
419
    tmp8 = s->sysctrl & 0xff;
420
    qemu_put_8s(f, &tmp8);
421
}
422

    
423
static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
424
{
425
    MiscState *s = opaque;
426
    uint32_t tmp;
427
    uint8_t tmp8;
428

    
429
    if (version_id != 1)
430
        return -EINVAL;
431

    
432
    qemu_get_be32s(f, &tmp);
433
    qemu_get_8s(f, &s->config);
434
    qemu_get_8s(f, &s->aux1);
435
    qemu_get_8s(f, &s->aux2);
436
    qemu_get_8s(f, &s->diag);
437
    qemu_get_8s(f, &s->mctrl);
438
    qemu_get_8s(f, &tmp8);
439
    s->sysctrl = (uint32_t)tmp8;
440
    return 0;
441
}
442

    
443
void *slavio_misc_init(target_phys_addr_t base,
444
                       target_phys_addr_t aux1_base,
445
                       target_phys_addr_t aux2_base, qemu_irq irq,
446
                       qemu_irq fdc_tc)
447
{
448
    DeviceState *dev;
449
    SysBusDevice *s;
450
    MiscState *d;
451

    
452
    dev = qdev_create(NULL, "slavio_misc");
453
    qdev_init(dev);
454
    s = sysbus_from_qdev(dev);
455
    if (base) {
456
        /* 8 bit registers */
457
        /* Slavio control */
458
        sysbus_mmio_map(s, 0, base + MISC_CFG);
459
        /* Diagnostics */
460
        sysbus_mmio_map(s, 1, base + MISC_DIAG);
461
        /* Modem control */
462
        sysbus_mmio_map(s, 2, base + MISC_MDM);
463
        /* 16 bit registers */
464
        /* ss600mp diag LEDs */
465
        sysbus_mmio_map(s, 3, base + MISC_LEDS);
466
        /* 32 bit registers */
467
        /* System control */
468
        sysbus_mmio_map(s, 4, base + MISC_SYS);
469
    }
470
    if (aux1_base) {
471
        /* AUX 1 (Misc System Functions) */
472
        sysbus_mmio_map(s, 5, aux1_base);
473
    }
474
    if (aux2_base) {
475
        /* AUX 2 (Software Powerdown Control) */
476
        sysbus_mmio_map(s, 6, aux2_base);
477
    }
478
    sysbus_connect_irq(s, 0, irq);
479
    sysbus_connect_irq(s, 1, fdc_tc);
480

    
481
    d = FROM_SYSBUS(MiscState, s);
482

    
483
    return d;
484
}
485

    
486
static void apc_init1(SysBusDevice *dev)
487
{
488
    APCState *s = FROM_SYSBUS(APCState, dev);
489
    int io;
490

    
491
    sysbus_init_irq(dev, &s->cpu_halt);
492

    
493
    /* Power management (APC) XXX: not a Slavio device */
494
    io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s);
495
    sysbus_init_mmio(dev, MISC_SIZE, io);
496
}
497

    
498
void apc_init(target_phys_addr_t power_base, qemu_irq cpu_halt)
499
{
500
    DeviceState *dev;
501
    SysBusDevice *s;
502

    
503
    dev = qdev_create(NULL, "apc");
504
    qdev_init(dev);
505
    s = sysbus_from_qdev(dev);
506
    /* Power management (APC) XXX: not a Slavio device */
507
    sysbus_mmio_map(s, 0, power_base);
508
    sysbus_connect_irq(s, 0, cpu_halt);
509
}
510

    
511
static void slavio_misc_init1(SysBusDevice *dev)
512
{
513
    MiscState *s = FROM_SYSBUS(MiscState, dev);
514
    int io;
515

    
516
    sysbus_init_irq(dev, &s->irq);
517
    sysbus_init_irq(dev, &s->fdc_tc);
518

    
519
    /* 8 bit registers */
520
    /* Slavio control */
521
    io = cpu_register_io_memory(slavio_cfg_mem_read,
522
                                slavio_cfg_mem_write, s);
523
    sysbus_init_mmio(dev, MISC_SIZE, io);
524

    
525
    /* Diagnostics */
526
    io = cpu_register_io_memory(slavio_diag_mem_read,
527
                                slavio_diag_mem_write, s);
528
    sysbus_init_mmio(dev, MISC_SIZE, io);
529

    
530
    /* Modem control */
531
    io = cpu_register_io_memory(slavio_mdm_mem_read,
532
                                slavio_mdm_mem_write, s);
533
    sysbus_init_mmio(dev, MISC_SIZE, io);
534

    
535
    /* 16 bit registers */
536
    /* ss600mp diag LEDs */
537
    io = cpu_register_io_memory(slavio_led_mem_read,
538
                                slavio_led_mem_write, s);
539
    sysbus_init_mmio(dev, MISC_SIZE, io);
540

    
541
    /* 32 bit registers */
542
    /* System control */
543
    io = cpu_register_io_memory(slavio_sysctrl_mem_read,
544
                                slavio_sysctrl_mem_write, s);
545
    sysbus_init_mmio(dev, SYSCTRL_SIZE, io);
546

    
547
    /* AUX 1 (Misc System Functions) */
548
    io = cpu_register_io_memory(slavio_aux1_mem_read,
549
                                slavio_aux1_mem_write, s);
550
    sysbus_init_mmio(dev, MISC_SIZE, io);
551

    
552
    /* AUX 2 (Software Powerdown Control) */
553
    io = cpu_register_io_memory(slavio_aux2_mem_read,
554
                                slavio_aux2_mem_write, s);
555
    sysbus_init_mmio(dev, MISC_SIZE, io);
556

    
557
    register_savevm("slavio_misc", -1, 1, slavio_misc_save, slavio_misc_load,
558
                    s);
559
    qemu_register_reset(slavio_misc_reset, s);
560
    slavio_misc_reset(s);
561
}
562

    
563
static SysBusDeviceInfo slavio_misc_info = {
564
    .init = slavio_misc_init1,
565
    .qdev.name  = "slavio_misc",
566
    .qdev.size  = sizeof(MiscState),
567
};
568

    
569
static SysBusDeviceInfo apc_info = {
570
    .init = apc_init1,
571
    .qdev.name  = "apc",
572
    .qdev.size  = sizeof(MiscState),
573
};
574

    
575
static void slavio_misc_register_devices(void)
576
{
577
    sysbus_register_withprop(&slavio_misc_info);
578
    sysbus_register_withprop(&apc_info);
579
}
580

    
581
device_init(slavio_misc_register_devices)