Statistics
| Branch: | Revision:

root / hw / slavio_misc.c @ 423d65f4

History | View | Annotate | Download (10.6 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
    target_phys_addr_t power_base;
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_AUX1 0x01900000
66
#define MISC_AUX2 0x01910000
67
#define MISC_DIAG 0x01a00000
68
#define MISC_MDM  0x01b00000
69
#define MISC_SYS  0x01f00000
70

    
71
#define AUX2_PWROFF    0x01
72
#define AUX2_PWRINTCLR 0x02
73
#define AUX2_PWRFAIL   0x20
74

    
75
#define CFG_PWRINTEN   0x08
76

    
77
#define SYS_RESET      0x01
78
#define SYS_RESETSTAT  0x02
79

    
80
static void slavio_misc_update_irq(void *opaque)
81
{
82
    MiscState *s = opaque;
83

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

    
93
static void slavio_misc_reset(void *opaque)
94
{
95
    MiscState *s = opaque;
96

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

    
101
void slavio_set_power_fail(void *opaque, int power_failing)
102
{
103
    MiscState *s = opaque;
104

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

    
114
static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr,
115
                                   uint32_t val)
116
{
117
    MiscState *s = opaque;
118

    
119
    switch (addr & MISC_MASK) {
120
    case MISC_CFG:
121
        MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
122
        s->config = val & 0xff;
123
        slavio_misc_update_irq(s);
124
        break;
125
    case MISC_AUX1:
126
        MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
127
        s->aux1 = val & 0xff;
128
        break;
129
    case MISC_AUX2:
130
        val &= AUX2_PWRINTCLR | AUX2_PWROFF;
131
        MISC_DPRINTF("Write aux2 %2.2x\n", val);
132
        val |= s->aux2 & AUX2_PWRFAIL;
133
        if (val & AUX2_PWRINTCLR) // Clear Power Fail int
134
            val &= AUX2_PWROFF;
135
        s->aux2 = val;
136
        if (val & AUX2_PWROFF)
137
            qemu_system_shutdown_request();
138
        slavio_misc_update_irq(s);
139
        break;
140
    case MISC_DIAG:
141
        MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
142
        s->diag = val & 0xff;
143
        break;
144
    case MISC_MDM:
145
        MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
146
        s->mctrl = val & 0xff;
147
        break;
148
    default:
149
        if (addr == s->power_base) {
150
            MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
151
            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
152
        }
153
        break;
154
    }
155
}
156

    
157
static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
158
{
159
    MiscState *s = opaque;
160
    uint32_t ret = 0;
161

    
162
    switch (addr & MISC_MASK) {
163
    case MISC_CFG:
164
        ret = s->config;
165
        MISC_DPRINTF("Read config %2.2x\n", ret);
166
        break;
167
    case MISC_AUX1:
168
        ret = s->aux1;
169
        MISC_DPRINTF("Read aux1 %2.2x\n", ret);
170
        break;
171
    case MISC_AUX2:
172
        ret = s->aux2;
173
        MISC_DPRINTF("Read aux2 %2.2x\n", ret);
174
        break;
175
    case MISC_DIAG:
176
        ret = s->diag;
177
        MISC_DPRINTF("Read diag %2.2x\n", ret);
178
        break;
179
    case MISC_MDM:
180
        ret = s->mctrl;
181
        MISC_DPRINTF("Read modem control %2.2x\n", ret);
182
        break;
183
    default:
184
        if (addr == s->power_base) {
185
            MISC_DPRINTF("Read power management %2.2x\n", ret);
186
        }
187
        break;
188
    }
189
    return ret;
190
}
191

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

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

    
204
static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
205
{
206
    MiscState *s = opaque;
207
    uint32_t ret = 0, saddr;
208

    
209
    saddr = addr & SYSCTRL_MAXADDR;
210
    switch (saddr) {
211
    case 0:
212
        ret = s->sysctrl;
213
        break;
214
    default:
215
        break;
216
    }
217
    MISC_DPRINTF("Read system control reg 0x" TARGET_FMT_plx " = %x\n", addr,
218
                 ret);
219
    return ret;
220
}
221

    
222
static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
223
                                      uint32_t val)
224
{
225
    MiscState *s = opaque;
226
    uint32_t saddr;
227

    
228
    saddr = addr & SYSCTRL_MAXADDR;
229
    MISC_DPRINTF("Write system control reg 0x" TARGET_FMT_plx " =  %x\n", addr,
230
                 val);
231
    switch (saddr) {
232
    case 0:
233
        if (val & SYS_RESET) {
234
            s->sysctrl = SYS_RESETSTAT;
235
            qemu_system_reset_request();
236
        }
237
        break;
238
    default:
239
        break;
240
    }
241
}
242

    
243
static CPUReadMemoryFunc *slavio_sysctrl_mem_read[3] = {
244
    NULL,
245
    NULL,
246
    slavio_sysctrl_mem_readl,
247
};
248

    
249
static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = {
250
    NULL,
251
    NULL,
252
    slavio_sysctrl_mem_writel,
253
};
254

    
255
static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
256
{
257
    MiscState *s = opaque;
258
    uint32_t ret = 0, saddr;
259

    
260
    saddr = addr & LED_MAXADDR;
261
    switch (saddr) {
262
    case 0:
263
        ret = s->leds;
264
        break;
265
    default:
266
        break;
267
    }
268
    MISC_DPRINTF("Read diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr,
269
                 ret);
270
    return ret;
271
}
272

    
273
static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
274
                                  uint32_t val)
275
{
276
    MiscState *s = opaque;
277
    uint32_t saddr;
278

    
279
    saddr = addr & LED_MAXADDR;
280
    MISC_DPRINTF("Write diagnostic LED reg 0x" TARGET_FMT_plx " =  %x\n", addr,
281
                 val);
282
    switch (saddr) {
283
    case 0:
284
        s->leds = val;
285
        break;
286
    default:
287
        break;
288
    }
289
}
290

    
291
static CPUReadMemoryFunc *slavio_led_mem_read[3] = {
292
    NULL,
293
    slavio_led_mem_readw,
294
    NULL,
295
};
296

    
297
static CPUWriteMemoryFunc *slavio_led_mem_write[3] = {
298
    NULL,
299
    slavio_led_mem_writew,
300
    NULL,
301
};
302

    
303
static void slavio_misc_save(QEMUFile *f, void *opaque)
304
{
305
    MiscState *s = opaque;
306
    int tmp;
307
    uint8_t tmp8;
308

    
309
    tmp = 0;
310
    qemu_put_be32s(f, &tmp); /* ignored, was IRQ.  */
311
    qemu_put_8s(f, &s->config);
312
    qemu_put_8s(f, &s->aux1);
313
    qemu_put_8s(f, &s->aux2);
314
    qemu_put_8s(f, &s->diag);
315
    qemu_put_8s(f, &s->mctrl);
316
    tmp8 = s->sysctrl & 0xff;
317
    qemu_put_8s(f, &tmp8);
318
}
319

    
320
static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
321
{
322
    MiscState *s = opaque;
323
    int tmp;
324
    uint8_t tmp8;
325

    
326
    if (version_id != 1)
327
        return -EINVAL;
328

    
329
    qemu_get_be32s(f, &tmp);
330
    qemu_get_8s(f, &s->config);
331
    qemu_get_8s(f, &s->aux1);
332
    qemu_get_8s(f, &s->aux2);
333
    qemu_get_8s(f, &s->diag);
334
    qemu_get_8s(f, &s->mctrl);
335
    qemu_get_8s(f, &tmp8);
336
    s->sysctrl = (uint32_t)tmp8;
337
    return 0;
338
}
339

    
340
void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base,
341
                       qemu_irq irq)
