Statistics
| Branch: | Revision:

root / hw / slavio_misc.c @ d60efc6b

History | View | Annotate | Download (12.5 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 AUX1_TC        0x02
67

    
68
#define AUX2_PWROFF    0x01
69
#define AUX2_PWRINTCLR 0x02
70
#define AUX2_PWRFAIL   0x20
71

    
72
#define CFG_PWRINTEN   0x08
73

    
74
#define SYS_RESET      0x01
75
#define SYS_RESETSTAT  0x02
76

    
77
static void slavio_misc_update_irq(void *opaque)
78
{
79
    MiscState *s = opaque;
80

    
81
    if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
82
        MISC_DPRINTF("Raise IRQ\n");
83
        qemu_irq_raise(s->irq);
84
    } else {
85
        MISC_DPRINTF("Lower IRQ\n");
86
        qemu_irq_lower(s->irq);
87
    }
88
}
89

    
90
static void slavio_misc_reset(void *opaque)
91
{
92
    MiscState *s = opaque;
93

    
94
    // Diagnostic and system control registers not cleared in reset
95
    s->config = s->aux1 = s->aux2 = s->mctrl = 0;
96
}
97

    
98
static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
99
{
100
    MiscState *s = opaque;
101

    
102
    MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
103
    if (power_failing && (s->config & CFG_PWRINTEN)) {
104
        s->aux2 |= AUX2_PWRFAIL;
105
    } else {
106
        s->aux2 &= ~AUX2_PWRFAIL;
107
    }
108
    slavio_misc_update_irq(s);
109
}
110

    
111
static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
112
                                  uint32_t val)
113
{
114
    MiscState *s = opaque;
115

    
116
    MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
117
    s->config = val & 0xff;
118
    slavio_misc_update_irq(s);
119
}
120

    
121
static uint32_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr)
122
{
123
    MiscState *s = opaque;
124
    uint32_t ret = 0;
125

    
126
    ret = s->config;
127
    MISC_DPRINTF("Read config %2.2x\n", ret);
128
    return ret;
129
}
130

    
131
static CPUReadMemoryFunc * const slavio_cfg_mem_read[3] = {
132
    slavio_cfg_mem_readb,
133
    NULL,
134
    NULL,
135
};
136

    
137
static CPUWriteMemoryFunc * const slavio_cfg_mem_write[3] = {
138
    slavio_cfg_mem_writeb,
139
    NULL,
140
    NULL,
141
};
142

    
143
static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
144
                                   uint32_t val)
145
{
146
    MiscState *s = opaque;
147

    
148
    MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
149
    s->diag = val & 0xff;
150
}
151

    
152
static uint32_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr)
153
{
154
    MiscState *s = opaque;
155
    uint32_t ret = 0;
156

    
157
    ret = s->diag;
158
    MISC_DPRINTF("Read diag %2.2x\n", ret);
159
    return ret;
160
}
161

    
162
static CPUReadMemoryFunc * const slavio_diag_mem_read[3] = {
163
    slavio_diag_mem_readb,
164
    NULL,
165
    NULL,
166
};
167

    
168
static CPUWriteMemoryFunc * const slavio_diag_mem_write[3] = {
169
    slavio_diag_mem_writeb,
170
    NULL,
171
    NULL,
172
};
173

    
174
static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
175
                                  uint32_t val)
176
{
177
    MiscState *s = opaque;
178

    
179
    MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
180
    s->mctrl = val & 0xff;
181
}
182

    
183
static uint32_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr)
184
{
185
    MiscState *s = opaque;
186
    uint32_t ret = 0;
187

    
188
    ret = s->mctrl;
189
    MISC_DPRINTF("Read modem control %2.2x\n", ret);
190
    return ret;
191
}
192

    
193
static CPUReadMemoryFunc * const slavio_mdm_mem_read[3] = {
194
    slavio_mdm_mem_readb,
195
    NULL,
196
    NULL,
197
};
198

    
199
static CPUWriteMemoryFunc * const slavio_mdm_mem_write[3] = {
200
    slavio_mdm_mem_writeb,
201
    NULL,
202
    NULL,
203
};
204

    
205
static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
206
                                   uint32_t val)
207
{
208
    MiscState *s = opaque;
209

    
210
    MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
211
    if (val & AUX1_TC) {
212
        // Send a pulse to floppy terminal count line
213
        if (s->fdc_tc) {
214
            qemu_irq_raise(s->fdc_tc);
215
            qemu_irq_lower(s->fdc_tc);
216
        }
217
        val &= ~AUX1_TC;
218
    }
219
    s->aux1 = val & 0xff;
220
}
221

    
222
static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr)
223
{
224
    MiscState *s = opaque;
225
    uint32_t ret = 0;
226

    
227
    ret = s->aux1;
228
    MISC_DPRINTF("Read aux1 %2.2x\n", ret);
229

    
230
    return ret;
231
}
232

    
233
static CPUReadMemoryFunc * const slavio_aux1_mem_read[3] = {
234
    slavio_aux1_mem_readb,
235
    NULL,
236
    NULL,
237
};
238

    
239
static CPUWriteMemoryFunc * const slavio_aux1_mem_write[3] = {
240
    slavio_aux1_mem_writeb,
241
    NULL,
242
    NULL,
243
};
244

    
245
static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
246
                                   uint32_t val)
