Wire the Octeon UART and its alias to the existing serial-mm device.
Provide the special transmit register window and connect the UART
interrupt to CIU and CIU3.
---
hw/mips/Kconfig | 1 +
hw/mips/octeon.c | 69 +++++++++++++++++++++++++++++++++++++++
hw/mips/octeon_internal.h | 5 +++
3 files changed, 75 insertions(+)
diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
index cb6057fe38..5fe5f885e3 100644
--- a/hw/mips/Kconfig
+++ b/hw/mips/Kconfig
@@ -72,6 +72,7 @@ config MIPS_OCTEON
default y
depends on MIPS64 && TARGET_BIG_ENDIAN
select PFLASH_CFI02
+ select SERIAL_MM
config MIPS_CPS
bool
diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c
index 59754cb741..133b3636a0 100644
--- a/hw/mips/octeon.c
+++ b/hw/mips/octeon.c
@@ -10,6 +10,7 @@
#include "qemu/units.h"
#include "qemu/datadir.h"
#include "qapi/error.h"
+#include "hw/char/serial-mm.h"
#include "hw/core/clock.h"
#include "hw/core/irq.h"
#include "hw/core/boards.h"
@@ -48,7 +49,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonIntcState, OCTEON_INTC)
#define TYPE_OCTEON_CSR_BANK "octeon-csr-bank"
OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState, OCTEON_CSR_BANK)
+#define OCTEON_CSR_32BIT_SIZE 4
#define OCTEON_CSR_64BIT_SIZE 8
+#define OCTEON_CSR_HI32_OFFSET 0
/*
* Clock defaults follow a Ubiquiti E1000 EBB7304 U-Boot banner.
@@ -155,6 +158,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState,
OCTEON_CSR_BANK)
#define OCTEON_RST_BOOT_C_MUL_SHIFT 30
#define OCTEON_RST_BOOT_PNR_MUL_SHIFT 24
+#define OCTEON_UART0_BASE 0x1180000000800ULL
+#define OCTEON_UART0_ALIAS_BASE 0x1180000000c00ULL
+#define OCTEON_UART_TX_REG 0x40
+#define OCTEON_UART_TX_HI32_OFFSET OCTEON_CSR_HI32_OFFSET
+#define OCTEON_UART_TX_SIZE OCTEON_CSR_64BIT_SIZE
+
/*
* QEMU-only backing for per-core CVMSEG. Keep it outside guest DRAM;
* the guest sees the virtual CVMSEG window, not this physical address.
@@ -1613,6 +1622,65 @@ static void octeon_init_mio_boot_loc(OcteonState *s)
}
+static uint64_t octeon_uart_tx_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return 0;
+}
+
+static void octeon_uart_tx_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ OcteonState *s = opaque;
+
+ if (size == OCTEON_CSR_32BIT_SIZE &&
+ addr == OCTEON_UART_TX_HI32_OFFSET) {
+ return;
+ }
+
+ serial_io_ops.write(&s->uart->serial, 0, value & 0xff, 1);
+}
+
+static const MemoryRegionOps octeon_uart_tx_ops = {
+ .read = octeon_uart_tx_read,
+ .write = octeon_uart_tx_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+};
+
+static void octeon_init_uart(OcteonState *s)
+{
+ SerialMM *uart;
+ qemu_irq uart_irq;
+ MemoryRegion *uart_mmio;
+ int baudbase = s->io_hz / 16;
+
+ uart_irq = qemu_allocate_irq(octeon_irq_set, s, OCTEON_IRQ_UART);
+ uart = serial_mm_init(get_system_memory(), OCTEON_UART0_BASE, 3, uart_irq,
+ baudbase, serial_hd(0), DEVICE_BIG_ENDIAN);
+ s->uart = uart;
+
+ uart_mmio = sysbus_mmio_get_region(SYS_BUS_DEVICE(uart), 0);
+ memory_region_init_alias(&s->uart_alias, NULL, "octeon.uart0-alias",
+ uart_mmio, 0, memory_region_size(uart_mmio));
+ memory_region_add_subregion(get_system_memory(), OCTEON_UART0_ALIAS_BASE,
+ &s->uart_alias);
+
+ memory_region_init_io(&s->uart_tx, NULL, &octeon_uart_tx_ops, s,
+ "octeon.uart0-tx", OCTEON_UART_TX_SIZE);
+ memory_region_add_subregion(get_system_memory(),
+ OCTEON_UART0_BASE + OCTEON_UART_TX_REG,
+ &s->uart_tx);
+ memory_region_init_io(&s->uart_alias_tx, NULL, &octeon_uart_tx_ops, s,
+ "octeon.uart0-alias-tx", OCTEON_UART_TX_SIZE);
+ memory_region_add_subregion(get_system_memory(),
+ OCTEON_UART0_ALIAS_BASE + OCTEON_UART_TX_REG,
+ &s->uart_alias_tx);
+}
+
+
static void octeon_mio_reset_hold(Object *obj, ResetType type)
{
OcteonPeripheralClass *opc = OCTEON_PERIPHERAL_GET_CLASS(obj);
@@ -1833,6 +1901,7 @@ static void mips_octeon_init(MachineState *machine)
memory_region_add_subregion(get_system_memory(), OCTEON_CIU3_BASE,
&s->intc->ciu3);
+ octeon_init_uart(s);
memory_region_init_io(&s->csr_bank->csr, OBJECT(s->csr_bank),
&octeon_csr_ops, s,
"octeon.csr", OCTEON_CSR_SIZE);
diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h
index 7b45daba10..fbe4875d66 100644
--- a/hw/mips/octeon_internal.h
+++ b/hw/mips/octeon_internal.h
@@ -10,6 +10,7 @@
#define HW_MIPS_OCTEON_INTERNAL_H
#include "qemu/typedefs.h"
+#include "hw/char/serial-mm.h"
#include "system/memory.h"
#include "target/mips/cpu.h"
@@ -64,6 +65,10 @@ struct OcteonState {
OcteonRstState *rst;
OcteonIntcState *intc;
OcteonCsrBankState *csr_bank;
+ SerialMM *uart;
+ MemoryRegion uart_alias;
+ MemoryRegion uart_tx;
+ MemoryRegion uart_alias_tx;
};
guint octeon_uint64_hash(gconstpointer v);
--
2.54.0