Statistics
| Branch: | Revision:

root / hw / slavio_misc.c @ 870cef1d

History | View | Annotate | Download (11.8 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 "sysemu.h"
26
#include "sysbus.h"
27
#include "trace.h"
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

    
37
typedef struct MiscState {
38
    SysBusDevice busdev;
39
    qemu_irq irq;
40
    uint32_t dummy;
41
    uint8_t config;
42
    uint8_t aux1, aux2;
43
    uint8_t diag, mctrl;
44
    uint8_t sysctrl;
45
    uint16_t leds;
46
    qemu_irq fdc_tc;
47
} MiscState;
48

    
49
typedef struct APCState {
50
    SysBusDevice busdev;
51
    qemu_irq cpu_halt;
52
} APCState;
53

    
54
#define MISC_SIZE 1
55
#define SYSCTRL_SIZE 4
56

    
57
#define AUX1_TC        0x02
58

    
59
#define AUX2_PWROFF    0x01
60
#define AUX2_PWRINTCLR 0x02
61
#define AUX2_PWRFAIL   0x20
62

    
63
#define CFG_PWRINTEN   0x08
64

    
65
#define SYS_RESET      0x01
66
#define SYS_RESETSTAT  0x02
67

    
68
static void slavio_misc_update_irq(void *opaque)
69
{
70
    MiscState *s = opaque;
71

    
72
    if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
73
        trace_slavio_misc_update_irq_raise();
74
        qemu_irq_raise(s->irq);
75
    } else {
76
        trace_slavio_misc_update_irq_lower();
77
        qemu_irq_lower(s->irq);
78
    }
79
}
80

    
81
static void slavio_misc_reset(DeviceState *d)
82
{
83
    MiscState *s = container_of(d, MiscState, busdev.qdev);
84

    
85
    // Diagnostic and system control registers not cleared in reset
86
    s->config = s->aux1 = s->aux2 = s->mctrl = 0;
87
}
88

    
89
static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
90
{
91
    MiscState *s = opaque;
92

    
93
    trace_slavio_set_power_fail(power_failing, s->config);
94
    if (power_failing && (s->config & CFG_PWRINTEN)) {
95
        s->aux2 |= AUX2_PWRFAIL;
96
    } else {
97
        s->aux2 &= ~AUX2_PWRFAIL;
98
    }
99
    slavio_misc_update_irq(s);
100
}
101

    
102
static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
103
                                  uint32_t val)
104
{
105
    MiscState *s = opaque;
106

    
107
    trace_slavio_cfg_mem_writeb(val & 0xff);
108
    s->config = val & 0xff;
109
    slavio_misc_update_irq(s);
110
}
111

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

    
117
    ret = s->config;
118
    trace_slavio_cfg_mem_readb(ret);
119
    return ret;
120
}
121

    
122
static CPUReadMemoryFunc * const slavio_cfg_mem_read[3] = {
123
    slavio_cfg_mem_readb,
124
    NULL,
125
    NULL,
126
};
127

    
128
static CPUWriteMemoryFunc * const slavio_cfg_mem_write[3] = {
129
    slavio_cfg_mem_writeb,
130
    NULL,
131
    NULL,
132
};
133

    
134
static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
135
                                   uint32_t val)
136
{
137
    MiscState *s = opaque;
138

    
139
    trace_slavio_diag_mem_writeb(val & 0xff);
140
    s->diag = val & 0xff;
141
}
142

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

    
148
    ret = s->diag;
149
    trace_slavio_diag_mem_readb(ret);
150
    return ret;
151
}
152

    
153
static CPUReadMemoryFunc * const slavio_diag_mem_read[3] = {
154
    slavio_diag_mem_readb,
155
    NULL,
156
    NULL,
157
};
158

    
159
static CPUWriteMemoryFunc * const slavio_diag_mem_write[3] = {
160
    slavio_diag_mem_writeb,
161
    NULL,
162
    NULL,
163
};
164

    
165
static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
166
                                  uint32_t val)
167
{
168
    MiscState *s = opaque;
169

    
170
    trace_slavio_mdm_mem_writeb(val & 0xff);
171
    s->mctrl = val & 0xff;
172
}
173

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

    
179
    ret = s->mctrl;
180
    trace_slavio_mdm_mem_readb(ret);
181
    return ret;
182
}
183

    
184
static CPUReadMemoryFunc * const slavio_mdm_mem_read[3] = {
185
    slavio_mdm_mem_readb,
186
    NULL,
187
    NULL,
188
};
189

    
190
static CPUWriteMemoryFunc * const slavio_mdm_mem_write[3] = {
191
    slavio_mdm_mem_writeb,
192
    NULL,
193
    NULL,
194
};
195

    
196
static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
197
                                   uint32_t val)
