~ubuntu-branches/ubuntu/saucy/qemu/saucy-proposed

« back to all changes in this revision

Viewing changes to hw/pl061.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2013-05-28 08:18:30 UTC
  • mfrom: (1.8.2) (10.1.37 sid)
  • Revision ID: package-import@ubuntu.com-20130528081830-87xl2z9fq516a814
Tags: 1.5.0+dfsg-2ubuntu1
* Merge 1.5.0+dfs-2 from debian unstable.  Remaining changes:
  - debian/control
    * update maintainer
    * remove libiscsi, usb-redir, vde, vnc-jpeg, and libssh2-1-dev
      from build-deps
    * enable rbd
    * add qemu-system and qemu-common B/R to qemu-keymaps
    * add D:udev, R:qemu, R:qemu-common and B:qemu-common to
      qemu-system-common
    * qemu-system-arm, qemu-system-ppc, qemu-system-sparc:
      - add qemu-kvm to Provides
      - add qemu-common, qemu-kvm, kvm to B/R
      - remove openbios-sparc from qemu-system-sparc D
    * qemu-system-x86:
      - add qemu-common to Breaks/Replaces.
      - add cpu-checker to Recommends.
    * qemu-user: add B/R:qemu-kvm
    * qemu-kvm:
      - add armhf armel powerpc sparc to Architecture
      - C/R/P: qemu-kvm-spice
    * add qemu-common package
    * drop qemu-slof which is not packaged in ubuntu
  - add qemu-system-common.links for tap ifup/down scripts and OVMF link.
  - qemu-system-x86.links:
    * remove pxe rom links which are in kvm-ipxe
    * add symlink for kvm.1 manpage
  - debian/rules
    * add kvm-spice symlink to qemu-kvm
    * call dh_installmodules for qemu-system-x86
    * update dh_installinit to install upstart script
    * run dh_installman (Closes: #709241) (cherrypicked from 1.5.0+dfsg-2)
  - Add qemu-utils.links for kvm-* symlinks.
  - Add qemu-system-x86.qemu-kvm.upstart and .default
  - Add qemu-system-x86.modprobe to set nesting=1
  - Add qemu-system-common.preinst to add kvm group
  - qemu-system-common.postinst: remove bad group acl if there, then have
    udev relabel /dev/kvm.
  - Dropped patches:
    * 0001-fix-wrong-output-with-info-chardev-for-tcp-socket.patch
  - Kept patches:
    * expose_vms_qemu64cpu.patch - updated
    * gridcentric patch - updated
    * linaro arm patches from qemu-linaro rebasing branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Arm PrimeCell PL061 General Purpose IO with additional
3
 
 * Luminary Micro Stellaris bits.
4
 
 *
5
 
 * Copyright (c) 2007 CodeSourcery.
6
 
 * Written by Paul Brook
7
 
 *
8
 
 * This code is licensed under the GPL.
9
 
 */
10
 
 
11
 
#include "sysbus.h"
12
 
 
13
 
//#define DEBUG_PL061 1
14
 
 
15
 
#ifdef DEBUG_PL061
16
 
#define DPRINTF(fmt, ...) \
17
 
do { printf("pl061: " fmt , ## __VA_ARGS__); } while (0)
18
 
#define BADF(fmt, ...) \
19
 
do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
20
 
#else
21
 
#define DPRINTF(fmt, ...) do {} while(0)
22
 
#define BADF(fmt, ...) \
23
 
do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__);} while (0)
24
 
#endif
25
 
 
26
 
static const uint8_t pl061_id[12] =
27
 
  { 0x00, 0x00, 0x00, 0x00, 0x61, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
28
 
static const uint8_t pl061_id_luminary[12] =
29
 
  { 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
30
 
 
31
 
typedef struct {
32
 
    SysBusDevice busdev;
33
 
    MemoryRegion iomem;
34
 
    uint32_t locked;
35
 
    uint32_t data;
36
 
    uint32_t old_data;
37
 
    uint32_t dir;
38
 
    uint32_t isense;
39
 
    uint32_t ibe;
40
 
    uint32_t iev;
41
 
    uint32_t im;
42
 
    uint32_t istate;
43
 
    uint32_t afsel;
44
 
    uint32_t dr2r;
45
 
    uint32_t dr4r;
46
 
    uint32_t dr8r;
47
 
    uint32_t odr;
48
 
    uint32_t pur;
49
 
    uint32_t pdr;
50
 
    uint32_t slr;
51
 
    uint32_t den;
52
 
    uint32_t cr;
53
 
    uint32_t float_high;
54
 
    uint32_t amsel;
55
 
    qemu_irq irq;
56
 
    qemu_irq out[8];
57
 
    const unsigned char *id;
58
 
} pl061_state;
59
 
 
60
 
static const VMStateDescription vmstate_pl061 = {
61
 
    .name = "pl061",
62
 
    .version_id = 2,
63
 
    .minimum_version_id = 1,
64
 
    .fields = (VMStateField[]) {
65
 
        VMSTATE_UINT32(locked, pl061_state),
66
 
        VMSTATE_UINT32(data, pl061_state),
67
 
        VMSTATE_UINT32(old_data, pl061_state),
68
 
        VMSTATE_UINT32(dir, pl061_state),
69
 
        VMSTATE_UINT32(isense, pl061_state),
70
 
        VMSTATE_UINT32(ibe, pl061_state),
71
 
        VMSTATE_UINT32(iev, pl061_state),
72
 
        VMSTATE_UINT32(im, pl061_state),
73
 
        VMSTATE_UINT32(istate, pl061_state),
74
 
        VMSTATE_UINT32(afsel, pl061_state),
75
 
        VMSTATE_UINT32(dr2r, pl061_state),
76
 
        VMSTATE_UINT32(dr4r, pl061_state),
77
 
        VMSTATE_UINT32(dr8r, pl061_state),
78
 
        VMSTATE_UINT32(odr, pl061_state),
79
 
        VMSTATE_UINT32(pur, pl061_state),
80
 
        VMSTATE_UINT32(pdr, pl061_state),
81
 
        VMSTATE_UINT32(slr, pl061_state),
82
 
        VMSTATE_UINT32(den, pl061_state),
83
 
        VMSTATE_UINT32(cr, pl061_state),
84
 
        VMSTATE_UINT32(float_high, pl061_state),
85
 
        VMSTATE_UINT32_V(amsel, pl061_state, 2),
86
 
        VMSTATE_END_OF_LIST()
87
 
    }
88
 
};
89
 
 
90
 
static void pl061_update(pl061_state *s)
91
 
{
92
 
    uint8_t changed;
93
 
    uint8_t mask;
94
 
    uint8_t out;
95
 
    int i;
96
 
 
97
 
    /* Outputs float high.  */
98
 
    /* FIXME: This is board dependent.  */
99
 
    out = (s->data & s->dir) | ~s->dir;
100
 
    changed = s->old_data ^ out;
101
 
    if (!changed)
102
 
        return;
103
 
 
104
 
    s->old_data = out;
105
 
    for (i = 0; i < 8; i++) {
106
 
        mask = 1 << i;
107
 
        if (changed & mask) {
108
 
            DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
109
 
            qemu_set_irq(s->out[i], (out & mask) != 0);
110
 
        }
111
 
    }
112
 
 
113
 
    /* FIXME: Implement input interrupts.  */
114
 
}
115
 
 
116
 
static uint64_t pl061_read(void *opaque, hwaddr offset,
117
 
                           unsigned size)
118
 
{
119
 
    pl061_state *s = (pl061_state *)opaque;
120
 
 
121
 
    if (offset >= 0xfd0 && offset < 0x1000) {
122
 
        return s->id[(offset - 0xfd0) >> 2];
123
 
    }
124
 
    if (offset < 0x400) {
125
 
        return s->data & (offset >> 2);
126
 
    }
127
 
    switch (offset) {
128
 
    case 0x400: /* Direction */
129
 
        return s->dir;
130
 
    case 0x404: /* Interrupt sense */
131
 
        return s->isense;
132
 
    case 0x408: /* Interrupt both edges */
133
 
        return s->ibe;
134
 
    case 0x40c: /* Interrupt event */
135
 
        return s->iev;
136
 
    case 0x410: /* Interrupt mask */
137
 
        return s->im;
138
 
    case 0x414: /* Raw interrupt status */
139
 
        return s->istate;
140
 
    case 0x418: /* Masked interrupt status */
141
 
        return s->istate | s->im;
142
 
    case 0x420: /* Alternate function select */
143
 
        return s->afsel;
144
 
    case 0x500: /* 2mA drive */
145
 
        return s->dr2r;
146
 
    case 0x504: /* 4mA drive */
147
 
        return s->dr4r;
148
 
    case 0x508: /* 8mA drive */
149
 
        return s->dr8r;
150
 
    case 0x50c: /* Open drain */
151
 
        return s->odr;
152
 
    case 0x510: /* Pull-up */
153
 
        return s->pur;
154
 
    case 0x514: /* Pull-down */
155
 
        return s->pdr;
156
 
    case 0x518: /* Slew rate control */
157
 
        return s->slr;
158
 
    case 0x51c: /* Digital enable */
159
 
        return s->den;
160
 
    case 0x520: /* Lock */
161
 
        return s->locked;
162
 
    case 0x524: /* Commit */
163
 
        return s->cr;
164
 
    case 0x528: /* Analog mode select */
165
 
        return s->amsel;
166
 
    default:
167
 
        qemu_log_mask(LOG_GUEST_ERROR,
168
 
                      "pl061_read: Bad offset %x\n", (int)offset);
169
 
        return 0;
170
 
    }
171
 
}
172
 
 
173
 
static void pl061_write(void *opaque, hwaddr offset,
174
 
                        uint64_t value, unsigned size)
175
 
{
176
 
    pl061_state *s = (pl061_state *)opaque;
177
 
    uint8_t mask;
178
 
 
179
 
    if (offset < 0x400) {
180
 
        mask = (offset >> 2) & s->dir;
181
 
        s->data = (s->data & ~mask) | (value & mask);
182
 
        pl061_update(s);
183
 
        return;
184
 
    }
185
 
    switch (offset) {
186
 
    case 0x400: /* Direction */
187
 
        s->dir = value & 0xff;
188
 
        break;
189
 
    case 0x404: /* Interrupt sense */
190
 
        s->isense = value & 0xff;
191
 
        break;
192
 
    case 0x408: /* Interrupt both edges */
193
 
        s->ibe = value & 0xff;
194
 
        break;
195
 
    case 0x40c: /* Interrupt event */
196
 
        s->iev = value & 0xff;
197
 
        break;
198
 
    case 0x410: /* Interrupt mask */
199
 
        s->im = value & 0xff;
200
 
        break;
201
 
    case 0x41c: /* Interrupt clear */
202
 
        s->istate &= ~value;
203
 
        break;
204
 
    case 0x420: /* Alternate function select */
205
 
        mask = s->cr;
206
 
        s->afsel = (s->afsel & ~mask) | (value & mask);
207
 
        break;
208
 
    case 0x500: /* 2mA drive */
209
 
        s->dr2r = value & 0xff;
210
 
        break;
211
 
    case 0x504: /* 4mA drive */
212
 
        s->dr4r = value & 0xff;
213
 
        break;
214
 
    case 0x508: /* 8mA drive */
215
 
        s->dr8r = value & 0xff;
216
 
        break;
217
 
    case 0x50c: /* Open drain */
218
 
        s->odr = value & 0xff;
219
 
        break;
220
 
    case 0x510: /* Pull-up */
221
 
        s->pur = value & 0xff;
222
 
        break;
223
 
    case 0x514: /* Pull-down */
224
 
        s->pdr = value & 0xff;
225
 
        break;
226
 
    case 0x518: /* Slew rate control */
227
 
        s->slr = value & 0xff;
228
 
        break;
229
 
    case 0x51c: /* Digital enable */
230
 
        s->den = value & 0xff;
231
 
        break;
232
 
    case 0x520: /* Lock */
233
 
        s->locked = (value != 0xacce551);
234
 
        break;
235
 
    case 0x524: /* Commit */
236
 
        if (!s->locked)
237
 
            s->cr = value & 0xff;
238
 
        break;
239
 
    case 0x528:
240
 
        s->amsel = value & 0xff;
241
 
        break;
242
 
    default:
243
 
        qemu_log_mask(LOG_GUEST_ERROR,
244
 
                      "pl061_write: Bad offset %x\n", (int)offset);
245
 
    }
246
 
    pl061_update(s);
247
 
}
248
 
 
249
 
static void pl061_reset(pl061_state *s)
250
 
{
251
 
  s->locked = 1;
252
 
  s->cr = 0xff;
253
 
}
254
 
 
255
 
static void pl061_set_irq(void * opaque, int irq, int level)
256
 
{
257
 
    pl061_state *s = (pl061_state *)opaque;
258
 
    uint8_t mask;
259
 
 
260
 
    mask = 1 << irq;
261
 
    if ((s->dir & mask) == 0) {
262
 
        s->data &= ~mask;
263
 
        if (level)
264
 
            s->data |= mask;
265
 
        pl061_update(s);
266
 
    }
267
 
}
268
 
 
269
 
static const MemoryRegionOps pl061_ops = {
270
 
    .read = pl061_read,
271
 
    .write = pl061_write,
272
 
    .endianness = DEVICE_NATIVE_ENDIAN,
273
 
};
274
 
 
275
 
static int pl061_init(SysBusDevice *dev, const unsigned char *id)
276
 
{
277
 
    pl061_state *s = FROM_SYSBUS(pl061_state, dev);
278
 
    s->id = id;
279
 
    memory_region_init_io(&s->iomem, &pl061_ops, s, "pl061", 0x1000);
280
 
    sysbus_init_mmio(dev, &s->iomem);
281
 
    sysbus_init_irq(dev, &s->irq);
282
 
    qdev_init_gpio_in(&dev->qdev, pl061_set_irq, 8);
283
 
    qdev_init_gpio_out(&dev->qdev, s->out, 8);
284
 
    pl061_reset(s);
285
 
    return 0;
286
 
}
287
 
 
288
 
static int pl061_init_luminary(SysBusDevice *dev)
289
 
{
290
 
    return pl061_init(dev, pl061_id_luminary);
291
 
}
292
 
 
293
 
static int pl061_init_arm(SysBusDevice *dev)
294
 
{
295
 
    return pl061_init(dev, pl061_id);
296
 
}
297
 
 
298
 
static void pl061_class_init(ObjectClass *klass, void *data)
299
 
{
300
 
    DeviceClass *dc = DEVICE_CLASS(klass);
301
 
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
302
 
 
303
 
    k->init = pl061_init_arm;
304
 
    dc->vmsd = &vmstate_pl061;
305
 
}
306
 
 
307
 
static const TypeInfo pl061_info = {
308
 
    .name          = "pl061",
309
 
    .parent        = TYPE_SYS_BUS_DEVICE,
310
 
    .instance_size = sizeof(pl061_state),
311
 
    .class_init    = pl061_class_init,
312
 
};
313
 
 
314
 
static void pl061_luminary_class_init(ObjectClass *klass, void *data)
315
 
{
316
 
    DeviceClass *dc = DEVICE_CLASS(klass);
317
 
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
318
 
 
319
 
    k->init = pl061_init_luminary;
320
 
    dc->vmsd = &vmstate_pl061;
321
 
}
322
 
 
323
 
static const TypeInfo pl061_luminary_info = {
324
 
    .name          = "pl061_luminary",
325
 
    .parent        = TYPE_SYS_BUS_DEVICE,
326
 
    .instance_size = sizeof(pl061_state),
327
 
    .class_init    = pl061_luminary_class_init,
328
 
};
329
 
 
330
 
static void pl061_register_types(void)
331
 
{
332
 
    type_register_static(&pl061_info);
333
 
    type_register_static(&pl061_luminary_info);
334
 
}
335
 
 
336
 
type_init(pl061_register_types)