Statistics
| Branch: | Revision:

root / hw / arm_sysctl.c @ 291155cb

History | View | Annotate | Download (16.7 kB)

1
/*
2
 * Status and system control registers for ARM RealView/Versatile boards.
3
 *
4
 * Copyright (c) 2006-2007 CodeSourcery.
5
 * Written by Paul Brook
6
 *
7
 * This code is licensed under the GPL.
8
 */
9

    
10
#include "hw/hw.h"
11
#include "qemu/timer.h"
12
#include "qemu/bitops.h"
13
#include "hw/sysbus.h"
14
#include "hw/primecell.h"
15
#include "sysemu/sysemu.h"
16

    
17
#define LOCK_VALUE 0xa05f
18

    
19
typedef struct {
20
    SysBusDevice busdev;
21
    MemoryRegion iomem;
22
    qemu_irq pl110_mux_ctrl;
23

    
24
    uint32_t sys_id;
25
    uint32_t leds;
26
    uint16_t lockval;
27
    uint32_t cfgdata1;
28
    uint32_t cfgdata2;
29
    uint32_t flags;
30
    uint32_t nvflags;
31
    uint32_t resetlevel;
32
    uint32_t proc_id;
33
    uint32_t sys_mci;
34
    uint32_t sys_cfgdata;
35
    uint32_t sys_cfgctrl;
36
    uint32_t sys_cfgstat;
37
    uint32_t sys_clcd;
38
} arm_sysctl_state;
39

    
40
static const VMStateDescription vmstate_arm_sysctl = {
41
    .name = "realview_sysctl",
42
    .version_id = 3,
43
    .minimum_version_id = 1,
44
    .fields = (VMStateField[]) {
45
        VMSTATE_UINT32(leds, arm_sysctl_state),
46
        VMSTATE_UINT16(lockval, arm_sysctl_state),
47
        VMSTATE_UINT32(cfgdata1, arm_sysctl_state),
48
        VMSTATE_UINT32(cfgdata2, arm_sysctl_state),
49
        VMSTATE_UINT32(flags, arm_sysctl_state),
50
        VMSTATE_UINT32(nvflags, arm_sysctl_state),
51
        VMSTATE_UINT32(resetlevel, arm_sysctl_state),
52
        VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2),
53
        VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2),
54
        VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),
55
        VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),
56
        VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3),
57
        VMSTATE_END_OF_LIST()
58
    }
59
};
60

    
61
/* The PB926 actually uses a different format for
62
 * its SYS_ID register. Fortunately the bits which are
63
 * board type on later boards are distinct.
64
 */
65
#define BOARD_ID_PB926 0x100
66
#define BOARD_ID_EB 0x140
67
#define BOARD_ID_PBA8 0x178
68
#define BOARD_ID_PBX 0x182
69
#define BOARD_ID_VEXPRESS 0x190
70

    
71
static int board_id(arm_sysctl_state *s)
72
{
73
    /* Extract the board ID field from the SYS_ID register value */
74
    return (s->sys_id >> 16) & 0xfff;
75
}
76

    
77
static void arm_sysctl_reset(DeviceState *d)
78
{
79
    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d));
80

    
81
    s->leds = 0;
82
    s->lockval = 0;
83
    s->cfgdata1 = 0;
84
    s->cfgdata2 = 0;
85
    s->flags = 0;
86
    s->resetlevel = 0;
87
    if (board_id(s) == BOARD_ID_VEXPRESS) {
88
        /* On VExpress this register will RAZ/WI */
89
        s->sys_clcd = 0;
90
    } else {
91
        /* All others: CLCDID 0x1f, indicating VGA */
92
        s->sys_clcd = 0x1f00;
93
    }
94
}
95

    
96
static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,
97
                                unsigned size)
