Statistics
| Branch: | Revision:

root / hw / slavio_misc.c @ 0019ad53

History | View | Annotate | Download (11.7 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
#include "hw.h"
25
#include "sun4m.h"
26
#include "sysemu.h"
27

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

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

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

    
46
typedef struct MiscState {
47
    qemu_irq irq;
48
    uint8_t config;
49
    uint8_t aux1, aux2;
50
    uint8_t diag, mctrl;
51
    uint32_t sysctrl;
52
    uint16_t leds;
53
    CPUState *env;
54
} MiscState;
55

    
56
#define MISC_SIZE 1
57
#define SYSCTRL_MAXADDR 3
58
#define SYSCTRL_SIZE (SYSCTRL_MAXADDR + 1)
59
#define LED_MAXADDR 1
60
#define LED_SIZE (LED_MAXADDR + 1)
61

    
62
#define MISC_MASK 0x0fff0000
63
#define MISC_LEDS 0x01600000
64
#define MISC_CFG  0x01800000
65
#define MISC_DIAG 0x01a00000
66
#define MISC_MDM  0x01b00000
67
#define MISC_SYS  0x01f00000
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
void slavio_set_power_fail(void *opaque, 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_misc_mem_writeb(void *opaque, target_phys_addr_t addr,
113
                                   uint32_t val)
114
{
115
    MiscState *s = opaque;
116

    
117
    switch (addr & MISC_MASK) {
118
    case MISC_CFG:
119
        MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
120
        s->config = val & 0xff;
121
        slavio_misc_update_irq(s);
122
        break;
123
    case MISC_DIAG:
124
        MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
125
        s->diag = val & 0xff;
126
        break;
127
    case MISC_MDM:
128
        MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
129
        s->mctrl = val & 0xff;
130
        break;
131
    default:
132
        break;
133
    }
134
}
135

    
136
static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
137
{
138
    MiscState *s = opaque;
139
    uint32_t ret = 0;
140

    
141
    switch (addr & MISC_MASK) {
142
    case MISC_CFG:
143
        ret = s->config;
144
        MISC_DPRINTF("Read config %2.2x\n", ret);
145
        break;
146
    case MISC_DIAG:
147
        ret = s->diag;
148
        MISC_DPRINTF("Read diag %2.2x\n", ret);
149
        break;
150
    case MISC_MDM:
151
        ret = s->mctrl;
152
        MISC_DPRINTF("Read modem control %2.2x\n", ret);
153
        break;
154
    default:
155
        break;
156
    }
157
    return ret;
158
}
159

    
160
static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
161
    slavio_misc_mem_readb,
162
    NULL,
163
    NULL,
164
};
165

    
166
static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
167
    slavio_misc_mem_writeb,
168
    NULL,
169
    NULL,
170
};
171

    
172
static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
173
                                   uint32_t val)
174
{
175
    MiscState *s = opaque;
176

    
177
    MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
178
    s->aux1 = val & 0xff;
179
}
180

    
181
static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr)
182
{
183
    MiscState *s = opaque;
184
    uint32_t ret = 0;
185

    
186
    ret = s->aux1;
187
    MISC_DPRINTF("Read aux1 %2.2x\n", ret);
188

    
189
    return ret;
190
}
191

    
192
static CPUReadMemoryFunc *slavio_aux1_mem_read[3] = {
193
    slavio_aux1_mem_readb,
194
    NULL,
195
    NULL,
196
};
197

    
198
static CPUWriteMemoryFunc *slavio_aux1_mem_write[3] = {
199
    slavio_aux1_mem_writeb,
200
    NULL,
201
    NULL,
202
};
203

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

    
209
    val &= AUX2_PWRINTCLR | AUX2_PWROFF;
210
    MISC_DPRINTF("Write aux2 %2.2x\n", val);
211
    val |= s->aux2 & AUX2_PWRFAIL;
212
    if (val & AUX2_PWRINTCLR) // Clear Power Fail int
213
        val &= AUX2_PWROFF;
214
    s->aux2 = val;
215
    if (val & AUX2_PWROFF)
216
        qemu_system_shutdown_request();
