diff mbox series

[7/7] arm: Instantiate Microbit board-level devices

Message ID 20180811090836.4024-8-contrib@steffen-goertz.de
State New
Headers show
Series arm: Instantiation of nRF51 SOC and bbc:microbit devices | expand

Commit Message

Steffen Görtz Aug. 11, 2018, 9:08 a.m. UTC
Instantiate the LED matrix and set board-level
pull-up default values to buttons A and B.
This is necessary to calm down the microsoft pxt
javascript runtime available for the micro:bit.

Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
---
 hw/arm/microbit.c         | 52 ++++++++++++++++++++++++++++++++++-----
 include/hw/arm/microbit.h |  1 +
 2 files changed, 47 insertions(+), 6 deletions(-)

Comments

Peter Maydell Aug. 16, 2018, 3:22 p.m. UTC | #1
On 11 August 2018 at 10:08, Steffen Görtz <contrib@steffen-goertz.de> wrote:
> Instantiate the LED matrix and set board-level
> pull-up default values to buttons A and B.
> This is necessary to calm down the microsoft pxt
> javascript runtime available for the micro:bit.
>
> Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>

> +static void microbit_reset(void)
> +{
> +    MachineState *machine = MACHINE(qdev_get_machine());
> +    MicrobitMachineState *s = MICROBIT_MACHINE(machine);
> +
> +    qemu_devices_reset();
> +
> +    /* Board level pull-up */
> +    if (!qtest_enabled()) {
> +        qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->nrf51), BUTTON_A_PIN), 1);
> +        qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->nrf51), BUTTON_B_PIN), 1);
> +    }

Reset functions should not call qemu_set_irq().

The problem is that there's no ordering on device reset functions,
so there's no guarantee that the reset function on this end is
called after the reset function for the device it's trying to set
the input GPIO line for. If the two resets happen in the other order
then the device will forget that the input line was high.

There is no good way to handle a line that is supposed to be
pulled high on reset, I'm afraid. You just have to try to avoid
modelling things in a way that requires it.

(Yes, our modelling of reset is basically broken. It's a
hard design problem that nobody's found the time to tackle
properly. You'll see various more-or-less dubious workarounds
if you dig in the right parts of the code base...)

> +}
> +
>
>  static void microbit_machine_init(MachineClass *mc)
>  {
>      mc->desc = "BBC micro:bit";
>      mc->init = microbit_init;
>      mc->max_cpus = 1;
> +    mc->reset = microbit_reset;
>  }
>
>  static void microbit_machine_init_class_init(ObjectClass *oc, void *data)
> diff --git a/include/hw/arm/microbit.h b/include/hw/arm/microbit.h
> index 89f0c6bc07..094326b4ae 100644
> --- a/include/hw/arm/microbit.h
> +++ b/include/hw/arm/microbit.h
> @@ -24,6 +24,7 @@ typedef struct MicrobitMachineState {
>      MachineState parent_obj;
>
>      NRF51State nrf51;
> +    LEDMatrixState matrix;
>  } MicrobitMachineState;

thanks
-- PMM
diff mbox series

Patch

diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c
index bb6ddb6a79..6fad0de2cd 100644
--- a/hw/arm/microbit.c
+++ b/hw/arm/microbit.c
@@ -13,34 +13,74 @@ 
 #include "qapi/error.h"
 #include "hw/boards.h"
 #include "hw/arm/arm.h"
+#include "sysemu/qtest.h"
 #include "exec/address-spaces.h"
 
 #include "hw/arm/microbit.h"
 
