Statistics
| Branch: | Revision:

root / hw / slavio_misc.c @ edcca5a3

History | View | Annotate | Download (12.2 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
    uint32_t dummy;
51
    uint8_t config;
52
    uint8_t aux1, aux2;
53
    uint8_t diag, mctrl;
54
    uint8_t sysctrl;
55
    uint16_t leds;
56
    qemu_irq fdc_tc;
57
} MiscState;
58

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

    
64
#define MISC_SIZE 1
65
#define SYSCTRL_SIZE 4
66

    
67
#define AUX1_TC        0x02
68

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

    
73
#define CFG_PWRINTEN   0x08
74

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
231
    return ret;
232
}
233

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

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

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

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

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

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

    
270
    return ret;
271
}
272

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
402
static const VMStateDescription vmstate_misc = {
403
    .name ="slavio_misc",
404
    .version_id = 1,
405
    .minimum_version_id = 1,
406
    .minimum_version_id_old = 1,
407
    .fields      = (VMStateField []) {
408
        VMSTATE_UINT32(dummy, MiscState),
409
        VMSTATE_UINT8(config, MiscState),
410
        VMSTATE_UINT8(aux1, MiscState),
411
        VMSTATE_UINT8(aux2, MiscState),
412
        VMSTATE_UINT8(diag, MiscState),
413
        VMSTATE_UINT8(mctrl, MiscState),
414
        VMSTATE_UINT8(sysctrl, MiscState),
415
        VMSTATE_END_OF_LIST()
416
    }
417
};
418

    
419
static int apc_init1(SysBusDevice *dev)
420
{
421
    APCState *s = FROM_SYSBUS(APCState, dev);
422
    int io;
423

    
424
    sysbus_init_irq(dev, &s->cpu_halt);
425

    
426
    /* Power management (APC) XXX: not a Slavio device */
427
    io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s);
428
    sysbus_init_mmio(dev, MISC_SIZE, io);
429
    return 0;
430
}
431

    
432
static int slavio_misc_init1(SysBusDevice *dev)
433
{
434
    MiscState *s = FROM_SYSBUS(MiscState, dev);
435
    int io;
436

    
437
    sysbus_init_irq(dev, &s->irq);
438
    sysbus_init_irq(dev, &s->fdc_tc);
439

    
440
    /* 8 bit registers */
441
    /* Slavio control */
442
    io = cpu_register_io_memory(slavio_cfg_mem_read,
443
                                slavio_cfg_mem_write, s);
444
    sysbus_init_mmio(dev, MISC_SIZE, io);
445

    
446
    /* Diagnostics */
447
    io = cpu_register_io_memory(slavio_diag_mem_read,
448
                                slavio_diag_mem_write, s);
449
    sysbus_init_mmio(dev, MISC_SIZE, io);
450

    
451
    /* Modem control */
452
    io = cpu_register_io_memory(slavio_mdm_mem_read,
453
                                slavio_mdm_mem_write, s);
454
    sysbus_init_mmio(dev, MISC_SIZE, io);
455

    
456
    /* 16 bit registers */
457
    /* ss600mp diag LEDs */
458
    io = cpu_register_io_memory(slavio_led_mem_read,
459
                                slavio_led_mem_write, s);
460
    sysbus_init_mmio(dev, MISC_SIZE, io);
461

    
462
    /* 32 bit registers */
463
    /* System control */
464
    io = cpu_register_io_memory(slavio_sysctrl_mem_read,
465
                                slavio_sysctrl_mem_write, s);
466
    sysbus_init_mmio(dev, SYSCTRL_SIZE, io);
467

    
468
    /* AUX 1 (Misc System Functions) */
469
    io = cpu_register_io_memory(slavio_aux1_mem_read,
470
                                slavio_aux1_mem_write, s);
471
    sysbus_init_mmio(dev, MISC_SIZE, io);
472

    
473
    /* AUX 2 (Software Powerdown Control) */
474
    io = cpu_register_io_memory(slavio_aux2_mem_read,
475
                                slavio_aux2_mem_write, s);
476
    sysbus_init_mmio(dev, MISC_SIZE, io);
477

    
478
    qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
479

    
480
    vmstate_register(-1, &vmstate_misc, s);
481
    qemu_register_reset(slavio_misc_reset, s);
482
    slavio_misc_reset(s);
483
    return 0;
484
}
485

    
486
static SysBusDeviceInfo slavio_misc_info = {
487
    .init = slavio_misc_init1,
488
    .qdev.name  = "slavio_misc",
489
    .qdev.size  = sizeof(MiscState),
490
};
491

    
492
static SysBusDeviceInfo apc_info = {
493
    .init = apc_init1,
494
    .qdev.name  = "apc",
495
    .qdev.size  = sizeof(MiscState),
496
};
497

    
498
static void slavio_misc_register_devices(void)
499
{
500
    sysbus_register_withprop(&slavio_misc_info);
501
    sysbus_register_withprop(&apc_info);
502
}
503

    
504
device_init(slavio_misc_register_devices)