217
    slavio_misc_update_irq(s);
218
}
219

    
220
static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr)
221
{
222
    MiscState *s = opaque;
223
    uint32_t ret = 0;
224

    
225
    ret = s->aux2;
226
    MISC_DPRINTF("Read aux2 %2.2x\n", ret);
227

    
228
    return ret;
229
}
230

    
231
static CPUReadMemoryFunc *slavio_aux2_mem_read[3] = {
232
    slavio_aux2_mem_readb,
233
    NULL,
234
    NULL,
235
};
236

    
237
static CPUWriteMemoryFunc *slavio_aux2_mem_write[3] = {
238
    slavio_aux2_mem_writeb,
239
    NULL,
240
    NULL,
241
};
242

    
243
static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
244
{
245
    MiscState *s = opaque;
246

    
247
    MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
248
    cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
249
}
250

    
251
static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr)
252
{
253
    uint32_t ret = 0;
254

    
255
    MISC_DPRINTF("Read power management %2.2x\n", ret);
256
    return ret;
257
}
258

    
259
static CPUReadMemoryFunc *apc_mem_read[3] = {
260
    apc_mem_readb,
261
    NULL,
262
    NULL,
263
};
264

    
265
static CPUWriteMemoryFunc *apc_mem_write[3] = {
266
    apc_mem_writeb,
267
    NULL,
268
    NULL,
269
};
270

    
271
static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
272
{
273
    MiscState *s = opaque;
274
    uint32_t ret = 0, saddr;
275

    
276
    saddr = addr & SYSCTRL_MAXADDR;
277
    switch (saddr) {
278
    case 0:
279
        ret = s->sysctrl;
280
        break;
281
    default:
282
        break;
283
    }
284
    MISC_DPRINTF("Read system control reg 0x" TARGET_FMT_plx " = %x\n", addr,
285
                 ret);
286
    return ret;
287
}
288

    
289
static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
290
                                      uint32_t val)
291
{
292
    MiscState *s = opaque;
293
    uint32_t saddr;
294

    
295
    saddr = addr & SYSCTRL_MAXADDR;
296
    MISC_DPRINTF("Write system control reg 0x" TARGET_FMT_plx " =  %x\n", addr,
297
                 val);
298
    switch (saddr) {
299
    case 0:
300
        if (val & SYS_RESET) {
301
            s->sysctrl = SYS_RESETSTAT;
302
            qemu_system_reset_request();
303
        }
304
        break;
305
    default:
306
        break;
307
    }
308
}
309

    
310
static CPUReadMemoryFunc *slavio_sysctrl_mem_read[3] = {
311
    NULL,
312
    NULL,
313
    slavio_sysctrl_mem_readl,
314
};
315

    
316
static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = {
317
    NULL,
318
    NULL,
319
    slavio_sysctrl_mem_writel,
320
};
321

    
322
static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
323
{
324
    MiscState *s = opaque;
325
    uint32_t ret = 0, saddr;
326

    
327
    saddr = addr & LED_MAXADDR;
328
    switch (saddr) {
329
    case 0:
330
        ret = s->leds;
331
        break;
332
    default:
333
        break;
334
    }
335
    MISC_DPRINTF("Read diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr,
336
                 ret);
337
    return ret;
338
}
339

    
340
static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
341
                                  uint32_t val)