342
{
343
    int slavio_misc_io_memory;
344
    MiscState *s;
345

    
346
    s = qemu_mallocz(sizeof(MiscState));
347
    if (!s)
348
        return NULL;
349

    
350
    /* 8 bit registers */
351
    slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read,
352
                                                   slavio_misc_mem_write, s);
353
    // Slavio control
354
    cpu_register_physical_memory(base + MISC_CFG, MISC_SIZE,
355
                                 slavio_misc_io_memory);
356
    // AUX 1
357
    cpu_register_physical_memory(base + MISC_AUX1, MISC_SIZE,
358
                                 slavio_misc_io_memory);
359
    // AUX 2
360
    cpu_register_physical_memory(base + MISC_AUX2, MISC_SIZE,
361
                                 slavio_misc_io_memory);
362
    // Diagnostics
363
    cpu_register_physical_memory(base + MISC_DIAG, MISC_SIZE,
364
                                 slavio_misc_io_memory);
365
    // Modem control
366
    cpu_register_physical_memory(base + MISC_MDM, MISC_SIZE,
367
                                 slavio_misc_io_memory);
368
    // Power management
369
    cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory);
370
    s->power_base = power_base;
371

    
372
    /* 16 bit registers */
373
    slavio_misc_io_memory = cpu_register_io_memory(0, slavio_led_mem_read,
374
                                                   slavio_led_mem_write, s);
375
    /* ss600mp diag LEDs */
376
    cpu_register_physical_memory(base + MISC_LEDS, MISC_SIZE,
377
                                 slavio_misc_io_memory);
378

    
379
    /* 32 bit registers */
380
    slavio_misc_io_memory = cpu_register_io_memory(0, slavio_sysctrl_mem_read,
381
                                                   slavio_sysctrl_mem_write,
382
                                                   s);
383
    // System control
384
    cpu_register_physical_memory(base + MISC_SYS, SYSCTRL_SIZE,
385
                                 slavio_misc_io_memory);
386

    
387
    s->irq = irq;
388

    
389
    register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load,
390
                    s);
391
    qemu_register_reset(slavio_misc_reset, s);
392
    slavio_misc_reset(s);
393
    return s;
394
}