Statistics
| Branch: | Revision:

root / hw / slavio_misc.c @ 6a3b9cc9

History | View | Annotate | Download (10.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
#include "vl.h"
25
/* debug misc */
26
//#define DEBUG_MISC
27

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

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

    
43
typedef struct MiscState {
44
    qemu_irq irq;
45
    uint8_t config;
46
    uint8_t aux1, aux2;
47
    uint8_t diag, mctrl;
48
    uint32_t sysctrl;
49
    uint16_t leds;
50
} MiscState;
51

    
52
#define MISC_SIZE 1
53
#define SYSCTRL_MAXADDR 3
54
#define SYSCTRL_SIZE (SYSCTRL_MAXADDR + 1)
55
#define LED_MAXADDR 2
56
#define LED_SIZE (LED_MAXADDR + 1)
57

    
58
static void slavio_misc_update_irq(void *opaque)
59
{
60
    MiscState *s = opaque;
61

    
62
    if ((s->aux2 & 0x4) && (s->config & 0x8)) {
63
        MISC_DPRINTF("Raise IRQ\n");
64
        qemu_irq_raise(s->irq);
65
    } else {
66
        MISC_DPRINTF("Lower IRQ\n");
67
        qemu_irq_lower(s->irq);
68
    }
69
}
70

    
71
static void slavio_misc_reset(void *opaque)
72
{
73
    MiscState *s = opaque;
74

    
75
    // Diagnostic and system control registers not cleared in reset
76
    s->config = s->aux1 = s->aux2 = s->mctrl = 0;
77
}
78

    
79
void slavio_set_power_fail(void *opaque, int power_failing)
80
{
81
    MiscState *s = opaque;
82

    
83
    MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
84
    if (power_failing && (s->config & 0x8)) {
85
        s->aux2 |= 0x4;
86
    } else {
87
        s->aux2 &= ~0x4;
88
    }
89
    slavio_misc_update_irq(s);
90
}
91

    
92
static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr,
93
                                   uint32_t val)
94
{
95
    MiscState *s = opaque;
96

    
97
    switch (addr & 0xfff0000) {
98
    case 0x1800000:
99
        MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
100
        s->config = val & 0xff;
101
        slavio_misc_update_irq(s);
102
        break;
103
    case 0x1900000:
104
        MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
105
        s->aux1 = val & 0xff;
106
        break;
107
    case 0x1910000:
108
        val &= 0x3;
109
        MISC_DPRINTF("Write aux2 %2.2x\n", val);
110
        val |= s->aux2 & 0x4;
111
        if (val & 0x2) // Clear Power Fail int
112
            val &= 0x1;
113
        s->aux2 = val;
114
        if (val & 1)
115
            qemu_system_shutdown_request();
116
        slavio_misc_update_irq(s);
117
        break;
118
    case 0x1a00000:
119
        MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
120
        s->diag = val & 0xff;
121
        break;
122
    case 0x1b00000:
123
        MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
124
        s->mctrl = val & 0xff;
125
        break;
126
    case 0xa000000:
127
        MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
128
        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
129
        break;
130
    }
131
}
132

    
133
static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
134
{
135
    MiscState *s = opaque;
136
    uint32_t ret = 0;
137

    
138
    switch (addr & 0xfff0000) {
139
    case 0x1800000:
140
        ret = s->config;
141
        MISC_DPRINTF("Read config %2.2x\n", ret);
142
        break;
143
    case 0x1900000:
144
        ret = s->aux1;
145
        MISC_DPRINTF("Read aux1 %2.2x\n", ret);
146
        break;
147
    case 0x1910000:
148
        ret = s->aux2;
149
        MISC_DPRINTF("Read aux2 %2.2x\n", ret);
150
        break;
151
    case 0x1a00000:
152
        ret = s->diag;
153
        MISC_DPRINTF("Read diag %2.2x\n", ret);
154
        break;
155
    case 0x1b00000:
156
        ret = s->mctrl;
157
        MISC_DPRINTF("Read modem control %2.2x\n", ret);
158
        break;
159
    case 0xa000000:
160
        MISC_DPRINTF("Read power management %2.2x\n", ret);
161
        break;
162
    }
163
    return ret;
164
}
165

    
166
static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
167
    slavio_misc_mem_readb,
168
    slavio_misc_mem_readb,
169
    slavio_misc_mem_readb,
170
};
171

    
172
static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
173
    slavio_misc_mem_writeb,
174
    slavio_misc_mem_writeb,
175
    slavio_misc_mem_writeb,
176
};
177

    
178
static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
179
{
180
    MiscState *s = opaque;
181
    uint32_t ret = 0, saddr;
182

    
183
    saddr = addr & SYSCTRL_MAXADDR;
184
    switch (saddr) {
185
    case 0:
186
        ret = s->sysctrl;
187
        break;
188
    default:
189
        break;
190
    }
191
    MISC_DPRINTF("Read system control reg 0x" TARGET_FMT_plx " = %x\n", addr,
192
                 ret);
193
    return ret;
194
}
195

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

    
202
    saddr = addr & SYSCTRL_MAXADDR;
203
    MISC_DPRINTF("Write system control reg 0x" TARGET_FMT_plx " =  %x\n", addr,
204
                 val);
205
    switch (saddr) {
206
    case 0:
207
        if (val & 1) {
208
            s->sysctrl = 0x2;
209
            qemu_system_reset_request();
210
        }
211
        break;
212
    default:
213
        break;
214
    }