342
{
343
    MiscState *s = opaque;
344
    uint32_t saddr;
345

    
346
    saddr = addr & LED_MAXADDR;
347
    MISC_DPRINTF("Write diagnostic LED reg 0x" TARGET_FMT_plx " =  %x\n", addr,
348
                 val);
349
    switch (saddr) {
350
    case 0:
351
        s->leds = val;
352
        break;
353
    default:
354
        break;
355
    }
356
}
357

    
358
static CPUReadMemoryFunc *slavio_led_mem_read[3] = {
359
    NULL,
360
    slavio_led_mem_readw,
361
    NULL,
362
};
363

    
364
static CPUWriteMemoryFunc *slavio_led_mem_write[3] = {
365
    NULL,
366
    slavio_led_mem_writew,
367
    NULL,
368
};
369

    
370
static void slavio_misc_save(QEMUFile *f, void *opaque)
371
{
372
    MiscState *s = opaque;
373
    int tmp;
374
    uint8_t tmp8;
375

    
376
    tmp = 0;
377
    qemu_put_be32s(f, &tmp); /* ignored, was IRQ.  */
378
    qemu_put_8s(f, &s->config);
379
    qemu_put_8s(f, &s->aux1);
380
    qemu_put_8s(f, &s->aux2);
381
    qemu_put_8s(f, &s->diag);
382
    qemu_put_8s(f, &s->mctrl);
383
    tmp8 = s->sysctrl & 0xff;
384
    qemu_put_8s(f, &tmp8);
385
}
386

    
387
static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
388
{
389
    MiscState *s = opaque;
390
    int tmp;
391
    uint8_t tmp8;
392

    
393
    if (version_id != 1)
394
        return -EINVAL;
395

    
396
    qemu_get_be32s(f, &tmp);
397
    qemu_get_8s(f, &s->config);
398
    qemu_get_8s(f, &s->aux1);
399
    qemu_get_8s(f, &s->aux2);
400
    qemu_get_8s(f, &s->diag);
401
    qemu_get_8s(f, &s->mctrl);
402
    qemu_get_8s(f, &tmp8);
403
    s->sysctrl = (uint32_t)tmp8;
404
    return 0;
405
}
406

    
407
void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base,
408
                       target_phys_addr_t aux1_base,
409
                       target_phys_addr_t aux2_base, qemu_irq irq,
410
                       CPUState *env)
411
{
412
    int io;
413
    MiscState *s;
414

    
415
    s = qemu_mallocz(sizeof(MiscState));
416
    if (!s)
417
        return NULL;
418

    
419
    if (base) {
420
        /* 8 bit registers */
421
        io = cpu_register_io_memory(0, slavio_misc_mem_read,
422
                                    slavio_misc_mem_write, s);
423
        // Slavio control
424
        cpu_register_physical_memory(base + MISC_CFG, MISC_SIZE, io);
425
        // Diagnostics
426
        cpu_register_physical_memory(base + MISC_DIAG, MISC_SIZE, io);
427
        // Modem control
428
        cpu_register_physical_memory(base + MISC_MDM, MISC_SIZE, io);
429

    
430
        /* 16 bit registers */
431
        io = cpu_register_io_memory(0, slavio_led_mem_read,
432
                                    slavio_led_mem_write, s);
433
        /* ss600mp diag LEDs */
434
        cpu_register_physical_memory(base + MISC_LEDS, MISC_SIZE, io);
435

    
436
        /* 32 bit registers */
437
        io = cpu_register_io_memory(0, slavio_sysctrl_mem_read,
438
                                    slavio_sysctrl_mem_write, s);
439
        // System control
440
        cpu_register_physical_memory(base + MISC_SYS, SYSCTRL_SIZE, io);
441
    }
442

    
443
    // AUX 1 (Misc System Functions)
444
    if (aux1_base) {
445
        io = cpu_register_io_memory(0, slavio_aux1_mem_read,
446
                                    slavio_aux1_mem_write, s);
447
        cpu_register_physical_memory(aux1_base, MISC_SIZE, io);
448
    }
449

    
450
    // AUX 2 (Software Powerdown Control)
451
    if (aux2_base) {
452
        io = cpu_register_io_memory(0, slavio_aux2_mem_read,
453
                                    slavio_aux2_mem_write, s);
454
        cpu_register_physical_memory(aux2_base, MISC_SIZE, io);
455
    }
456

    
457
    // Power management (APC) XXX: not a Slavio device
458
    if (power_base) {
459
        io = cpu_register_io_memory(0, apc_mem_read, apc_mem_write, s);
460
        cpu_register_physical_memory(power_base, MISC_SIZE, io);
461
    }
462

    
463
    s->irq = irq;
464
    s->env = env;
465

    
466
    register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load,
467
                    s);
468
    qemu_register_reset(slavio_misc_reset, s);
469
    slavio_misc_reset(s);
470

    
471
    return s;
472
}