Statistics
| Branch: | Revision:

root / hw / misc / slavio_misc.c @ a8aec295

History | View | Annotate | Download (13.1 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/sysemu.h"
26
#include "hw/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
    MemoryRegion cfg_iomem;
40
    MemoryRegion diag_iomem;
41
    MemoryRegion mdm_iomem;
42
    MemoryRegion led_iomem;
43
    MemoryRegion sysctrl_iomem;
44
    MemoryRegion aux1_iomem;
45
    MemoryRegion aux2_iomem;
46
    qemu_irq irq;
47
    qemu_irq fdc_tc;
48
    uint32_t dummy;
49
    uint8_t config;
50
    uint8_t aux1, aux2;
51
    uint8_t diag, mctrl;
52
    uint8_t sysctrl;
53
    uint16_t leds;
54
} MiscState;
55

    
56
typedef struct APCState {
57
    SysBusDevice busdev;
58
    MemoryRegion iomem;
59
    qemu_irq cpu_halt;
60
} APCState;
61

    
62
#define MISC_SIZE 1
63
#define SYSCTRL_SIZE 4
64

    
65
#define AUX1_TC        0x02
66

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

    
71
#define CFG_PWRINTEN   0x08
72

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

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

    
80
    if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
81
        trace_slavio_misc_update_irq_raise();
82
        qemu_irq_raise(s->irq);
83
    } else {
84
        trace_slavio_misc_update_irq_lower();
85
        qemu_irq_lower(s->irq);
86
    }
87
}
88

    
89
static void slavio_misc_reset(DeviceState *d)
90
{
91
    MiscState *s = container_of(d, MiscState, busdev.qdev);
92

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

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

    
101
    trace_slavio_set_power_fail(power_failing, s->config);
102
    if (power_failing && (s->config & CFG_PWRINTEN)) {
103
        s->aux2 |= AUX2_PWRFAIL;
104
    } else {
105
        s->aux2 &= ~AUX2_PWRFAIL;
106
    }
107
    slavio_misc_update_irq(s);
108
}
109

    
110
static void slavio_cfg_mem_writeb(void *opaque, hwaddr addr,
111
                                  uint64_t val, unsigned size)
112
{
113
    MiscState *s = opaque;
114

    
115
    trace_slavio_cfg_mem_writeb(val & 0xff);
116
    s->config = val & 0xff;
117
    slavio_misc_update_irq(s);
118
}
119

    
120
static uint64_t slavio_cfg_mem_readb(void *opaque, hwaddr addr,
121
                                     unsigned size)
122
{
123
    MiscState *s = opaque;
124
    uint32_t ret = 0;
125

    
126
    ret = s->config;
127
    trace_slavio_cfg_mem_readb(ret);
128
    return ret;
129
}
130

    
131
static const MemoryRegionOps slavio_cfg_mem_ops = {
132
    .read = slavio_cfg_mem_readb,
133
    .write = slavio_cfg_mem_writeb,
134
    .endianness = DEVICE_NATIVE_ENDIAN,
135
    .valid = {
136
        .min_access_size = 1,
137
        .max_access_size = 1,
138
    },
139
};
140

    
141
static void slavio_diag_mem_writeb(void *opaque, hwaddr addr,
142
                                   uint64_t val, unsigned size)
143
{
144
    MiscState *s = opaque;
145

    
146
    trace_slavio_diag_mem_writeb(val & 0xff);
147
    s->diag = val & 0xff;
148
}
149

    
150
static uint64_t slavio_diag_mem_readb(void *opaque, hwaddr addr,
151
                                      unsigned size)
152
{
153
    MiscState *s = opaque;
154
    uint32_t ret = 0;
155

    
156
    ret = s->diag;
157
    trace_slavio_diag_mem_readb(ret);
158
    return ret;
159
}
160

    
161
static const MemoryRegionOps slavio_diag_mem_ops = {
162
    .read = slavio_diag_mem_readb,
163
    .write = slavio_diag_mem_writeb,
164
    .endianness = DEVICE_NATIVE_ENDIAN,
165
    .valid = {
166
        .min_access_size = 1,
167
        .max_access_size = 1,
168
    },
169
};
170

    
171
static void slavio_mdm_mem_writeb(void *opaque, hwaddr addr,
172
                                  uint64_t val, unsigned size)
173
{
174
    MiscState *s = opaque;
175

    
176
    trace_slavio_mdm_mem_writeb(val & 0xff);
177
    s->mctrl = val & 0xff;
178
}
179

    
180
static uint64_t slavio_mdm_mem_readb(void *opaque, hwaddr addr,
181
                                     unsigned size)
