diff mbox

[3/7] hw/arm/mps2: Add UARTs

Message ID 1499771839-32518-4-git-send-email-peter.maydell@linaro.org
State New
Headers show

Commit Message

Peter Maydell July 11, 2017, 11:17 a.m. UTC
Add the UARTs to the MPS2 board models.

Unfortunately the details of the wiring of the interrupts through
various OR gates differ between AN511 and AN385 so this can't
be purely a data-driven difference.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/mps2.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

Comments

Alistair Francis July 13, 2017, 7:37 a.m. UTC | #1
On Tue, Jul 11, 2017 at 1:17 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Add the UARTs to the MPS2 board models.
>
> Unfortunately the details of the wiring of the interrupts through
> various OR gates differ between AN511 and AN385 so this can't
> be purely a data-driven difference.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@xilinx.com>

Woo! I'm glad the OR IRQ stuff is useful.

Thanks,
Alistair

> ---
>  hw/arm/mps2.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 86 insertions(+)
>
> diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
> index 28838bc..1b60b12 100644
> --- a/hw/arm/mps2.c
> +++ b/hw/arm/mps2.c
> @@ -27,9 +27,12 @@
>  #include "qemu/error-report.h"
>  #include "hw/arm/arm.h"
>  #include "hw/arm/armv7m.h"
> +#include "hw/or-irq.h"
>  #include "hw/boards.h"
>  #include "exec/address-spaces.h"
> +#include "sysemu/sysemu.h"
>  #include "hw/misc/unimp.h"
> +#include "hw/char/cmsdk-apb-uart.h"
>
>  typedef enum MPS2FPGAType {
>      FPGA_AN385,
> @@ -208,6 +211,89 @@ static void mps2_common_init(MachineState *machine)
>      create_unimplemented_device("Ethernet", 0x40200000, 0x00100000);
>      create_unimplemented_device("VGA", 0x41000000, 0x0200000);
>
> +    switch (mmc->fpga_type) {
> +    case FPGA_AN385:
> +    {
> +        /* The overflow IRQs for UARTs 0, 1 and 2 are ORed together.
> +         * Overflow for UARTs 4 and 5 doesn't trigger any interrupt.
> +         */
> +        Object *orgate;
> +        DeviceState *orgate_dev;
> +        int i;
> +
> +        orgate = object_new(TYPE_OR_IRQ);
> +        object_property_set_int(orgate, 6, "num-lines", &error_fatal);
> +        object_property_set_bool(orgate, true, "realized", &error_fatal);
> +        orgate_dev = DEVICE(orgate);
> +        qdev_connect_gpio_out(orgate_dev, 0, qdev_get_gpio_in(armv7m, 12));
> +
> +        for (i = 0; i < 5; i++) {
> +            hwaddr uartbase[] = {0x40004000, 0x40005000, 0x40006000,
> +                                 0x40007000, 0x40009000};
> +            Chardev *uartchr = i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL;
> +            /* RX irq number; TX irq is always one greater */
> +            int uartirq[] = {0, 2, 4, 18, 20};
> +            qemu_irq txovrint = NULL, rxovrint = NULL;
> +
> +            if (i < 3) {
> +                txovrint = qdev_get_gpio_in(orgate_dev, i * 2);
> +                rxovrint = qdev_get_gpio_in(orgate_dev, i * 2 + 1);
> +            }
> +
> +            cmsdk_apb_uart_create(uartbase[i],
> +                                  qdev_get_gpio_in(armv7m, uartirq[i] + 1),
> +                                  qdev_get_gpio_in(armv7m, uartirq[i]),
> +                                  txovrint, rxovrint,
> +                                  NULL,
> +                                  uartchr, SYSCLK_FRQ);
> +        }
> +        break;
> +    }
> +    case FPGA_AN511:
> +    {
> +        /* The overflow IRQs for all UARTs are ORed together.
> +         * Tx and Rx IRQs for each UART are ORed together.
> +         */
> +        Object *orgate;
> +        DeviceState *orgate_dev;
> +        int i;
> +
> +        orgate = object_new(TYPE_OR_IRQ);
> +        object_property_set_int(orgate, 10, "num-lines", &error_fatal);
> +        object_property_set_bool(orgate, true, "realized", &error_fatal);
> +        orgate_dev = DEVICE(orgate);
> +        qdev_connect_gpio_out(orgate_dev, 0, qdev_get_gpio_in(armv7m, 12));
> +
> +        for (i = 0; i < 5; i++) {
> +            /* system irq numbers for the combined tx/rx for each UART */
> +            const int uart_txrx_irqno[] = {0, 2, 45, 46, 56};
> +            hwaddr uartbase[] = {0x40004000, 0x40005000, 0x4002c000,
> +                                 0x4002d000, 0x4002e000};
> +            Chardev *uartchr = i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL;
> +            Object *txrx_orgate;
> +            DeviceState *txrx_orgate_dev;
> +
> +            txrx_orgate = object_new(TYPE_OR_IRQ);
> +            object_property_set_int(txrx_orgate, 2, "num-lines", &error_fatal);
> +            object_property_set_bool(txrx_orgate, true, "realized",
> +                                     &error_fatal);
> +            txrx_orgate_dev = DEVICE(txrx_orgate);
> +            qdev_connect_gpio_out(txrx_orgate_dev, 0,
> +                                  qdev_get_gpio_in(armv7m, uart_txrx_irqno[i]));
> +            cmsdk_apb_uart_create(uartbase[i],
> +                                  qdev_get_gpio_in(txrx_orgate_dev, 0),
> +                                  qdev_get_gpio_in(txrx_orgate_dev, 1),
> +                                  qdev_get_gpio_in(orgate_dev, 0),
> +                                  qdev_get_gpio_in(orgate_dev, 1),
> +                                  NULL,
> +                                  uartchr, SYSCLK_FRQ);
> +        }
> +        break;
> +    }
> +    default:
> +        g_assert_not_reached();
> +    }
> +
>      system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;
>
>      armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
> --
> 2.7.4
>
>
diff mbox

Patch

diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
index 28838bc..1b60b12 100644
--- a/hw/arm/mps2.c
+++ b/hw/arm/mps2.c
@@ -27,9 +27,12 @@ 
 #include "qemu/error-report.h"
 #include "hw/arm/arm.h"
 #include "hw/arm/armv7m.h"
+#include "hw/or-irq.h"
 #include "hw/boards.h"
 #include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
 #include "hw/misc/unimp.h"
+#include "hw/char/cmsdk-apb-uart.h"
 
 typedef enum MPS2FPGAType {
     FPGA_AN385,
@@ -208,6 +211,89 @@  static void mps2_common_init(MachineState *machine)
     create_unimplemented_device("Ethernet", 0x40200000, 0x00100000);
     create_unimplemented_device("VGA", 0x41000000, 0x0200000);
 
+    switch (mmc->fpga_type) {
+    case FPGA_AN385:
+    {
+        /* The overflow IRQs for UARTs 0, 1 and 2 are ORed together.
+         * Overflow for UARTs 4 and 5 doesn't trigger any interrupt.
+         */
+        Object *orgate;
+        DeviceState *orgate_dev;
+        int i;
+
+        orgate = object_new(TYPE_OR_IRQ);
+        object_property_set_int(orgate, 6, "num-lines", &error_fatal);
+        object_property_set_bool(orgate, true, "realized", &error_fatal);
+        orgate_dev = DEVICE(orgate);
+        qdev_connect_gpio_out(orgate_dev, 0, qdev_get_gpio_in(armv7m, 12));
+
+        for (i = 0; i < 5; i++) {
+            hwaddr uartbase[] = {0x40004000, 0x40005000, 0x40006000,
+                                 0x40007000, 0x40009000};
+            Chardev *uartchr = i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL;
+            /* RX irq number; TX irq is always one greater */
+            int uartirq[] = {0, 2, 4, 18, 20};
+            qemu_irq txovrint = NULL, rxovrint = NULL;
+
+            if (i < 3) {
+                txovrint = qdev_get_gpio_in(orgate_dev, i * 2);
+                rxovrint = qdev_get_gpio_in(orgate_dev, i * 2 + 1);
+            }
+
+            cmsdk_apb_uart_create(uartbase[i],
+                                  qdev_get_gpio_in(armv7m, uartirq[i] + 1),
+                                  qdev_get_gpio_in(armv7m, uartirq[i]),
+                                  txovrint, rxovrint,
+                                  NULL,
+                                  uartchr, SYSCLK_FRQ);
+        }
+        break;
+    }
+    case FPGA_AN511:
+    {
+        /* The overflow IRQs for all UARTs are ORed together.
+         * Tx and Rx IRQs for each UART are ORed together.
+         */
+        Object *orgate;
+        DeviceState *orgate_dev;
+        int i;
+
+        orgate = object_new(TYPE_OR_IRQ);
+        object_property_set_int(orgate, 10, "num-lines", &error_fatal);
+        object_property_set_bool(orgate, true, "realized", &error_fatal);
+        orgate_dev = DEVICE(orgate);
+        qdev_connect_gpio_out(orgate_dev, 0, qdev_get_gpio_in(armv7m, 12));
+
+        for (i = 0; i < 5; i++) {
+            /* system irq numbers for the combined tx/rx for each UART */
+            const int uart_txrx_irqno[] = {0, 2, 45, 46, 56};
+            hwaddr uartbase[] = {0x40004000, 0x40005000, 0x4002c000,
+                                 0x4002d000, 0x4002e000};
+            Chardev *uartchr = i < MAX_SERIAL_PORTS ? serial_hds[i] : NULL;
+            Object *txrx_orgate;
+            DeviceState *txrx_orgate_dev;
+
+            txrx_orgate = object_new(TYPE_OR_IRQ);
+            object_property_set_int(txrx_orgate, 2, "num-lines", &error_fatal);
+            object_property_set_bool(txrx_orgate, true, "realized",
+                                     &error_fatal);
+            txrx_orgate_dev = DEVICE(txrx_orgate);
+            qdev_connect_gpio_out(txrx_orgate_dev, 0,
+                                  qdev_get_gpio_in(armv7m, uart_txrx_irqno[i]));
+            cmsdk_apb_uart_create(uartbase[i],
+                                  qdev_get_gpio_in(txrx_orgate_dev, 0),
+                                  qdev_get_gpio_in(txrx_orgate_dev, 1),
+                                  qdev_get_gpio_in(orgate_dev, 0),
+                                  qdev_get_gpio_in(orgate_dev, 1),
+                                  NULL,
+                                  uartchr, SYSCLK_FRQ);
+        }
+        break;
+    }
+    default:
+        g_assert_not_reached();
+    }
+
     system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;
 
     armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,