247
{
248
    MiscState *s = opaque;
249

    
250
    val &= AUX2_PWRINTCLR | AUX2_PWROFF;
251
    MISC_DPRINTF("Write aux2 %2.2x\n", val);
252
    val |= s->aux2 & AUX2_PWRFAIL;
253
    if (val & AUX2_PWRINTCLR) // Clear Power Fail int
254
        val &= AUX2_PWROFF;
255
    s->aux2 = val;
256
    if (val & AUX2_PWROFF)
257
        qemu_system_shutdown_request();
258
    slavio_misc_update_irq(s);
259
}
260

    
261
static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr)
262
{
263
    MiscState *s = opaque;
264
    uint32_t ret = 0;
265

    
266
    ret = s->aux2;
267
    MISC_DPRINTF("Read aux2 %2.2x\n", ret);
268

    
269
    return ret;
270
}
271

    
272
static CPUReadMemoryFunc * const slavio_aux2_mem_read[3] = {
273
    slavio_aux2_mem_readb,
274
    NULL,
275
    NULL,
276
};
277

    
278
static CPUWriteMemoryFunc * const slavio_aux2_mem_write[3] = {
279
    slavio_aux2_mem_writeb,
280
    NULL,
281
    NULL,
282
};
283

    
284
static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
285
{
286
    APCState *s = opaque;
287

    
288
    MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
289
    qemu_irq_raise(s->cpu_halt);
290
}
291

    
292
static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr)
293
{
294
    uint32_t ret = 0;
295

    
296
    MISC_DPRINTF("Read power management %2.2x\n", ret);
297
    return ret;
298
}
299

    
300
static CPUReadMemoryFunc * const apc_mem_read[3] = {
301
    apc_mem_readb,
302
    NULL,
303
    NULL,
304
};
305

    
306
static CPUWriteMemoryFunc * const apc_mem_write[3] = {
307
    apc_mem_writeb,
308
    NULL,
309
    NULL,
310
};
311

    
312
static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
313
{
314
    MiscState *s = opaque;
315
    uint32_t ret = 0;
316

    
317
    switch (addr) {
318
    case 0:
319
        ret = s->sysctrl;
320
        break;
321
    default:
322
        break;
323
    }
324
    MISC_DPRINTF("Read system control %08x\n", ret);
325
    return ret;
326
}
327

    
328
static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
329
                                      uint32_t val)
330
{
331
    MiscState *s = opaque;
332

    
333
    MISC_DPRINTF("Write system control %08x\n", val);
334
    switch (addr) {
335
    case 0:
336
        if (val & SYS_RESET) {
337
            s->sysctrl = SYS_RESETSTAT;
338
            qemu_system_reset_request();
339
        }
340
        break;
341
    default:
342
        break;
343
    }
344
}
345

    
346
static CPUReadMemoryFunc * const slavio_sysctrl_mem_read[3] = {
347
    NULL,
348
    NULL,
349
    slavio_sysctrl_mem_readl,
350
};
351

    
352
static CPUWriteMemoryFunc * const slavio_sysctrl_mem_write[3] = {
353
    NULL,
354
    NULL,
355
    slavio_sysctrl_mem_writel,
356
};
357

    
358
static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
359
{
360
    MiscState *s = opaque;
361
    uint32_t ret = 0;
362

    
363
    switch (addr) {
364
    case 0:
365
        ret = s->leds;
366
        break;
367
    default:
368
        break;
369
    }
370
    MISC_DPRINTF("Read diagnostic LED %04x\n", ret);
371
    return ret;
372
}
373

    
374
static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
375
                                  uint32_t val)