198
{
199
    MiscState *s = opaque;
200

    
201
    trace_slavio_aux1_mem_writeb(val & 0xff);
202
    if (val & AUX1_TC) {
203
        // Send a pulse to floppy terminal count line
204
        if (s->fdc_tc) {
205
            qemu_irq_raise(s->fdc_tc);
206
            qemu_irq_lower(s->fdc_tc);
207
        }
208
        val &= ~AUX1_TC;
209
    }
210
    s->aux1 = val & 0xff;
211
}
212

    
213
static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr)
214
{
215
    MiscState *s = opaque;
216
    uint32_t ret = 0;
217

    
218
    ret = s->aux1;
219
    trace_slavio_aux1_mem_readb(ret);
220
    return ret;
221
}
222

    
223
static CPUReadMemoryFunc * const slavio_aux1_mem_read[3] = {
224
    slavio_aux1_mem_readb,
225
    NULL,
226
    NULL,
227
};
228

    
229
static CPUWriteMemoryFunc * const slavio_aux1_mem_write[3] = {
230
    slavio_aux1_mem_writeb,
231
    NULL,
232
    NULL,
233
};
234

    
235
static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
236
                                   uint32_t val)
237
{
238
    MiscState *s = opaque;
239

    
240
    val &= AUX2_PWRINTCLR | AUX2_PWROFF;
241
    trace_slavio_aux2_mem_writeb(val & 0xff);
242
    val |= s->aux2 & AUX2_PWRFAIL;
243
    if (val & AUX2_PWRINTCLR) // Clear Power Fail int
244
        val &= AUX2_PWROFF;
245
    s->aux2 = val;
246
    if (val & AUX2_PWROFF)
247
        qemu_system_shutdown_request();
248
    slavio_misc_update_irq(s);
249
}
250

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

    
256
    ret = s->aux2;
257
    trace_slavio_aux2_mem_readb(ret);
258
    return ret;
259
}
260

    
261
static CPUReadMemoryFunc * const slavio_aux2_mem_read[3] = {
262
    slavio_aux2_mem_readb,
263
    NULL,
264
    NULL,
265
};
266

    
267
static CPUWriteMemoryFunc * const slavio_aux2_mem_write[3] = {
268
    slavio_aux2_mem_writeb,
269
    NULL,
270
    NULL,
271
};
272

    
273
static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
274
{
275
    APCState *s = opaque;
276

    
277
    trace_apc_mem_writeb(val & 0xff);
278
    qemu_irq_raise(s->cpu_halt);
279
}
280

    
281
static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr)
282
{
283
    uint32_t ret = 0;
284

    
285
    trace_apc_mem_readb(ret);
286
    return ret;
287
}
288

    
289
static CPUReadMemoryFunc * const apc_mem_read[3] = {
290
    apc_mem_readb,
291
    NULL,
292
    NULL,
293
};
294

    
295
static CPUWriteMemoryFunc * const apc_mem_write[3] = {
296
    apc_mem_writeb,
297
    NULL,
298
    NULL,
299
};
300

    
301
static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
302
{
303
    MiscState *s = opaque;
304
    uint32_t ret = 0;
305

    
306
    switch (addr) {
307
    case 0:
308
        ret = s->sysctrl;
309
        break;
310
    default:
311
        break;
312
    }
313
    trace_slavio_sysctrl_mem_readl(ret);
314
    return ret;
315
}
316

    
317
static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
318
                                      uint32_t val)
319
{
320
    MiscState *s = opaque;
321

    
322
    trace_slavio_sysctrl_mem_writel(val);
323
    switch (addr) {
324
    case 0:
325
        if (val & SYS_RESET) {
326
            s->sysctrl = SYS_RESETSTAT;
327
            qemu_system_reset_request();
328
        }
329
        break;
330
    default:
331
        break;
332
    }
333
}
334

    
335
static CPUReadMemoryFunc * const slavio_sysctrl_mem_read[3] = {
336
    NULL,
337
    NULL,
338
    slavio_sysctrl_mem_readl,
339
};
340

    
341
static CPUWriteMemoryFunc * const slavio_sysctrl_mem_write[3] = {
342
    NULL,
343
    NULL,
344
    slavio_sysctrl_mem_writel,
345
};
346

    
347
static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
348
{
349
    MiscState *s = opaque;
350
    uint32_t ret = 0;
351

    
352
    switch (addr) {
353
    case 0:
354
        ret = s->leds;
355
        break;
356
    default:
357
        break;
358
    }
359
    trace_slavio_led_mem_readw(ret);
360
    return ret;
361
}
362

    
363
static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
364
                                  uint32_t val)