98
{
99
    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
100

    
101
    switch (offset) {
102
    case 0x00: /* ID */
103
        return s->sys_id;
104
    case 0x04: /* SW */
105
        /* General purpose hardware switches.
106
           We don't have a useful way of exposing these to the user.  */
107
        return 0;
108
    case 0x08: /* LED */
109
        return s->leds;
110
    case 0x20: /* LOCK */
111
        return s->lockval;
112
    case 0x0c: /* OSC0 */
113
    case 0x10: /* OSC1 */
114
    case 0x14: /* OSC2 */
115
    case 0x18: /* OSC3 */
116
    case 0x1c: /* OSC4 */
117
    case 0x24: /* 100HZ */
118
        /* ??? Implement these.  */
119
        return 0;
120
    case 0x28: /* CFGDATA1 */
121
        return s->cfgdata1;
122
    case 0x2c: /* CFGDATA2 */
123
        return s->cfgdata2;
124
    case 0x30: /* FLAGS */
125
        return s->flags;
126
    case 0x38: /* NVFLAGS */
127
        return s->nvflags;
128
    case 0x40: /* RESETCTL */
129
        if (board_id(s) == BOARD_ID_VEXPRESS) {
130
            /* reserved: RAZ/WI */
131
            return 0;
132
        }
133
        return s->resetlevel;
134
    case 0x44: /* PCICTL */
135
        return 1;
136
    case 0x48: /* MCI */
137
        return s->sys_mci;
138
    case 0x4c: /* FLASH */
139
        return 0;
140
    case 0x50: /* CLCD */
141
        return s->sys_clcd;
142
    case 0x54: /* CLCDSER */
143
        return 0;
144
    case 0x58: /* BOOTCS */
145
        return 0;
146
    case 0x5c: /* 24MHz */
147
        return muldiv64(qemu_get_clock_ns(vm_clock), 24000000, get_ticks_per_sec());
148
    case 0x60: /* MISC */
149
        return 0;
150
    case 0x84: /* PROCID0 */
151
        return s->proc_id;
152
    case 0x88: /* PROCID1 */
153
        return 0xff000000;
154
    case 0x64: /* DMAPSR0 */
155
    case 0x68: /* DMAPSR1 */
156
    case 0x6c: /* DMAPSR2 */
157
    case 0x70: /* IOSEL */
158
    case 0x74: /* PLDCTL */
159
    case 0x80: /* BUSID */
160
    case 0x8c: /* OSCRESET0 */
161
    case 0x90: /* OSCRESET1 */
162
    case 0x94: /* OSCRESET2 */
163
    case 0x98: /* OSCRESET3 */
164
    case 0x9c: /* OSCRESET4 */
165
    case 0xc0: /* SYS_TEST_OSC0 */
166
    case 0xc4: /* SYS_TEST_OSC1 */
167
    case 0xc8: /* SYS_TEST_OSC2 */
168
    case 0xcc: /* SYS_TEST_OSC3 */
169
    case 0xd0: /* SYS_TEST_OSC4 */
170
        return 0;
171
    case 0xa0: /* SYS_CFGDATA */
172
        if (board_id(s) != BOARD_ID_VEXPRESS) {
173
            goto bad_reg;
174
        }
175
        return s->sys_cfgdata;
176
    case 0xa4: /* SYS_CFGCTRL */
177
        if (board_id(s) != BOARD_ID_VEXPRESS) {
178
            goto bad_reg;
179
        }
180
        return s->sys_cfgctrl;
181
    case 0xa8: /* SYS_CFGSTAT */
182
        if (board_id(s) != BOARD_ID_VEXPRESS) {
183
            goto bad_reg;
184
        }
185
        return s->sys_cfgstat;
186
    default:
187
    bad_reg:
188
        qemu_log_mask(LOG_GUEST_ERROR,
189
                      "arm_sysctl_read: Bad register offset 0x%x\n",
190
                      (int)offset);
191
        return 0;
192
    }
193
}
194

    
195
/* SYS_CFGCTRL functions */
196
#define SYS_CFG_OSC 1
197
#define SYS_CFG_VOLT 2
198
#define SYS_CFG_AMP 3
199
#define SYS_CFG_TEMP 4
200
#define SYS_CFG_RESET 5
201
#define SYS_CFG_SCC 6
202
#define SYS_CFG_MUXFPGA 7
203
#define SYS_CFG_SHUTDOWN 8
204
#define SYS_CFG_REBOOT 9
205
#define SYS_CFG_DVIMODE 11
206
#define SYS_CFG_POWER 12
207
#define SYS_CFG_ENERGY 13
208

    
209
/* SYS_CFGCTRL site field values */
210
#define SYS_CFG_SITE_MB 0
211
#define SYS_CFG_SITE_DB1 1
212
#define SYS_CFG_SITE_DB2 2
213

    
214
/**
215
 * vexpress_cfgctrl_read:
216
 * @s: arm_sysctl_state pointer
217
 * @dcc, @function, @site, @position, @device: split out values from
218
 * SYS_CFGCTRL register
219
 * @val: pointer to where to put the read data on success
220
 *
221
 * Handle a VExpress SYS_CFGCTRL register read. On success, return true and
222
 * write the read value to *val. On failure, return false (and val may
223
 * or may not be written to).
224
 */