182
{
183
    MiscState *s = opaque;
184
    uint32_t ret = 0;
185

    
186
    ret = s->mctrl;
187
    trace_slavio_mdm_mem_readb(ret);
188
    return ret;
189
}
190

    
191
static const MemoryRegionOps slavio_mdm_mem_ops = {
192
    .read = slavio_mdm_mem_readb,
193
    .write = slavio_mdm_mem_writeb,
194
    .endianness = DEVICE_NATIVE_ENDIAN,
195
    .valid = {
196
        .min_access_size = 1,
197
        .max_access_size = 1,
198
    },
199
};
200

    
201
static void slavio_aux1_mem_writeb(void *opaque, hwaddr addr,
202
                                   uint64_t val, unsigned size)
203
{
204
    MiscState *s = opaque;
205

    
206
    trace_slavio_aux1_mem_writeb(val & 0xff);
207
    if (val & AUX1_TC) {
208
        // Send a pulse to floppy terminal count line
209
        if (s->fdc_tc) {
210
            qemu_irq_raise(s->fdc_tc);
211
            qemu_irq_lower(s->fdc_tc);
212
        }
213
        val &= ~AUX1_TC;
214
    }
215
    s->aux1 = val & 0xff;
216
}
217

    
218
static uint64_t slavio_aux1_mem_readb(void *opaque, hwaddr addr,
219
                                      unsigned size)
220
{
221
    MiscState *s = opaque;
222
    uint32_t ret = 0;
223

    
224
    ret = s->aux1;
225
    trace_slavio_aux1_mem_readb(ret);
226
    return ret;
227
}
228

    
229
static const MemoryRegionOps slavio_aux1_mem_ops = {
230
    .read = slavio_aux1_mem_readb,
231
    .write = slavio_aux1_mem_writeb,
232
    .endianness = DEVICE_NATIVE_ENDIAN,
233
    .valid = {
234
        .min_access_size = 1,
235
        .max_access_size = 1,
236
    },
237
};
238

    
239
static void slavio_aux2_mem_writeb(void *opaque, hwaddr addr,
240
                                   uint64_t val, unsigned size)
