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.
Signed-off-by: Kirill A. Korinsky <[email protected]> --- 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.56.0