225
static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
226
                                  unsigned int function, unsigned int site,
227
                                  unsigned int position, unsigned int device,
228
                                  uint32_t *val)
229
{
230
    /* We don't support anything other than DCC 0, board stack position 0
231
     * or sites other than motherboard/daughterboard:
232
     */
233
    if (dcc != 0 || position != 0 ||
234
        (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
235
        goto cfgctrl_unimp;
236
    }
237

    
238
    switch (function) {
239
    default:
240
        break;
241
    }
242

    
243
cfgctrl_unimp:
244
    qemu_log_mask(LOG_UNIMP,
245
                  "arm_sysctl: Unimplemented SYS_CFGCTRL read of function "
246
                  "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
247
                  function, dcc, site, position, device);
248
    return false;
249
}
250

    
251
/**
252
 * vexpress_cfgctrl_write:
253
 * @s: arm_sysctl_state pointer
254
 * @dcc, @function, @site, @position, @device: split out values from
255
 * SYS_CFGCTRL register
256
 * @val: data to write
257
 *
258
 * Handle a VExpress SYS_CFGCTRL register write. On success, return true.
259
 * On failure, return false.
260
 */
261
static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
262
                                   unsigned int function, unsigned int site,
263
                                   unsigned int position, unsigned int device,
264
                                   uint32_t val)
265
{
266
    /* We don't support anything other than DCC 0, board stack position 0
267
     * or sites other than motherboard/daughterboard:
268
     */
269
    if (dcc != 0 || position != 0 ||
270
        (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
271
        goto cfgctrl_unimp;
272
    }
273

    
274
    switch (function) {
275
    case SYS_CFG_MUXFPGA:
276
        if (site == SYS_CFG_SITE_MB && device == 0) {
277
            /* Select whether video output comes from motherboard
278
             * or daughterboard: log and ignore as QEMU doesn't
279
             * support this.
280
             */
281
            qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output "
282
                          "not supported, ignoring\n");
283
            return true;
284
        }
285
        break;
286
    case SYS_CFG_SHUTDOWN:
287
        if (site == SYS_CFG_SITE_MB && device == 0) {
288
            qemu_system_shutdown_request();
289
            return true;
290
        }
291
        break;
292
    case SYS_CFG_REBOOT:
293
        if (site == SYS_CFG_SITE_MB && device == 0) {
294
            qemu_system_reset_request();
295
            return true;
296
        }
297
        break;
298
    case SYS_CFG_DVIMODE:
299
        if (site == SYS_CFG_SITE_MB && device == 0) {
300
            /* Selecting DVI mode is meaningless for QEMU: we will
301
             * always display the output correctly according to the
302
             * pixel height/width programmed into the CLCD controller.
303
             */
304
            return true;
305
        }
306
    default:
307
        break;
308
    }
309

    
310
cfgctrl_unimp:
311
    qemu_log_mask(LOG_UNIMP,
312
                  "arm_sysctl: Unimplemented SYS_CFGCTRL write of function "
313
                  "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
314
                  function, dcc, site, position, device);
315
    return false;
316
}
317

    
318
static void arm_sysctl_write(void *opaque, hwaddr offset,
319
                             uint64_t val, unsigned size)