241
{
242
    MiscState *s = opaque;
243

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

    
255
static uint64_t slavio_aux2_mem_readb(void *opaque, hwaddr addr,
256
                                      unsigned size)
257
{
258
    MiscState *s = opaque;
259
    uint32_t ret = 0;
260

    
261
    ret = s->aux2;
262
    trace_slavio_aux2_mem_readb(ret);
263
    return ret;
264
}
265

    
266
static const MemoryRegionOps slavio_aux2_mem_ops = {
267
    .read = slavio_aux2_mem_readb,
268
    .write = slavio_aux2_mem_writeb,
269
    .endianness = DEVICE_NATIVE_ENDIAN,
270
    .valid = {
271
        .min_access_size = 1,
272
        .max_access_size = 1,
273
    },
274
};
275

    
276
static void apc_mem_writeb(void *opaque, hwaddr addr,
277
                           uint64_t val, unsigned size)
278
{
279
    APCState *s = opaque;
280

    
281
    trace_apc_mem_writeb(val & 0xff);
282
    qemu_irq_raise(s->cpu_halt);
283
}
284

    
285
static uint64_t apc_mem_readb(void *opaque, hwaddr addr,
286
                              unsigned size)
287
{
288
    uint32_t ret = 0;
289

    
290
    trace_apc_mem_readb(ret);
291
    return ret;
292
}
293

    
294
static const MemoryRegionOps apc_mem_ops = {
295
    .read = apc_mem_readb,
296
    .write = apc_mem_writeb,
297
    .endianness = DEVICE_NATIVE_ENDIAN,
298
    .valid = {
299
        .min_access_size = 1,
300
        .max_access_size = 1,
301
    }
302
};
303

    
304
static uint64_t slavio_sysctrl_mem_readl(void *opaque, hwaddr addr,
305
                                         unsigned size)
306
{
307
    MiscState *s = opaque;
308
    uint32_t ret = 0;
309

    
310
    switch (addr) {
311
    case 0:
312
        ret = s->sysctrl;
313
        break;
314
    default:
315
        break;
316
    }
317
    trace_slavio_sysctrl_mem_readl(ret);
318
    return ret;
319
}
320

    
321
static void slavio_sysctrl_mem_writel(void *opaque, hwaddr addr,
322
                                      uint64_t val, unsigned size)
323
{
324
    MiscState *s = opaque;
325

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

    
339
static const MemoryRegionOps slavio_sysctrl_mem_ops = {
340
    .read = slavio_sysctrl_mem_readl,
341
    .write = slavio_sysctrl_mem_writel,
342
    .endianness = DEVICE_NATIVE_ENDIAN,
343
    .valid = {
344
        .min_access_size = 4,
345
        .max_access_size = 4,
346
    },
347
};
348

    
349
static uint64_t slavio_led_mem_readw(void *opaque, hwaddr addr,
350
                                     unsigned size)
351
{
352
    MiscState *s = opaque;
353
    uint32_t ret = 0;
354

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

    
366
static void slavio_led_mem_writew(void *opaque, hwaddr addr,
367
                                  uint64_t val, unsigned size)
368
{
369
    MiscState *s = opaque;
370

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

    
381
static const MemoryRegionOps slavio_led_mem_ops = {
382
    .read = slavio_led_mem_readw,
383
    .write = slavio_led_mem_writew,
384
    .endianness = DEVICE_NATIVE_ENDIAN,
385
    .valid = {
386
        .min_access_size = 2,
387
        .max_access_size = 2,
388
    },
389
};
390

    
391
static 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
};
407

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

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

    
414
    /* Power management (APC) XXX: not a Slavio device */
415
    memory_region_init_io(&s->iomem, &apc_mem_ops, s,
416
                          "apc", MISC_SIZE);
417
    sysbus_init_mmio(dev, &s->iomem);
418
    return 0;
419
}
420

    
421
static int slavio_misc_init1(SysBusDevice *dev)
422
{
423
    MiscState *s = FROM_SYSBUS(MiscState, dev);
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
    memory_region_init_io(&s->cfg_iomem, &slavio_cfg_mem_ops, s,
431
                          "configuration", MISC_SIZE);
432
    sysbus_init_mmio(dev, &s->cfg_iomem);
433

    
434
    /* Diagnostics */
435
    memory_region_init_io(&s->diag_iomem, &slavio_diag_mem_ops, s,
436
                          "diagnostic", MISC_SIZE);
437
    sysbus_init_mmio(dev, &s->diag_iomem);
438

    
439
    /* Modem control */
440
    memory_region_init_io(&s->mdm_iomem, &slavio_mdm_mem_ops, s,
441
                          "modem", MISC_SIZE);
442
    sysbus_init_mmio(dev, &s->mdm_iomem);
443

    
444
    /* 16 bit registers */
445
    /* ss600mp diag LEDs */
446
    memory_region_init_io(&s->led_iomem, &slavio_led_mem_ops, s,
447
                          "leds", MISC_SIZE);
448
    sysbus_init_mmio(dev, &s->led_iomem);
449

    
450
    /* 32 bit registers */
451
    /* System control */
452
    memory_region_init_io(&s->sysctrl_iomem, &slavio_sysctrl_mem_ops, s,
453
                          "system-control", MISC_SIZE);
454
    sysbus_init_mmio(dev, &s->sysctrl_iomem);
455

    
456
    /* AUX 1 (Misc System Functions) */
457
    memory_region_init_io(&s->aux1_iomem, &slavio_aux1_mem_ops, s,
458
                          "misc-system-functions", MISC_SIZE);
459
    sysbus_init_mmio(dev, &s->aux1_iomem);
460

    
461
    /* AUX 2 (Software Powerdown Control) */
462
    memory_region_init_io(&s->aux2_iomem, &slavio_aux2_mem_ops, s,
463
                          "software-powerdown-control", MISC_SIZE);
464
    sysbus_init_mmio(dev, &s->aux2_iomem);
465

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

    
468
    return 0;
469
}
470

    
471
static void slavio_misc_class_init(ObjectClass *klass, void *data)
472
{
473
    DeviceClass *dc = DEVICE_CLASS(klass);
474
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
475

    
476
    k->init = slavio_misc_init1;
477
    dc->reset = slavio_misc_reset;
478
    dc->vmsd = &vmstate_misc;
479
}
480

    
481
static const TypeInfo slavio_misc_info = {
482
    .name          = "slavio_misc",
483
    .parent        = TYPE_SYS_BUS_DEVICE,
484
    .instance_size = sizeof(MiscState),
485
    .class_init    = slavio_misc_class_init,
486
};
487

    
488
static void apc_class_init(ObjectClass *klass, void *data)
489
{
490
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
491

    
492
    k->init = apc_init1;
493
}
494

    
495
static const TypeInfo apc_info = {
496
    .name          = "apc",
497
    .parent        = TYPE_SYS_BUS_DEVICE,
498
    .instance_size = sizeof(MiscState),
499
    .class_init    = apc_class_init,
500
};
501

    
502
static void slavio_misc_register_types(void)
503
{
504
    type_register_static(&slavio_misc_info);
505
    type_register_static(&apc_info);
506
}
507

    
508
type_init(slavio_misc_register_types)