summary refs log tree commit diff stats
path: root/hw/gpio/pl061.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/gpio/pl061.c')
-rw-r--r--hw/gpio/pl061.c51
1 files changed, 47 insertions, 4 deletions
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
index 9360c143ee..5ba398fcd4 100644
--- a/hw/gpio/pl061.c
+++ b/hw/gpio/pl061.c
@@ -13,12 +13,28 @@
  *  + unnamed GPIO inputs 0..7: inputs to connect to the emulated GPIO lines
  *  + unnamed GPIO outputs 0..7: the emulated GPIO lines, considered as
  *    outputs
+ *  + QOM property "pullups": an integer defining whether non-floating lines
+ *    configured as inputs should be pulled up to logical 1 (ie whether in
+ *    real hardware they have a pullup resistor on the line out of the PL061).
+ *    This should be an 8-bit value, where bit 0 is 1 if GPIO line 0 should
+ *    be pulled high, bit 1 configures line 1, and so on. The default is 0xff,
+ *    indicating that all GPIO lines are pulled up to logical 1.
+ *  + QOM property "pulldowns": an integer defining whether non-floating lines
+ *    configured as inputs should be pulled down to logical 0 (ie whether in
+ *    real hardware they have a pulldown resistor on the line out of the PL061).
+ *    This should be an 8-bit value, where bit 0 is 1 if GPIO line 0 should
+ *    be pulled low, bit 1 configures line 1, and so on. The default is 0x0.
+ *    It is an error to set a bit in both "pullups" and "pulldowns". If a bit
+ *    is 0 in both, then the line is considered to be floating, and it will
+ *    not have qemu_set_irq() called on it when it is configured as an input.
  */
 
 #include "qemu/osdep.h"
 #include "hw/irq.h"
 #include "hw/sysbus.h"
+#include "hw/qdev-properties.h"
 #include "migration/vmstate.h"
+#include "qapi/error.h"
 #include "qemu/log.h"
 #include "qemu/module.h"
 #include "qom/object.h"
@@ -62,6 +78,9 @@ struct PL061State {
     qemu_irq irq;
     qemu_irq out[N_GPIOS];
     const unsigned char *id;
+    /* Properties, for non-Luminary PL061 */
+    uint32_t pullups;
+    uint32_t pulldowns;
 };
 
 static const VMStateDescription vmstate_pl061 = {
@@ -109,8 +128,7 @@ static uint8_t pl061_floating(PL061State *s)
          */
         floating = ~(s->pur | s->pdr);
     } else {
-        /* Assume outputs are pulled high. FIXME: this is board dependent. */
-        floating = 0;
+        floating = ~(s->pullups | s->pulldowns);
     }
     return floating & ~s->dir;
 }
@@ -131,8 +149,7 @@ static uint8_t pl061_pullups(PL061State *s)
          */
         pullups = s->pur;
     } else {
-        /* Assume outputs are pulled high. FIXME: this is board dependent. */
-        pullups = 0xff;
+        pullups = s->pullups;
     }
     return pullups & ~s->dir;
 }
@@ -499,12 +516,38 @@ static void pl061_init(Object *obj)
     qdev_init_gpio_out(dev, s->out, N_GPIOS);
 }
 
+static void pl061_realize(DeviceState *dev, Error **errp)
+{
+    PL061State *s = PL061(dev);
+
+    if (s->pullups > 0xff) {
+        error_setg(errp, "pullups property must be between 0 and 0xff");
+        return;
+    }
+    if (s->pulldowns > 0xff) {
+        error_setg(errp, "pulldowns property must be between 0 and 0xff");
+        return;
+    }
+    if (s->pullups & s->pulldowns) {
+        error_setg(errp, "no bit may be set both in pullups and pulldowns");
+        return;
+    }
+}
+
+static Property pl061_props[] = {
+    DEFINE_PROP_UINT32("pullups", PL061State, pullups, 0xff),
+    DEFINE_PROP_UINT32("pulldowns", PL061State, pulldowns, 0x0),
+    DEFINE_PROP_END_OF_LIST()
+};
+
 static void pl061_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->vmsd = &vmstate_pl061;
     dc->reset = &pl061_reset;
+    dc->realize = pl061_realize;
+    device_class_set_props(dc, pl061_props);
 }
 
 static const TypeInfo pl061_info = {