+#define BUTTON_A_PIN 17
+#define BUTTON_B_PIN 26
+
 static void microbit_init(MachineState *machine)
 {
     MicrobitMachineState *s = MICROBIT_MACHINE(machine);
     MemoryRegion *system_memory = get_system_memory();
-    Object *soc;
+    DeviceState *soc, *matrix;
 
     object_initialize(&s->nrf51, sizeof(s->nrf51), TYPE_NRF51_SOC);
-    soc = OBJECT(&s->nrf51);
-    object_property_add_child(OBJECT(machine), "nrf51", soc, &error_fatal);
-    object_property_set_link(soc, OBJECT(system_memory),
+    soc = DEVICE(&s->nrf51);
+    object_property_add_child(OBJECT(machine), "nrf51", OBJECT(soc),
+                              &error_fatal);
+    object_property_set_link(OBJECT(soc), OBJECT(system_memory),
                              "memory", &error_abort);
-    qdev_prop_set_uint32(DEVICE(soc), "variant", NRF51_VARIANT_AA);
+    qdev_prop_set_uint32(soc, "variant", NRF51_VARIANT_AA);
 
-    object_property_set_bool(soc, true, "realized", &error_abort);
+    object_property_set_bool(OBJECT(soc), true, "realized", &error_abort);
+
+    object_initialize(&s->matrix, sizeof(s->matrix), TYPE_LED_MATRIX);
+    matrix = DEVICE(&s->matrix);
+    qdev_prop_set_uint16(matrix, "rows", 3);
+    qdev_prop_set_uint16(matrix, "cols", 9);
+    object_property_set_bool(OBJECT(matrix), true, "realized", &error_fatal);
+
+    qdev_connect_gpio_out(soc, 4, qdev_get_gpio_in_named(matrix, "col", 0));
+    qdev_connect_gpio_out(soc, 5, qdev_get_gpio_in_named(matrix, "col", 1));
+    qdev_connect_gpio_out(soc, 6, qdev_get_gpio_in_named(matrix, "col", 2));
+    qdev_connect_gpio_out(soc, 7, qdev_get_gpio_in_named(matrix, "col", 3));
+    qdev_connect_gpio_out(soc, 8, qdev_get_gpio_in_named(matrix, "col", 4));
+    qdev_connect_gpio_out(soc, 9, qdev_get_gpio_in_named(matrix, "col", 5));
+    qdev_connect_gpio_out(soc, 10, qdev_get_gpio_in_named(matrix, "col", 6));
+    qdev_connect_gpio_out(soc, 11, qdev_get_gpio_in_named(matrix, "col", 7));
+    qdev_connect_gpio_out(soc, 12, qdev_get_gpio_in_named(matrix, "col", 8));
+
+    qdev_connect_gpio_out(soc, 13, qdev_get_gpio_in_named(matrix, "row", 0));
+    qdev_connect_gpio_out(soc, 14, qdev_get_gpio_in_named(matrix, "row", 1));
+    qdev_connect_gpio_out(soc, 15, qdev_get_gpio_in_named(matrix, "row", 2));
 
     armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x00);
 }
 
+static void microbit_reset(void)
+{
+    MachineState *machine = MACHINE(qdev_get_machine());
+    MicrobitMachineState *s = MICROBIT_MACHINE(machine);
+
+    qemu_devices_reset();
+
+    /* Board level pull-up */
+    if (!qtest_enabled()) {
+        qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->nrf51), BUTTON_A_PIN), 1);
+        qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->nrf51), BUTTON_B_PIN), 1);
+    }
+}
+
 
 static void microbit_machine_init(MachineClass *mc)
 {
     mc->desc = "BBC micro:bit";
     mc->init = microbit_init;
     mc->max_cpus = 1;
+    mc->reset = microbit_reset;
 }
 
 static void microbit_machine_init_class_init(ObjectClass *oc, void *data)
diff --git a/include/hw/arm/microbit.h b/include/hw/arm/microbit.h
index 89f0c6bc07..094326b4ae 100644
--- a/include/hw/arm/microbit.h
+++ b/include/hw/arm/microbit.h
@@ -24,6 +24,7 @@  typedef struct MicrobitMachineState {
     MachineState parent_obj;
 
     NRF51State nrf51;
+    LEDMatrixState matrix;
 } MicrobitMachineState;
 
 #endif