320
{
321
    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
322

    
323
    switch (offset) {
324
    case 0x08: /* LED */
325
        s->leds = val;
326
        break;
327
    case 0x0c: /* OSC0 */
328
    case 0x10: /* OSC1 */
329
    case 0x14: /* OSC2 */
330
    case 0x18: /* OSC3 */
331
    case 0x1c: /* OSC4 */
332
        /* ??? */
333
        break;
334
    case 0x20: /* LOCK */
335
        if (val == LOCK_VALUE)
336
            s->lockval = val;
337
        else
338
            s->lockval = val & 0x7fff;
339
        break;
340
    case 0x28: /* CFGDATA1 */
341
        /* ??? Need to implement this.  */
342
        s->cfgdata1 = val;
343
        break;
344
    case 0x2c: /* CFGDATA2 */
345
        /* ??? Need to implement this.  */
346
        s->cfgdata2 = val;
347
        break;
348
    case 0x30: /* FLAGSSET */
349
        s->flags |= val;
350
        break;
351
    case 0x34: /* FLAGSCLR */
352
        s->flags &= ~val;
353
        break;
354
    case 0x38: /* NVFLAGSSET */
355
        s->nvflags |= val;
356
        break;
357
    case 0x3c: /* NVFLAGSCLR */
358
        s->nvflags &= ~val;
359
        break;
360
    case 0x40: /* RESETCTL */
361
        switch (board_id(s)) {
362
        case BOARD_ID_PB926:
363
            if (s->lockval == LOCK_VALUE) {
364
                s->resetlevel = val;
365
                if (val & 0x100) {
366
                    qemu_system_reset_request();
367
                }
368
            }
369
            break;
370
        case BOARD_ID_PBX:
371
        case BOARD_ID_PBA8:
372
            if (s->lockval == LOCK_VALUE) {
373
                s->resetlevel = val;
374
                if (val & 0x04) {
375
                    qemu_system_reset_request();
376
                }
377
            }
378
            break;
379
        case BOARD_ID_VEXPRESS:
380
        case BOARD_ID_EB:
381
        default:
382
            /* reserved: RAZ/WI */
383
            break;
384
        }
385
        break;
386
    case 0x44: /* PCICTL */
387
        /* nothing to do.  */
388
        break;
389
    case 0x4c: /* FLASH */
390
        break;
391
    case 0x50: /* CLCD */
392
        switch (board_id(s)) {
393
        case BOARD_ID_PB926:
394
            /* On 926 bits 13:8 are R/O, bits 1:0 control
395
             * the mux that defines how to interpret the PL110
396
             * graphics format, and other bits are r/w but we
397
             * don't implement them to do anything.
398
             */
399
            s->sys_clcd &= 0x3f00;
400
            s->sys_clcd |= val & ~0x3f00;
401
            qemu_set_irq(s->pl110_mux_ctrl, val & 3);
402
            break;
403
        case BOARD_ID_EB:
404
            /* The EB is the same except that there is no mux since
405
             * the EB has a PL111.
406
             */
407
            s->sys_clcd &= 0x3f00;
408
            s->sys_clcd |= val & ~0x3f00;
409
            break;
410
        case BOARD_ID_PBA8:
411
        case BOARD_ID_PBX:
412
            /* On PBA8 and PBX bit 7 is r/w and all other bits
413
             * are either r/o or RAZ/WI.
414
             */
415
            s->sys_clcd &= (1 << 7);
416
            s->sys_clcd |= val & ~(1 << 7);
417
            break;
418
        case BOARD_ID_VEXPRESS:
419
        default:
420
            /* On VExpress this register is unimplemented and will RAZ/WI */
421
            break;
422
        }
423
        break;
424
    case 0x54: /* CLCDSER */
425
    case 0x64: /* DMAPSR0 */
426
    case 0x68: /* DMAPSR1 */
427
    case 0x6c: /* DMAPSR2 */
428
    case 0x70: /* IOSEL */
429
    case 0x74: /* PLDCTL */
430
    case 0x80: /* BUSID */
431
    case 0x84: /* PROCID0 */
432
    case 0x88: /* PROCID1 */
433
    case 0x8c: /* OSCRESET0 */
434
    case 0x90: /* OSCRESET1 */
435
    case 0x94: /* OSCRESET2 */
436
    case 0x98: /* OSCRESET3 */
437
    case 0x9c: /* OSCRESET4 */
438
        break;
439
    case 0xa0: /* SYS_CFGDATA */
440
        if (board_id(s) != BOARD_ID_VEXPRESS) {
441
            goto bad_reg;
442
        }
443
        s->sys_cfgdata = val;
444
        return;
445
    case 0xa4: /* SYS_CFGCTRL */
446
        if (board_id(s) != BOARD_ID_VEXPRESS) {
447
            goto bad_reg;
448
        }
449
        /* Undefined bits [19:18] are RAZ/WI, and writing to
450
         * the start bit just triggers the action; it always reads
451
         * as zero.
452
         */
453
        s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31));