365
{
366
    MiscState *s = opaque;
367

    
368
    trace_slavio_led_mem_readw(val & 0xffff);
369
    switch (addr) {
370
    case 0:
371
        s->leds = val;
372
        break;
373
    default:
374
        break;
375
    }
376
}
377

    
378
static CPUReadMemoryFunc * const slavio_led_mem_read[3] = {
379
    NULL,
380
    slavio_led_mem_readw,
381
    NULL,
382
};
383

    
384
static CPUWriteMemoryFunc * const slavio_led_mem_write[3] = {
385
    NULL,
386
    slavio_led_mem_writew,
387
    NULL,
388
};
389

    
390
static const VMStateDescription vmstate_misc = {
391
    .name ="slavio_misc",
392
    .version_id = 1,
393
    .minimum_version_id = 1,
394
    .minimum_version_id_old = 1,
395
    .fields      = (VMStateField []) {
396
        VMSTATE_UINT32(dummy, MiscState),
397
        VMSTATE_UINT8(config, MiscState),
398
        VMSTATE_UINT8(aux1, MiscState),
399
        VMSTATE_UINT8(aux2, MiscState),
400
        VMSTATE_UINT8(diag, MiscState),
401
        VMSTATE_UINT8(mctrl, MiscState),
402
        VMSTATE_UINT8(sysctrl, MiscState),
403
        VMSTATE_END_OF_LIST()
404
    }
405
};
406

    
407
static int apc_init1(SysBusDevice *dev)
408
{
409
    APCState *s = FROM_SYSBUS(APCState, dev);
410
    int io;
411

    
412
    sysbus_init_irq(dev, &s->cpu_halt);
413

    
414
    /* Power management (APC) XXX: not a Slavio device */
415
    io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s);
416
    sysbus_init_mmio(dev, MISC_SIZE, io);
417
    return 0;
418
}
419

    
420
static int slavio_misc_init1(SysBusDevice *dev)
421
{
422
    MiscState *s = FROM_SYSBUS(MiscState, dev);
423
    int io;
424

    
425
    sysbus_init_irq(dev, &s->irq);
426
    sysbus_init_irq(dev, &s->fdc_tc);
427

    
428
    /* 8 bit registers */
429
    /* Slavio control */
430
    io = cpu_register_io_memory(slavio_cfg_mem_read,
431
                                slavio_cfg_mem_write, s);
432
    sysbus_init_mmio(dev, MISC_SIZE, io);
433

    
434
    /* Diagnostics */
435
    io = cpu_register_io_memory(slavio_diag_mem_read,
436
                                slavio_diag_mem_write, s);
437
    sysbus_init_mmio(dev, MISC_SIZE, io);
438

    
439
    /* Modem control */
440
    io = cpu_register_io_memory(slavio_mdm_mem_read,
441
                                slavio_mdm_mem_write, s);
442
    sysbus_init_mmio(dev, MISC_SIZE, io);
443

    
444
    /* 16 bit registers */
445
    /* ss600mp diag LEDs */
446
    io = cpu_register_io_memory(slavio_led_mem_read,
447
                                slavio_led_mem_write, s);
448
    sysbus_init_mmio(dev, MISC_SIZE, io);
449

    
450
    /* 32 bit registers */
451
    /* System control */
452
    io = cpu_register_io_memory(slavio_sysctrl_mem_read,
453
                                slavio_sysctrl_mem_write, s);
454
    sysbus_init_mmio(dev, SYSCTRL_SIZE, io);
455

    
456
    /* AUX 1 (Misc System Functions) */
457
    io = cpu_register_io_memory(slavio_aux1_mem_read,
458
                                slavio_aux1_mem_write, s);
459
    sysbus_init_mmio(dev, MISC_SIZE, io);
460

    
461
    /* AUX 2 (Software Powerdown Control) */
462
    io = cpu_register_io_memory(slavio_aux2_mem_read,
463
                                slavio_aux2_mem_write, s);
464
    sysbus_init_mmio(dev, MISC_SIZE, io);
465

    
466
    qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
467

    
468
    return 0;
469
}
470

    
471
static SysBusDeviceInfo slavio_misc_info = {
472
    .init = slavio_misc_init1,
473
    .qdev.name  = "slavio_misc",
474
    .qdev.size  = sizeof(MiscState),
475
    .qdev.vmsd  = &vmstate_misc,
476
    .qdev.reset  = slavio_misc_reset,
477
};
478

    
479
static SysBusDeviceInfo apc_info = {
480
    .init = apc_init1,
481
    .qdev.name  = "apc",
482
    .qdev.size  = sizeof(MiscState),
483
};
484

    
485
static void slavio_misc_register_devices(void)
486
{
487
    sysbus_register_withprop(&slavio_misc_info);
488
    sysbus_register_withprop(&apc_info);
489
}
490

    
491
device_init(slavio_misc_register_devices)