376
{
377
    MiscState *s = opaque;
378

    
379
    MISC_DPRINTF("Write diagnostic LED %04x\n", val & 0xffff);
380
    switch (addr) {
381
    case 0:
382
        s->leds = val;
383
        break;
384
    default:
385
        break;
386
    }
387
}
388

    
389
static CPUReadMemoryFunc * const slavio_led_mem_read[3] = {
390
    NULL,
391
    slavio_led_mem_readw,
392
    NULL,
393
};
394

    
395
static CPUWriteMemoryFunc * const slavio_led_mem_write[3] = {
396
    NULL,
397
    slavio_led_mem_writew,
398
    NULL,
399
};
400

    
401
static void slavio_misc_save(QEMUFile *f, void *opaque)
402
{
403
    MiscState *s = opaque;
404
    uint32_t tmp = 0;
405
    uint8_t tmp8;
406

    
407
    qemu_put_be32s(f, &tmp); /* ignored, was IRQ.  */
408
    qemu_put_8s(f, &s->config);
409
    qemu_put_8s(f, &s->aux1);
410
    qemu_put_8s(f, &s->aux2);
411
    qemu_put_8s(f, &s->diag);
412
    qemu_put_8s(f, &s->mctrl);
413
    tmp8 = s->sysctrl & 0xff;
414
    qemu_put_8s(f, &tmp8);
415
}
416

    
417
static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
418
{
419
    MiscState *s = opaque;
420
    uint32_t tmp;
421
    uint8_t tmp8;
422

    
423
    if (version_id != 1)
424
        return -EINVAL;
425

    
426
    qemu_get_be32s(f, &tmp);
427
    qemu_get_8s(f, &s->config);
428
    qemu_get_8s(f, &s->aux1);
429
    qemu_get_8s(f, &s->aux2);
430
    qemu_get_8s(f, &s->diag);
431
    qemu_get_8s(f, &s->mctrl);
432
    qemu_get_8s(f, &tmp8);
433
    s->sysctrl = (uint32_t)tmp8;
434
    return 0;
435
}
436

    
437
static void apc_init1(SysBusDevice *dev)
438
{
439
    APCState *s = FROM_SYSBUS(APCState, dev);
440
    int io;
441

    
442
    sysbus_init_irq(dev, &s->cpu_halt);
443

    
444
    /* Power management (APC) XXX: not a Slavio device */
445
    io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s);
446
    sysbus_init_mmio(dev, MISC_SIZE, io);
447
}
448

    
449
static void slavio_misc_init1(SysBusDevice *dev)
450
{
451
    MiscState *s = FROM_SYSBUS(MiscState, dev);
452
    int io;
453

    
454
    sysbus_init_irq(dev, &s->irq);
455
    sysbus_init_irq(dev, &s->fdc_tc);
456

    
457
    /* 8 bit registers */
458
    /* Slavio control */
459
    io = cpu_register_io_memory(slavio_cfg_mem_read,
460
                                slavio_cfg_mem_write, s);
461
    sysbus_init_mmio(dev, MISC_SIZE, io);
462

    
463
    /* Diagnostics */
464
    io = cpu_register_io_memory(slavio_diag_mem_read,
465
                                slavio_diag_mem_write, s);
466
    sysbus_init_mmio(dev, MISC_SIZE, io);
467

    
468
    /* Modem control */
469
    io = cpu_register_io_memory(slavio_mdm_mem_read,
470
                                slavio_mdm_mem_write, s);
471
    sysbus_init_mmio(dev, MISC_SIZE, io);
472

    
473
    /* 16 bit registers */
474
    /* ss600mp diag LEDs */
475
    io = cpu_register_io_memory(slavio_led_mem_read,
476
                                slavio_led_mem_write, s);
477
    sysbus_init_mmio(dev, MISC_SIZE, io);
478

    
479
    /* 32 bit registers */
480
    /* System control */
481
    io = cpu_register_io_memory(slavio_sysctrl_mem_read,
482
                                slavio_sysctrl_mem_write, s);
483
    sysbus_init_mmio(dev, SYSCTRL_SIZE, io);
484

    
485
    /* AUX 1 (Misc System Functions) */
486
    io = cpu_register_io_memory(slavio_aux1_mem_read,
487
                                slavio_aux1_mem_write, s);
488
    sysbus_init_mmio(dev, MISC_SIZE, io);
489

    
490
    /* AUX 2 (Software Powerdown Control) */
491
    io = cpu_register_io_memory(slavio_aux2_mem_read,
492
                                slavio_aux2_mem_write, s);
493
    sysbus_init_mmio(dev, MISC_SIZE, io);
494

    
495
    qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
496

    
497
    register_savevm("slavio_misc", -1, 1, slavio_misc_save, slavio_misc_load,
498
                    s);
499
    qemu_register_reset(slavio_misc_reset, s);
500
    slavio_misc_reset(s);
501
}
502

    
503
static SysBusDeviceInfo slavio_misc_info = {
504
    .init = slavio_misc_init1,
505
    .qdev.name  = "slavio_misc",
506
    .qdev.size  = sizeof(MiscState),
507
};
508

    
509
static SysBusDeviceInfo apc_info = {
510
    .init = apc_init1,
511
    .qdev.name  = "apc",
512
    .qdev.size  = sizeof(MiscState),
513
};
514

    
515
static void slavio_misc_register_devices(void)
516
{
517
    sysbus_register_withprop(&slavio_misc_info);
518
    sysbus_register_withprop(&apc_info);
519
}
520

    
521
device_init(slavio_misc_register_devices)