454
        if (val & (1 << 31)) {
455
            /* Start bit set -- actually do something */
456
            unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4);
457
            unsigned int function = extract32(s->sys_cfgctrl, 20, 6);
458
            unsigned int site = extract32(s->sys_cfgctrl, 16, 2);
459
            unsigned int position = extract32(s->sys_cfgctrl, 12, 4);
460
            unsigned int device = extract32(s->sys_cfgctrl, 0, 12);
461
            s->sys_cfgstat = 1;            /* complete */
462
            if (s->sys_cfgctrl & (1 << 30)) {
463
                if (!vexpress_cfgctrl_write(s, dcc, function, site, position,
464
                                            device, s->sys_cfgdata)) {
465
                    s->sys_cfgstat |= 2;        /* error */
466
                }
467
            } else {
468
                uint32_t val;
469
                if (!vexpress_cfgctrl_read(s, dcc, function, site, position,
470
                                           device, &val)) {
471
                    s->sys_cfgstat |= 2;        /* error */
472
                } else {
473
                    s->sys_cfgdata = val;
474
                }
475
            }
476
        }
477
        s->sys_cfgctrl &= ~(1 << 31);
478
        return;
479
    case 0xa8: /* SYS_CFGSTAT */
480
        if (board_id(s) != BOARD_ID_VEXPRESS) {
481
            goto bad_reg;
482
        }
483
        s->sys_cfgstat = val & 3;
484
        return;
485
    default:
486
    bad_reg:
487
        qemu_log_mask(LOG_GUEST_ERROR,
488
                      "arm_sysctl_write: Bad register offset 0x%x\n",
489
                      (int)offset);
490
        return;
491
    }
492
}
493

    
494
static const MemoryRegionOps arm_sysctl_ops = {
495
    .read = arm_sysctl_read,
496
    .write = arm_sysctl_write,
497
    .endianness = DEVICE_NATIVE_ENDIAN,
498
};
499

    
500
static void arm_sysctl_gpio_set(void *opaque, int line, int level)
501
{
502
    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
503
    switch (line) {
504
    case ARM_SYSCTL_GPIO_MMC_WPROT:
505
    {
506
        /* For PB926 and EB write-protect is bit 2 of SYS_MCI;
507
         * for all later boards it is bit 1.
508
         */
509
        int bit = 2;
510
        if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {
511
            bit = 4;
512
        }
513
        s->sys_mci &= ~bit;
514
        if (level) {
515
            s->sys_mci |= bit;
516
        }
517
        break;
518
    }
519
    case ARM_SYSCTL_GPIO_MMC_CARDIN:
520
        s->sys_mci &= ~1;
521
        if (level) {
522
            s->sys_mci |= 1;
523
        }
524
        break;
525
    }
526
}
527

    
528
static int arm_sysctl_init(SysBusDevice *dev)
529
{
530
    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
531

    
532
    memory_region_init_io(&s->iomem, &arm_sysctl_ops, s, "arm-sysctl", 0x1000);
533
    sysbus_init_mmio(dev, &s->iomem);
534
    qdev_init_gpio_in(&s->busdev.qdev, arm_sysctl_gpio_set, 2);
535
    qdev_init_gpio_out(&s->busdev.qdev, &s->pl110_mux_ctrl, 1);
536
    return 0;
537
}
538

    
539
static Property arm_sysctl_properties[] = {
540
    DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
541
    DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
542
    DEFINE_PROP_END_OF_LIST(),
543
};
544

    
545
static void arm_sysctl_class_init(ObjectClass *klass, void *data)
546
{
547
    DeviceClass *dc = DEVICE_CLASS(klass);
548
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
549

    
550
    k->init = arm_sysctl_init;
551
    dc->reset = arm_sysctl_reset;
552
    dc->vmsd = &vmstate_arm_sysctl;
553
    dc->props = arm_sysctl_properties;
554
}
555

    
556
static const TypeInfo arm_sysctl_info = {
557
    .name          = "realview_sysctl",
558
    .parent        = TYPE_SYS_BUS_DEVICE,
559
    .instance_size = sizeof(arm_sysctl_state),
560
    .class_init    = arm_sysctl_class_init,
561
};
562

    
563
static void arm_sysctl_register_types(void)
564
{
565
    type_register_static(&arm_sysctl_info);
566
}
567

    
568
type_init(arm_sysctl_register_types)