215
}
216

    
217
static CPUReadMemoryFunc *slavio_sysctrl_mem_read[3] = {
218
    slavio_sysctrl_mem_readl,
219
    slavio_sysctrl_mem_readl,
220
    slavio_sysctrl_mem_readl,
221
};
222

    
223
static CPUWriteMemoryFunc *slavio_sysctrl_mem_write[3] = {
224
    slavio_sysctrl_mem_writel,
225
    slavio_sysctrl_mem_writel,
226
    slavio_sysctrl_mem_writel,
227
};
228

    
229
static uint32_t slavio_led_mem_reads(void *opaque, target_phys_addr_t addr)
230
{
231
    MiscState *s = opaque;
232
    uint32_t ret = 0, saddr;
233

    
234
    saddr = addr & LED_MAXADDR;
235
    switch (saddr) {
236
    case 0:
237
        ret = s->leds;
238
        break;
239
    default:
240
        break;
241
    }
242
    MISC_DPRINTF("Read diagnostic LED reg 0x" TARGET_FMT_plx " = %x\n", addr,
243
                 ret);
244
    return ret;
245
}
246

    
247
static void slavio_led_mem_writes(void *opaque, target_phys_addr_t addr,
248
                                  uint32_t val)
249
{
250
    MiscState *s = opaque;
251
    uint32_t saddr;
252

    
253
    saddr = addr & LED_MAXADDR;
254
    MISC_DPRINTF("Write diagnostic LED reg 0x" TARGET_FMT_plx " =  %x\n", addr,
255
                 val);
256
    switch (saddr) {
257
    case 0:
258
        s->sysctrl = val;
259
        break;
260
    default:
261
        break;
262
    }
263
}
264

    
265
static CPUReadMemoryFunc *slavio_led_mem_read[3] = {
266
    slavio_led_mem_reads,
267
    slavio_led_mem_reads,
268
    slavio_led_mem_reads,
269
};
270

    
271
static CPUWriteMemoryFunc *slavio_led_mem_write[3] = {
272
    slavio_led_mem_writes,
273
    slavio_led_mem_writes,
274
    slavio_led_mem_writes,
275
};
276

    
277
static void slavio_misc_save(QEMUFile *f, void *opaque)
278
{
279
    MiscState *s = opaque;
280
    int tmp;
281
    uint8_t tmp8;
282

    
283
    tmp = 0;
284
    qemu_put_be32s(f, &tmp); /* ignored, was IRQ.  */
285
    qemu_put_8s(f, &s->config);
286
    qemu_put_8s(f, &s->aux1);
287
    qemu_put_8s(f, &s->aux2);
288
    qemu_put_8s(f, &s->diag);
289
    qemu_put_8s(f, &s->mctrl);
290
    tmp8 = s->sysctrl & 0xff;
291
    qemu_put_8s(f, &tmp8);
292
}
293

    
294
static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
295
{
296
    MiscState *s = opaque;
297
    int tmp;
298
    uint8_t tmp8;
299

    
300
    if (version_id != 1)
301
        return -EINVAL;
302

    
303
    qemu_get_be32s(f, &tmp);
304
    qemu_get_8s(f, &s->config);
305
    qemu_get_8s(f, &s->aux1);
306
    qemu_get_8s(f, &s->aux2);
307
    qemu_get_8s(f, &s->diag);
308
    qemu_get_8s(f, &s->mctrl);
309
    qemu_get_8s(f, &tmp8);
310
    s->sysctrl = (uint32_t)tmp8;
311
    return 0;
312
}
313

    
314
void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base,
315
                       qemu_irq irq)
316
{
317
    int slavio_misc_io_memory;
318
    MiscState *s;
319

    
320
    s = qemu_mallocz(sizeof(MiscState));
321
    if (!s)
322
        return NULL;
323

    
324
    /* 8 bit registers */
325
    slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read,
326
                                                   slavio_misc_mem_write, s);
327
    // Slavio control
328
    cpu_register_physical_memory(base + 0x1800000, MISC_SIZE,
329
                                 slavio_misc_io_memory);
330
    // AUX 1
331
    cpu_register_physical_memory(base + 0x1900000, MISC_SIZE,
332
                                 slavio_misc_io_memory);
333
    // AUX 2
334
    cpu_register_physical_memory(base + 0x1910000, MISC_SIZE,
335
                                 slavio_misc_io_memory);
336
    // Diagnostics
337
    cpu_register_physical_memory(base + 0x1a00000, MISC_SIZE,
338
                                 slavio_misc_io_memory);
339
    // Modem control
340
    cpu_register_physical_memory(base + 0x1b00000, MISC_SIZE,
341
                                 slavio_misc_io_memory);
342
    // Power management
343
    cpu_register_physical_memory(power_base, MISC_SIZE, slavio_misc_io_memory);
344

    
345
    /* 16 bit registers */
346
    slavio_misc_io_memory = cpu_register_io_memory(0, slavio_led_mem_read,
347
                                                   slavio_led_mem_write, s);
348
    /* ss600mp diag LEDs */
349
    cpu_register_physical_memory(base + 0x1600000, MISC_SIZE,
350
                                 slavio_misc_io_memory);
351

    
352
    /* 32 bit registers */
353
    slavio_misc_io_memory = cpu_register_io_memory(0, slavio_sysctrl_mem_read,
354
                                                   slavio_sysctrl_mem_write,
355
                                                   s);
356
    // System control
357
    cpu_register_physical_memory(base + 0x1f00000, SYSCTRL_SIZE,
358
                                 slavio_misc_io_memory);
359

    
360
    s->irq = irq;
361

    
362
    register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load,
363
                    s);
364
    qemu_register_reset(slavio_misc_reset, s);
365
    slavio_misc_reset(s);
366
    return s;
367
}