* [Qemu-devel] [PATCH 01/11] qtest: Add set_irq_in command to set IRQ/GPIO level
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 02/11] arm: Add header to host common definition for nRF51 SOC peripherals Stefan Hajnoczi
` (10 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
Adds a new qtest command "set_irq_in" which allows
to set qemu gpio lines to a given level.
Based on https://lists.gnu.org/archive/html/qemu-devel/2012-12/msg02363.html
which never got merged.
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Originally-by: Matthew Ogilvie <mmogilvi_qemu@miniinfo.net>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Laurent Vivier <lvivier@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
tests/libqtest.h | 13 +++++++++++++
qtest.c | 43 +++++++++++++++++++++++++++++++++++++++++++
tests/libqtest.c | 10 ++++++++++
3 files changed, 66 insertions(+)
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 9758c51be6..7ea94139b0 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -230,6 +230,19 @@ void qtest_irq_intercept_in(QTestState *s, const char *string);
*/
void qtest_irq_intercept_out(QTestState *s, const char *string);
+/**
+ * qtest_set_irq_in:
+ * @s: QTestState instance to operate on.
+ * @string: QOM path of a device
+ * @name: IRQ name
+ * @irq: IRQ number
+ * @level: IRQ level
+ *
+ * Force given device/irq GPIO-in pin to the given level.
+ */
+void qtest_set_irq_in(QTestState *s, const char *string, const char *name,
+ int irq, int level);
+
/**
* qtest_outb:
* @s: #QTestState instance to operate on.
diff --git a/qtest.c b/qtest.c
index 69b9e9962b..451696b5da 100644
--- a/qtest.c
+++ b/qtest.c
@@ -164,6 +164,17 @@ static bool qtest_opened;
* where NUM is an IRQ number. For the PC, interrupts can be intercepted
* simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
* NUM=0 even though it is remapped to GSI 2).
+ *
+ * Setting interrupt level:
+ *
+ * > set_irq_in QOM-PATH NAME NUM LEVEL
+ * < OK
+ *
+ * where NAME is the name of the irq/gpio list, NUM is an IRQ number and
+ * LEVEL is an signed integer IRQ level.
+ *
+ * Forcibly set the given interrupt pin to the given level.
+ *
*/
static int hex2nib(char ch)
@@ -326,7 +337,39 @@ static void qtest_process_command(CharBackend *chr, gchar **words)
irq_intercept_dev = dev;
qtest_send_prefix(chr);
qtest_send(chr, "OK\n");
+ } else if (strcmp(words[0], "set_irq_in") == 0) {
+ DeviceState *dev;
+ qemu_irq irq;
+ char *name;
+ int ret;
+ int num;
+ int level;
+ g_assert(words[1] && words[2] && words[3] && words[4]);
+
+ dev = DEVICE(object_resolve_path(words[1], NULL));
+ if (!dev) {
+ qtest_send_prefix(chr);
+ qtest_send(chr, "FAIL Unknown device\n");
+ return;
+ }
+
+ if (strcmp(words[2], "unnamed-gpio-in") == 0) {
+ name = NULL;
+ } else {
+ name = words[2];
+ }
+
+ ret = qemu_strtoi(words[3], NULL, 0, &num);
+ g_assert(!ret);
+ ret = qemu_strtoi(words[4], NULL, 0, &level);
+ g_assert(!ret);
+
+ irq = qdev_get_gpio_in_named(dev, name, num);
+
+ qemu_set_irq(irq, level);
+ qtest_send_prefix(chr);
+ qtest_send(chr, "OK\n");
} else if (strcmp(words[0], "outb") == 0 ||
strcmp(words[0], "outw") == 0 ||
strcmp(words[0], "outl") == 0) {
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 1d75d3c936..55750dd68d 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -753,6 +753,16 @@ void qtest_irq_intercept_in(QTestState *s, const char *qom_path)
qtest_rsp(s, 0);
}
+void qtest_set_irq_in(QTestState *s, const char *qom_path, const char *name,
+ int num, int level)
+{
+ if (!name) {
+ name = "unnamed-gpio-in";
+ }
+ qtest_sendf(s, "set_irq_in %s %s %d %d\n", qom_path, name, num, level);
+ qtest_rsp(s, 0);
+}
+
static void qtest_out(QTestState *s, const char *cmd, uint16_t addr, uint32_t value)
{
qtest_sendf(s, "%s 0x%x 0x%x\n", cmd, addr, value);
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 02/11] arm: Add header to host common definition for nRF51 SOC peripherals
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 01/11] qtest: Add set_irq_in command to set IRQ/GPIO level Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-03 10:40 ` Philippe Mathieu-Daudé
2019-01-03 9:11 ` [Qemu-devel] [PATCH 03/11] hw/misc/nrf51_rng: Add NRF51 random number generator peripheral Stefan Hajnoczi
` (9 subsequent siblings)
11 siblings, 1 reply; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
Adds a header that provides definitions that are used
across nRF51 peripherals
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/hw/arm/nrf51.h | 45 ++++++++++++++++++++++++++++++++++++
include/hw/char/nrf51_uart.h | 1 -
hw/arm/nrf51_soc.c | 33 ++++++++++----------------
3 files changed, 57 insertions(+), 22 deletions(-)
create mode 100644 include/hw/arm/nrf51.h
diff --git a/include/hw/arm/nrf51.h b/include/hw/arm/nrf51.h
new file mode 100644
index 0000000000..175bb6c301
--- /dev/null
+++ b/include/hw/arm/nrf51.h
@@ -0,0 +1,45 @@
+/*
+ * Nordic Semiconductor nRF51 Series SOC Common Defines
+ *
+ * This file hosts generic defines used in various nRF51 peripheral devices.
+ *
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
+ * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef NRF51_H
+#define NRF51_H
+
+#define NRF51_FLASH_BASE 0x00000000
+#define NRF51_FICR_BASE 0x10000000
+#define NRF51_FICR_SIZE 0x00000100
+#define NRF51_UICR_BASE 0x10001000
+#define NRF51_SRAM_BASE 0x20000000
+
+#define NRF51_IOMEM_BASE 0x40000000
+#define NRF51_IOMEM_SIZE 0x20000000
+
+#define NRF51_UART_BASE 0x40002000
+#define NRF51_TIMER_BASE 0x40008000
+#define NRF51_TIMER_SIZE 0x00001000
+#define NRF51_RNG_BASE 0x4000D000
+#define NRF51_NVMC_BASE 0x4001E000
+#define NRF51_GPIO_BASE 0x50000000
+
+#define NRF51_PRIVATE_BASE 0xF0000000
+#define NRF51_PRIVATE_SIZE 0x10000000
+
+#define NRF51_PAGE_SIZE 1024
+
+/* Trigger */
+#define NRF51_TRIGGER_TASK 0x01
+
+/* Events */
+#define NRF51_EVENT_CLEAR 0x00
+
+#endif
diff --git a/include/hw/char/nrf51_uart.h b/include/hw/char/nrf51_uart.h
index e3ecb7c81c..eb1c15b490 100644
--- a/include/hw/char/nrf51_uart.h
+++ b/include/hw/char/nrf51_uart.h
@@ -16,7 +16,6 @@
#include "hw/registerfields.h"
#define UART_FIFO_LENGTH 6
-#define UART_BASE 0x40002000
#define UART_SIZE 0x1000
#define TYPE_NRF51_UART "nrf51_soc.uart"
diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c
index b89c1bdea0..55f8eaafcb 100644
--- a/hw/arm/nrf51_soc.c
+++ b/hw/arm/nrf51_soc.c
@@ -21,27 +21,16 @@
#include "qemu/log.h"
#include "cpu.h"
+#include "hw/arm/nrf51.h"
#include "hw/arm/nrf51_soc.h"
-#define IOMEM_BASE 0x40000000
-#define IOMEM_SIZE 0x20000000
-
-#define FICR_BASE 0x10000000
-#define FICR_SIZE 0x000000fc
-
-#define FLASH_BASE 0x00000000
-#define SRAM_BASE 0x20000000
-
-#define PRIVATE_BASE 0xF0000000
-#define PRIVATE_SIZE 0x10000000
-
/*
* The size and base is for the NRF51822 part. If other parts
* are supported in the future, add a sub-class of NRF51SoC for
* the specific variants
*/
-#define NRF51822_FLASH_SIZE (256 * 1024)
-#define NRF51822_SRAM_SIZE (16 * 1024)
+#define NRF51822_FLASH_SIZE (256 * NRF51_PAGE_SIZE)
+#define NRF51822_SRAM_SIZE (16 * NRF51_PAGE_SIZE)
#define BASE_TO_IRQ(base) ((base >> 12) & 0x1F)
@@ -76,14 +65,14 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
error_propagate(errp, err);
return;
}
- memory_region_add_subregion(&s->container, FLASH_BASE, &s->flash);
+ memory_region_add_subregion(&s->container, NRF51_FLASH_BASE, &s->flash);
memory_region_init_ram(&s->sram, NULL, "nrf51.sram", s->sram_size, &err);
if (err) {
error_propagate(errp, err);
return;
}
- memory_region_add_subregion(&s->container, SRAM_BASE, &s->sram);
+ memory_region_add_subregion(&s->container, NRF51_SRAM_BASE, &s->sram);
/* UART */
object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
@@ -92,15 +81,17 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
return;
}
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart), 0);
- memory_region_add_subregion_overlap(&s->container, UART_BASE, mr, 0);
+ memory_region_add_subregion_overlap(&s->container, NRF51_UART_BASE, mr, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 0,
qdev_get_gpio_in(DEVICE(&s->cpu),
- BASE_TO_IRQ(UART_BASE)));
+ BASE_TO_IRQ(NRF51_UART_BASE)));
- create_unimplemented_device("nrf51_soc.io", IOMEM_BASE, IOMEM_SIZE);
- create_unimplemented_device("nrf51_soc.ficr", FICR_BASE, FICR_SIZE);
+ create_unimplemented_device("nrf51_soc.io", NRF51_IOMEM_BASE,
+ NRF51_IOMEM_SIZE);
+ create_unimplemented_device("nrf51_soc.ficr", NRF51_FICR_BASE,
+ NRF51_FICR_SIZE);
create_unimplemented_device("nrf51_soc.private",
- PRIVATE_BASE, PRIVATE_SIZE);
+ NRF51_PRIVATE_BASE, NRF51_PRIVATE_SIZE);
}
static void nrf51_soc_init(Object *obj)
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 02/11] arm: Add header to host common definition for nRF51 SOC peripherals
2019-01-03 9:11 ` [Qemu-devel] [PATCH 02/11] arm: Add header to host common definition for nRF51 SOC peripherals Stefan Hajnoczi
@ 2019-01-03 10:40 ` Philippe Mathieu-Daudé
2019-01-04 9:51 ` Stefan Hajnoczi
0 siblings, 1 reply; 15+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-01-03 10:40 UTC (permalink / raw)
To: Stefan Hajnoczi, qemu-devel
Cc: Laurent Vivier, Peter Maydell, Thomas Huth, Steffen Görtz,
Jim Mussared, qemu-arm, Joel Stanley, Paolo Bonzini,
Julia Suvorova
On 1/3/19 10:11 AM, Stefan Hajnoczi wrote:
> From: Steffen Görtz <contrib@steffen-goertz.de>
>
> Adds a header that provides definitions that are used
> across nRF51 peripherals
>
> Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
> include/hw/arm/nrf51.h | 45 ++++++++++++++++++++++++++++++++++++
> include/hw/char/nrf51_uart.h | 1 -
> hw/arm/nrf51_soc.c | 33 ++++++++++----------------
> 3 files changed, 57 insertions(+), 22 deletions(-)
> create mode 100644 include/hw/arm/nrf51.h
>
> diff --git a/include/hw/arm/nrf51.h b/include/hw/arm/nrf51.h
> new file mode 100644
> index 0000000000..175bb6c301
> --- /dev/null
> +++ b/include/hw/arm/nrf51.h
> @@ -0,0 +1,45 @@
> +/*
> + * Nordic Semiconductor nRF51 Series SOC Common Defines
> + *
> + * This file hosts generic defines used in various nRF51 peripheral devices.
> + *
> + * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
> + * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
> + *
> + * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
> + *
> + * This code is licensed under the GPL version 2 or later. See
> + * the COPYING file in the top-level directory.
> + */
> +
> +#ifndef NRF51_H
> +#define NRF51_H
> +
> +#define NRF51_FLASH_BASE 0x00000000
> +#define NRF51_FICR_BASE 0x10000000
> +#define NRF51_FICR_SIZE 0x00000100
> +#define NRF51_UICR_BASE 0x10001000
> +#define NRF51_SRAM_BASE 0x20000000
> +
> +#define NRF51_IOMEM_BASE 0x40000000
> +#define NRF51_IOMEM_SIZE 0x20000000
> +
> +#define NRF51_UART_BASE 0x40002000
> +#define NRF51_TIMER_BASE 0x40008000
> +#define NRF51_TIMER_SIZE 0x00001000
> +#define NRF51_RNG_BASE 0x4000D000
> +#define NRF51_NVMC_BASE 0x4001E000
> +#define NRF51_GPIO_BASE 0x50000000
> +
> +#define NRF51_PRIVATE_BASE 0xF0000000
> +#define NRF51_PRIVATE_SIZE 0x10000000
> +
> +#define NRF51_PAGE_SIZE 1024
I'd keep this file in hw/arm (not include/...).
> +
> +/* Trigger */
> +#define NRF51_TRIGGER_TASK 0x01
> +
> +/* Events */
> +#define NRF51_EVENT_CLEAR 0x00
These definitions might be the only one used out of hw/arm/.
> +
> +#endif
> diff --git a/include/hw/char/nrf51_uart.h b/include/hw/char/nrf51_uart.h
> index e3ecb7c81c..eb1c15b490 100644
> --- a/include/hw/char/nrf51_uart.h
> +++ b/include/hw/char/nrf51_uart.h
> @@ -16,7 +16,6 @@
> #include "hw/registerfields.h"
>
> #define UART_FIFO_LENGTH 6
> -#define UART_BASE 0x40002000
> #define UART_SIZE 0x1000
>
> #define TYPE_NRF51_UART "nrf51_soc.uart"
> diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c
> index b89c1bdea0..55f8eaafcb 100644
> --- a/hw/arm/nrf51_soc.c
> +++ b/hw/arm/nrf51_soc.c
> @@ -21,27 +21,16 @@
> #include "qemu/log.h"
> #include "cpu.h"
>
> +#include "hw/arm/nrf51.h"
> #include "hw/arm/nrf51_soc.h"
>
> -#define IOMEM_BASE 0x40000000
> -#define IOMEM_SIZE 0x20000000
> -
> -#define FICR_BASE 0x10000000
> -#define FICR_SIZE 0x000000fc
> -
> -#define FLASH_BASE 0x00000000
> -#define SRAM_BASE 0x20000000
> -
> -#define PRIVATE_BASE 0xF0000000
> -#define PRIVATE_SIZE 0x10000000
> -
> /*
> * The size and base is for the NRF51822 part. If other parts
> * are supported in the future, add a sub-class of NRF51SoC for
> * the specific variants
> */
> -#define NRF51822_FLASH_SIZE (256 * 1024)
> -#define NRF51822_SRAM_SIZE (16 * 1024)
> +#define NRF51822_FLASH_SIZE (256 * NRF51_PAGE_SIZE)
> +#define NRF51822_SRAM_SIZE (16 * NRF51_PAGE_SIZE)
>
> #define BASE_TO_IRQ(base) ((base >> 12) & 0x1F)
>
> @@ -76,14 +65,14 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
> error_propagate(errp, err);
> return;
> }
> - memory_region_add_subregion(&s->container, FLASH_BASE, &s->flash);
> + memory_region_add_subregion(&s->container, NRF51_FLASH_BASE, &s->flash);
>
> memory_region_init_ram(&s->sram, NULL, "nrf51.sram", s->sram_size, &err);
> if (err) {
> error_propagate(errp, err);
> return;
> }
> - memory_region_add_subregion(&s->container, SRAM_BASE, &s->sram);
> + memory_region_add_subregion(&s->container, NRF51_SRAM_BASE, &s->sram);
>
> /* UART */
> object_property_set_bool(OBJECT(&s->uart), true, "realized", &err);
> @@ -92,15 +81,17 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
> return;
> }
> mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart), 0);
> - memory_region_add_subregion_overlap(&s->container, UART_BASE, mr, 0);
> + memory_region_add_subregion_overlap(&s->container, NRF51_UART_BASE, mr, 0);
> sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart), 0,
> qdev_get_gpio_in(DEVICE(&s->cpu),
> - BASE_TO_IRQ(UART_BASE)));
> + BASE_TO_IRQ(NRF51_UART_BASE)));
>
> - create_unimplemented_device("nrf51_soc.io", IOMEM_BASE, IOMEM_SIZE);
> - create_unimplemented_device("nrf51_soc.ficr", FICR_BASE, FICR_SIZE);
> + create_unimplemented_device("nrf51_soc.io", NRF51_IOMEM_BASE,
> + NRF51_IOMEM_SIZE);
> + create_unimplemented_device("nrf51_soc.ficr", NRF51_FICR_BASE,
> + NRF51_FICR_SIZE);
> create_unimplemented_device("nrf51_soc.private",
> - PRIVATE_BASE, PRIVATE_SIZE);
> + NRF51_PRIVATE_BASE, NRF51_PRIVATE_SIZE);
> }
>
> static void nrf51_soc_init(Object *obj)
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 02/11] arm: Add header to host common definition for nRF51 SOC peripherals
2019-01-03 10:40 ` Philippe Mathieu-Daudé
@ 2019-01-04 9:51 ` Stefan Hajnoczi
0 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-04 9:51 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: qemu-devel, Laurent Vivier, Peter Maydell, Thomas Huth,
Steffen Görtz, Jim Mussared, qemu-arm, Joel Stanley,
Paolo Bonzini, Julia Suvorova
[-- Attachment #1: Type: text/plain, Size: 2586 bytes --]
On Thu, Jan 03, 2019 at 11:40:30AM +0100, Philippe Mathieu-Daudé wrote:
> On 1/3/19 10:11 AM, Stefan Hajnoczi wrote:
> > From: Steffen Görtz <contrib@steffen-goertz.de>
> >
> > Adds a header that provides definitions that are used
> > across nRF51 peripherals
> >
> > Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
> > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> > Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> > ---
> > include/hw/arm/nrf51.h | 45 ++++++++++++++++++++++++++++++++++++
> > include/hw/char/nrf51_uart.h | 1 -
> > hw/arm/nrf51_soc.c | 33 ++++++++++----------------
> > 3 files changed, 57 insertions(+), 22 deletions(-)
> > create mode 100644 include/hw/arm/nrf51.h
> >
> > diff --git a/include/hw/arm/nrf51.h b/include/hw/arm/nrf51.h
> > new file mode 100644
> > index 0000000000..175bb6c301
> > --- /dev/null
> > +++ b/include/hw/arm/nrf51.h
> > @@ -0,0 +1,45 @@
> > +/*
> > + * Nordic Semiconductor nRF51 Series SOC Common Defines
> > + *
> > + * This file hosts generic defines used in various nRF51 peripheral devices.
> > + *
> > + * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
> > + * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
> > + *
> > + * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
> > + *
> > + * This code is licensed under the GPL version 2 or later. See
> > + * the COPYING file in the top-level directory.
> > + */
> > +
> > +#ifndef NRF51_H
> > +#define NRF51_H
> > +
> > +#define NRF51_FLASH_BASE 0x00000000
> > +#define NRF51_FICR_BASE 0x10000000
> > +#define NRF51_FICR_SIZE 0x00000100
> > +#define NRF51_UICR_BASE 0x10001000
> > +#define NRF51_SRAM_BASE 0x20000000
> > +
> > +#define NRF51_IOMEM_BASE 0x40000000
> > +#define NRF51_IOMEM_SIZE 0x20000000
> > +
> > +#define NRF51_UART_BASE 0x40002000
> > +#define NRF51_TIMER_BASE 0x40008000
> > +#define NRF51_TIMER_SIZE 0x00001000
> > +#define NRF51_RNG_BASE 0x4000D000
> > +#define NRF51_NVMC_BASE 0x4001E000
> > +#define NRF51_GPIO_BASE 0x50000000
> > +
> > +#define NRF51_PRIVATE_BASE 0xF0000000
> > +#define NRF51_PRIVATE_SIZE 0x10000000
> > +
> > +#define NRF51_PAGE_SIZE 1024
>
> I'd keep this file in hw/arm (not include/...).
This header file avoids duplicating definitions in
tests/microbit-test.c.
How would you structure it differently?
Stefan
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 455 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 03/11] hw/misc/nrf51_rng: Add NRF51 random number generator peripheral
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 01/11] qtest: Add set_irq_in command to set IRQ/GPIO level Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 02/11] arm: Add header to host common definition for nRF51 SOC peripherals Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 04/11] arm: Instantiate NRF51 random number generator Stefan Hajnoczi
` (8 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
Add a model of the NRF51 random number generator peripheral.
This is a simple random generator that continuously generates
new random values after startup.
Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
hw/misc/Makefile.objs | 1 +
include/hw/misc/nrf51_rng.h | 83 ++++++++++++
hw/misc/nrf51_rng.c | 262 ++++++++++++++++++++++++++++++++++++
3 files changed, 346 insertions(+)
create mode 100644 include/hw/misc/nrf51_rng.h
create mode 100644 hw/misc/nrf51_rng.c
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 680350b3c3..04f3bfa516 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -74,3 +74,4 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_AUX) += auxbus.o
obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
obj-$(CONFIG_MSF2) += msf2-sysreg.o
+obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o
diff --git a/include/hw/misc/nrf51_rng.h b/include/hw/misc/nrf51_rng.h
new file mode 100644
index 0000000000..3d6bf79997
--- /dev/null
+++ b/include/hw/misc/nrf51_rng.h
@@ -0,0 +1,83 @@
+/*
+ * nRF51 Random Number Generator
+ *
+ * QEMU interface:
+ * + Property "period_unfiltered_us": Time between two biased values in
+ * microseconds.
+ * + Property "period_filtered_us": Time between two unbiased values in
+ * microseconds.
+ * + sysbus MMIO regions 0: Memory Region with tasks, events and registers
+ * to be mapped to the peripherals instance address by the SOC.
+ * + Named GPIO output "irq": Interrupt line of the peripheral. Must be
+ * connected to the associated peripheral interrupt line of the NVIC.
+ * + Named GPIO output "eep_valrdy": Event set when new random value is ready
+ * to be read.
+ * + Named GPIO input "tep_start": Task that triggers start of continuous
+ * generation of random values.
+ * + Named GPIO input "tep_stop": Task that ends continuous generation of
+ * random values.
+ *
+ * Accuracy of the peripheral model:
+ * + Stochastic properties of different configurations of the random source
+ * are not modeled.
+ * + Generation of unfiltered and filtered random values take at least the
+ * average generation time stated in the production specification;
+ * non-deterministic generation times are not modeled.
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef NRF51_RNG_H
+#define NRF51_RNG_H
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#define TYPE_NRF51_RNG "nrf51_soc.rng"
+#define NRF51_RNG(obj) OBJECT_CHECK(NRF51RNGState, (obj), TYPE_NRF51_RNG)
+
+#define NRF51_RNG_SIZE 0x1000
+
+#define NRF51_RNG_TASK_START 0x000
+#define NRF51_RNG_TASK_STOP 0x004
+#define NRF51_RNG_EVENT_VALRDY 0x100
+#define NRF51_RNG_REG_SHORTS 0x200
+#define NRF51_RNG_REG_SHORTS_VALRDY_STOP 0
+#define NRF51_RNG_REG_INTEN 0x300
+#define NRF51_RNG_REG_INTEN_VALRDY 0
+#define NRF51_RNG_REG_INTENSET 0x304
+#define NRF51_RNG_REG_INTENCLR 0x308
+#define NRF51_RNG_REG_CONFIG 0x504
+#define NRF51_RNG_REG_CONFIG_DECEN 0
+#define NRF51_RNG_REG_VALUE 0x508
+
+typedef struct {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+ qemu_irq irq;
+
+ /* Event End Points */
+ qemu_irq eep_valrdy;
+
+ QEMUTimer timer;
+
+ /* Time between generation of successive unfiltered values in us */
+ uint16_t period_unfiltered_us;
+ /* Time between generation of successive filtered values in us */
+ uint16_t period_filtered_us;
+
+ uint8_t value;
+
+ uint32_t active;
+ uint32_t event_valrdy;
+ uint32_t shortcut_stop_on_valrdy;
+ uint32_t interrupt_enabled;
+ uint32_t filter_enabled;
+
+} NRF51RNGState;
+
+
+#endif /* NRF51_RNG_H_ */
diff --git a/hw/misc/nrf51_rng.c b/hw/misc/nrf51_rng.c
new file mode 100644
index 0000000000..d188f044f4
--- /dev/null
+++ b/hw/misc/nrf51_rng.c
@@ -0,0 +1,262 @@
+/*
+ * nRF51 Random Number Generator
+ *
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.1.pdf
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "hw/arm/nrf51.h"
+#include "hw/misc/nrf51_rng.h"
+#include "crypto/random.h"
+
+static void update_irq(NRF51RNGState *s)
+{
+ bool irq = s->interrupt_enabled && s->event_valrdy;
+ qemu_set_irq(s->irq, irq);
+}
+
+static uint64_t rng_read(void *opaque, hwaddr offset, unsigned int size)
+{
+ NRF51RNGState *s = NRF51_RNG(opaque);
+ uint64_t r = 0;
+
+ switch (offset) {
+ case NRF51_RNG_EVENT_VALRDY:
+ r = s->event_valrdy;
+ break;
+ case NRF51_RNG_REG_SHORTS:
+ r = s->shortcut_stop_on_valrdy;
+ break;
+ case NRF51_RNG_REG_INTEN:
+ case NRF51_RNG_REG_INTENSET:
+ case NRF51_RNG_REG_INTENCLR:
+ r = s->interrupt_enabled;
+ break;
+ case NRF51_RNG_REG_CONFIG:
+ r = s->filter_enabled;
+ break;
+ case NRF51_RNG_REG_VALUE:
+ r = s->value;
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad read offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ return r;
+}
+
+static int64_t calc_next_timeout(NRF51RNGState *s)
+{
+ int64_t timeout = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
+ if (s->filter_enabled) {
+ timeout += s->period_filtered_us;
+ } else {
+ timeout += s->period_unfiltered_us;
+ }
+
+ return timeout;
+}
+
+
+static void rng_update_timer(NRF51RNGState *s)
+{
+ if (s->active) {
+ timer_mod(&s->timer, calc_next_timeout(s));
+ } else {
+ timer_del(&s->timer);
+ }
+}
+
+
+static void rng_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned int size)
+{
+ NRF51RNGState *s = NRF51_RNG(opaque);
+
+ switch (offset) {
+ case NRF51_RNG_TASK_START:
+ if (value == NRF51_TRIGGER_TASK) {
+ s->active = 1;
+ rng_update_timer(s);
+ }
+ break;
+ case NRF51_RNG_TASK_STOP:
+ if (value == NRF51_TRIGGER_TASK) {
+ s->active = 0;
+ rng_update_timer(s);
+ }
+ break;
+ case NRF51_RNG_EVENT_VALRDY:
+ if (value == NRF51_EVENT_CLEAR) {
+ s->event_valrdy = 0;
+ }
+ break;
+ case NRF51_RNG_REG_SHORTS:
+ s->shortcut_stop_on_valrdy =
+ (value & BIT_MASK(NRF51_RNG_REG_SHORTS_VALRDY_STOP)) ? 1 : 0;
+ break;
+ case NRF51_RNG_REG_INTEN:
+ s->interrupt_enabled =
+ (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) ? 1 : 0;
+ break;
+ case NRF51_RNG_REG_INTENSET:
+ if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
+ s->interrupt_enabled = 1;
+ }
+ break;
+ case NRF51_RNG_REG_INTENCLR:
+ if (value & BIT_MASK(NRF51_RNG_REG_INTEN_VALRDY)) {
+ s->interrupt_enabled = 0;
+ }
+ break;
+ case NRF51_RNG_REG_CONFIG:
+ s->filter_enabled =
+ (value & BIT_MASK(NRF51_RNG_REG_CONFIG_DECEN)) ? 1 : 0;
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad write offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ update_irq(s);
+}
+
+static const MemoryRegionOps rng_ops = {
+ .read = rng_read,
+ .write = rng_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4
+};
+
+static void nrf51_rng_timer_expire(void *opaque)
+{
+ NRF51RNGState *s = NRF51_RNG(opaque);
+
+ qcrypto_random_bytes(&s->value, 1, &error_abort);
+
+ s->event_valrdy = 1;
+ qemu_set_irq(s->eep_valrdy, 1);
+
+ if (s->shortcut_stop_on_valrdy) {
+ s->active = 0;
+ }
+
+ rng_update_timer(s);
+ update_irq(s);
+}
+
+static void nrf51_rng_tep_start(void *opaque, int n, int level)
+{
+ NRF51RNGState *s = NRF51_RNG(opaque);
+
+ if (level) {
+ s->active = 1;
+ rng_update_timer(s);
+ }
+}
+
+static void nrf51_rng_tep_stop(void *opaque, int n, int level)
+{
+ NRF51RNGState *s = NRF51_RNG(opaque);
+
+ if (level) {
+ s->active = 0;
+ rng_update_timer(s);
+ }
+}
+
+
+static void nrf51_rng_init(Object *obj)
+{
+ NRF51RNGState *s = NRF51_RNG(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&s->mmio, obj, &rng_ops, s,
+ TYPE_NRF51_RNG, NRF51_RNG_SIZE);
+ sysbus_init_mmio(sbd, &s->mmio);
+
+ timer_init_us(&s->timer, QEMU_CLOCK_VIRTUAL, nrf51_rng_timer_expire, s);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ /* Tasks */
+ qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_start, "tep_start", 1);
+ qdev_init_gpio_in_named(DEVICE(s), nrf51_rng_tep_stop, "tep_stop", 1);
+
+ /* Events */
+ qdev_init_gpio_out_named(DEVICE(s), &s->eep_valrdy, "eep_valrdy", 1);
+}
+
+static void nrf51_rng_reset(DeviceState *dev)
+{
+ NRF51RNGState *s = NRF51_RNG(dev);
+
+ s->value = 0;
+ s->active = 0;
+ s->event_valrdy = 0;
+ s->shortcut_stop_on_valrdy = 0;
+ s->interrupt_enabled = 0;
+ s->filter_enabled = 0;
+
+ rng_update_timer(s);
+}
+
+
+static Property nrf51_rng_properties[] = {
+ DEFINE_PROP_UINT16("period_unfiltered_us", NRF51RNGState,
+ period_unfiltered_us, 167),
+ DEFINE_PROP_UINT16("period_filtered_us", NRF51RNGState,
+ period_filtered_us, 660),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_rng = {
+ .name = "nrf51_soc.rng",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(active, NRF51RNGState),
+ VMSTATE_UINT32(event_valrdy, NRF51RNGState),
+ VMSTATE_UINT32(shortcut_stop_on_valrdy, NRF51RNGState),
+ VMSTATE_UINT32(interrupt_enabled, NRF51RNGState),
+ VMSTATE_UINT32(filter_enabled, NRF51RNGState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void nrf51_rng_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = nrf51_rng_properties;
+ dc->vmsd = &vmstate_rng;
+ dc->reset = nrf51_rng_reset;
+}
+
+static const TypeInfo nrf51_rng_info = {
+ .name = TYPE_NRF51_RNG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NRF51RNGState),
+ .instance_init = nrf51_rng_init,
+ .class_init = nrf51_rng_class_init
+};
+
+static void nrf51_rng_register_types(void)
+{
+ type_register_static(&nrf51_rng_info);
+}
+
+type_init(nrf51_rng_register_types)
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 04/11] arm: Instantiate NRF51 random number generator
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
` (2 preceding siblings ...)
2019-01-03 9:11 ` [Qemu-devel] [PATCH 03/11] hw/misc/nrf51_rng: Add NRF51 random number generator peripheral Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 05/11] hw/gpio/nrf51_gpio: Add nRF51 GPIO peripheral Stefan Hajnoczi
` (7 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
Use RNG in SOC.
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/hw/arm/nrf51_soc.h | 2 ++
hw/arm/nrf51_soc.c | 16 ++++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/include/hw/arm/nrf51_soc.h b/include/hw/arm/nrf51_soc.h
index 73fc92e9a8..9e3ba916bd 100644
--- a/include/hw/arm/nrf51_soc.h
+++ b/include/hw/arm/nrf51_soc.h
@@ -13,6 +13,7 @@
#include "hw/sysbus.h"
#include "hw/arm/armv7m.h"
#include "hw/char/nrf51_uart.h"
+#include "hw/misc/nrf51_rng.h"
#define TYPE_NRF51_SOC "nrf51-soc"
#define NRF51_SOC(obj) \
@@ -26,6 +27,7 @@ typedef struct NRF51State {
ARMv7MState cpu;
NRF51UARTState uart;
+ NRF51RNGState rng;
MemoryRegion iomem;
MemoryRegion sram;
diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c
index 55f8eaafcb..d2a19b8ead 100644
--- a/hw/arm/nrf51_soc.c
+++ b/hw/arm/nrf51_soc.c
@@ -86,6 +86,19 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
qdev_get_gpio_in(DEVICE(&s->cpu),
BASE_TO_IRQ(NRF51_UART_BASE)));
+ /* RNG */
+ object_property_set_bool(OBJECT(&s->rng), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rng), 0);
+ memory_region_add_subregion_overlap(&s->container, NRF51_RNG_BASE, mr, 0);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rng), 0,
+ qdev_get_gpio_in(DEVICE(&s->cpu),
+ BASE_TO_IRQ(NRF51_RNG_BASE)));
+
create_unimplemented_device("nrf51_soc.io", NRF51_IOMEM_BASE,
NRF51_IOMEM_SIZE);
create_unimplemented_device("nrf51_soc.ficr", NRF51_FICR_BASE,
@@ -110,6 +123,9 @@ static void nrf51_soc_init(Object *obj)
TYPE_NRF51_UART);
object_property_add_alias(obj, "serial0", OBJECT(&s->uart), "chardev",
&error_abort);
+
+ sysbus_init_child_obj(obj, "rng", &s->rng, sizeof(s->rng),
+ TYPE_NRF51_RNG);
}
static Property nrf51_soc_properties[] = {
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 05/11] hw/gpio/nrf51_gpio: Add nRF51 GPIO peripheral
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
` (3 preceding siblings ...)
2019-01-03 9:11 ` [Qemu-devel] [PATCH 04/11] arm: Instantiate NRF51 random number generator Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 06/11] arm: Instantiate NRF51 general purpose I/O Stefan Hajnoczi
` (6 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
This adds a model of the nRF51 GPIO peripheral.
Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
The nRF51 series microcontrollers support up to 32 GPIO pins in various configurations.
The pins can be used as input pins with pull-ups or pull-down.
Furthermore, three different output driver modes per level are
available (disconnected, standard, high-current).
The GPIO-Peripheral has a mechanism for detecting level changes which is
not featured in this model.
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
Makefile.objs | 1 +
hw/gpio/Makefile.objs | 1 +
include/hw/gpio/nrf51_gpio.h | 69 ++++++++
hw/gpio/nrf51_gpio.c | 300 +++++++++++++++++++++++++++++++++++
hw/gpio/trace-events | 7 +
5 files changed, 378 insertions(+)
create mode 100644 include/hw/gpio/nrf51_gpio.h
create mode 100644 hw/gpio/nrf51_gpio.c
create mode 100644 hw/gpio/trace-events
diff --git a/Makefile.objs b/Makefile.objs
index bc5b8a8442..456115992a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -184,6 +184,7 @@ trace-events-subdirs += hw/vfio
trace-events-subdirs += hw/virtio
trace-events-subdirs += hw/watchdog
trace-events-subdirs += hw/xen
+trace-events-subdirs += hw/gpio
trace-events-subdirs += io
trace-events-subdirs += linux-user
trace-events-subdirs += migration
diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs
index fa0a72e6d0..e5da0cb54f 100644
--- a/hw/gpio/Makefile.objs
+++ b/hw/gpio/Makefile.objs
@@ -8,3 +8,4 @@ common-obj-$(CONFIG_GPIO_KEY) += gpio_key.o
obj-$(CONFIG_OMAP) += omap_gpio.o
obj-$(CONFIG_IMX) += imx_gpio.o
obj-$(CONFIG_RASPI) += bcm2835_gpio.o
+obj-$(CONFIG_NRF51_SOC) += nrf51_gpio.o
diff --git a/include/hw/gpio/nrf51_gpio.h b/include/hw/gpio/nrf51_gpio.h
new file mode 100644
index 0000000000..337ee534bb
--- /dev/null
+++ b/include/hw/gpio/nrf51_gpio.h
@@ -0,0 +1,69 @@
+/*
+ * nRF51 System-on-Chip general purpose input/output register definition
+ *
+ * QEMU interface:
+ * + sysbus MMIO regions 0: GPIO registers
+ * + Unnamed GPIO inputs 0-31: Set tri-state input level for GPIO pin.
+ * Level -1: Externally Disconnected/Floating; Pull-up/down will be regarded
+ * Level 0: Input externally driven LOW
+ * Level 1: Input externally driven HIGH
+ * + Unnamed GPIO outputs 0-31:
+ * Level -1: Disconnected/Floating
+ * Level 0: Driven LOW
+ * Level 1: Driven HIGH
+ *
+ * Accuracy of the peripheral model:
+ * + The nRF51 GPIO output driver supports two modes, standard and high-current
+ * mode. These different drive modes are not modeled and handled the same.
+ * + Pin SENSEing is not modeled/implemented.
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef NRF51_GPIO_H
+#define NRF51_GPIO_H
+
+#include "hw/sysbus.h"
+#define TYPE_NRF51_GPIO "nrf51_soc.gpio"
+#define NRF51_GPIO(obj) OBJECT_CHECK(NRF51GPIOState, (obj), TYPE_NRF51_GPIO)
+
+#define NRF51_GPIO_PINS 32
+
+#define NRF51_GPIO_SIZE 0x1000
+
+#define NRF51_GPIO_REG_OUT 0x504
+#define NRF51_GPIO_REG_OUTSET 0x508
+#define NRF51_GPIO_REG_OUTCLR 0x50C
+#define NRF51_GPIO_REG_IN 0x510
+#define NRF51_GPIO_REG_DIR 0x514
+#define NRF51_GPIO_REG_DIRSET 0x518
+#define NRF51_GPIO_REG_DIRCLR 0x51C
+#define NRF51_GPIO_REG_CNF_START 0x700
+#define NRF51_GPIO_REG_CNF_END 0x77F
+
+#define NRF51_GPIO_PULLDOWN 1
+#define NRF51_GPIO_PULLUP 3
+
+typedef struct NRF51GPIOState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion mmio;
+ qemu_irq irq;
+
+ uint32_t out;
+ uint32_t in;
+ uint32_t in_mask;
+ uint32_t dir;
+ uint32_t cnf[NRF51_GPIO_PINS];
+
+ uint32_t old_out;
+ uint32_t old_out_connected;
+
+ qemu_irq output[NRF51_GPIO_PINS];
+} NRF51GPIOState;
+
+
+#endif
diff --git a/hw/gpio/nrf51_gpio.c b/hw/gpio/nrf51_gpio.c
new file mode 100644
index 0000000000..86e047d649
--- /dev/null
+++ b/hw/gpio/nrf51_gpio.c
@@ -0,0 +1,300 @@
+/*
+ * nRF51 System-on-Chip general purpose input/output register definition
+ *
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
+ * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/gpio/nrf51_gpio.h"
+#include "trace.h"
+
+/*
+ * Check if the output driver is connected to the direction switch
+ * given the current configuration and logic level.
+ * It is not differentiated between standard and "high"(-power) drive modes.
+ */
+static bool is_connected(uint32_t config, uint32_t level)
+{
+ bool state;
+ uint32_t drive_config = extract32(config, 8, 3);
+
+ switch (drive_config) {
+ case 0 ... 3:
+ state = true;
+ break;
+ case 4 ... 5:
+ state = level != 0;
+ break;
+ case 6 ... 7:
+ state = level == 0;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ return state;
+}
+
+static void update_output_irq(NRF51GPIOState *s, size_t i,
+ bool connected, bool level)
+{
+ int64_t irq_level = connected ? level : -1;
+ bool old_connected = extract32(s->old_out_connected, i, 1);
+ bool old_level = extract32(s->old_out, i, 1);
+
+ if ((old_connected != connected) || (old_level != level)) {
+ qemu_set_irq(s->output[i], irq_level);
+ trace_nrf51_gpio_update_output_irq(i, irq_level);
+ }
+
+ s->old_out = deposit32(s->old_out, i, 1, level);
+ s->old_out_connected = deposit32(s->old_out_connected, i, 1, connected);
+}
+
+static void update_state(NRF51GPIOState *s)
+{
+ uint32_t pull;
+ size_t i;
+ bool connected_out, dir, connected_in, out, input;
+
+ for (i = 0; i < NRF51_GPIO_PINS; i++) {
+ pull = extract32(s->cnf[i], 2, 2);
+ dir = extract32(s->cnf[i], 0, 1);
+ connected_in = extract32(s->in_mask, i, 1);
+ out = extract32(s->out, i, 1);
+ input = !extract32(s->cnf[i], 1, 1);
+ connected_out = is_connected(s->cnf[i], out) && dir;
+
+ update_output_irq(s, i, connected_out, out);
+
+ /* Pin both driven externally and internally */
+ if (connected_out && connected_in) {
+ qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i);
+ }
+
+ /*
+ * Input buffer disconnected from internal/external drives, so
+ * pull-up/pull-down becomes relevant
+ */
+ if (!input || (input && !connected_in && !connected_out)) {
+ if (pull == NRF51_GPIO_PULLDOWN) {
+ s->in = deposit32(s->in, i, 1, 0);
+ } else if (pull == NRF51_GPIO_PULLUP) {
+ s->in = deposit32(s->in, i, 1, 1);
+ }
+ }
+
+ /* Self stimulation through internal output driver */
+ if (connected_out && !connected_in && input) {
+ s->in = deposit32(s->in, i, 1, out);
+ }
+ }
+
+}
+
+/*
+ * Direction is exposed in both the DIR register and the DIR bit
+ * of each PINs CNF configuration register. Reflect bits for pins in DIR
+ * to individual pin configuration registers.
+ */
+static void reflect_dir_bit_in_cnf(NRF51GPIOState *s)
+{
+ size_t i;
+
+ uint32_t value = s->dir;
+
+ for (i = 0; i < NRF51_GPIO_PINS; i++) {
+ s->cnf[i] = (s->cnf[i] & ~(1UL)) | ((value >> i) & 0x01);
+ }
+}
+
+static uint64_t nrf51_gpio_read(void *opaque, hwaddr offset, unsigned int size)
+{
+ NRF51GPIOState *s = NRF51_GPIO(opaque);
+ uint64_t r = 0;
+ size_t idx;
+
+ switch (offset) {
+ case NRF51_GPIO_REG_OUT ... NRF51_GPIO_REG_OUTCLR:
+ r = s->out;
+ break;
+
+ case NRF51_GPIO_REG_IN:
+ r = s->in;
+ break;
+
+ case NRF51_GPIO_REG_DIR ... NRF51_GPIO_REG_DIRCLR:
+ r = s->dir;
+ break;
+
+ case NRF51_GPIO_REG_CNF_START ... NRF51_GPIO_REG_CNF_END:
+ idx = (offset - NRF51_GPIO_REG_CNF_START) / 4;
+ r = s->cnf[idx];
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad read offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ trace_nrf51_gpio_read(offset, r);
+
+ return r;
+}
+
+static void nrf51_gpio_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned int size)
+{
+ NRF51GPIOState *s = NRF51_GPIO(opaque);
+ size_t idx;
+
+ trace_nrf51_gpio_write(offset, value);
+
+ switch (offset) {
+ case NRF51_GPIO_REG_OUT:
+ s->out = value;
+ break;
+
+ case NRF51_GPIO_REG_OUTSET:
+ s->out |= value;
+ break;
+
+ case NRF51_GPIO_REG_OUTCLR:
+ s->out &= ~value;
+ break;
+
+ case NRF51_GPIO_REG_DIR:
+ s->dir = value;
+ reflect_dir_bit_in_cnf(s);
+ break;
+
+ case NRF51_GPIO_REG_DIRSET:
+ s->dir |= value;
+ reflect_dir_bit_in_cnf(s);
+ break;
+
+ case NRF51_GPIO_REG_DIRCLR:
+ s->dir &= ~value;
+ reflect_dir_bit_in_cnf(s);
+ break;
+
+ case NRF51_GPIO_REG_CNF_START ... NRF51_GPIO_REG_CNF_END:
+ idx = (offset - NRF51_GPIO_REG_CNF_START) / 4;
+ s->cnf[idx] = value;
+ /*
+ * direction is exposed in both the DIR register and the DIR bit
+ * of each PINs CNF configuration register.
+ */
+ s->dir = (s->dir & ~(1UL << idx)) | ((value & 0x01) << idx);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad write offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ update_state(s);
+}
+
+static const MemoryRegionOps gpio_ops = {
+ .read = nrf51_gpio_read,
+ .write = nrf51_gpio_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+};
+
+static void nrf51_gpio_set(void *opaque, int line, int value)
+{
+ NRF51GPIOState *s = NRF51_GPIO(opaque);
+
+ trace_nrf51_gpio_set(line, value);
+
+ assert(line >= 0 && line < NRF51_GPIO_PINS);
+
+ s->in_mask = deposit32(s->in_mask, line, 1, value >= 0);
+ if (value >= 0) {
+ s->in = deposit32(s->in, line, 1, value != 0);
+ }
+
+ update_state(s);
+}
+
+static void nrf51_gpio_reset(DeviceState *dev)
+{
+ NRF51GPIOState *s = NRF51_GPIO(dev);
+ size_t i;
+
+ s->out = 0;
+ s->old_out = 0;
+ s->old_out_connected = 0;
+ s->in = 0;
+ s->in_mask = 0;
+ s->dir = 0;
+
+ for (i = 0; i < NRF51_GPIO_PINS; i++) {
+ s->cnf[i] = 0x00000002;
+ }
+}
+
+static const VMStateDescription vmstate_nrf51_gpio = {
+ .name = TYPE_NRF51_GPIO,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(out, NRF51GPIOState),
+ VMSTATE_UINT32(in, NRF51GPIOState),
+ VMSTATE_UINT32(in_mask, NRF51GPIOState),
+ VMSTATE_UINT32(dir, NRF51GPIOState),
+ VMSTATE_UINT32_ARRAY(cnf, NRF51GPIOState, NRF51_GPIO_PINS),
+ VMSTATE_UINT32(old_out, NRF51GPIOState),
+ VMSTATE_UINT32(old_out_connected, NRF51GPIOState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void nrf51_gpio_init(Object *obj)
+{
+ NRF51GPIOState *s = NRF51_GPIO(obj);
+
+ memory_region_init_io(&s->mmio, obj, &gpio_ops, s,
+ TYPE_NRF51_GPIO, NRF51_GPIO_SIZE);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ qdev_init_gpio_in(DEVICE(s), nrf51_gpio_set, NRF51_GPIO_PINS);
+ qdev_init_gpio_out(DEVICE(s), s->output, NRF51_GPIO_PINS);
+}
+
+static void nrf51_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_nrf51_gpio;
+ dc->reset = nrf51_gpio_reset;
+ dc->desc = "nRF51 GPIO";
+}
+
+static const TypeInfo nrf51_gpio_info = {
+ .name = TYPE_NRF51_GPIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NRF51GPIOState),
+ .instance_init = nrf51_gpio_init,
+ .class_init = nrf51_gpio_class_init
+};
+
+static void nrf51_gpio_register_types(void)
+{
+ type_register_static(&nrf51_gpio_info);
+}
+
+type_init(nrf51_gpio_register_types)
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
new file mode 100644
index 0000000000..cb41a89756
--- /dev/null
+++ b/hw/gpio/trace-events
@@ -0,0 +1,7 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# hw/gpio/nrf51_gpio.c
+nrf51_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
+nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
+nrf51_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
+nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
\ No newline at end of file
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 06/11] arm: Instantiate NRF51 general purpose I/O
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
` (4 preceding siblings ...)
2019-01-03 9:11 ` [Qemu-devel] [PATCH 05/11] hw/gpio/nrf51_gpio: Add nRF51 GPIO peripheral Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 07/11] tests/microbit-test: Add Tests for nRF51 GPIO Stefan Hajnoczi
` (5 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
Instantiates GPIO peripheral model
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/hw/arm/nrf51_soc.h | 2 ++
hw/arm/nrf51_soc.c | 16 ++++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/include/hw/arm/nrf51_soc.h b/include/hw/arm/nrf51_soc.h
index 9e3ba916bd..84e0278881 100644
--- a/include/hw/arm/nrf51_soc.h
+++ b/include/hw/arm/nrf51_soc.h
@@ -14,6 +14,7 @@
#include "hw/arm/armv7m.h"
#include "hw/char/nrf51_uart.h"
#include "hw/misc/nrf51_rng.h"
+#include "hw/gpio/nrf51_gpio.h"
#define TYPE_NRF51_SOC "nrf51-soc"
#define NRF51_SOC(obj) \
@@ -28,6 +29,7 @@ typedef struct NRF51State {
NRF51UARTState uart;
NRF51RNGState rng;
+ NRF51GPIOState gpio;
MemoryRegion iomem;
MemoryRegion sram;
diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c
index d2a19b8ead..db817fe506 100644
--- a/hw/arm/nrf51_soc.c
+++ b/hw/arm/nrf51_soc.c
@@ -99,6 +99,19 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
qdev_get_gpio_in(DEVICE(&s->cpu),
BASE_TO_IRQ(NRF51_RNG_BASE)));
+ /* GPIO */
+ object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gpio), 0);
+ memory_region_add_subregion_overlap(&s->container, NRF51_GPIO_BASE, mr, 0);
+
+ /* Pass all GPIOs to the SOC layer so they are available to the board */
+ qdev_pass_gpios(DEVICE(&s->gpio), dev_soc, NULL);
+
create_unimplemented_device("nrf51_soc.io", NRF51_IOMEM_BASE,
NRF51_IOMEM_SIZE);
create_unimplemented_device("nrf51_soc.ficr", NRF51_FICR_BASE,
@@ -126,6 +139,9 @@ static void nrf51_soc_init(Object *obj)
sysbus_init_child_obj(obj, "rng", &s->rng, sizeof(s->rng),
TYPE_NRF51_RNG);
+
+ sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio),
+ TYPE_NRF51_GPIO);
}
static Property nrf51_soc_properties[] = {
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 07/11] tests/microbit-test: Add Tests for nRF51 GPIO
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
` (5 preceding siblings ...)
2019-01-03 9:11 ` [Qemu-devel] [PATCH 06/11] arm: Instantiate NRF51 general purpose I/O Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 08/11] hw/timer/nrf51_timer: Add nRF51 Timer peripheral Stefan Hajnoczi
` (4 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
The test suite for the nRF51 GPIO peripheral for now
only tests initial state. Additionally a set of
tests testing an implementation detail of the model
are included.
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
tests/Makefile.include | 2 +
tests/microbit-test.c | 160 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 162 insertions(+)
create mode 100644 tests/microbit-test.c
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 3f5a1d0c30..9c84bbd829 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -277,6 +277,7 @@ check-qtest-sparc64-y += tests/boot-serial-test$(EXESUF)
check-qtest-arm-y += tests/tmp105-test$(EXESUF)
check-qtest-arm-y += tests/pca9552-test$(EXESUF)
check-qtest-arm-y += tests/ds1338-test$(EXESUF)
+check-qtest-arm-y += tests/microbit-test$(EXESUF)
check-qtest-arm-y += tests/m25p80-test$(EXESUF)
check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
@@ -708,6 +709,7 @@ tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y)
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
tests/pca9552-test$(EXESUF): tests/pca9552-test.o $(libqos-omap-obj-y)
tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y)
+tests/microbit-test$(EXESUF): tests/microbit-test.o
tests/m25p80-test$(EXESUF): tests/m25p80-test.o
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y)
diff --git a/tests/microbit-test.c b/tests/microbit-test.c
new file mode 100644
index 0000000000..535714797a
--- /dev/null
+++ b/tests/microbit-test.c
@@ -0,0 +1,160 @@
+ /*
+ * QTest testcase for Microbit board using the Nordic Semiconductor nRF51 SoC.
+ *
+ * nRF51:
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
+ * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
+ *
+ * Microbit Board: http://microbit.org/
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+
+#include "qemu/osdep.h"
+#include "exec/hwaddr.h"
+#include "libqtest.h"
+
+#include "hw/arm/nrf51.h"
+#include "hw/gpio/nrf51_gpio.h"
+
+static void test_nrf51_gpio(void)
+{
+ size_t i;
+ uint32_t actual, expected;
+
+ struct {
+ hwaddr addr;
+ uint32_t expected;
+ } const reset_state[] = {
+ {NRF51_GPIO_REG_OUT, 0x00000000}, {NRF51_GPIO_REG_OUTSET, 0x00000000},
+ {NRF51_GPIO_REG_OUTCLR, 0x00000000}, {NRF51_GPIO_REG_IN, 0x00000000},
+ {NRF51_GPIO_REG_DIR, 0x00000000}, {NRF51_GPIO_REG_DIRSET, 0x00000000},
+ {NRF51_GPIO_REG_DIRCLR, 0x00000000}
+ };
+
+ /* Check reset state */
+ for (i = 0; i < ARRAY_SIZE(reset_state); i++) {
+ expected = reset_state[i].expected;
+ actual = readl(NRF51_GPIO_BASE + reset_state[i].addr);
+ g_assert_cmpuint(actual, ==, expected);
+ }
+
+ for (i = 0; i < NRF51_GPIO_PINS; i++) {
+ expected = 0x00000002;
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START + i * 4);
+ g_assert_cmpuint(actual, ==, expected);
+ }
+
+ /* Check dir bit consistency between dir and cnf */
+ /* Check set via DIRSET */
+ expected = 0x80000001;
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRSET, expected);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
+ g_assert_cmpuint(actual, ==, expected);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+
+ /* Check clear via DIRCLR */
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIRCLR, 0x80000001);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
+ g_assert_cmpuint(actual, ==, 0x00000000);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+
+ /* Check set via DIR */
+ expected = 0x80000001;
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, expected);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR);
+ g_assert_cmpuint(actual, ==, expected);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_END) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+
+ /* Reset DIR */
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_DIR, 0x00000000);
+
+ /* Check Input propagates */
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x00);
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, -1);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
+
+ /* Check pull-up working */
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b1110);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
+
+ /* Check pull-down working */
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 1);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0000);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0110);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0x02);
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, -1);
+
+ /* Check Output propagates */
+ irq_intercept_out("/machine/nrf51");
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b0011);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
+ g_assert_true(get_irq(0));
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01);
+ g_assert_false(get_irq(0));
+
+ /* Check self-stimulation */
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x01);
+
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTCLR, 0x01);
+ actual = readl(NRF51_GPIO_BASE + NRF51_GPIO_REG_IN) & 0x01;
+ g_assert_cmpuint(actual, ==, 0x00);
+
+ /*
+ * Check short-circuit - generates an guest_error which must be checked
+ * manually as long as qtest can not scan qemu_log messages
+ */
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_CNF_START, 0b01);
+ writel(NRF51_GPIO_BASE + NRF51_GPIO_REG_OUTSET, 0x01);
+ qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ global_qtest = qtest_initf("-machine microbit");
+
+ qtest_add_func("/microbit/nrf51/gpio", test_nrf51_gpio);
+
+ ret = g_test_run();
+
+ qtest_quit(global_qtest);
+ return ret;
+}
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 08/11] hw/timer/nrf51_timer: Add nRF51 Timer peripheral
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
` (6 preceding siblings ...)
2019-01-03 9:11 ` [Qemu-devel] [PATCH 07/11] tests/microbit-test: Add Tests for nRF51 GPIO Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 09/11] arm: Instantiate NRF51 Timers Stefan Hajnoczi
` (3 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
This patch adds the model for the nRF51 timer peripheral.
Currently, only the TIMER mode is implemented.
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
hw/timer/Makefile.objs | 1 +
include/hw/timer/nrf51_timer.h | 80 +++++++
hw/timer/nrf51_timer.c | 393 +++++++++++++++++++++++++++++++++
hw/timer/trace-events | 5 +
4 files changed, 479 insertions(+)
create mode 100644 include/hw/timer/nrf51_timer.h
create mode 100644 hw/timer/nrf51_timer.c
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index b32194d153..0e9a4530f8 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -23,6 +23,7 @@ common-obj-$(CONFIG_IMX) += imx_gpt.o
common-obj-$(CONFIG_LM32) += lm32_timer.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
common-obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp-rtc.o
+common-obj-$(CONFIG_NRF51_SOC) += nrf51_timer.o
obj-$(CONFIG_ALTERA_TIMER) += altera_timer.o
obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
diff --git a/include/hw/timer/nrf51_timer.h b/include/hw/timer/nrf51_timer.h
new file mode 100644
index 0000000000..85cad2300d
--- /dev/null
+++ b/include/hw/timer/nrf51_timer.h
@@ -0,0 +1,80 @@
+/*
+ * nRF51 System-on-Chip Timer peripheral
+ *
+ * QEMU interface:
+ * + sysbus MMIO regions 0: GPIO registers
+ * + sysbus irq
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+#ifndef NRF51_TIMER_H
+#define NRF51_TIMER_H
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#define TYPE_NRF51_TIMER "nrf51_soc.timer"
+#define NRF51_TIMER(obj) OBJECT_CHECK(NRF51TimerState, (obj), TYPE_NRF51_TIMER)
+
+#define NRF51_TIMER_REG_COUNT 4
+
+#define NRF51_TIMER_TASK_START 0x000
+#define NRF51_TIMER_TASK_STOP 0x004
+#define NRF51_TIMER_TASK_COUNT 0x008
+#define NRF51_TIMER_TASK_CLEAR 0x00C
+#define NRF51_TIMER_TASK_SHUTDOWN 0x010
+#define NRF51_TIMER_TASK_CAPTURE_0 0x040
+#define NRF51_TIMER_TASK_CAPTURE_3 0x04C
+
+#define NRF51_TIMER_EVENT_COMPARE_0 0x140
+#define NRF51_TIMER_EVENT_COMPARE_1 0x144
+#define NRF51_TIMER_EVENT_COMPARE_2 0x148
+#define NRF51_TIMER_EVENT_COMPARE_3 0x14C
+
+#define NRF51_TIMER_REG_SHORTS 0x200
+#define NRF51_TIMER_REG_SHORTS_MASK 0xf0f
+#define NRF51_TIMER_REG_INTENSET 0x304
+#define NRF51_TIMER_REG_INTENCLR 0x308
+#define NRF51_TIMER_REG_INTEN_MASK 0xf0000
+#define NRF51_TIMER_REG_MODE 0x504
+#define NRF51_TIMER_REG_MODE_MASK 0x01
+#define NRF51_TIMER_TIMER 0
+#define NRF51_TIMER_COUNTER 1
+#define NRF51_TIMER_REG_BITMODE 0x508
+#define NRF51_TIMER_REG_BITMODE_MASK 0x03
+#define NRF51_TIMER_WIDTH_16 0
+#define NRF51_TIMER_WIDTH_8 1
+#define NRF51_TIMER_WIDTH_24 2
+#define NRF51_TIMER_WIDTH_32 3
+#define NRF51_TIMER_REG_PRESCALER 0x510
+#define NRF51_TIMER_REG_PRESCALER_MASK 0x0F
+#define NRF51_TIMER_REG_CC0 0x540
+#define NRF51_TIMER_REG_CC3 0x54C
+
+typedef struct NRF51TimerState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ qemu_irq irq;
+
+ QEMUTimer timer;
+ int64_t timer_start_ns;
+ int64_t update_counter_ns;
+ uint32_t counter;
+
+ bool running;
+
+ uint8_t events_compare[NRF51_TIMER_REG_COUNT];
+ uint32_t cc[NRF51_TIMER_REG_COUNT];
+ uint32_t shorts;
+ uint32_t inten;
+ uint32_t mode;
+ uint32_t bitmode;
+ uint32_t prescaler;
+
+} NRF51TimerState;
+
+
+#endif
diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c
new file mode 100644
index 0000000000..0c90662896
--- /dev/null
+++ b/hw/timer/nrf51_timer.c
@@ -0,0 +1,393 @@
+/*
+ * nRF51 System-on-Chip Timer peripheral
+ *
+ * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
+ * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
+ *
+ * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ * Copyright (c) 2019 Red Hat, Inc.
+ *
+ * This code is licensed under the GPL version 2 or later. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/arm/nrf51.h"
+#include "hw/timer/nrf51_timer.h"
+#include "trace.h"
+
+#define TIMER_CLK_FREQ 16000000UL
+
+static uint32_t const bitwidths[] = {16, 8, 24, 32};
+
+static uint32_t ns_to_ticks(NRF51TimerState *s, int64_t ns)
+{
+ uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
+
+ return muldiv64(ns, freq, NANOSECONDS_PER_SECOND);
+}
+
+static int64_t ticks_to_ns(NRF51TimerState *s, uint32_t ticks)
+{
+ uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
+
+ return muldiv64(ticks, NANOSECONDS_PER_SECOND, freq);
+}
+
+/* Returns number of ticks since last call */
+static uint32_t update_counter(NRF51TimerState *s, int64_t now)
+{
+ uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
+
+ s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
+ s->update_counter_ns = now;
+ return ticks;
+}
+
+/* Assumes s->counter is up-to-date */
+static void rearm_timer(NRF51TimerState *s, int64_t now)
+{
+ int64_t min_ns = INT64_MAX;
+ size_t i;
+
+ for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
+ int64_t delta_ns;
+
+ if (s->events_compare[i]) {
+ continue; /* already expired, ignore it for now */
+ }
+
+ if (s->cc[i] <= s->counter) {
+ delta_ns = ticks_to_ns(s, BIT(bitwidths[s->bitmode]) -
+ s->counter + s->cc[i]);
+ } else {
+ delta_ns = ticks_to_ns(s, s->cc[i] - s->counter);
+ }
+
+ if (delta_ns < min_ns) {
+ min_ns = delta_ns;
+ }
+ }
+
+ if (min_ns != INT64_MAX) {
+ timer_mod_ns(&s->timer, now + min_ns);
+ }
+}
+
+static void update_irq(NRF51TimerState *s)
+{
+ bool flag = false;
+ size_t i;
+
+ for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
+ flag |= s->events_compare[i] && extract32(s->inten, 16 + i, 1);
+ }
+ qemu_set_irq(s->irq, flag);
+}
+
+static void timer_expire(void *opaque)
+{
+ NRF51TimerState *s = NRF51_TIMER(opaque);
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ uint32_t cc_remaining[NRF51_TIMER_REG_COUNT];
+ bool should_stop = false;
+ uint32_t ticks;
+ size_t i;
+
+ for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
+ if (s->cc[i] > s->counter) {
+ cc_remaining[i] = s->cc[i] - s->counter;
+ } else {
+ cc_remaining[i] = BIT(bitwidths[s->bitmode]) -
+ s->counter + s->cc[i];
+ }
+ }
+
+ ticks = update_counter(s, now);
+
+ for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
+ if (cc_remaining[i] <= ticks) {
+ s->events_compare[i] = 1;
+
+ if (s->shorts & BIT(i)) {
+ s->timer_start_ns = now;
+ s->update_counter_ns = s->timer_start_ns;
+ s->counter = 0;
+ }
+
+ should_stop |= s->shorts & BIT(i + 8);
+ }
+ }
+
+ update_irq(s);
+
+ if (should_stop) {
+ s->running = false;
+ timer_del(&s->timer);
+ } else {
+ rearm_timer(s, now);
+ }
+}
+
+static void counter_compare(NRF51TimerState *s)
+{
+ uint32_t counter = s->counter;
+ size_t i;
+
+ for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
+ if (counter == s->cc[i]) {
+ s->events_compare[i] = 1;
+
+ if (s->shorts & BIT(i)) {
+ s->counter = 0;
+ }
+ }
+ }
+}
+
+static uint64_t nrf51_timer_read(void *opaque, hwaddr offset, unsigned int size)
+{
+ NRF51TimerState *s = NRF51_TIMER(opaque);
+ uint64_t r = 0;
+
+ switch (offset) {
+ case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
+ r = s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4];
+ break;
+ case NRF51_TIMER_REG_SHORTS:
+ r = s->shorts;
+ break;
+ case NRF51_TIMER_REG_INTENSET:
+ r = s->inten;
+ break;
+ case NRF51_TIMER_REG_INTENCLR:
+ r = s->inten;
+ break;
+ case NRF51_TIMER_REG_MODE:
+ r = s->mode;
+ break;
+ case NRF51_TIMER_REG_BITMODE:
+ r = s->bitmode;
+ break;
+ case NRF51_TIMER_REG_PRESCALER:
+ r = s->prescaler;
+ break;
+ case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
+ r = s->cc[(offset - NRF51_TIMER_REG_CC0) / 4];
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad read offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ trace_nrf51_timer_read(offset, r, size);
+
+ return r;
+}
+
+static void nrf51_timer_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned int size)
+{
+ NRF51TimerState *s = NRF51_TIMER(opaque);
+ uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ size_t idx;
+
+ trace_nrf51_timer_write(offset, value, size);
+
+ switch (offset) {
+ case NRF51_TIMER_TASK_START:
+ if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_TIMER) {
+ s->running = true;
+ s->timer_start_ns = now - ticks_to_ns(s, s->counter);
+ s->update_counter_ns = s->timer_start_ns;
+ rearm_timer(s, now);
+ }
+ break;
+ case NRF51_TIMER_TASK_STOP:
+ case NRF51_TIMER_TASK_SHUTDOWN:
+ if (value == NRF51_TRIGGER_TASK) {
+ s->running = false;
+ timer_del(&s->timer);
+ }
+ break;
+ case NRF51_TIMER_TASK_COUNT:
+ if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_COUNTER) {
+ s->counter = (s->counter + 1) % BIT(bitwidths[s->bitmode]);
+ counter_compare(s);
+ }
+ break;
+ case NRF51_TIMER_TASK_CLEAR:
+ if (value == NRF51_TRIGGER_TASK) {
+ s->timer_start_ns = now;
+ s->update_counter_ns = s->timer_start_ns;
+ s->counter = 0;
+ if (s->running) {
+ rearm_timer(s, now);
+ }
+ }
+ break;
+ case NRF51_TIMER_TASK_CAPTURE_0 ... NRF51_TIMER_TASK_CAPTURE_3:
+ if (value == NRF51_TRIGGER_TASK) {
+ if (s->running) {
+ timer_expire(s); /* update counter and all state */
+ }
+
+ idx = (offset - NRF51_TIMER_TASK_CAPTURE_0) / 4;
+ s->cc[idx] = s->counter;
+ }
+ break;
+ case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
+ if (value == NRF51_EVENT_CLEAR) {
+ s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4] = 0;
+
+ if (s->running) {
+ timer_expire(s); /* update counter and all state */
+ }
+ }
+ break;
+ case NRF51_TIMER_REG_SHORTS:
+ s->shorts = value & NRF51_TIMER_REG_SHORTS_MASK;
+ break;
+ case NRF51_TIMER_REG_INTENSET:
+ s->inten |= value & NRF51_TIMER_REG_INTEN_MASK;
+ break;
+ case NRF51_TIMER_REG_INTENCLR:
+ s->inten &= ~(value & NRF51_TIMER_REG_INTEN_MASK);
+ break;
+ case NRF51_TIMER_REG_MODE:
+ s->mode = value;
+ break;
+ case NRF51_TIMER_REG_BITMODE:
+ if (s->mode == NRF51_TIMER_TIMER && s->running) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: erroneous change of BITMODE while timer is running\n",
+ __func__);
+ }
+ s->bitmode = value & NRF51_TIMER_REG_BITMODE_MASK;
+ break;
+ case NRF51_TIMER_REG_PRESCALER:
+ if (s->mode == NRF51_TIMER_TIMER && s->running) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: erroneous change of PRESCALER while timer is running\n",
+ __func__);
+ }
+ s->prescaler = value & NRF51_TIMER_REG_PRESCALER_MASK;
+ break;
+ case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
+ if (s->running) {
+ timer_expire(s); /* update counter */
+ }
+
+ idx = (offset - NRF51_TIMER_REG_CC0) / 4;
+ s->cc[idx] = value % BIT(bitwidths[s->bitmode]);
+
+ if (s->running) {
+ rearm_timer(s, now);
+ }
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: bad write offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ }
+
+ update_irq(s);
+}
+
+static const MemoryRegionOps rng_ops = {
+ .read = nrf51_timer_read,
+ .write = nrf51_timer_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+};
+
+static void nrf51_timer_init(Object *obj)
+{
+ NRF51TimerState *s = NRF51_TIMER(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&s->iomem, obj, &rng_ops, s,
+ TYPE_NRF51_TIMER, NRF51_TIMER_SIZE);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq);
+
+ timer_init_ns(&s->timer, QEMU_CLOCK_VIRTUAL, timer_expire, s);
+}
+
+static void nrf51_timer_reset(DeviceState *dev)
+{
+ NRF51TimerState *s = NRF51_TIMER(dev);
+
+ timer_del(&s->timer);
+ s->timer_start_ns = 0x00;
+ s->update_counter_ns = 0x00;
+ s->counter = 0x00;
+ s->running = false;
+
+ memset(s->events_compare, 0x00, sizeof(s->events_compare));
+ memset(s->cc, 0x00, sizeof(s->cc));
+
+ s->shorts = 0x00;
+ s->inten = 0x00;
+ s->mode = 0x00;
+ s->bitmode = 0x00;
+ s->prescaler = 0x00;
+}
+
+static int nrf51_timer_post_load(void *opaque, int version_id)
+{
+ NRF51TimerState *s = NRF51_TIMER(opaque);
+
+ if (s->running && s->mode == NRF51_TIMER_TIMER) {
+ timer_expire(s);
+ }
+ return 0;
+}
+
+static const VMStateDescription vmstate_nrf51_timer = {
+ .name = TYPE_NRF51_TIMER,
+ .version_id = 1,
+ .post_load = nrf51_timer_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_TIMER(timer, NRF51TimerState),
+ VMSTATE_INT64(timer_start_ns, NRF51TimerState),
+ VMSTATE_INT64(update_counter_ns, NRF51TimerState),
+ VMSTATE_UINT32(counter, NRF51TimerState),
+ VMSTATE_BOOL(running, NRF51TimerState),
+ VMSTATE_UINT8_ARRAY(events_compare, NRF51TimerState,
+ NRF51_TIMER_REG_COUNT),
+ VMSTATE_UINT32_ARRAY(cc, NRF51TimerState, NRF51_TIMER_REG_COUNT),
+ VMSTATE_UINT32(shorts, NRF51TimerState),
+ VMSTATE_UINT32(inten, NRF51TimerState),
+ VMSTATE_UINT32(mode, NRF51TimerState),
+ VMSTATE_UINT32(bitmode, NRF51TimerState),
+ VMSTATE_UINT32(prescaler, NRF51TimerState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void nrf51_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = nrf51_timer_reset;
+ dc->vmsd = &vmstate_nrf51_timer;
+}
+
+static const TypeInfo nrf51_timer_info = {
+ .name = TYPE_NRF51_TIMER,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NRF51TimerState),
+ .instance_init = nrf51_timer_init,
+ .class_init = nrf51_timer_class_init
+};
+
+static void nrf51_timer_register_types(void)
+{
+ type_register_static(&nrf51_timer_info);
+}
+
+type_init(nrf51_timer_register_types)
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index 75bd3b1042..0144a68951 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -72,3 +72,8 @@ sun4v_rtc_write(uint64_t addr, uint64_t value) "write: addr 0x%" PRIx64 " value
# hw/timer/xlnx-zynqmp-rtc.c
xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d"
+
+# hw/timer/nrf51_timer.c
+nrf51_timer_read(uint64_t addr, uint32_t value, unsigned size) "read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
+nrf51_timer_write(uint64_t addr, uint32_t value, unsigned size) "write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
+
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 09/11] arm: Instantiate NRF51 Timers
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
` (7 preceding siblings ...)
2019-01-03 9:11 ` [Qemu-devel] [PATCH 08/11] hw/timer/nrf51_timer: Add nRF51 Timer peripheral Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 10/11] tests/microbit-test: Add Tests for nRF51 Timer Stefan Hajnoczi
` (2 subsequent siblings)
11 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
Instantiates TIMER0 - TIMER2
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/hw/arm/nrf51_soc.h | 4 ++++
hw/arm/nrf51_soc.c | 26 ++++++++++++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/include/hw/arm/nrf51_soc.h b/include/hw/arm/nrf51_soc.h
index 84e0278881..39e613e1c9 100644
--- a/include/hw/arm/nrf51_soc.h
+++ b/include/hw/arm/nrf51_soc.h
@@ -15,11 +15,14 @@
#include "hw/char/nrf51_uart.h"
#include "hw/misc/nrf51_rng.h"
#include "hw/gpio/nrf51_gpio.h"
+#include "hw/timer/nrf51_timer.h"
#define TYPE_NRF51_SOC "nrf51-soc"
#define NRF51_SOC(obj) \
OBJECT_CHECK(NRF51State, (obj), TYPE_NRF51_SOC)
+#define NRF51_NUM_TIMERS 3
+
typedef struct NRF51State {
/*< private >*/
SysBusDevice parent_obj;
@@ -30,6 +33,7 @@ typedef struct NRF51State {
NRF51UARTState uart;
NRF51RNGState rng;
NRF51GPIOState gpio;
+ NRF51TimerState timer[NRF51_NUM_TIMERS];
MemoryRegion iomem;
MemoryRegion sram;
diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c
index db817fe506..ef70bd62fa 100644
--- a/hw/arm/nrf51_soc.c
+++ b/hw/arm/nrf51_soc.c
@@ -39,6 +39,8 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
NRF51State *s = NRF51_SOC(dev_soc);
MemoryRegion *mr;
Error *err = NULL;
+ uint8_t i = 0;
+ hwaddr base_addr = 0;
if (!s->board_memory) {
error_setg(errp, "memory property was not set");
@@ -112,6 +114,22 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
/* Pass all GPIOs to the SOC layer so they are available to the board */
qdev_pass_gpios(DEVICE(&s->gpio), dev_soc, NULL);
+ /* TIMER */
+ for (i = 0; i < NRF51_NUM_TIMERS; i++) {
+ object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
+
+ base_addr = NRF51_TIMER_BASE + i * NRF51_TIMER_SIZE;
+
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->timer[i]), 0, base_addr);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->cpu),
+ BASE_TO_IRQ(base_addr)));
+ }
+
create_unimplemented_device("nrf51_soc.io", NRF51_IOMEM_BASE,
NRF51_IOMEM_SIZE);
create_unimplemented_device("nrf51_soc.ficr", NRF51_FICR_BASE,
@@ -122,6 +140,8 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
static void nrf51_soc_init(Object *obj)
{
+ uint8_t i = 0;
+
NRF51State *s = NRF51_SOC(obj);
memory_region_init(&s->container, obj, "nrf51-container", UINT64_MAX);
@@ -142,6 +162,12 @@ static void nrf51_soc_init(Object *obj)
sysbus_init_child_obj(obj, "gpio", &s->gpio, sizeof(s->gpio),
TYPE_NRF51_GPIO);
+
+ for (i = 0; i < NRF51_NUM_TIMERS; i++) {
+ sysbus_init_child_obj(obj, "timer[*]", &s->timer[i],
+ sizeof(s->timer[i]), TYPE_NRF51_TIMER);
+
+ }
}
static Property nrf51_soc_properties[] = {
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 10/11] tests/microbit-test: Add Tests for nRF51 Timer
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
` (8 preceding siblings ...)
2019-01-03 9:11 ` [Qemu-devel] [PATCH 09/11] arm: Instantiate NRF51 Timers Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-03 9:11 ` [Qemu-devel] [PATCH 11/11] arm: Add Clock peripheral stub to NRF51 SOC Stefan Hajnoczi
2019-01-07 15:19 ` [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Peter Maydell
11 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
Basic tests for nRF51 Timer Peripheral.
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
tests/microbit-test.c | 95 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/tests/microbit-test.c b/tests/microbit-test.c
index 535714797a..16dffb1396 100644
--- a/tests/microbit-test.c
+++ b/tests/microbit-test.c
@@ -20,6 +20,7 @@
#include "hw/arm/nrf51.h"
#include "hw/gpio/nrf51_gpio.h"
+#include "hw/timer/nrf51_timer.h"
static void test_nrf51_gpio(void)
{
@@ -143,6 +144,99 @@ static void test_nrf51_gpio(void)
qtest_set_irq_in(global_qtest, "/machine/nrf51", "unnamed-gpio-in", 0, 0);
}
+static void timer_task(hwaddr task)
+{
+ writel(NRF51_TIMER_BASE + task, NRF51_TRIGGER_TASK);
+}
+
+static void timer_clear_event(hwaddr event)
+{
+ writel(NRF51_TIMER_BASE + event, NRF51_EVENT_CLEAR);
+}
+
+static void timer_set_bitmode(uint8_t mode)
+{
+ writel(NRF51_TIMER_BASE + NRF51_TIMER_REG_BITMODE, mode);
+}
+
+static void timer_set_prescaler(uint8_t prescaler)
+{
+ writel(NRF51_TIMER_BASE + NRF51_TIMER_REG_PRESCALER, prescaler);
+}
+
+static void timer_set_cc(size_t idx, uint32_t value)
+{
+ writel(NRF51_TIMER_BASE + NRF51_TIMER_REG_CC0 + idx * 4, value);
+}
+
+static void timer_assert_events(uint32_t ev0, uint32_t ev1, uint32_t ev2,
+ uint32_t ev3)
+{
+ g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_0) == ev0);
+ g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_1) == ev1);
+ g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_2) == ev2);
+ g_assert(readl(NRF51_TIMER_BASE + NRF51_TIMER_EVENT_COMPARE_3) == ev3);
+}
+
+static void test_nrf51_timer(void)
+{
+ uint32_t steps_to_overflow = 408;
+
+ /* Compare Match */
+ timer_task(NRF51_TIMER_TASK_STOP);
+ timer_task(NRF51_TIMER_TASK_CLEAR);
+
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_0);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_1);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_2);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_3);
+
+ timer_set_bitmode(NRF51_TIMER_WIDTH_16); /* 16 MHz Timer */
+ timer_set_prescaler(0);
+ /* Swept over in first step */
+ timer_set_cc(0, 2);
+ /* Barely miss on first step */
+ timer_set_cc(1, 162);
+ /* Spot on on third step */
+ timer_set_cc(2, 480);
+
+ timer_assert_events(0, 0, 0, 0);
+
+ timer_task(NRF51_TIMER_TASK_START);
+ clock_step(10000);
+ timer_assert_events(1, 0, 0, 0);
+
+ /* Swept over on first overflow */
+ timer_set_cc(3, 114);
+
+ clock_step(10000);
+ timer_assert_events(1, 1, 0, 0);
+
+ clock_step(10000);
+ timer_assert_events(1, 1, 1, 0);
+
+ /* Wrap time until internal counter overflows */
+ while (steps_to_overflow--) {
+ timer_assert_events(1, 1, 1, 0);
+ clock_step(10000);
+ }
+
+ timer_assert_events(1, 1, 1, 1);
+
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_0);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_1);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_2);
+ timer_clear_event(NRF51_TIMER_EVENT_COMPARE_3);
+ timer_assert_events(0, 0, 0, 0);
+
+ timer_task(NRF51_TIMER_TASK_STOP);
+
+ /* Test Proposal: Stop/Shutdown */
+ /* Test Proposal: Shortcut Compare -> Clear */
+ /* Test Proposal: Shortcut Compare -> Stop */
+ /* Test Proposal: Counter Mode */
+}
+
int main(int argc, char **argv)
{
int ret;
@@ -152,6 +246,7 @@ int main(int argc, char **argv)
global_qtest = qtest_initf("-machine microbit");
qtest_add_func("/microbit/nrf51/gpio", test_nrf51_gpio);
+ qtest_add_func("/microbit/nrf51/timer", test_nrf51_timer);
ret = g_test_run();
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [Qemu-devel] [PATCH 11/11] arm: Add Clock peripheral stub to NRF51 SOC
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
` (9 preceding siblings ...)
2019-01-03 9:11 ` [Qemu-devel] [PATCH 10/11] tests/microbit-test: Add Tests for nRF51 Timer Stefan Hajnoczi
@ 2019-01-03 9:11 ` Stefan Hajnoczi
2019-01-07 15:19 ` [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Peter Maydell
11 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2019-01-03 9:11 UTC (permalink / raw)
To: qemu-devel
Cc: Thomas Huth, qemu-arm, Joel Stanley, Julia Suvorova,
Paolo Bonzini, Jim Mussared, Steffen Görtz, Peter Maydell,
Laurent Vivier, Stefan Hajnoczi
From: Steffen Görtz <contrib@steffen-goertz.de>
This stubs enables the microbit-micropython firmware to run
on the microbit machine.
Signed-off-by: Steffen Görtz <contrib@steffen-goertz.de>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/hw/arm/nrf51_soc.h | 1 +
hw/arm/nrf51_soc.c | 26 ++++++++++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/include/hw/arm/nrf51_soc.h b/include/hw/arm/nrf51_soc.h
index 39e613e1c9..e06f0304b4 100644
--- a/include/hw/arm/nrf51_soc.h
+++ b/include/hw/arm/nrf51_soc.h
@@ -38,6 +38,7 @@ typedef struct NRF51State {
MemoryRegion iomem;
MemoryRegion sram;
MemoryRegion flash;
+ MemoryRegion clock;
uint32_t sram_size;
uint32_t flash_size;
diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c
index ef70bd62fa..1630c27594 100644
--- a/hw/arm/nrf51_soc.c
+++ b/hw/arm/nrf51_soc.c
@@ -34,6 +34,26 @@
#define BASE_TO_IRQ(base) ((base >> 12) & 0x1F)
+static uint64_t clock_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n",
+ __func__, addr, size);
+ return 1;
+}
+
+static void clock_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned int size)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n",
+ __func__, addr, data, size);
+}
+
+static const MemoryRegionOps clock_ops = {
+ .read = clock_read,
+ .write = clock_write
+};
+
+
static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
{
NRF51State *s = NRF51_SOC(dev_soc);
@@ -130,6 +150,12 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
BASE_TO_IRQ(base_addr)));
}
+ /* STUB Peripherals */
+ memory_region_init_io(&s->clock, NULL, &clock_ops, NULL,
+ "nrf51_soc.clock", 0x1000);
+ memory_region_add_subregion_overlap(&s->container,
+ NRF51_IOMEM_BASE, &s->clock, -1);
+
create_unimplemented_device("nrf51_soc.io", NRF51_IOMEM_BASE,
NRF51_IOMEM_SIZE);
create_unimplemented_device("nrf51_soc.ficr", NRF51_FICR_BASE,
--
2.19.2
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support
2019-01-03 9:11 [Qemu-devel] [PATCH 00/11] arm: Core nRF51 Devices and Microbit Support Stefan Hajnoczi
` (10 preceding siblings ...)
2019-01-03 9:11 ` [Qemu-devel] [PATCH 11/11] arm: Add Clock peripheral stub to NRF51 SOC Stefan Hajnoczi
@ 2019-01-07 15:19 ` Peter Maydell
11 siblings, 0 replies; 15+ messages in thread
From: Peter Maydell @ 2019-01-07 15:19 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: QEMU Developers, Thomas Huth, qemu-arm, Joel Stanley,
Julia Suvorova, Paolo Bonzini, Jim Mussared, Steffen Görtz,
Laurent Vivier
On Thu, 3 Jan 2019 at 09:12, Stefan Hajnoczi <stefanha@redhat.com> wrote:
>
> Steffen has been busy so I picked up "[PATCH v5 00/14] arm: nRF51 Devices and
> Microbit Support". This series includes the core devices needed to boot basic
> guest software on the "microbit" board.
>
> This series includes Steffen's random number generator, GPIO, timer, and a
> stubbed clock. Also, this series adds the tests/microbit-test.c qtest.
>
> Changes from Steffen's series:
> * Made timer tickless [Peter]
> * Dropped non-volatile memory controller. More work is needed there and I
> don't want to hold back other devices in this series that are ready for
> merge.
> * Rebased and re-tested with make check and real micro:bit programs
> (requires out-of-tree -kernel and stub TWI device patches)
Applied to target-arm.next, thanks.
-- PMM
^ permalink raw reply [flat|nested] 15+ messages in thread