diff options
Diffstat (limited to 'qemu/hw/gpio/pl061.c')
-rw-r--r-- | qemu/hw/gpio/pl061.c | 68 |
1 files changed, 52 insertions, 16 deletions
diff --git a/qemu/hw/gpio/pl061.c b/qemu/hw/gpio/pl061.c index 4ba730b47..29dc7fc38 100644 --- a/qemu/hw/gpio/pl061.c +++ b/qemu/hw/gpio/pl061.c @@ -8,6 +8,7 @@ * This code is licensed under the GPL. */ +#include "qemu/osdep.h" #include "hw/sysbus.h" //#define DEBUG_PL061 1 @@ -55,17 +56,17 @@ typedef struct PL061State { uint32_t slr; uint32_t den; uint32_t cr; - uint32_t float_high; uint32_t amsel; qemu_irq irq; qemu_irq out[8]; const unsigned char *id; + uint32_t rsvd_start; /* reserved area: [rsvd_start, 0xfcc] */ } PL061State; static const VMStateDescription vmstate_pl061 = { .name = "pl061", - .version_id = 3, - .minimum_version_id = 3, + .version_id = 4, + .minimum_version_id = 4, .fields = (VMStateField[]) { VMSTATE_UINT32(locked, PL061State), VMSTATE_UINT32(data, PL061State), @@ -87,7 +88,6 @@ static const VMStateDescription vmstate_pl061 = { VMSTATE_UINT32(slr, PL061State), VMSTATE_UINT32(den, PL061State), VMSTATE_UINT32(cr, PL061State), - VMSTATE_UINT32(float_high, PL061State), VMSTATE_UINT32_V(amsel, PL061State, 2), VMSTATE_END_OF_LIST() } @@ -153,12 +153,15 @@ static uint64_t pl061_read(void *opaque, hwaddr offset, { PL061State *s = (PL061State *)opaque; - if (offset >= 0xfd0 && offset < 0x1000) { - return s->id[(offset - 0xfd0) >> 2]; - } if (offset < 0x400) { return s->data & (offset >> 2); } + if (offset >= s->rsvd_start && offset <= 0xfcc) { + goto err_out; + } + if (offset >= 0xfd0 && offset < 0x1000) { + return s->id[(offset - 0xfd0) >> 2]; + } switch (offset) { case 0x400: /* Direction */ return s->dir; @@ -199,10 +202,12 @@ static uint64_t pl061_read(void *opaque, hwaddr offset, case 0x528: /* Analog mode select */ return s->amsel; default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl061_read: Bad offset %x\n", (int)offset); - return 0; + break; } +err_out: + qemu_log_mask(LOG_GUEST_ERROR, + "pl061_read: Bad offset %x\n", (int)offset); + return 0; } static void pl061_write(void *opaque, hwaddr offset, @@ -217,6 +222,9 @@ static void pl061_write(void *opaque, hwaddr offset, pl061_update(s); return; } + if (offset >= s->rsvd_start) { + goto err_out; + } switch (offset) { case 0x400: /* Direction */ s->dir = value & 0xff; @@ -275,16 +283,41 @@ static void pl061_write(void *opaque, hwaddr offset, s->amsel = value & 0xff; break; default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl061_write: Bad offset %x\n", (int)offset); + goto err_out; } pl061_update(s); + return; +err_out: + qemu_log_mask(LOG_GUEST_ERROR, + "pl061_write: Bad offset %x\n", (int)offset); } -static void pl061_reset(PL061State *s) +static void pl061_reset(DeviceState *dev) { - s->locked = 1; - s->cr = 0xff; + PL061State *s = PL061(dev); + + /* reset values from PL061 TRM, Stellaris LM3S5P31 & LM3S8962 Data Sheet */ + s->data = 0; + s->old_out_data = 0; + s->old_in_data = 0; + s->dir = 0; + s->isense = 0; + s->ibe = 0; + s->iev = 0; + s->im = 0; + s->istate = 0; + s->afsel = 0; + s->dr2r = 0xff; + s->dr4r = 0; + s->dr8r = 0; + s->odr = 0; + s->pur = 0; + s->pdr = 0; + s->slr = 0; + s->den = 0; + s->locked = 1; + s->cr = 0xff; + s->amsel = 0; } static void pl061_set_irq(void * opaque, int irq, int level) @@ -317,7 +350,7 @@ static int pl061_initfn(SysBusDevice *sbd) sysbus_init_irq(sbd, &s->irq); qdev_init_gpio_in(dev, pl061_set_irq, 8); qdev_init_gpio_out(dev, s->out, 8); - pl061_reset(s); + return 0; } @@ -326,6 +359,7 @@ static void pl061_luminary_init(Object *obj) PL061State *s = PL061(obj); s->id = pl061_id_luminary; + s->rsvd_start = 0x52c; } static void pl061_init(Object *obj) @@ -333,6 +367,7 @@ static void pl061_init(Object *obj) PL061State *s = PL061(obj); s->id = pl061_id; + s->rsvd_start = 0x424; } static void pl061_class_init(ObjectClass *klass, void *data) @@ -342,6 +377,7 @@ static void pl061_class_init(ObjectClass *klass, void *data) k->init = pl061_initfn; dc->vmsd = &vmstate_pl061; + dc->reset = &pl061_reset; } static const TypeInfo pl061_info = { |