(no changes since v3)
Changes in v3:
- Separate interrupt state ownership from the NOTIFY fix
- Link SYSREG to IOSCB for MESSAGE_INT reads and writes
- Support both clearing and setting the MESSAGE_INT pending bit
include/hw/misc/mchp_pfsoc_ioscb.h | 4 ++++
include/hw/misc/mchp_pfsoc_sysreg.h | 3 ++-
hw/misc/mchp_pfsoc_ioscb.c | 20 ++++++++++++++--
hw/misc/mchp_pfsoc_sysreg.c | 37 ++++++++++++++++++++++-------
hw/riscv/microchip_pfsoc.c | 5 ++--
5 files changed, 55 insertions(+), 14 deletions(-)
diff --git a/include/hw/misc/mchp_pfsoc_ioscb.h
b/include/hw/misc/mchp_pfsoc_ioscb.h
index aa108d2d88..e8386f9794 100644
--- a/include/hw/misc/mchp_pfsoc_ioscb.h
+++ b/include/hw/misc/mchp_pfsoc_ioscb.h
@@ -53,6 +53,7 @@ typedef struct MchpPfSoCIoscbState {
uint32_t services_sr;
uint8_t mailbox_data[MCHP_PFSOC_IOSCB_MAILBOX_SIZE];
char *serial_number;
+ bool irq_pending;
qemu_irq irq;
} MchpPfSoCIoscbState;
@@ -61,4 +62,7 @@ typedef struct MchpPfSoCIoscbState {
#define MCHP_PFSOC_IOSCB(obj) \
OBJECT_CHECK(MchpPfSoCIoscbState, (obj), TYPE_MCHP_PFSOC_IOSCB)
+bool mchp_pfsoc_ioscb_get_irq_pending(MchpPfSoCIoscbState *s);
+void mchp_pfsoc_ioscb_set_irq_pending(MchpPfSoCIoscbState *s, bool pending);
+
#endif /* MCHP_PFSOC_IOSCB_H */
diff --git a/include/hw/misc/mchp_pfsoc_sysreg.h
b/include/hw/misc/mchp_pfsoc_sysreg.h
index c2b3688a94..d6c9027f2d 100644
--- a/include/hw/misc/mchp_pfsoc_sysreg.h
+++ b/include/hw/misc/mchp_pfsoc_sysreg.h
@@ -24,13 +24,14 @@
#define MCHP_PFSOC_SYSREG_H
#include "hw/core/sysbus.h"
+#include "hw/misc/mchp_pfsoc_ioscb.h"
#define MCHP_PFSOC_SYSREG_REG_SIZE 0x2000
typedef struct MchpPfSoCSysregState {
SysBusDevice parent;
MemoryRegion sysreg;
- qemu_irq irq;
+ MchpPfSoCIoscbState *ioscb;
} MchpPfSoCSysregState;
#define TYPE_MCHP_PFSOC_SYSREG "mchp.pfsoc.sysreg"
diff --git a/hw/misc/mchp_pfsoc_ioscb.c b/hw/misc/mchp_pfsoc_ioscb.c
index bde1917c10..1f77da6852 100644
--- a/hw/misc/mchp_pfsoc_ioscb.c
+++ b/hw/misc/mchp_pfsoc_ioscb.c
@@ -209,6 +209,22 @@ static const MemoryRegionOps mchp_pfsoc_io_calib_ddr_ops =
{
#define SERVICES_STATUS_SUCCESS 0
#define SERVICES_STATUS_FAILED 1
+static void mchp_pfsoc_ioscb_update_irq(MchpPfSoCIoscbState *s)
+{
+ qemu_set_irq(s->irq, s->irq_pending);
+}
+
+bool mchp_pfsoc_ioscb_get_irq_pending(MchpPfSoCIoscbState *s)
+{
+ return s->irq_pending;
+}
+
+void mchp_pfsoc_ioscb_set_irq_pending(MchpPfSoCIoscbState *s, bool pending)
+{
+ s->irq_pending = pending;
+ mchp_pfsoc_ioscb_update_irq(s);
+}
+
static void services_cr_write(MchpPfSoCIoscbState *s, uint32_t value)
{
uint32_t command;
@@ -248,7 +264,7 @@ static void services_cr_write(MchpPfSoCIoscbState *s,
uint32_t value)
s->services_sr = status << SERVICES_SR_STATUS_SHIFT;
if (value & SERVICES_CR_NOTIFY) {
- qemu_irq_raise(s->irq);
+ mchp_pfsoc_ioscb_set_irq_pending(s, true);
}
}
@@ -339,7 +355,7 @@ static void mchp_pfsoc_ioscb_reset(DeviceState *dev)
s->services_cr = 0;
s->services_sr = 0;
memset(s->mailbox_data, 0, sizeof(s->mailbox_data));
- qemu_irq_lower(s->irq);
+ mchp_pfsoc_ioscb_set_irq_pending(s, false);
}
static const Property mchp_pfsoc_ioscb_properties[] = {
diff --git a/hw/misc/mchp_pfsoc_sysreg.c b/hw/misc/mchp_pfsoc_sysreg.c
index 1d9154280a..4c52338c8a 100644
--- a/hw/misc/mchp_pfsoc_sysreg.c
+++ b/hw/misc/mchp_pfsoc_sysreg.c
@@ -24,20 +24,22 @@
#include "qemu/bitops.h"
#include "qemu/log.h"
#include "qapi/error.h"
-#include "hw/core/irq.h"
+#include "hw/core/qdev-properties.h"
#include "hw/core/sysbus.h"
#include "hw/misc/mchp_pfsoc_sysreg.h"
#include "system/runstate.h"
-#define CLOCK_CONFIG_CR 0x8
-#define RTC_CLOCK_CR 0xc
-#define MSS_RESET_CR 0x18
-#define ENVM_CR 0xb8
-#define MESSAGE_INT 0x118c
+#define CLOCK_CONFIG_CR 0x8
+#define RTC_CLOCK_CR 0xc
+#define MSS_RESET_CR 0x18
+#define ENVM_CR 0xb8
+#define MESSAGE_INT 0x118c
+#define MESSAGE_INT_PENDING BIT(0)
static uint64_t mchp_pfsoc_sysreg_read(void *opaque, hwaddr offset,
unsigned size)
{
+ MchpPfSoCSysregState *s = opaque;
uint32_t val = 0;
switch (offset) {
@@ -56,6 +58,10 @@ static uint64_t mchp_pfsoc_sysreg_read(void *opaque, hwaddr
offset,
/* Indicate the eNVM is running at the configured divider rate */
val = BIT(6);
break;
+ case MESSAGE_INT:
+ val = mchp_pfsoc_ioscb_get_irq_pending(s->ioscb) ?
+ MESSAGE_INT_PENDING : 0;
+ break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
"(size %d, offset 0x%" HWADDR_PRIx ")\n",
@@ -77,7 +83,12 @@ static void mchp_pfsoc_sysreg_write(void *opaque, hwaddr
offset,
}
break;
case MESSAGE_INT:
- qemu_irq_lower(s->irq);
+ /*
+ * MESSAGE_INT bit 0 is read/write: writing zero clears the interrupt
+ * and writing one sets it. IOSCB owns the state and PLIC output.
+ */
+ mchp_pfsoc_ioscb_set_irq_pending(s->ioscb,
+ value & MESSAGE_INT_PENDING);
break;
default:
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
@@ -97,20 +108,30 @@ static void mchp_pfsoc_sysreg_realize(DeviceState *dev,
Error **errp)
{
MchpPfSoCSysregState *s = MCHP_PFSOC_SYSREG(dev);
+ if (!s->ioscb) {
+ error_setg(errp, "The 'ioscb' link must be set");
+ return;
+ }
+
memory_region_init_io(&s->sysreg, OBJECT(dev),
&mchp_pfsoc_sysreg_ops, s,
"mchp.pfsoc.sysreg",
MCHP_PFSOC_SYSREG_REG_SIZE);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->sysreg);
- sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
}
+static const Property mchp_pfsoc_sysreg_properties[] = {
+ DEFINE_PROP_LINK("ioscb", MchpPfSoCSysregState, ioscb,
+ TYPE_MCHP_PFSOC_IOSCB, MchpPfSoCIoscbState *),
+};
+
static void mchp_pfsoc_sysreg_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "Microchip PolarFire SoC SYSREG module";
dc->realize = mchp_pfsoc_sysreg_realize;
+ device_class_set_props(dc, mchp_pfsoc_sysreg_properties);
}
static const TypeInfo mchp_pfsoc_sysreg_info = {
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index 36c894b677..38f4e7d799 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -315,12 +315,11 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev,
Error **errp)
}
/* SYSREG */
+ object_property_set_link(OBJECT(&s->sysreg), "ioscb", OBJECT(&s->ioscb),
+ &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->sysreg), errp);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysreg), 0,
memmap[MICROCHIP_PFSOC_SYSREG].base);
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->sysreg), 0,
- qdev_get_gpio_in(DEVICE(s->plic),
- MICROCHIP_PFSOC_MAILBOX_IRQ));
/* AXISW */
create_unimplemented_device("microchip.pfsoc.axisw",