Add the small DPI, FPA, IPD, PKO, RNG and POW register windows needed
while firmware initializes the platform. Reuse the CSR bank for stored
values and compute clock and random values on demand.
---
hw/mips/octeon.c | 218 ++++++++++++++++++++++++++++++++++++++
hw/mips/octeon_internal.h | 6 ++
2 files changed, 224 insertions(+)
diff --git a/hw/mips/octeon.c b/hw/mips/octeon.c
index 0553f8ea05..7e78511b8f 100644
--- a/hw/mips/octeon.c
+++ b/hw/mips/octeon.c
@@ -30,6 +30,7 @@
#include "system/runstate.h"
#include "system/system.h"
#include "exec/cpu-interrupt.h"
+#include "qemu/guest-random.h"
#include "qemu/error-report.h"
#include "qemu/atomic.h"
#include "hw/mips/octeon_internal.h"
@@ -140,6 +141,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(OcteonCsrBankState,
OCTEON_CSR_BANK)
#define OCTEON_CIU3_UART0_INTSN 0x8000
#define OCTEON_CSR_BASE 0x1180000000000ULL
#define OCTEON_CSR_SIZE 0x100000000ULL
+#define OCTEON_DPI_BASE 0x1df0000000000ULL
+#define OCTEON_DPI_SIZE 0x10000
#define OCTEON_MIO_BOOT_REG_CFGX(x) \
(0x0000000 + (x) * OCTEON_CSR_64BIT_SIZE)
#define OCTEON_MIO_BOOT_REG_CFG_INDEX(reg) \
@@ -267,6 +270,23 @@ 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_FPA_BASE 0x1280000000000ULL
+#define OCTEON_FPA_SIZE 0x1000
+#define OCTEON_FPA_CLK_COUNT 0xf0
+
+#define OCTEON_IPD_BASE 0x14f0000000000ULL
+#define OCTEON_IPD_SIZE 0x1000
+#define OCTEON_IPD_CLK_COUNT 0x338
+
+#define OCTEON_PKO_BASE 0x1540000000000ULL
+#define OCTEON_PKO_SIZE 0x1000000
+
+#define OCTEON_RNG_BASE 0x1400000000000ULL
+#define OCTEON_RNG_SIZE 0x8
+
+#define OCTEON_POW_BASE 0x1670000000000ULL
+#define OCTEON_POW_SIZE 0x2000
+
#define OCTEON_UART0_BASE 0x1180000000800ULL
#define OCTEON_UART0_ALIAS_BASE 0x1180000000c00ULL
#define OCTEON_UART_TX_REG 0x40
@@ -1955,6 +1975,174 @@ static const MemoryRegionOps octeon_csr_ops = {
},
};
+static uint64_t octeon_stateful_io_read(OcteonState *s, uint64_t base,
+ hwaddr addr, unsigned size)
+{
+ uint64_t value;
+ uint64_t reg = base + (addr & ~7ULL);
+
+ if (!octeon_csr_lookup(s, reg, &value)) {
+ value = 0;
+ }
+
+ return octeon_read64(value, addr, size);
+}
+
+static void octeon_stateful_io_write(OcteonState *s, uint64_t base,
+ hwaddr addr, uint64_t value,
+ unsigned size)
+{
+ uint64_t reg = base + (addr & ~7ULL);
+ uint64_t old;
+
+ if (!octeon_csr_lookup(s, reg, &old)) {
+ old = 0;
+ }
+
+ octeon_csr_store(s, reg, octeon_write64(old, addr, value, size));
+}
+
+static uint64_t octeon_dpi_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return octeon_stateful_io_read(opaque, OCTEON_DPI_BASE, addr, size);
+}
+
+static void octeon_dpi_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ octeon_stateful_io_write(opaque, OCTEON_DPI_BASE, addr, value, size);
+}
+
+static const MemoryRegionOps octeon_dpi_ops = {
+ .read = octeon_dpi_read,
+ .write = octeon_dpi_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+};
+
+static uint64_t octeon_fpa_read(void *opaque, hwaddr addr, unsigned size)
+{
+ OcteonState *s = opaque;
+ hwaddr reg = addr & ~7ULL;
+
+ if (reg == OCTEON_FPA_CLK_COUNT) {
+ return octeon_read64(octeon_clock_count(s->io_hz), addr, size);
+ }
+
+ return 0;
+}
+
+static void octeon_fpa_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+}
+
+static const MemoryRegionOps octeon_fpa_ops = {
+ .read = octeon_fpa_read,
+ .write = octeon_fpa_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+};
+
+static uint64_t octeon_ipd_read(void *opaque, hwaddr addr, unsigned size)
+{
+ OcteonState *s = opaque;
+ hwaddr reg = addr & ~7ULL;
+
+ if (reg == OCTEON_IPD_CLK_COUNT) {
+ return octeon_read64(octeon_clock_count(s->io_hz), addr, size);
+ }
+
+ return 0;
+}
+
+static void octeon_ipd_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+}
+
+static const MemoryRegionOps octeon_ipd_ops = {
+ .read = octeon_ipd_read,
+ .write = octeon_ipd_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+};
+
+static uint64_t octeon_pko_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return octeon_stateful_io_read(opaque, OCTEON_PKO_BASE, addr, size);
+}
+
+static void octeon_pko_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ octeon_stateful_io_write(opaque, OCTEON_PKO_BASE, addr, value, size);
+}
+
+static const MemoryRegionOps octeon_pko_ops = {
+ .read = octeon_pko_read,
+ .write = octeon_pko_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+};
+
+static uint64_t octeon_rng_read(void *opaque, hwaddr addr, unsigned size)
+{
+ uint64_t value;
+
+ qemu_guest_getrandom_nofail(&value, sizeof(value));
+ return octeon_read64(value, addr, size);
+}
+
+static void octeon_rng_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+}
+
+static const MemoryRegionOps octeon_rng_ops = {
+ .read = octeon_rng_read,
+ .write = octeon_rng_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+};
+
+static uint64_t octeon_pow_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return octeon_stateful_io_read(opaque, OCTEON_POW_BASE, addr, size);
+}
+
+static void octeon_pow_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ octeon_stateful_io_write(opaque, OCTEON_POW_BASE, addr, value, size);
+}
+
+static const MemoryRegionOps octeon_pow_ops = {
+ .read = octeon_pow_read,
+ .write = octeon_pow_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+};
+
+
void octeon_irq_set(void *opaque, int irq, int level)
{
OcteonState *s = opaque;
@@ -2573,6 +2761,36 @@ static void mips_octeon_init(MachineState *machine)
memory_region_add_subregion_overlap(get_system_memory(), OCTEON_CSR_BASE,
&s->csr_bank->csr, -1);
+ memory_region_init_io(&s->dpi, NULL, &octeon_dpi_ops, s,
+ "octeon.dpi", OCTEON_DPI_SIZE);
+ memory_region_add_subregion(get_system_memory(), OCTEON_DPI_BASE,
+ &s->dpi);
+
+ memory_region_init_io(&s->fpa, NULL, &octeon_fpa_ops, s,
+ "octeon.fpa", OCTEON_FPA_SIZE);
+ memory_region_add_subregion(get_system_memory(), OCTEON_FPA_BASE,
+ &s->fpa);
+
+ memory_region_init_io(&s->ipd, NULL, &octeon_ipd_ops, s,
+ "octeon.ipd", OCTEON_IPD_SIZE);
+ memory_region_add_subregion(get_system_memory(), OCTEON_IPD_BASE,
+ &s->ipd);
+
+ memory_region_init_io(&s->pko, NULL, &octeon_pko_ops, s,
+ "octeon.pko", OCTEON_PKO_SIZE);
+ memory_region_add_subregion(get_system_memory(), OCTEON_PKO_BASE,
+ &s->pko);
+
+ memory_region_init_io(&s->rng, NULL, &octeon_rng_ops, s,
+ "octeon.rng", OCTEON_RNG_SIZE);
+ memory_region_add_subregion(get_system_memory(), OCTEON_RNG_BASE,
+ &s->rng);
+
+ memory_region_init_io(&s->pow, NULL, &octeon_pow_ops, s,
+ "octeon.pow", OCTEON_POW_SIZE);
+ memory_region_add_subregion(get_system_memory(), OCTEON_POW_BASE,
+ &s->pow);
+
octeon_realize_peripherals(s);
}
diff --git a/hw/mips/octeon_internal.h b/hw/mips/octeon_internal.h
index 96443a9d64..f2daa35cdb 100644
--- a/hw/mips/octeon_internal.h
+++ b/hw/mips/octeon_internal.h
@@ -71,6 +71,12 @@ struct OcteonState {
MemoryRegion boot_flash;
MemoryRegion boot_flash_alias;
MemoryRegion cvmseg;
+ MemoryRegion dpi;
+ MemoryRegion fpa;
+ MemoryRegion ipd;
+ MemoryRegion pko;
+ MemoryRegion rng;
+ MemoryRegion pow;
OcteonMioState *mio;
OcteonEmmState *emm;
OcteonRstState *rst;
--
2.54.0