aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/arm/Kconfig1
-rw-r--r--hw/arm/npcm7xx.c25
-rw-r--r--hw/arm/smmu-common.c4
-rw-r--r--hw/arm/smmuv3-internal.h7
-rw-r--r--hw/arm/smmuv3.c43
-rw-r--r--hw/arm/virt.c10
-rw-r--r--hw/intc/armv7m_nvic.c38
-rw-r--r--hw/ssi/meson.build2
-rw-r--r--hw/ssi/npcm_pspi.c221
-rw-r--r--hw/ssi/trace-events5
10 files changed, 322 insertions, 34 deletions
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 2d157de..b5aed4a 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -389,6 +389,7 @@ config XLNX_ZYNQMP_ARM
select XLNX_CSU_DMA
select XLNX_ZYNQMP
select XLNX_ZDMA
+ select USB_DWC3
config XLNX_VERSAL
bool
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
index d85cc02..15ff21d 100644
--- a/hw/arm/npcm7xx.c
+++ b/hw/arm/npcm7xx.c
@@ -86,6 +86,8 @@ enum NPCM7xxInterrupt {
NPCM7XX_EMC1RX_IRQ = 15,
NPCM7XX_EMC1TX_IRQ,
NPCM7XX_MMC_IRQ = 26,
+ NPCM7XX_PSPI2_IRQ = 28,
+ NPCM7XX_PSPI1_IRQ = 31,
NPCM7XX_TIMER0_IRQ = 32, /* Timer Module 0 */
NPCM7XX_TIMER1_IRQ,
NPCM7XX_TIMER2_IRQ,
@@ -220,6 +222,12 @@ static const hwaddr npcm7xx_emc_addr[] = {
0xf0826000,
};
+/* Register base address for each PSPI Module */
+static const hwaddr npcm7xx_pspi_addr[] = {
+ 0xf0200000,
+ 0xf0201000,
+};
+
static const struct {
hwaddr regs_addr;
uint32_t unconnected_pins;
@@ -444,6 +452,10 @@ static void npcm7xx_init(Object *obj)
object_initialize_child(obj, "emc[*]", &s->emc[i], TYPE_NPCM7XX_EMC);
}
+ for (i = 0; i < ARRAY_SIZE(s->pspi); i++) {
+ object_initialize_child(obj, "pspi[*]", &s->pspi[i], TYPE_NPCM_PSPI);
+ }
+
object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI);
}
@@ -715,6 +727,17 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc), 0,
npcm7xx_irq(s, NPCM7XX_MMC_IRQ));
+ /* PSPI */
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pspi_addr) != ARRAY_SIZE(s->pspi));
+ for (i = 0; i < ARRAY_SIZE(s->pspi); i++) {
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pspi[i]);
+ int irq = (i == 0) ? NPCM7XX_PSPI1_IRQ : NPCM7XX_PSPI2_IRQ;
+
+ sysbus_realize(sbd, &error_abort);
+ sysbus_mmio_map(sbd, 0, npcm7xx_pspi_addr[i]);
+ sysbus_connect_irq(sbd, 0, npcm7xx_irq(s, irq));
+ }
+
create_unimplemented_device("npcm7xx.shm", 0xc0001000, 4 * KiB);
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
@@ -724,8 +747,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB);
create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB);
create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB);
- create_unimplemented_device("npcm7xx.pspi1", 0xf0200000, 4 * KiB);
- create_unimplemented_device("npcm7xx.pspi2", 0xf0201000, 4 * KiB);
create_unimplemented_device("npcm7xx.ahbpci", 0xf0400000, 1 * MiB);
create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB);
create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB);
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 733c964..0a5a60c 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -249,7 +249,7 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova)
/* there is a ttbr0 region and we are in it (high bits all zero) */
return &cfg->tt[0];
} else if (cfg->tt[1].tsz &&
- !extract64(iova, 64 - cfg->tt[1].tsz, cfg->tt[1].tsz - tbi_byte)) {
+ sextract64(iova, 64 - cfg->tt[1].tsz, cfg->tt[1].tsz - tbi_byte) == -1) {
/* there is a ttbr1 region and we are in it (high bits all one) */
return &cfg->tt[1];
} else if (!cfg->tt[0].tsz) {
@@ -439,7 +439,7 @@ static AddressSpace *smmu_find_add_as(PCIBus *bus, void *opaque, int devfn)
memory_region_init_iommu(&sdev->iommu, sizeof(sdev->iommu),
s->mrtypename,
- OBJECT(s), name, 1ULL << SMMU_MAX_VA_BITS);
+ OBJECT(s), name, UINT64_MAX);
address_space_init(&sdev->as,
MEMORY_REGION(&sdev->iommu), name);
trace_smmu_add_mr(name);
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index bce1618..e8f0ebf 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -79,6 +79,13 @@ REG32(CR0ACK, 0x24)
REG32(CR1, 0x28)
REG32(CR2, 0x2c)
REG32(STATUSR, 0x40)
+REG32(GBPA, 0x44)
+ FIELD(GBPA, ABORT, 20, 1)
+ FIELD(GBPA, UPDATE, 31, 1)
+
+/* Use incoming. */
+#define SMMU_GBPA_RESET_VAL 0x1000
+
REG32(IRQ_CTRL, 0x50)
FIELD(IRQ_CTRL, GERROR_IRQEN, 0, 1)
FIELD(IRQ_CTRL, PRI_IRQEN, 1, 1)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 955b89c..270c80b 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -285,6 +285,7 @@ static void smmuv3_init_regs(SMMUv3State *s)
s->gerror = 0;
s->gerrorn = 0;
s->statusr = 0;
+ s->gbpa = SMMU_GBPA_RESET_VAL;
}
static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
@@ -659,7 +660,11 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
qemu_mutex_lock(&s->mutex);
if (!smmu_enabled(s)) {
- status = SMMU_TRANS_DISABLE;
+ if (FIELD_EX32(s->gbpa, GBPA, ABORT)) {
+ status = SMMU_TRANS_ABORT;
+ } else {
+ status = SMMU_TRANS_DISABLE;
+ }
goto epilogue;
}
@@ -1170,6 +1175,16 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
case A_GERROR_IRQ_CFG2:
s->gerror_irq_cfg2 = data;
return MEMTX_OK;
+ case A_GBPA:
+ /*
+ * If UPDATE is not set, the write is ignored. This is the only
+ * permitted behavior in SMMUv3.2 and later.
+ */
+ if (data & R_GBPA_UPDATE_MASK) {
+ /* Ignore update bit as write is synchronous. */
+ s->gbpa = data & ~R_GBPA_UPDATE_MASK;
+ }
+ return MEMTX_OK;
case A_STRTAB_BASE: /* 64b */
s->strtab_base = deposit64(s->strtab_base, 0, 32, data);
return MEMTX_OK;
@@ -1318,6 +1333,9 @@ static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
case A_STATUSR:
*data = s->statusr;
return MEMTX_OK;
+ case A_GBPA:
+ *data = s->gbpa;
+ return MEMTX_OK;
case A_IRQ_CTRL:
case A_IRQ_CTRL_ACK:
*data = s->irq_ctrl;
@@ -1482,6 +1500,25 @@ static const VMStateDescription vmstate_smmuv3_queue = {
},
};
+static bool smmuv3_gbpa_needed(void *opaque)
+{
+ SMMUv3State *s = opaque;
+
+ /* Only migrate GBPA if it has different reset value. */
+ return s->gbpa != SMMU_GBPA_RESET_VAL;
+}
+
+static const VMStateDescription vmstate_gbpa = {
+ .name = "smmuv3/gbpa",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = smmuv3_gbpa_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(gbpa, SMMUv3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_smmuv3 = {
.name = "smmuv3",
.version_id = 1,
@@ -1512,6 +1549,10 @@ static const VMStateDescription vmstate_smmuv3 = {
VMSTATE_END_OF_LIST(),
},
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_gbpa,
+ NULL
+ }
};
static void smmuv3_instance_init(Object *obj)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 75f2894..ac626b3 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2133,21 +2133,21 @@ static void machvirt_init(MachineState *machine)
if (vms->secure && (kvm_enabled() || hvf_enabled())) {
error_report("mach-virt: %s does not support providing "
"Security extensions (TrustZone) to the guest CPU",
- kvm_enabled() ? "KVM" : "HVF");
+ current_accel_name());
exit(1);
}
if (vms->virt && (kvm_enabled() || hvf_enabled())) {
error_report("mach-virt: %s does not support providing "
"Virtualization extensions to the guest CPU",
- kvm_enabled() ? "KVM" : "HVF");
+ current_accel_name());
exit(1);
}
if (vms->mte && (kvm_enabled() || hvf_enabled())) {
error_report("mach-virt: %s does not support providing "
"MTE to the guest CPU",
- kvm_enabled() ? "KVM" : "HVF");
+ current_accel_name());
exit(1);
}
@@ -3013,7 +3013,11 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
mc->minimum_page_bits = 12;
mc->possible_cpu_arch_ids = virt_possible_cpu_arch_ids;
mc->cpu_index_to_instance_props = virt_cpu_index_to_props;
+#ifdef CONFIG_TCG
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
+#else
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("max");
+#endif
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
mc->kvm_type = virt_kvm_type;
assert(!mc->get_hotplug_handler);
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 1f77639..e545532 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -389,7 +389,7 @@ static inline int nvic_exec_prio(NVICState *s)
return MIN(running, s->exception_prio);
}
-bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
+bool armv7m_nvic_neg_prio_requested(NVICState *s, bool secure)
{
/* Return true if the requested execution priority is negative
* for the specified security state, ie that security state
@@ -399,8 +399,6 @@ bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
* mean we don't allow FAULTMASK_NS to actually make the execution
* priority negative). Compare pseudocode IsReqExcPriNeg().
*/
- NVICState *s = opaque;
-
if (s->cpu->env.v7m.faultmask[secure]) {
return true;
}
@@ -418,17 +416,13 @@ bool armv7m_nvic_neg_prio_requested(void *opaque, bool secure)
return false;
}
-bool armv7m_nvic_can_take_pending_exception(void *opaque)
+bool armv7m_nvic_can_take_pending_exception(NVICState *s)
{
- NVICState *s = opaque;
-
return nvic_exec_prio(s) > nvic_pending_prio(s);
}
-int armv7m_nvic_raw_execution_priority(void *opaque)
+int armv7m_nvic_raw_execution_priority(NVICState *s)
{
- NVICState *s = opaque;
-
return s->exception_prio;
}
@@ -506,9 +500,8 @@ static void nvic_irq_update(NVICState *s)
* if @secure is true and @irq does not specify one of the fixed set
* of architecturally banked exceptions.
*/
-static void armv7m_nvic_clear_pending(void *opaque, int irq, bool secure)
+static void armv7m_nvic_clear_pending(NVICState *s, int irq, bool secure)
{
- NVICState *s = (NVICState *)opaque;
VecInfo *vec;
assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq);
@@ -666,17 +659,17 @@ static void do_armv7m_nvic_set_pending(void *opaque, int irq, bool secure,
}
}
-void armv7m_nvic_set_pending(void *opaque, int irq, bool secure)
+void armv7m_nvic_set_pending(NVICState *s, int irq, bool secure)
{
- do_armv7m_nvic_set_pending(opaque, irq, secure, false);
+ do_armv7m_nvic_set_pending(s, irq, secure, false);
}
-void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure)
+void armv7m_nvic_set_pending_derived(NVICState *s, int irq, bool secure)
{
- do_armv7m_nvic_set_pending(opaque, irq, secure, true);
+ do_armv7m_nvic_set_pending(s, irq, secure, true);
}
-void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure)
+void armv7m_nvic_set_pending_lazyfp(NVICState *s, int irq, bool secure)
{
/*
* Pend an exception during lazy FP stacking. This differs
@@ -684,7 +677,6 @@ void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure)
* whether we should escalate depends on the saved context
* in the FPCCR register, not on the current state of the CPU/NVIC.
*/
- NVICState *s = (NVICState *)opaque;
bool banked = exc_is_banked(irq);
VecInfo *vec;
bool targets_secure;
@@ -773,9 +765,8 @@ void armv7m_nvic_set_pending_lazyfp(void *opaque, int irq, bool secure)
}
/* Make pending IRQ active. */
-void armv7m_nvic_acknowledge_irq(void *opaque)
+void armv7m_nvic_acknowledge_irq(NVICState *s)
{
- NVICState *s = (NVICState *)opaque;
CPUARMState *env = &s->cpu->env;
const int pending = s->vectpending;
const int running = nvic_exec_prio(s);
@@ -814,10 +805,9 @@ static bool vectpending_targets_secure(NVICState *s)
exc_targets_secure(s, s->vectpending);
}
-void armv7m_nvic_get_pending_irq_info(void *opaque,
+void armv7m_nvic_get_pending_irq_info(NVICState *s,
int *pirq, bool *ptargets_secure)
{
- NVICState *s = (NVICState *)opaque;
const int pending = s->vectpending;
bool targets_secure;
@@ -831,9 +821,8 @@ void armv7m_nvic_get_pending_irq_info(void *opaque,
*pirq = pending;
}
-int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure)
+int armv7m_nvic_complete_irq(NVICState *s, int irq, bool secure)
{
- NVICState *s = (NVICState *)opaque;
VecInfo *vec = NULL;
int ret = 0;
@@ -915,7 +904,7 @@ int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure)
return ret;
}
-bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure)
+bool armv7m_nvic_get_ready_status(NVICState *s, int irq, bool secure)
{
/*
* Return whether an exception is "ready", i.e. it is enabled and is
@@ -926,7 +915,6 @@ bool armv7m_nvic_get_ready_status(void *opaque, int irq, bool secure)
* for non-banked exceptions secure is always false; for banked exceptions
* it indicates which of the exceptions is required.
*/
- NVICState *s = (NVICState *)opaque;
bool banked = exc_is_banked(irq);
VecInfo *vec;
int running = nvic_exec_prio(s);
diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build
index 702aa5e..904a471 100644
--- a/hw/ssi/meson.build
+++ b/hw/ssi/meson.build
@@ -1,6 +1,6 @@
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_smc.c'))
softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-spi.c'))
-softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c'))
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c', 'npcm_pspi.c'))
softmmu_ss.add(when: 'CONFIG_PL022', if_true: files('pl022.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_SPI', if_true: files('sifive_spi.c'))
softmmu_ss.add(when: 'CONFIG_SSI', if_true: files('ssi.c'))
diff --git a/hw/ssi/npcm_pspi.c b/hw/ssi/npcm_pspi.c
new file mode 100644
index 0000000..3fb9350
--- /dev/null
+++ b/hw/ssi/npcm_pspi.c
@@ -0,0 +1,221 @@
+/*
+ * Nuvoton NPCM Peripheral SPI Module (PSPI)
+ *
+ * Copyright 2023 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/irq.h"
+#include "hw/registerfields.h"
+#include "hw/ssi/npcm_pspi.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/units.h"
+
+#include "trace.h"
+
+REG16(PSPI_DATA, 0x0)
+REG16(PSPI_CTL1, 0x2)
+ FIELD(PSPI_CTL1, SPIEN, 0, 1)
+ FIELD(PSPI_CTL1, MOD, 2, 1)
+ FIELD(PSPI_CTL1, EIR, 5, 1)
+ FIELD(PSPI_CTL1, EIW, 6, 1)
+ FIELD(PSPI_CTL1, SCM, 7, 1)
+ FIELD(PSPI_CTL1, SCIDL, 8, 1)
+ FIELD(PSPI_CTL1, SCDV, 9, 7)
+REG16(PSPI_STAT, 0x4)
+ FIELD(PSPI_STAT, BSY, 0, 1)
+ FIELD(PSPI_STAT, RBF, 1, 1)
+
+static void npcm_pspi_update_irq(NPCMPSPIState *s)
+{
+ int level = 0;
+
+ /* Only fire IRQ when the module is enabled. */
+ if (FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, SPIEN)) {
+ /* Update interrupt as BSY is cleared. */
+ if ((!FIELD_EX16(s->regs[R_PSPI_STAT], PSPI_STAT, BSY)) &&
+ FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, EIW)) {
+ level = 1;
+ }
+
+ /* Update interrupt as RBF is set. */
+ if (FIELD_EX16(s->regs[R_PSPI_STAT], PSPI_STAT, RBF) &&
+ FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, EIR)) {
+ level = 1;
+ }
+ }
+ qemu_set_irq(s->irq, level);
+}
+
+static uint16_t npcm_pspi_read_data(NPCMPSPIState *s)
+{
+ uint16_t value = s->regs[R_PSPI_DATA];
+
+ /* Clear stat bits as the value are read out. */
+ s->regs[R_PSPI_STAT] = 0;
+
+ return value;
+}
+
+static void npcm_pspi_write_data(NPCMPSPIState *s, uint16_t data)
+{
+ uint16_t value = 0;
+
+ if (FIELD_EX16(s->regs[R_PSPI_CTL1], PSPI_CTL1, MOD)) {
+ value = ssi_transfer(s->spi, extract16(data, 8, 8)) << 8;
+ }
+ value |= ssi_transfer(s->spi, extract16(data, 0, 8));
+ s->regs[R_PSPI_DATA] = value;
+
+ /* Mark data as available */
+ s->regs[R_PSPI_STAT] = R_PSPI_STAT_BSY_MASK | R_PSPI_STAT_RBF_MASK;
+}
+
+/* Control register read handler. */
+static uint64_t npcm_pspi_ctrl_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ NPCMPSPIState *s = opaque;
+ uint16_t value;
+
+ switch (addr) {
+ case A_PSPI_DATA:
+ value = npcm_pspi_read_data(s);
+ break;
+
+ case A_PSPI_CTL1:
+ value = s->regs[R_PSPI_CTL1];
+ break;
+
+ case A_PSPI_STAT:
+ value = s->regs[R_PSPI_STAT];
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to invalid offset 0x%" PRIx64 "\n",
+ DEVICE(s)->canonical_path, addr);
+ return 0;
+ }
+ trace_npcm_pspi_ctrl_read(DEVICE(s)->canonical_path, addr, value);
+ npcm_pspi_update_irq(s);
+
+ return value;
+}
+
+/* Control register write handler. */
+static void npcm_pspi_ctrl_write(void *opaque, hwaddr addr, uint64_t v,
+ unsigned int size)
+{
+ NPCMPSPIState *s = opaque;
+ uint16_t value = v;
+
+ trace_npcm_pspi_ctrl_write(DEVICE(s)->canonical_path, addr, value);
+
+ switch (addr) {
+ case A_PSPI_DATA:
+ npcm_pspi_write_data(s, value);
+ break;
+
+ case A_PSPI_CTL1:
+ s->regs[R_PSPI_CTL1] = value;
+ break;
+
+ case A_PSPI_STAT:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to read-only register PSPI_STAT: 0x%08"
+ PRIx64 "\n", DEVICE(s)->canonical_path, v);
+ break;
+
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to invalid offset 0x%" PRIx64 "\n",
+ DEVICE(s)->canonical_path, addr);
+ return;
+ }
+ npcm_pspi_update_irq(s);
+}
+
+static const MemoryRegionOps npcm_pspi_ctrl_ops = {
+ .read = npcm_pspi_ctrl_read,
+ .write = npcm_pspi_ctrl_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 2,
+ .unaligned = false,
+ },
+ .impl = {
+ .min_access_size = 2,
+ .max_access_size = 2,
+ .unaligned = false,
+ },
+};
+
+static void npcm_pspi_enter_reset(Object *obj, ResetType type)
+{
+ NPCMPSPIState *s = NPCM_PSPI(obj);
+
+ trace_npcm_pspi_enter_reset(DEVICE(obj)->canonical_path, type);
+ memset(s->regs, 0, sizeof(s->regs));
+}
+
+static void npcm_pspi_realize(DeviceState *dev, Error **errp)
+{
+ NPCMPSPIState *s = NPCM_PSPI(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ Object *obj = OBJECT(dev);
+
+ s->spi = ssi_create_bus(dev, "pspi");
+ memory_region_init_io(&s->mmio, obj, &npcm_pspi_ctrl_ops, s,
+ "mmio", 4 * KiB);
+ sysbus_init_mmio(sbd, &s->mmio);
+ sysbus_init_irq(sbd, &s->irq);
+}
+
+static const VMStateDescription vmstate_npcm_pspi = {
+ .name = "npcm-pspi",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16_ARRAY(regs, NPCMPSPIState, NPCM_PSPI_NR_REGS),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+
+static void npcm_pspi_class_init(ObjectClass *klass, void *data)
+{
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "NPCM Peripheral SPI Module";
+ dc->realize = npcm_pspi_realize;
+ dc->vmsd = &vmstate_npcm_pspi;
+ rc->phases.enter = npcm_pspi_enter_reset;
+}
+
+static const TypeInfo npcm_pspi_types[] = {
+ {
+ .name = TYPE_NPCM_PSPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NPCMPSPIState),
+ .class_init = npcm_pspi_class_init,
+ },
+};
+DEFINE_TYPES(npcm_pspi_types);
diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events
index c707d4a..2d5bd2b 100644
--- a/hw/ssi/trace-events
+++ b/hw/ssi/trace-events
@@ -21,6 +21,11 @@ npcm7xx_fiu_ctrl_write(const char *id, uint64_t addr, uint32_t data) "%s offset:
npcm7xx_fiu_flash_read(const char *id, int cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64
npcm7xx_fiu_flash_write(const char *id, unsigned cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64
+# npcm_pspi.c
+npcm_pspi_enter_reset(const char *id, int reset_type) "%s reset type: %d"
+npcm_pspi_ctrl_read(const char *id, uint64_t addr, uint16_t data) "%s offset: 0x%03" PRIx64 " value: 0x%04" PRIx16
+npcm_pspi_ctrl_write(const char *id, uint64_t addr, uint16_t data) "%s offset: 0x%03" PRIx64 " value: 0x%04" PRIx16
+
# ibex_spi_host.c
ibex_spi_host_reset(const char *msg) "%s"