diff options
author | Peter Maydell | 2021-07-02 12:40:16 +0200 |
---|---|---|
committer | Peter Maydell | 2021-07-09 17:09:12 +0200 |
commit | ef4989b0a898ae20a974d261b14d4e5c1c097292 (patch) | |
tree | 5b454d45a858580d48f5d4a98296f3b4a246f964 /hw/gpio/pl061.c | |
parent | hw/arm/virt: Make PL061 GPIO lines pulled low, not high (diff) | |
download | qemu-ef4989b0a898ae20a974d261b14d4e5c1c097292.tar.gz qemu-ef4989b0a898ae20a974d261b14d4e5c1c097292.tar.xz qemu-ef4989b0a898ae20a974d261b14d4e5c1c097292.zip |
hw/gpio/pl061: Convert to 3-phase reset and assert GPIO lines correctly on reset
The PL061 comes out of reset with all its lines configured as input,
which means they might need to be pulled to 0 or 1 depending on the
'pullups' and 'pulldowns' properties. Currently we do not assert
these lines on reset; they will only be set whenever the guest first
touches a register that triggers a call to pl061_update().
Convert the device to three-phase reset so we have a place where we
can safely call qemu_set_irq() to set the floating lines to their
correct values.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'hw/gpio/pl061.c')
-rw-r--r-- | hw/gpio/pl061.c | 29 |
1 files changed, 25 insertions, 4 deletions
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index 5ba398fcd4..4002ab5154 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -446,13 +446,14 @@ static void pl061_write(void *opaque, hwaddr offset, return; } -static void pl061_reset(DeviceState *dev) +static void pl061_enter_reset(Object *obj, ResetType type) { - PL061State *s = PL061(dev); + PL061State *s = PL061(obj); + + trace_pl061_reset(DEVICE(s)->canonical_path); /* 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; @@ -474,6 +475,24 @@ static void pl061_reset(DeviceState *dev) s->amsel = 0; } +static void pl061_hold_reset(Object *obj) +{ + PL061State *s = PL061(obj); + int i, level; + uint8_t floating = pl061_floating(s); + uint8_t pullups = pl061_pullups(s); + + for (i = 0; i < N_GPIOS; i++) { + if (extract32(floating, i, 1)) { + continue; + } + level = extract32(pullups, i, 1); + trace_pl061_set_output(DEVICE(s)->canonical_path, i, level); + qemu_set_irq(s->out[i], level); + } + s->old_out_data = pullups; +} + static void pl061_set_irq(void * opaque, int irq, int level) { PL061State *s = (PL061State *)opaque; @@ -543,11 +562,13 @@ static Property pl061_props[] = { static void pl061_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); dc->vmsd = &vmstate_pl061; - dc->reset = &pl061_reset; dc->realize = pl061_realize; device_class_set_props(dc, pl061_props); + rc->phases.enter = pl061_enter_reset; + rc->phases.hold = pl061_hold_reset; } static const TypeInfo pl061_info = { |