aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/arm/fsl-imx6ul.c2
-rw-r--r--hw/arm/fsl-imx7.c41
-rw-r--r--hw/arm/nseries.c28
-rw-r--r--hw/arm/smmu-common.c15
-rw-r--r--hw/core/cpu-common.c1
-rw-r--r--hw/input/tsc2005.c2
-rw-r--r--hw/input/tsc210x.c3
-rw-r--r--hw/intc/Kconfig3
-rw-r--r--hw/intc/loongarch_pch_msi.c29
-rw-r--r--hw/intc/loongarch_pch_pic.c35
-rw-r--r--hw/intc/sifive_plic.c66
-rw-r--r--hw/loongarch/virt.c19
-rw-r--r--hw/mips/mips_int.c11
-rw-r--r--hw/misc/imx6ul_ccm.c6
-rw-r--r--hw/misc/imx7_ccm.c49
-rw-r--r--hw/misc/mchp_pfsoc_ioscb.c78
-rw-r--r--hw/misc/mchp_pfsoc_sysreg.c18
-rw-r--r--hw/net/imx_fec.c8
-rw-r--r--hw/ppc/ppc.c10
-rw-r--r--hw/riscv/Kconfig22
-rw-r--r--hw/riscv/microchip_pfsoc.c121
-rw-r--r--hw/riscv/opentitan.c26
-rw-r--r--hw/riscv/sifive_u.c3
-rw-r--r--hw/riscv/spike.c1
-rw-r--r--hw/riscv/virt.c7
-rw-r--r--hw/timer/imx_epit.c370
-rw-r--r--hw/timer/imx_gpt.c25
27 files changed, 662 insertions, 337 deletions
diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c
index f189712..d88d6cc 100644
--- a/hw/arm/fsl-imx6ul.c
+++ b/hw/arm/fsl-imx6ul.c
@@ -81,7 +81,7 @@ static void fsl_imx6ul_init(Object *obj)
*/
for (i = 0; i < FSL_IMX6UL_NUM_GPTS; i++) {
snprintf(name, NAME_SIZE, "gpt%d", i);
- object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX7_GPT);
+ object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX6UL_GPT);
}
/*
diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c
index cc6fdb9..afc7480 100644
--- a/hw/arm/fsl-imx7.c
+++ b/hw/arm/fsl-imx7.c
@@ -219,9 +219,19 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
FSL_IMX7_GPT4_ADDR,
};
+ static const int FSL_IMX7_GPTn_IRQ[FSL_IMX7_NUM_GPTS] = {
+ FSL_IMX7_GPT1_IRQ,
+ FSL_IMX7_GPT2_IRQ,
+ FSL_IMX7_GPT3_IRQ,
+ FSL_IMX7_GPT4_IRQ,
+ };
+
s->gpt[i].ccm = IMX_CCM(&s->ccm);
sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, FSL_IMX7_GPTn_ADDR[i]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->a7mpcore),
+ FSL_IMX7_GPTn_IRQ[i]));
}
for (i = 0; i < FSL_IMX7_NUM_GPIOS; i++) {
@@ -235,8 +245,37 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
FSL_IMX7_GPIO7_ADDR,
};
+ static const int FSL_IMX7_GPIOn_LOW_IRQ[FSL_IMX7_NUM_GPIOS] = {
+ FSL_IMX7_GPIO1_LOW_IRQ,
+ FSL_IMX7_GPIO2_LOW_IRQ,
+ FSL_IMX7_GPIO3_LOW_IRQ,
+ FSL_IMX7_GPIO4_LOW_IRQ,
+ FSL_IMX7_GPIO5_LOW_IRQ,
+ FSL_IMX7_GPIO6_LOW_IRQ,
+ FSL_IMX7_GPIO7_LOW_IRQ,
+ };
+
+ static const int FSL_IMX7_GPIOn_HIGH_IRQ[FSL_IMX7_NUM_GPIOS] = {
+ FSL_IMX7_GPIO1_HIGH_IRQ,
+ FSL_IMX7_GPIO2_HIGH_IRQ,
+ FSL_IMX7_GPIO3_HIGH_IRQ,
+ FSL_IMX7_GPIO4_HIGH_IRQ,
+ FSL_IMX7_GPIO5_HIGH_IRQ,
+ FSL_IMX7_GPIO6_HIGH_IRQ,
+ FSL_IMX7_GPIO7_HIGH_IRQ,
+ };
+
sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &error_abort);
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, FSL_IMX7_GPIOn_ADDR[i]);
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0,
+ FSL_IMX7_GPIOn_ADDR[i]);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
+ qdev_get_gpio_in(DEVICE(&s->a7mpcore),
+ FSL_IMX7_GPIOn_LOW_IRQ[i]));
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
+ qdev_get_gpio_in(DEVICE(&s->a7mpcore),
+ FSL_IMX7_GPIOn_HIGH_IRQ[i]));
}
/*
diff --git a/hw/arm/nseries.c b/hw/arm/nseries.c
index b151113..c9df063 100644
--- a/hw/arm/nseries.c
+++ b/hw/arm/nseries.c
@@ -230,13 +230,13 @@ static void n8x0_i2c_setup(struct n800_s *s)
}
/* Touchscreen and keypad controller */
-static MouseTransformInfo n800_pointercal = {
+static const MouseTransformInfo n800_pointercal = {
.x = 800,
.y = 480,
.a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
};
-static MouseTransformInfo n810_pointercal = {
+static const MouseTransformInfo n810_pointercal = {
.x = 800,
.y = 480,
.a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
@@ -334,7 +334,7 @@ static void n810_key_event(void *opaque, int keycode)
#define M 0
-static int n810_keys[0x80] = {
+static const int n810_keys[0x80] = {
[0x01] = 16, /* Q */
[0x02] = 37, /* K */
[0x03] = 24, /* O */
@@ -810,7 +810,7 @@ static void n8x0_usb_setup(struct n800_s *s)
/* Setup done before the main bootloader starts by some early setup code
* - used when we want to run the main bootloader in emulation. This
* isn't documented. */
-static uint32_t n800_pinout[104] = {
+static const uint32_t n800_pinout[104] = {
0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
@@ -1060,7 +1060,7 @@ static void n8x0_boot_init(void *opaque)
#define OMAP_TAG_CBUS 0x4e03
#define OMAP_TAG_EM_ASIC_BB5 0x4e04
-static struct omap_gpiosw_info_s {
+static const struct omap_gpiosw_info_s {
const char *name;
int line;
int type;
@@ -1078,7 +1078,7 @@ static struct omap_gpiosw_info_s {
"headphone", N8X0_HEADPHONE_GPIO,
OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
},
- { NULL }
+ { /* end of list */ }
}, n810_gpiosw_info[] = {
{
"gps_reset", N810_GPS_RESET_GPIO,
@@ -1099,10 +1099,10 @@ static struct omap_gpiosw_info_s {
"slide", N810_SLIDE_GPIO,
OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
},
- { NULL }
+ { /* end of list */ }
};
-static struct omap_partition_info_s {
+static const struct omap_partition_info_s {
uint32_t offset;
uint32_t size;
int mask;
@@ -1113,27 +1113,25 @@ static struct omap_partition_info_s {
{ 0x00080000, 0x00200000, 0x0, "kernel" },
{ 0x00280000, 0x00200000, 0x3, "initfs" },
{ 0x00480000, 0x0fb80000, 0x3, "rootfs" },
-
- { 0, 0, 0, NULL }
+ { /* end of list */ }
}, n810_part_info[] = {
{ 0x00000000, 0x00020000, 0x3, "bootloader" },
{ 0x00020000, 0x00060000, 0x0, "config" },
{ 0x00080000, 0x00220000, 0x0, "kernel" },
{ 0x002a0000, 0x00400000, 0x0, "initfs" },
{ 0x006a0000, 0x0f960000, 0x0, "rootfs" },
-
- { 0, 0, 0, NULL }
+ { /* end of list */ }
};
-static uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR };
+static const uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR };
static int n8x0_atag_setup(void *p, int model)
{
uint8_t *b;
uint16_t *w;
uint32_t *l;
- struct omap_gpiosw_info_s *gpiosw;
- struct omap_partition_info_s *partition;
+ const struct omap_gpiosw_info_s *gpiosw;
+ const struct omap_partition_info_s *partition;
const char *tag;
w = p;
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 2208385..54186f3 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -116,7 +116,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
g_hash_table_insert(bs->iotlb, key, new);
}
-inline void smmu_iotlb_inv_all(SMMUState *s)
+void smmu_iotlb_inv_all(SMMUState *s)
{
trace_smmu_iotlb_inv_all();
g_hash_table_remove_all(s->iotlb);
@@ -146,9 +146,8 @@ static gboolean smmu_hash_remove_by_asid_iova(gpointer key, gpointer value,
((entry->iova & ~info->mask) == info->iova);
}
-inline void
-smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
- uint8_t tg, uint64_t num_pages, uint8_t ttl)
+void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
+ uint8_t tg, uint64_t num_pages, uint8_t ttl)
{
/* if tg is not set we use 4KB range invalidation */
uint8_t granule = tg ? tg * 2 + 10 : 12;
@@ -174,7 +173,7 @@ smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
&info);
}
-inline void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
+void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
{
trace_smmu_iotlb_inv_asid(asid);
g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
@@ -374,8 +373,8 @@ error:
*
* return 0 on success
*/
-inline int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
- SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
+int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
+ SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
{
if (!cfg->aa64) {
/*
@@ -483,7 +482,7 @@ static void smmu_unmap_notifier_range(IOMMUNotifier *n)
}
/* Unmap all notifiers attached to @mr */
-inline void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr)
+static void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr)
{
IOMMUNotifier *n;
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 78b5f35..b177e76 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -235,6 +235,7 @@ static void cpu_common_initfn(Object *obj)
/* the default value is changed by qemu_init_vcpu() for softmmu */
cpu->nr_cores = 1;
cpu->nr_threads = 1;
+ cpu->cflags_next_tb = -1;
qemu_mutex_init(&cpu->work_mutex);
QSIMPLEQ_INIT(&cpu->work_list);
diff --git a/hw/input/tsc2005.c b/hw/input/tsc2005.c
index 14698ce..555b677 100644
--- a/hw/input/tsc2005.c
+++ b/hw/input/tsc2005.c
@@ -523,7 +523,7 @@ void *tsc2005_init(qemu_irq pintdav)
* from the touchscreen. Assuming 12-bit precision was used during
* tslib calibration.
*/
-void tsc2005_set_transform(void *opaque, MouseTransformInfo *info)
+void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info)
{
TSC2005State *s = (TSC2005State *) opaque;
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
index df7313d..fdd5ff8 100644
--- a/hw/input/tsc210x.c
+++ b/hw/input/tsc210x.c
@@ -1176,8 +1176,7 @@ I2SCodec *tsc210x_codec(uWireSlave *chip)
* from the touchscreen. Assuming 12-bit precision was used during
* tslib calibration.
*/
-void tsc210x_set_transform(uWireSlave *chip,
- MouseTransformInfo *info)
+void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info)
{
TSC210xState *s = (TSC210xState *) chip->opaque;
#if 0
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index ecd2883..21441d0 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -72,12 +72,15 @@ config RISCV_ACLINT
config RISCV_APLIC
bool
+ select MSI_NONBROKEN
config RISCV_IMSIC
bool
+ select MSI_NONBROKEN
config SIFIVE_PLIC
bool
+ select MSI_NONBROKEN
config GOLDFISH_PIC
bool
diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c
index b36d6d7..ecf3ed0 100644
--- a/hw/intc/loongarch_pch_msi.c
+++ b/hw/intc/loongarch_pch_msi.c
@@ -32,7 +32,7 @@ static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
*/
irq_num = (val & 0xff) - s->irq_base;
trace_loongarch_msi_set_irq(irq_num);
- assert(irq_num < PCH_MSI_IRQ_NUM);
+ assert(irq_num < s->irq_num);
qemu_set_irq(s->pch_msi_irq[irq_num], 1);
}
@@ -49,6 +49,28 @@ static void pch_msi_irq_handler(void *opaque, int irq, int level)
qemu_set_irq(s->pch_msi_irq[irq], level);
}
+static void loongarch_pch_msi_realize(DeviceState *dev, Error **errp)
+{
+ LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(dev);
+
+ if (!s->irq_num || s->irq_num > PCH_MSI_IRQ_NUM) {
+ error_setg(errp, "Invalid 'msi_irq_num'");
+ return;
+ }
+
+ s->pch_msi_irq = g_new(qemu_irq, s->irq_num);
+
+ qdev_init_gpio_out(dev, s->pch_msi_irq, s->irq_num);
+ qdev_init_gpio_in(dev, pch_msi_irq_handler, s->irq_num);
+}
+
+static void loongarch_pch_msi_unrealize(DeviceState *dev)
+{
+ LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(dev);
+
+ g_free(s->pch_msi_irq);
+}
+
static void loongarch_pch_msi_init(Object *obj)
{
LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(obj);
@@ -59,12 +81,11 @@ static void loongarch_pch_msi_init(Object *obj)
sysbus_init_mmio(sbd, &s->msi_mmio);
msi_nonbroken = true;
- qdev_init_gpio_out(DEVICE(obj), s->pch_msi_irq, PCH_MSI_IRQ_NUM);
- qdev_init_gpio_in(DEVICE(obj), pch_msi_irq_handler, PCH_MSI_IRQ_NUM);
}
static Property loongarch_msi_properties[] = {
DEFINE_PROP_UINT32("msi_irq_base", LoongArchPCHMSI, irq_base, 0),
+ DEFINE_PROP_UINT32("msi_irq_num", LoongArchPCHMSI, irq_num, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -72,6 +93,8 @@ static void loongarch_pch_msi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->realize = loongarch_pch_msi_realize;
+ dc->unrealize = loongarch_pch_msi_unrealize;
device_class_set_props(dc, loongarch_msi_properties);
}
diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
index 3380b09..9208fc4 100644
--- a/hw/intc/loongarch_pch_pic.c
+++ b/hw/intc/loongarch_pch_pic.c
@@ -6,12 +6,16 @@
*/
#include "qemu/osdep.h"
+#include "qemu/bitops.h"
#include "hw/sysbus.h"
#include "hw/loongarch/virt.h"
+#include "hw/pci-host/ls7a.h"
#include "hw/irq.h"
#include "hw/intc/loongarch_pch_pic.h"
+#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "trace.h"
+#include "qapi/error.h"
static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
{
@@ -40,7 +44,7 @@ static void pch_pic_irq_handler(void *opaque, int irq, int level)
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
uint64_t mask = 1ULL << irq;
- assert(irq < PCH_PIC_IRQ_NUM);
+ assert(irq < s->irq_num);
trace_loongarch_pch_pic_irq_handler(irq, level);
if (s->intedge & mask) {
@@ -78,7 +82,12 @@ static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr,
val = PCH_PIC_INT_ID_VAL;
break;
case PCH_PIC_INT_ID_HI:
- val = PCH_PIC_INT_ID_NUM;
+ /*
+ * With 7A1000 manual
+ * bit 0-15 pch irqchip version
+ * bit 16-31 irq number supported with pch irqchip
+ */
+ val = deposit32(PCH_PIC_INT_ID_VER, 16, 16, s->irq_num - 1);
break;
case PCH_PIC_INT_MASK_LO:
val = (uint32_t)s->int_mask;
@@ -365,6 +374,19 @@ static void loongarch_pch_pic_reset(DeviceState *d)
s->int_polarity = 0x0;
}
+static void loongarch_pch_pic_realize(DeviceState *dev, Error **errp)
+{
+ LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(dev);
+
+ if (!s->irq_num || s->irq_num > VIRT_PCH_PIC_IRQ_NUM) {
+ error_setg(errp, "Invalid 'pic_irq_num'");
+ return;
+ }
+
+ qdev_init_gpio_out(dev, s->parent_irq, s->irq_num);
+ qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num);
+}
+
static void loongarch_pch_pic_init(Object *obj)
{
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj);
@@ -382,10 +404,13 @@ static void loongarch_pch_pic_init(Object *obj)
sysbus_init_mmio(sbd, &s->iomem8);
sysbus_init_mmio(sbd, &s->iomem32_high);
- qdev_init_gpio_out(DEVICE(obj), s->parent_irq, PCH_PIC_IRQ_NUM);
- qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
}
+static Property loongarch_pch_pic_properties[] = {
+ DEFINE_PROP_UINT32("pch_pic_irq_num", LoongArchPCHPIC, irq_num, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static const VMStateDescription vmstate_loongarch_pch_pic = {
.name = TYPE_LOONGARCH_PCH_PIC,
.version_id = 1,
@@ -411,8 +436,10 @@ static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->realize = loongarch_pch_pic_realize;
dc->reset = loongarch_pch_pic_reset;
dc->vmsd = &vmstate_loongarch_pch_pic;
+ device_class_set_props(dc, loongarch_pch_pic_properties);
}
static const TypeInfo loongarch_pch_pic_info = {
diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c
index c2dfacf..5522ede 100644
--- a/hw/intc/sifive_plic.c
+++ b/hw/intc/sifive_plic.c
@@ -42,7 +42,6 @@ static PLICMode char_to_mode(char c)
switch (c) {
case 'U': return PLICMode_U;
case 'S': return PLICMode_S;
- case 'H': return PLICMode_H;
case 'M': return PLICMode_M;
default:
error_report("plic: invalid mode '%c'", c);
@@ -78,6 +77,7 @@ static uint32_t sifive_plic_claimed(SiFivePLICState *plic, uint32_t addrid)
uint32_t max_irq = 0;
uint32_t max_prio = plic->target_priority[addrid];
int i, j;
+ int num_irq_in_word = 32;
for (i = 0; i < plic->bitfield_words; i++) {
uint32_t pending_enabled_not_claimed =
@@ -88,7 +88,16 @@ static uint32_t sifive_plic_claimed(SiFivePLICState *plic, uint32_t addrid)
continue;
}
- for (j = 0; j < 32; j++) {
+ if (i == (plic->bitfield_words - 1)) {
+ /*
+ * If plic->num_sources is not multiple of 32, num-of-irq in last
+ * word is not 32. Compute the num-of-irq of last word to avoid
+ * out-of-bound access of source_priority array.
+ */
+ num_irq_in_word = plic->num_sources - ((plic->bitfield_words - 1) << 5);
+ }
+
+ for (j = 0; j < num_irq_in_word; j++) {
int irq = (i << 5) + j;
uint32_t prio = plic->source_priority[irq];
int enabled = pending_enabled_not_claimed & (1 << j);
@@ -131,10 +140,11 @@ static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size)
SiFivePLICState *plic = opaque;
if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) {
- uint32_t irq = ((addr - plic->priority_base) >> 2) + 1;
+ uint32_t irq = (addr - plic->priority_base) >> 2;
return plic->source_priority[irq];
- } else if (addr_between(addr, plic->pending_base, plic->num_sources >> 3)) {
+ } else if (addr_between(addr, plic->pending_base,
+ (plic->num_sources + 31) >> 3)) {
uint32_t word = (addr - plic->pending_base) >> 2;
return plic->pending[word];
@@ -178,7 +188,7 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
SiFivePLICState *plic = opaque;
if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) {
- uint32_t irq = ((addr - plic->priority_base) >> 2) + 1;
+ uint32_t irq = (addr - plic->priority_base) >> 2;
if (((plic->num_priorities + 1) & plic->num_priorities) == 0) {
/*
@@ -193,7 +203,7 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
sifive_plic_update(plic);
}
} else if (addr_between(addr, plic->pending_base,
- plic->num_sources >> 3)) {
+ (plic->num_sources + 31) >> 3)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid pending write: 0x%" HWADDR_PRIx "",
__func__, addr);
@@ -281,7 +291,7 @@ static void sifive_plic_reset(DeviceState *dev)
*/
static void parse_hart_config(SiFivePLICState *plic)
{
- int addrid, hartid, modes;
+ int addrid, hartid, modes, m;
const char *p;
char c;
@@ -290,11 +300,13 @@ static void parse_hart_config(SiFivePLICState *plic)
p = plic->hart_config;
while ((c = *p++)) {
if (c == ',') {
- addrid += ctpop8(modes);
- modes = 0;
- hartid++;
+ if (modes) {
+ addrid += ctpop8(modes);
+ hartid++;
+ modes = 0;
+ }
} else {
- int m = 1 << char_to_mode(c);
+ m = 1 << char_to_mode(c);
if (modes == (modes | m)) {
error_report("plic: duplicate mode '%c' in config: %s",
c, plic->hart_config);
@@ -305,8 +317,9 @@ static void parse_hart_config(SiFivePLICState *plic)
}
if (modes) {
addrid += ctpop8(modes);
+ hartid++;
+ modes = 0;
}
- hartid++;
plic->num_addrs = addrid;
plic->num_harts = hartid;
@@ -317,11 +330,16 @@ static void parse_hart_config(SiFivePLICState *plic)
p = plic->hart_config;
while ((c = *p++)) {
if (c == ',') {
- hartid++;
+ if (modes) {
+ hartid++;
+ modes = 0;
+ }
} else {
+ m = char_to_mode(c);
plic->addr_config[addrid].addrid = addrid;
plic->addr_config[addrid].hartid = hartid;
- plic->addr_config[addrid].mode = char_to_mode(c);
+ plic->addr_config[addrid].mode = m;
+ modes |= (1 << m);
addrid++;
}
}
@@ -346,6 +364,11 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp)
parse_hart_config(s);
+ if (!s->num_sources) {
+ error_setg(errp, "plic: invalid number of interrupt sources");
+ return;
+ }
+
s->bitfield_words = (s->num_sources + 31) >> 5;
s->num_enables = s->bitfield_words * s->num_addrs;
s->source_priority = g_new0(uint32_t, s->num_sources);
@@ -362,7 +385,8 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp)
s->m_external_irqs = g_malloc(sizeof(qemu_irq) * s->num_harts);
qdev_init_gpio_out(dev, s->m_external_irqs, s->num_harts);
- /* We can't allow the supervisor to control SEIP as this would allow the
+ /*
+ * We can't allow the supervisor to control SEIP as this would allow the
* supervisor to clear a pending external interrupt which will result in
* lost a interrupt in the case a PLIC is attached. The SEIP bit must be
* hardware controlled when a PLIC is attached.
@@ -370,8 +394,8 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp)
for (i = 0; i < s->num_harts; i++) {
RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) {
- error_report("SEIP already claimed");
- exit(1);
+ error_setg(errp, "SEIP already claimed");
+ return;
}
}
@@ -402,8 +426,10 @@ static const VMStateDescription vmstate_sifive_plic = {
static Property sifive_plic_properties[] = {
DEFINE_PROP_STRING("hart-config", SiFivePLICState, hart_config),
DEFINE_PROP_UINT32("hartid-base", SiFivePLICState, hartid_base, 0),
- DEFINE_PROP_UINT32("num-sources", SiFivePLICState, num_sources, 0),
+ /* number of interrupt sources including interrupt source 0 */
+ DEFINE_PROP_UINT32("num-sources", SiFivePLICState, num_sources, 1),
DEFINE_PROP_UINT32("num-priorities", SiFivePLICState, num_priorities, 0),
+ /* interrupt priority register base starting from source 0 */
DEFINE_PROP_UINT32("priority-base", SiFivePLICState, priority_base, 0),
DEFINE_PROP_UINT32("pending-base", SiFivePLICState, pending_base, 0),
DEFINE_PROP_UINT32("enable-base", SiFivePLICState, enable_base, 0),
@@ -476,11 +502,11 @@ DeviceState *sifive_plic_create(hwaddr addr, char *hart_config,
CPUState *cpu = qemu_get_cpu(cpu_num);
if (plic->addr_config[i].mode == PLICMode_M) {
- qdev_connect_gpio_out(dev, num_harts - plic->hartid_base + cpu_num,
+ qdev_connect_gpio_out(dev, cpu_num - hartid_base + num_harts,
qdev_get_gpio_in(DEVICE(cpu), IRQ_M_EXT));
}
if (plic->addr_config[i].mode == PLICMode_S) {
- qdev_connect_gpio_out(dev, cpu_num,
+ qdev_connect_gpio_out(dev, cpu_num - hartid_base,
qdev_get_gpio_in(DEVICE(cpu), IRQ_S_EXT));
}
}
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index c8a495e..66be925 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -553,7 +553,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
LoongArchCPU *lacpu;
CPULoongArchState *env;
CPUState *cpu_state;
- int cpu, pin, i;
+ int cpu, pin, i, start, num;
ipi = qdev_new(TYPE_LOONGARCH_IPI);
sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
@@ -616,6 +616,8 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
}
pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
+ num = VIRT_PCH_PIC_IRQ_NUM;
+ qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
d = SYS_BUS_DEVICE(pch_pic);
sysbus_realize_and_unref(d, &error_fatal);
memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
@@ -627,20 +629,23 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO,
sysbus_mmio_get_region(d, 2));
- /* Connect 64 pch_pic irqs to extioi */
- for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
+ /* Connect pch_pic irqs to extioi */
+ for (int i = 0; i < num; i++) {
qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
}
pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
- qdev_prop_set_uint32(pch_msi, "msi_irq_base", PCH_MSI_IRQ_START);
+ start = num;
+ num = EXTIOI_IRQS - start;
+ qdev_prop_set_uint32(pch_msi, "msi_irq_base", start);
+ qdev_prop_set_uint32(pch_msi, "msi_irq_num", num);
d = SYS_BUS_DEVICE(pch_msi);
sysbus_realize_and_unref(d, &error_fatal);
sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
- for (i = 0; i < PCH_MSI_IRQ_NUM; i++) {
- /* Connect 192 pch_msi irqs to extioi */
+ for (i = 0; i < num; i++) {
+ /* Connect pch_msi irqs to extioi */
qdev_connect_gpio_out(DEVICE(d), i,
- qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
+ qdev_get_gpio_in(extioi, i + start));
}
loongarch_devices_init(pch_pic, lams);
diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c
index 2db5e10..73437cd 100644
--- a/hw/mips/mips_int.c
+++ b/hw/mips/mips_int.c
@@ -32,17 +32,12 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level)
MIPSCPU *cpu = opaque;
CPUMIPSState *env = &cpu->env;
CPUState *cs = CPU(cpu);
- bool locked = false;
if (irq < 0 || irq > 7) {
return;
}
- /* Make sure locking works even if BQL is already held by the caller */
- if (!qemu_mutex_iothread_locked()) {
- locked = true;
- qemu_mutex_lock_iothread();
- }
+ QEMU_IOTHREAD_LOCK_GUARD();
if (level) {
env->CP0_Cause |= 1 << (irq + CP0Ca_IP);
@@ -59,10 +54,6 @@ static void cpu_mips_irq_request(void *opaque, int irq, int level)
} else {
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
-
- if (locked) {
- qemu_mutex_unlock_iothread();
- }
}
void cpu_mips_irq_init_cpu(MIPSCPU *cpu)
diff --git a/hw/misc/imx6ul_ccm.c b/hw/misc/imx6ul_ccm.c
index a65d031..e01bb68 100644
--- a/hw/misc/imx6ul_ccm.c
+++ b/hw/misc/imx6ul_ccm.c
@@ -522,12 +522,6 @@ static uint32_t imx6ul_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
case CLK_32k:
freq = CKIL_FREQ;
break;
- case CLK_HIGH:
- freq = CKIH_FREQ;
- break;
- case CLK_HIGH_DIV:
- freq = CKIH_FREQ / 8;
- break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
TYPE_IMX6UL_CCM, __func__, clock);
diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c
index 075159e..f135ec7 100644
--- a/hw/misc/imx7_ccm.c
+++ b/hw/misc/imx7_ccm.c
@@ -16,6 +16,10 @@
#include "hw/misc/imx7_ccm.h"
#include "migration/vmstate.h"
+#include "trace.h"
+
+#define CKIH_FREQ 24000000 /* 24MHz crystal input */
+
static void imx7_analog_reset(DeviceState *dev)
{
IMX7AnalogState *s = IMX7_ANALOG(dev);
@@ -219,16 +223,43 @@ static const VMStateDescription vmstate_imx7_ccm = {
static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
{
/*
- * This function is "consumed" by GPT emulation code, however on
- * i.MX7 each GPT block can have their own clock root. This means
- * that this functions needs somehow to know requester's identity
- * and the way to pass it: be it via additional IMXClk constants
- * or by adding another argument to this method needs to be
- * figured out
+ * This function is "consumed" by GPT emulation code. Some clocks
+ * have fixed frequencies and we can provide requested frequency
+ * easily. However for CCM provided clocks (like IPG) each GPT
+ * timer can have its own clock root.
+ * This means we need additionnal information when calling this
+ * function to know the requester's identity.
*/
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Not implemented\n",
- TYPE_IMX7_CCM, __func__);
- return 0;
+ uint32_t freq = 0;
+
+ switch (clock) {
+ case CLK_NONE:
+ break;
+ case CLK_32k:
+ freq = CKIL_FREQ;
+ break;
+ case CLK_HIGH:
+ freq = CKIH_FREQ;
+ break;
+ case CLK_IPG:
+ case CLK_IPG_HIGH:
+ /*
+ * For now we don't have a way to figure out the device this
+ * function is called for. Until then the IPG derived clocks
+ * are left unimplemented.
+ */
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Clock %d Not implemented\n",
+ TYPE_IMX7_CCM, __func__, clock);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
+ TYPE_IMX7_CCM, __func__, clock);
+ break;
+ }
+
+ trace_ccm_clock_freq(clock, freq);
+
+ return freq;
}
static void imx7_ccm_class_init(ObjectClass *klass, void *data)
diff --git a/hw/misc/mchp_pfsoc_ioscb.c b/hw/misc/mchp_pfsoc_ioscb.c
index f4fd55a..a71d134 100644
--- a/hw/misc/mchp_pfsoc_ioscb.c
+++ b/hw/misc/mchp_pfsoc_ioscb.c
@@ -24,6 +24,7 @@
#include "qemu/bitops.h"
#include "qemu/log.h"
#include "qapi/error.h"
+#include "hw/irq.h"
#include "hw/sysbus.h"
#include "hw/misc/mchp_pfsoc_ioscb.h"
@@ -33,6 +34,10 @@
*/
#define IOSCB_WHOLE_REG_SIZE 0x10000000
#define IOSCB_SUBMOD_REG_SIZE 0x1000
+#define IOSCB_CCC_REG_SIZE 0x2000000
+#define IOSCB_CTRL_REG_SIZE 0x800
+#define IOSCB_QSPIXIP_REG_SIZE 0x200
+
/*
* There are many sub-modules in the IOSCB module.
@@ -44,7 +49,10 @@
#define IOSCB_LANE01_BASE 0x06500000
#define IOSCB_LANE23_BASE 0x06510000
#define IOSCB_CTRL_BASE 0x07020000
+#define IOSCB_QSPIXIP_BASE 0x07020100
+#define IOSCB_MAILBOX_BASE 0x07020800
#define IOSCB_CFG_BASE 0x07080000
+#define IOSCB_CCC_BASE 0x08000000
#define IOSCB_PLL_MSS_BASE 0x0E001000
#define IOSCB_CFM_MSS_BASE 0x0E002000
#define IOSCB_PLL_DDR_BASE 0x0E010000
@@ -141,6 +149,58 @@ static const MemoryRegionOps mchp_pfsoc_io_calib_ddr_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+#define SERVICES_CR 0x50
+#define SERVICES_SR 0x54
+#define SERVICES_STATUS_SHIFT 16
+
+static uint64_t mchp_pfsoc_ctrl_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ uint32_t val = 0;
+
+ switch (offset) {
+ case SERVICES_SR:
+ /*
+ * Although some services have no error codes, most do. All services
+ * that do implement errors, begin their error codes at 1. Treat all
+ * service requests as failures & return 1.
+ * See the "PolarFire® FPGA and PolarFire SoC FPGA System Services"
+ * user guide for more information on service error codes.
+ */
+ val = 1u << SERVICES_STATUS_SHIFT;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
+ "(size %d, offset 0x%" HWADDR_PRIx ")\n",
+ __func__, size, offset);
+ }
+
+ return val;
+}
+
+static void mchp_pfsoc_ctrl_write(void *opaque, hwaddr offset,
+ uint64_t value, unsigned size)
+{
+ MchpPfSoCIoscbState *s = opaque;
+
+ switch (offset) {
+ case SERVICES_CR:
+ qemu_irq_raise(s->irq);
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
+ "(size %d, value 0x%" PRIx64
+ ", offset 0x%" HWADDR_PRIx ")\n",
+ __func__, size, value, offset);
+ }
+}
+
+static const MemoryRegionOps mchp_pfsoc_ctrl_ops = {
+ .read = mchp_pfsoc_ctrl_read,
+ .write = mchp_pfsoc_ctrl_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp)
{
MchpPfSoCIoscbState *s = MCHP_PFSOC_IOSCB(dev);
@@ -160,14 +220,26 @@ static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp)
"mchp.pfsoc.ioscb.lane23", IOSCB_SUBMOD_REG_SIZE);
memory_region_add_subregion(&s->container, IOSCB_LANE23_BASE, &s->lane23);
- memory_region_init_io(&s->ctrl, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
- "mchp.pfsoc.ioscb.ctrl", IOSCB_SUBMOD_REG_SIZE);
+ memory_region_init_io(&s->ctrl, OBJECT(s), &mchp_pfsoc_ctrl_ops, s,
+ "mchp.pfsoc.ioscb.ctrl", IOSCB_CTRL_REG_SIZE);
memory_region_add_subregion(&s->container, IOSCB_CTRL_BASE, &s->ctrl);
+ memory_region_init_io(&s->qspixip, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
+ "mchp.pfsoc.ioscb.qspixip", IOSCB_QSPIXIP_REG_SIZE);
+ memory_region_add_subregion(&s->container, IOSCB_QSPIXIP_BASE, &s->qspixip);
+
+ memory_region_init_io(&s->mailbox, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
+ "mchp.pfsoc.ioscb.mailbox", IOSCB_SUBMOD_REG_SIZE);
+ memory_region_add_subregion(&s->container, IOSCB_MAILBOX_BASE, &s->mailbox);
+
memory_region_init_io(&s->cfg, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
"mchp.pfsoc.ioscb.cfg", IOSCB_SUBMOD_REG_SIZE);
memory_region_add_subregion(&s->container, IOSCB_CFG_BASE, &s->cfg);
+ memory_region_init_io(&s->ccc, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
+ "mchp.pfsoc.ioscb.ccc", IOSCB_CCC_REG_SIZE);
+ memory_region_add_subregion(&s->container, IOSCB_CCC_BASE, &s->ccc);
+
memory_region_init_io(&s->pll_mss, OBJECT(s), &mchp_pfsoc_pll_ops, s,
"mchp.pfsoc.ioscb.pll_mss", IOSCB_SUBMOD_REG_SIZE);
memory_region_add_subregion(&s->container, IOSCB_PLL_MSS_BASE, &s->pll_mss);
@@ -216,6 +288,8 @@ static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp)
IOSCB_SUBMOD_REG_SIZE);
memory_region_add_subregion(&s->container, IOSCB_IO_CALIB_SGMII_BASE,
&s->io_calib_sgmii);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
}
static void mchp_pfsoc_ioscb_class_init(ObjectClass *klass, void *data)
diff --git a/hw/misc/mchp_pfsoc_sysreg.c b/hw/misc/mchp_pfsoc_sysreg.c
index 89571ed..7876fe0 100644
--- a/hw/misc/mchp_pfsoc_sysreg.c
+++ b/hw/misc/mchp_pfsoc_sysreg.c
@@ -24,10 +24,12 @@
#include "qemu/bitops.h"
#include "qemu/log.h"
#include "qapi/error.h"
+#include "hw/irq.h"
#include "hw/sysbus.h"
#include "hw/misc/mchp_pfsoc_sysreg.h"
#define ENVM_CR 0xb8
+#define MESSAGE_INT 0x118c
static uint64_t mchp_pfsoc_sysreg_read(void *opaque, hwaddr offset,
unsigned size)
@@ -52,10 +54,17 @@ static uint64_t mchp_pfsoc_sysreg_read(void *opaque, hwaddr offset,
static void mchp_pfsoc_sysreg_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
- qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
- "(size %d, value 0x%" PRIx64
- ", offset 0x%" HWADDR_PRIx ")\n",
- __func__, size, value, offset);
+ MchpPfSoCSysregState *s = opaque;
+ switch (offset) {
+ case MESSAGE_INT:
+ qemu_irq_lower(s->irq);
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
+ "(size %d, value 0x%" PRIx64
+ ", offset 0x%" HWADDR_PRIx ")\n",
+ __func__, size, value, offset);
+ }
}
static const MemoryRegionOps mchp_pfsoc_sysreg_ops = {
@@ -73,6 +82,7 @@ static void mchp_pfsoc_sysreg_realize(DeviceState *dev, Error **errp)
"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 void mchp_pfsoc_sysreg_class_init(ObjectClass *klass, void *data)
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
index 8c11b23..c862d96 100644
--- a/hw/net/imx_fec.c
+++ b/hw/net/imx_fec.c
@@ -1068,9 +1068,9 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
return 0;
}
- /* 4 bytes for the CRC. */
- size += 4;
crc = cpu_to_be32(crc32(~0, buf, size));
+ /* Increase size by 4, loop below reads the last 4 bytes from crc_ptr. */
+ size += 4;
crc_ptr = (uint8_t *) &crc;
/* Huge frames are truncated. */
@@ -1164,9 +1164,9 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
return 0;
}
- /* 4 bytes for the CRC. */
- size += 4;
crc = cpu_to_be32(crc32(~0, buf, size));
+ /* Increase size by 4, loop below reads the last 4 bytes from crc_ptr. */
+ size += 4;
crc_ptr = (uint8_t *) &crc;
if (shift16) {
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index dc86c1c..4e816c6 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -44,13 +44,9 @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
{
CPUPPCState *env = &cpu->env;
unsigned int old_pending;
- bool locked = false;
/* We may already have the BQL if coming from the reset path */
- if (!qemu_mutex_iothread_locked()) {
- locked = true;
- qemu_mutex_lock_iothread();
- }
+ QEMU_IOTHREAD_LOCK_GUARD();
old_pending = env->pending_interrupts;
@@ -67,10 +63,6 @@ void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
CPU(cpu)->interrupt_request);
-
- if (locked) {
- qemu_mutex_unlock_iothread();
- }
}
/* PowerPC 6xx / 7xx internal IRQ controller */
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 79ff61c..4550b3b 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -4,6 +4,8 @@ config RISCV_NUMA
config IBEX
bool
+# RISC-V machines in alphabetical order
+
config MICROCHIP_PFSOC
bool
select CADENCE_SDHCI
@@ -11,7 +13,6 @@ config MICROCHIP_PFSOC
select MCHP_PFSOC_IOSCB
select MCHP_PFSOC_MMUART
select MCHP_PFSOC_SYSREG
- select MSI_NONBROKEN
select RISCV_ACLINT
select SIFIVE_PDMA
select SIFIVE_PLIC
@@ -20,14 +21,8 @@ config MICROCHIP_PFSOC
config OPENTITAN
bool
select IBEX
- select UNIMP
-
-config SHAKTI_C
- bool
- select UNIMP
- select SHAKTI_UART
- select RISCV_ACLINT
select SIFIVE_PLIC
+ select UNIMP
config RISCV_VIRT
bool
@@ -37,7 +32,6 @@ config RISCV_VIRT
imply TPM_TIS_SYSBUS
select RISCV_NUMA
select GOLDFISH_RTC
- select MSI_NONBROKEN
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01
@@ -51,9 +45,15 @@ config RISCV_VIRT
select FW_CFG_DMA
select PLATFORM_BUS
+config SHAKTI_C
+ bool
+ select RISCV_ACLINT
+ select SHAKTI_UART
+ select SIFIVE_PLIC
+ select UNIMP
+
config SIFIVE_E
bool
- select MSI_NONBROKEN
select RISCV_ACLINT
select SIFIVE_GPIO
select SIFIVE_PLIC
@@ -64,7 +64,6 @@ config SIFIVE_E
config SIFIVE_U
bool
select CADENCE
- select MSI_NONBROKEN
select RISCV_ACLINT
select SIFIVE_GPIO
select SIFIVE_PDMA
@@ -82,6 +81,5 @@ config SPIKE
bool
select RISCV_NUMA
select HTIF
- select MSI_NONBROKEN
select RISCV_ACLINT
select SIFIVE_PLIC
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index a821263..b10321b 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -86,58 +86,61 @@
* describes the complete IOSCB modules memory maps
*/
static const MemMapEntry microchip_pfsoc_memmap[] = {
- [MICROCHIP_PFSOC_RSVD0] = { 0x0, 0x100 },
- [MICROCHIP_PFSOC_DEBUG] = { 0x100, 0xf00 },
- [MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 },
- [MICROCHIP_PFSOC_BUSERR_UNIT0] = { 0x1700000, 0x1000 },
- [MICROCHIP_PFSOC_BUSERR_UNIT1] = { 0x1701000, 0x1000 },
- [MICROCHIP_PFSOC_BUSERR_UNIT2] = { 0x1702000, 0x1000 },
- [MICROCHIP_PFSOC_BUSERR_UNIT3] = { 0x1703000, 0x1000 },
- [MICROCHIP_PFSOC_BUSERR_UNIT4] = { 0x1704000, 0x1000 },
- [MICROCHIP_PFSOC_CLINT] = { 0x2000000, 0x10000 },
- [MICROCHIP_PFSOC_L2CC] = { 0x2010000, 0x1000 },
- [MICROCHIP_PFSOC_DMA] = { 0x3000000, 0x100000 },
- [MICROCHIP_PFSOC_L2LIM] = { 0x8000000, 0x2000000 },
- [MICROCHIP_PFSOC_PLIC] = { 0xc000000, 0x4000000 },
- [MICROCHIP_PFSOC_MMUART0] = { 0x20000000, 0x1000 },
- [MICROCHIP_PFSOC_WDOG0] = { 0x20001000, 0x1000 },
- [MICROCHIP_PFSOC_SYSREG] = { 0x20002000, 0x2000 },
- [MICROCHIP_PFSOC_AXISW] = { 0x20004000, 0x1000 },
- [MICROCHIP_PFSOC_MPUCFG] = { 0x20005000, 0x1000 },
- [MICROCHIP_PFSOC_FMETER] = { 0x20006000, 0x1000 },
- [MICROCHIP_PFSOC_DDR_SGMII_PHY] = { 0x20007000, 0x1000 },
- [MICROCHIP_PFSOC_EMMC_SD] = { 0x20008000, 0x1000 },
- [MICROCHIP_PFSOC_DDR_CFG] = { 0x20080000, 0x40000 },
- [MICROCHIP_PFSOC_MMUART1] = { 0x20100000, 0x1000 },
- [MICROCHIP_PFSOC_MMUART2] = { 0x20102000, 0x1000 },
- [MICROCHIP_PFSOC_MMUART3] = { 0x20104000, 0x1000 },
- [MICROCHIP_PFSOC_MMUART4] = { 0x20106000, 0x1000 },
- [MICROCHIP_PFSOC_WDOG1] = { 0x20101000, 0x1000 },
- [MICROCHIP_PFSOC_WDOG2] = { 0x20103000, 0x1000 },
- [MICROCHIP_PFSOC_WDOG3] = { 0x20105000, 0x1000 },
- [MICROCHIP_PFSOC_WDOG4] = { 0x20106000, 0x1000 },
- [MICROCHIP_PFSOC_SPI0] = { 0x20108000, 0x1000 },
- [MICROCHIP_PFSOC_SPI1] = { 0x20109000, 0x1000 },
- [MICROCHIP_PFSOC_I2C0] = { 0x2010a000, 0x1000 },
- [MICROCHIP_PFSOC_I2C1] = { 0x2010b000, 0x1000 },
- [MICROCHIP_PFSOC_CAN0] = { 0x2010c000, 0x1000 },
- [MICROCHIP_PFSOC_CAN1] = { 0x2010d000, 0x1000 },
- [MICROCHIP_PFSOC_GEM0] = { 0x20110000, 0x2000 },
- [MICROCHIP_PFSOC_GEM1] = { 0x20112000, 0x2000 },
- [MICROCHIP_PFSOC_GPIO0] = { 0x20120000, 0x1000 },
- [MICROCHIP_PFSOC_GPIO1] = { 0x20121000, 0x1000 },
- [MICROCHIP_PFSOC_GPIO2] = { 0x20122000, 0x1000 },
- [MICROCHIP_PFSOC_RTC] = { 0x20124000, 0x1000 },
- [MICROCHIP_PFSOC_ENVM_CFG] = { 0x20200000, 0x1000 },
- [MICROCHIP_PFSOC_ENVM_DATA] = { 0x20220000, 0x20000 },
- [MICROCHIP_PFSOC_USB] = { 0x20201000, 0x1000 },
- [MICROCHIP_PFSOC_QSPI_XIP] = { 0x21000000, 0x1000000 },
- [MICROCHIP_PFSOC_IOSCB] = { 0x30000000, 0x10000000 },
- [MICROCHIP_PFSOC_FABRIC_FIC3] = { 0x40000000, 0x20000000 },
- [MICROCHIP_PFSOC_DRAM_LO] = { 0x80000000, 0x40000000 },
- [MICROCHIP_PFSOC_DRAM_LO_ALIAS] = { 0xc0000000, 0x40000000 },
- [MICROCHIP_PFSOC_DRAM_HI] = { 0x1000000000, 0x0 },
- [MICROCHIP_PFSOC_DRAM_HI_ALIAS] = { 0x1400000000, 0x0 },
+ [MICROCHIP_PFSOC_RSVD0] = { 0x0, 0x100 },
+ [MICROCHIP_PFSOC_DEBUG] = { 0x100, 0xf00 },
+ [MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 },
+ [MICROCHIP_PFSOC_BUSERR_UNIT0] = { 0x1700000, 0x1000 },
+ [MICROCHIP_PFSOC_BUSERR_UNIT1] = { 0x1701000, 0x1000 },
+ [MICROCHIP_PFSOC_BUSERR_UNIT2] = { 0x1702000, 0x1000 },
+ [MICROCHIP_PFSOC_BUSERR_UNIT3] = { 0x1703000, 0x1000 },
+ [MICROCHIP_PFSOC_BUSERR_UNIT4] = { 0x1704000, 0x1000 },
+ [MICROCHIP_PFSOC_CLINT] = { 0x2000000, 0x10000 },
+ [MICROCHIP_PFSOC_L2CC] = { 0x2010000, 0x1000 },
+ [MICROCHIP_PFSOC_DMA] = { 0x3000000, 0x100000 },
+ [MICROCHIP_PFSOC_L2LIM] = { 0x8000000, 0x2000000 },
+ [MICROCHIP_PFSOC_PLIC] = { 0xc000000, 0x4000000 },
+ [MICROCHIP_PFSOC_MMUART0] = { 0x20000000, 0x1000 },
+ [MICROCHIP_PFSOC_WDOG0] = { 0x20001000, 0x1000 },
+ [MICROCHIP_PFSOC_SYSREG] = { 0x20002000, 0x2000 },
+ [MICROCHIP_PFSOC_AXISW] = { 0x20004000, 0x1000 },
+ [MICROCHIP_PFSOC_MPUCFG] = { 0x20005000, 0x1000 },
+ [MICROCHIP_PFSOC_FMETER] = { 0x20006000, 0x1000 },
+ [MICROCHIP_PFSOC_DDR_SGMII_PHY] = { 0x20007000, 0x1000 },
+ [MICROCHIP_PFSOC_EMMC_SD] = { 0x20008000, 0x1000 },
+ [MICROCHIP_PFSOC_DDR_CFG] = { 0x20080000, 0x40000 },
+ [MICROCHIP_PFSOC_MMUART1] = { 0x20100000, 0x1000 },
+ [MICROCHIP_PFSOC_MMUART2] = { 0x20102000, 0x1000 },
+ [MICROCHIP_PFSOC_MMUART3] = { 0x20104000, 0x1000 },
+ [MICROCHIP_PFSOC_MMUART4] = { 0x20106000, 0x1000 },
+ [MICROCHIP_PFSOC_WDOG1] = { 0x20101000, 0x1000 },
+ [MICROCHIP_PFSOC_WDOG2] = { 0x20103000, 0x1000 },
+ [MICROCHIP_PFSOC_WDOG3] = { 0x20105000, 0x1000 },
+ [MICROCHIP_PFSOC_WDOG4] = { 0x20106000, 0x1000 },
+ [MICROCHIP_PFSOC_SPI0] = { 0x20108000, 0x1000 },
+ [MICROCHIP_PFSOC_SPI1] = { 0x20109000, 0x1000 },
+ [MICROCHIP_PFSOC_I2C0] = { 0x2010a000, 0x1000 },
+ [MICROCHIP_PFSOC_I2C1] = { 0x2010b000, 0x1000 },
+ [MICROCHIP_PFSOC_CAN0] = { 0x2010c000, 0x1000 },
+ [MICROCHIP_PFSOC_CAN1] = { 0x2010d000, 0x1000 },
+ [MICROCHIP_PFSOC_GEM0] = { 0x20110000, 0x2000 },
+ [MICROCHIP_PFSOC_GEM1] = { 0x20112000, 0x2000 },
+ [MICROCHIP_PFSOC_GPIO0] = { 0x20120000, 0x1000 },
+ [MICROCHIP_PFSOC_GPIO1] = { 0x20121000, 0x1000 },
+ [MICROCHIP_PFSOC_GPIO2] = { 0x20122000, 0x1000 },
+ [MICROCHIP_PFSOC_RTC] = { 0x20124000, 0x1000 },
+ [MICROCHIP_PFSOC_ENVM_CFG] = { 0x20200000, 0x1000 },
+ [MICROCHIP_PFSOC_ENVM_DATA] = { 0x20220000, 0x20000 },
+ [MICROCHIP_PFSOC_USB] = { 0x20201000, 0x1000 },
+ [MICROCHIP_PFSOC_QSPI_XIP] = { 0x21000000, 0x1000000 },
+ [MICROCHIP_PFSOC_IOSCB] = { 0x30000000, 0x10000000 },
+ [MICROCHIP_PFSOC_FABRIC_FIC0] = { 0x2000000000, 0x1000000000 },
+ [MICROCHIP_PFSOC_FABRIC_FIC1] = { 0x3000000000, 0x1000000000 },
+ [MICROCHIP_PFSOC_FABRIC_FIC3] = { 0x40000000, 0x20000000 },
+ [MICROCHIP_PFSOC_DRAM_LO] = { 0x80000000, 0x40000000 },
+ [MICROCHIP_PFSOC_DRAM_LO_ALIAS] = { 0xc0000000, 0x40000000 },
+ [MICROCHIP_PFSOC_DRAM_HI] = { 0x1000000000, 0x0 },
+ [MICROCHIP_PFSOC_DRAM_HI_ALIAS] = { 0x1400000000, 0x0 },
+
};
static void microchip_pfsoc_soc_instance_init(Object *obj)
@@ -303,6 +306,9 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
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",
@@ -456,11 +462,22 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
sysbus_realize(SYS_BUS_DEVICE(&s->ioscb), errp);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ioscb), 0,
memmap[MICROCHIP_PFSOC_IOSCB].base);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ioscb), 0,
+ qdev_get_gpio_in(DEVICE(s->plic),
+ MICROCHIP_PFSOC_MAILBOX_IRQ));
/* FPGA Fabric */
create_unimplemented_device("microchip.pfsoc.fabricfic3",
memmap[MICROCHIP_PFSOC_FABRIC_FIC3].base,
memmap[MICROCHIP_PFSOC_FABRIC_FIC3].size);
+ /* FPGA Fabric */
+ create_unimplemented_device("microchip.pfsoc.fabricfic0",
+ memmap[MICROCHIP_PFSOC_FABRIC_FIC0].base,
+ memmap[MICROCHIP_PFSOC_FABRIC_FIC0].size);
+ /* FPGA Fabric */
+ create_unimplemented_device("microchip.pfsoc.fabricfic1",
+ memmap[MICROCHIP_PFSOC_FABRIC_FIC1].base,
+ memmap[MICROCHIP_PFSOC_FABRIC_FIC1].size);
/* QSPI Flash */
memory_region_init_rom(qspi_xip_mem, OBJECT(dev),
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index be7ff1e..85ffdac 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -28,8 +28,16 @@
#include "qemu/units.h"
#include "sysemu/sysemu.h"
+/*
+ * This version of the OpenTitan machine currently supports
+ * OpenTitan RTL version:
+ * <lowRISC/opentitan@d072ac505f82152678d6e04be95c72b728a347b8>
+ *
+ * MMIO mapping as per (specified commit):
+ * lowRISC/opentitan: hw/top_earlgrey/sw/autogen/top_earlgrey_memory.h
+ */
static const MemMapEntry ibex_memmap[] = {
- [IBEX_DEV_ROM] = { 0x00008000, 0x8000 },
+ [IBEX_DEV_ROM] = { 0x00008000, 0x8000 },
[IBEX_DEV_RAM] = { 0x10000000, 0x20000 },
[IBEX_DEV_FLASH] = { 0x20000000, 0x100000 },
[IBEX_DEV_UART] = { 0x40000000, 0x1000 },
@@ -38,17 +46,18 @@ static const MemMapEntry ibex_memmap[] = {
[IBEX_DEV_I2C] = { 0x40080000, 0x1000 },
[IBEX_DEV_PATTGEN] = { 0x400e0000, 0x1000 },
[IBEX_DEV_TIMER] = { 0x40100000, 0x1000 },
- [IBEX_DEV_SENSOR_CTRL] = { 0x40110000, 0x1000 },
[IBEX_DEV_OTP_CTRL] = { 0x40130000, 0x4000 },
[IBEX_DEV_LC_CTRL] = { 0x40140000, 0x1000 },
- [IBEX_DEV_USBDEV] = { 0x40150000, 0x1000 },
+ [IBEX_DEV_ALERT_HANDLER] = { 0x40150000, 0x1000 },
[IBEX_DEV_SPI_HOST0] = { 0x40300000, 0x1000 },
[IBEX_DEV_SPI_HOST1] = { 0x40310000, 0x1000 },
+ [IBEX_DEV_USBDEV] = { 0x40320000, 0x1000 },
[IBEX_DEV_PWRMGR] = { 0x40400000, 0x1000 },
[IBEX_DEV_RSTMGR] = { 0x40410000, 0x1000 },
[IBEX_DEV_CLKMGR] = { 0x40420000, 0x1000 },
[IBEX_DEV_PINMUX] = { 0x40460000, 0x1000 },
- [IBEX_DEV_PADCTRL] = { 0x40470000, 0x1000 },
+ [IBEX_DEV_AON_TIMER] = { 0x40470000, 0x1000 },
+ [IBEX_DEV_SENSOR_CTRL] = { 0x40490000, 0x1000 },
[IBEX_DEV_FLASH_CTRL] = { 0x41000000, 0x1000 },
[IBEX_DEV_AES] = { 0x41100000, 0x1000 },
[IBEX_DEV_HMAC] = { 0x41110000, 0x1000 },
@@ -59,10 +68,9 @@ static const MemMapEntry ibex_memmap[] = {
[IBEX_DEV_ENTROPY] = { 0x41160000, 0x1000 },
[IBEX_DEV_EDNO] = { 0x41170000, 0x1000 },
[IBEX_DEV_EDN1] = { 0x41180000, 0x1000 },
- [IBEX_DEV_ALERT_HANDLER] = { 0x411b0000, 0x1000 },
[IBEX_DEV_NMI_GEN] = { 0x411c0000, 0x1000 },
[IBEX_DEV_PERI] = { 0x411f0000, 0x10000 },
- [IBEX_DEV_PLIC] = { 0x48000000, 0x4005000 },
+ [IBEX_DEV_PLIC] = { 0x48000000, 0x4005000 },
[IBEX_DEV_FLASH_VIRTUAL] = { 0x80000000, 0x80000 },
};
@@ -165,10 +173,8 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
/* PLIC */
qdev_prop_set_string(DEVICE(&s->plic), "hart-config", "M");
- qdev_prop_set_uint32(DEVICE(&s->plic), "hartid-base", 0);
qdev_prop_set_uint32(DEVICE(&s->plic), "num-sources", 180);
qdev_prop_set_uint32(DEVICE(&s->plic), "num-priorities", 3);
- qdev_prop_set_uint32(DEVICE(&s->plic), "priority-base", 0x00);
qdev_prop_set_uint32(DEVICE(&s->plic), "pending-base", 0x1000);
qdev_prop_set_uint32(DEVICE(&s->plic), "enable-base", 0x2000);
qdev_prop_set_uint32(DEVICE(&s->plic), "enable-stride", 32);
@@ -265,8 +271,8 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
memmap[IBEX_DEV_CLKMGR].base, memmap[IBEX_DEV_CLKMGR].size);
create_unimplemented_device("riscv.lowrisc.ibex.pinmux",
memmap[IBEX_DEV_PINMUX].base, memmap[IBEX_DEV_PINMUX].size);
- create_unimplemented_device("riscv.lowrisc.ibex.padctrl",
- memmap[IBEX_DEV_PADCTRL].base, memmap[IBEX_DEV_PADCTRL].size);
+ create_unimplemented_device("riscv.lowrisc.ibex.aon_timer",
+ memmap[IBEX_DEV_AON_TIMER].base, memmap[IBEX_DEV_AON_TIMER].size);
create_unimplemented_device("riscv.lowrisc.ibex.usbdev",
memmap[IBEX_DEV_USBDEV].base, memmap[IBEX_DEV_USBDEV].size);
create_unimplemented_device("riscv.lowrisc.ibex.flash_ctrl",
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index b139824..b40a476 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -287,7 +287,8 @@ static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[SIFIVE_U_DEV_PLIC].base,
0x0, memmap[SIFIVE_U_DEV_PLIC].size);
- qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", 0x35);
+ qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev",
+ SIFIVE_U_PLIC_NUM_SOURCES - 1);
qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
g_free(cells);
diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c
index 1e1d752..13946ac 100644
--- a/hw/riscv/spike.c
+++ b/hw/riscv/spike.c
@@ -8,7 +8,6 @@
*
* 0) HTIF Console and Poweroff
* 1) CLINT (Timer and IPI)
- * 2) PLIC (Platform Level Interrupt Controller)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index a5bc735..94ff2a1 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -468,7 +468,8 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4);
qemu_fdt_setprop_cells(mc->fdt, plic_name, "reg",
0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size);
- qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", VIRTIO_NDEV);
+ qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev",
+ VIRT_IRQCHIP_NUM_SOURCES - 1);
riscv_socket_fdt_write_id(mc, mc->fdt, plic_name, socket);
qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle",
plic_phandles[socket]);
@@ -546,8 +547,6 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap,
riscv_socket_count(mc) * sizeof(uint32_t) * 4);
qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,num-ids",
VIRT_IRQCHIP_NUM_MSIS);
- qemu_fdt_setprop_cells(mc->fdt, imsic_name, "riscv,ipi-id",
- VIRT_IRQCHIP_IPI_MSI);
if (riscv_socket_count(mc) > 1) {
qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,hart-index-bits",
imsic_num_bits(imsic_max_hart_per_socket));
@@ -597,8 +596,6 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap,
riscv_socket_count(mc) * sizeof(uint32_t) * 4);
qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,num-ids",
VIRT_IRQCHIP_NUM_MSIS);
- qemu_fdt_setprop_cells(mc->fdt, imsic_name, "riscv,ipi-id",
- VIRT_IRQCHIP_IPI_MSI);
if (imsic_guest_bits) {
qemu_fdt_setprop_cell(mc->fdt, imsic_name, "riscv,guest-index-bits",
imsic_guest_bits);
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index ec0fa44..3a86978 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -6,6 +6,7 @@
* Originally written by Hans Jiang
* Updated by Peter Chubb
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
+ * Updated by Axel Heider
*
* This code is licensed under GPL version 2 or later. See
* the COPYING file in the top-level directory.
@@ -66,73 +67,54 @@ static const IMXClk imx_epit_clocks[] = {
*/
static void imx_epit_update_int(IMXEPITState *s)
{
- if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
+ if ((s->sr & SR_OCIF) && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
qemu_irq_raise(s->irq);
} else {
qemu_irq_lower(s->irq);
}
}
-/*
- * Must be called from within a ptimer_transaction_begin/commit block
- * for both s->timer_cmp and s->timer_reload.
- */
-static void imx_epit_set_freq(IMXEPITState *s)
+static uint32_t imx_epit_get_freq(IMXEPITState *s)
{
- uint32_t clksrc;
- uint32_t prescaler;
-
- clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
- prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
-
- s->freq = imx_ccm_get_clock_frequency(s->ccm,
- imx_epit_clocks[clksrc]) / prescaler;
-
- DPRINTF("Setting ptimer frequency to %u\n", s->freq);
-
- if (s->freq) {
- ptimer_set_freq(s->timer_reload, s->freq);
- ptimer_set_freq(s->timer_cmp, s->freq);
- }
+ uint32_t clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, CR_CLKSRC_BITS);
+ uint32_t prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, CR_PRESCALE_BITS);
+ uint32_t f_in = imx_ccm_get_clock_frequency(s->ccm, imx_epit_clocks[clksrc]);
+ uint32_t freq = f_in / prescaler;
+ DPRINTF("ptimer frequency is %u\n", freq);
+ return freq;
}
-static void imx_epit_reset(DeviceState *dev)
+/*
+ * This is called both on hardware (device) reset and software reset.
+ */
+static void imx_epit_reset(IMXEPITState *s, bool is_hard_reset)
{
- IMXEPITState *s = IMX_EPIT(dev);
-
- /*
- * Soft reset doesn't touch some bits; hard reset clears them
- */
- s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
+ /* Soft reset doesn't touch some bits; hard reset clears them */
+ if (is_hard_reset) {
+ s->cr = 0;
+ } else {
+ s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
+ }
s->sr = 0;
s->lr = EPIT_TIMER_MAX;
s->cmp = 0;
- s->cnt = 0;
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
- /* stop both timers */
+
+ /*
+ * The reset switches off the input clock, so even if the CR.EN is still
+ * set, the timers are no longer running.
+ */
+ assert(imx_epit_get_freq(s) == 0);
ptimer_stop(s->timer_cmp);
ptimer_stop(s->timer_reload);
- /* compute new frequency */
- imx_epit_set_freq(s);
/* init both timers to EPIT_TIMER_MAX */
ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
- if (s->freq && (s->cr & CR_EN)) {
- /* if the timer is still enabled, restart it */
- ptimer_run(s->timer_reload, 0);
- }
ptimer_transaction_commit(s->timer_cmp);
ptimer_transaction_commit(s->timer_reload);
}
-static uint32_t imx_epit_update_count(IMXEPITState *s)
-{
- s->cnt = ptimer_get_count(s->timer_reload);
-
- return s->cnt;
-}
-
static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
{
IMXEPITState *s = IMX_EPIT(opaque);
@@ -156,8 +138,7 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
break;
case 4: /* CNT */
- imx_epit_update_count(s);
- reg_value = s->cnt;
+ reg_value = ptimer_get_count(s->timer_reload);
break;
default:
@@ -171,144 +152,219 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
return reg_value;
}
-/* Must be called from ptimer_transaction_begin/commit block for s->timer_cmp */
-static void imx_epit_reload_compare_timer(IMXEPITState *s)
+/*
+ * Must be called from a ptimer_transaction_begin/commit block for
+ * s->timer_cmp, but outside of a transaction block of s->timer_reload,
+ * so the proper counter value is read.
+ */
+static void imx_epit_update_compare_timer(IMXEPITState *s)
{
- if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) {
- /* if the compare feature is on and timers are running */
- uint32_t tmp = imx_epit_update_count(s);
- uint64_t next;
- if (tmp > s->cmp) {
- /* It'll fire in this round of the timer */
- next = tmp - s->cmp;
- } else { /* catch it next time around */
- next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr);
+ uint64_t counter = 0;
+ bool is_oneshot = false;
+ /*
+ * The compare timer only has to run if the timer peripheral is active
+ * and there is an input clock, Otherwise it can be switched off.
+ */
+ bool is_active = (s->cr & CR_EN) && imx_epit_get_freq(s);
+ if (is_active) {
+ /*
+ * Calculate next timeout for compare timer. Reading the reload
+ * counter returns proper results only if pending transactions
+ * on it are committed here. Otherwise stale values are be read.
+ */
+ counter = ptimer_get_count(s->timer_reload);
+ uint64_t limit = ptimer_get_limit(s->timer_cmp);
+ /*
+ * The compare timer is a periodic timer if the limit is at least
+ * the compare value. Otherwise it may fire at most once in the
+ * current round.
+ */
+ bool is_oneshot = (limit >= s->cmp);
+ if (counter >= s->cmp) {
+ /* The compare timer fires in the current round. */
+ counter -= s->cmp;
+ } else if (!is_oneshot) {
+ /*
+ * The compare timer fires after a reload, as it is below the
+ * compare value already in this round. Note that the counter
+ * value calculated below can be above the 32-bit limit, which
+ * is legal here because the compare timer is an internal
+ * helper ptimer only.
+ */
+ counter += limit - s->cmp;
+ } else {
+ /*
+ * The compare timer won't fire in this round, and the limit is
+ * set to a value below the compare value. This practically means
+ * it will never fire, so it can be switched off.
+ */
+ is_active = false;
}
- ptimer_set_count(s->timer_cmp, next);
}
+
+ /*
+ * Set the compare timer and let it run, or stop it. This is agnostic
+ * of CR.OCIEN bit, as this bit affects interrupt generation only. The
+ * compare timer needs to run even if no interrupts are to be generated,
+ * because the SR.OCIF bit must be updated also.
+ * Note that the timer might already be stopped or be running with
+ * counter values. However, finding out when an update is needed and
+ * when not is not trivial. It's much easier applying the setting again,
+ * as this does not harm either and the overhead is negligible.
+ */
+ if (is_active) {
+ ptimer_set_count(s->timer_cmp, counter);
+ ptimer_run(s->timer_cmp, is_oneshot ? 1 : 0);
+ } else {
+ ptimer_stop(s->timer_cmp);
+ }
+
}
-static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
- unsigned size)
+static void imx_epit_write_cr(IMXEPITState *s, uint32_t value)
{
- IMXEPITState *s = IMX_EPIT(opaque);
- uint64_t oldcr;
+ uint32_t oldcr = s->cr;
- DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2),
- (uint32_t)value);
-
- switch (offset >> 2) {
- case 0: /* CR */
+ s->cr = value & 0x03ffffff;
- oldcr = s->cr;
- s->cr = value & 0x03ffffff;
- if (s->cr & CR_SWR) {
- /* handle the reset */
- imx_epit_reset(DEVICE(s));
- /*
- * TODO: could we 'break' here? following operations appear
- * to duplicate the work imx_epit_reset() already did.
- */
- }
+ if (s->cr & CR_SWR) {
+ /*
+ * Reset clears CR.SWR again. It does not touch CR.EN, but the timers
+ * are still stopped because the input clock is disabled.
+ */
+ imx_epit_reset(s, false);
+ } else {
+ uint32_t freq;
+ uint32_t toggled_cr_bits = oldcr ^ s->cr;
+ /* re-initialize the limits if CR.RLD has changed */
+ bool set_limit = toggled_cr_bits & CR_RLD;
+ /* set the counter if the timer got just enabled and CR.ENMOD is set */
+ bool is_switched_on = (toggled_cr_bits & s->cr) & CR_EN;
+ bool set_counter = is_switched_on && (s->cr & CR_ENMOD);
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
-
- if (!(s->cr & CR_SWR)) {
- imx_epit_set_freq(s);
+ freq = imx_epit_get_freq(s);
+ if (freq) {
+ ptimer_set_freq(s->timer_reload, freq);
+ ptimer_set_freq(s->timer_cmp, freq);
}
- if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
- if (s->cr & CR_ENMOD) {
- if (s->cr & CR_RLD) {
- ptimer_set_limit(s->timer_reload, s->lr, 1);
- ptimer_set_limit(s->timer_cmp, s->lr, 1);
- } else {
- ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
- ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
- }
+ if (set_limit || set_counter) {
+ uint64_t limit = (s->cr & CR_RLD) ? s->lr : EPIT_TIMER_MAX;
+ ptimer_set_limit(s->timer_reload, limit, set_counter ? 1 : 0);
+ if (set_limit) {
+ ptimer_set_limit(s->timer_cmp, limit, 0);
}
-
- imx_epit_reload_compare_timer(s);
+ }
+ /*
+ * If there is an input clock and the peripheral is enabled, then
+ * ensure the wall clock timer is ticking. Otherwise stop the timers.
+ * The compare timer will be updated later.
+ */
+ if (freq && (s->cr & CR_EN)) {
ptimer_run(s->timer_reload, 0);
- if (s->cr & CR_OCIEN) {
- ptimer_run(s->timer_cmp, 0);
- } else {
- ptimer_stop(s->timer_cmp);
- }
- } else if (!(s->cr & CR_EN)) {
- /* stop both timers */
- ptimer_stop(s->timer_reload);
- ptimer_stop(s->timer_cmp);
- } else if (s->cr & CR_OCIEN) {
- if (!(oldcr & CR_OCIEN)) {
- imx_epit_reload_compare_timer(s);
- ptimer_run(s->timer_cmp, 0);
- }
} else {
- ptimer_stop(s->timer_cmp);
+ ptimer_stop(s->timer_reload);
}
-
- ptimer_transaction_commit(s->timer_cmp);
+ /* Commit changes to reload timer, so they can propagate. */
ptimer_transaction_commit(s->timer_reload);
- break;
+ /* Update compare timer based on the committed reload timer value. */
+ imx_epit_update_compare_timer(s);
+ ptimer_transaction_commit(s->timer_cmp);
+ }
- case 1: /* SR - ACK*/
- /* writing 1 to OCIF clear the OCIF bit */
- if (value & 0x01) {
- s->sr = 0;
- imx_epit_update_int(s);
- }
- break;
+ /*
+ * The interrupt state can change due to:
+ * - reset clears both SR.OCIF and CR.OCIE
+ * - write to CR.EN or CR.OCIE
+ */
+ imx_epit_update_int(s);
+}
- case 2: /* LR - set ticks */
- s->lr = value;
+static void imx_epit_write_sr(IMXEPITState *s, uint32_t value)
+{
+ /* writing 1 to SR.OCIF clears this bit and turns the interrupt off */
+ if (value & SR_OCIF) {
+ s->sr = 0; /* SR.OCIF is the only bit in this register anyway */
+ imx_epit_update_int(s);
+ }
+}
- ptimer_transaction_begin(s->timer_cmp);
- ptimer_transaction_begin(s->timer_reload);
- if (s->cr & CR_RLD) {
- /* Also set the limit if the LRD bit is set */
- /* If IOVW bit is set then set the timer value */
- ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
- ptimer_set_limit(s->timer_cmp, s->lr, 0);
- } else if (s->cr & CR_IOVW) {
- /* If IOVW bit is set then set the timer value */
- ptimer_set_count(s->timer_reload, s->lr);
- }
- /*
- * Commit the change to s->timer_reload, so it can propagate. Otherwise
- * the timer interrupt may not fire properly. The commit must happen
- * before calling imx_epit_reload_compare_timer(), which reads
- * s->timer_reload internally again.
- */
- ptimer_transaction_commit(s->timer_reload);
- imx_epit_reload_compare_timer(s);
- ptimer_transaction_commit(s->timer_cmp);
+static void imx_epit_write_lr(IMXEPITState *s, uint32_t value)
+{
+ s->lr = value;
+
+ ptimer_transaction_begin(s->timer_cmp);
+ ptimer_transaction_begin(s->timer_reload);
+ if (s->cr & CR_RLD) {
+ /* Also set the limit if the LRD bit is set */
+ /* If IOVW bit is set then set the timer value */
+ ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
+ ptimer_set_limit(s->timer_cmp, s->lr, 0);
+ } else if (s->cr & CR_IOVW) {
+ /* If IOVW bit is set then set the timer value */
+ ptimer_set_count(s->timer_reload, s->lr);
+ }
+ /* Commit the changes to s->timer_reload, so they can propagate. */
+ ptimer_transaction_commit(s->timer_reload);
+ /* Update the compare timer based on the committed reload timer value. */
+ imx_epit_update_compare_timer(s);
+ ptimer_transaction_commit(s->timer_cmp);
+}
+
+static void imx_epit_write_cmp(IMXEPITState *s, uint32_t value)
+{
+ s->cmp = value;
+
+ /* Update the compare timer based on the committed reload timer value. */
+ ptimer_transaction_begin(s->timer_cmp);
+ imx_epit_update_compare_timer(s);
+ ptimer_transaction_commit(s->timer_cmp);
+}
+
+static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ IMXEPITState *s = IMX_EPIT(opaque);
+
+ DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2),
+ (uint32_t)value);
+
+ switch (offset >> 2) {
+ case 0: /* CR */
+ imx_epit_write_cr(s, (uint32_t)value);
break;
- case 3: /* CMP */
- s->cmp = value;
+ case 1: /* SR */
+ imx_epit_write_sr(s, (uint32_t)value);
+ break;
- ptimer_transaction_begin(s->timer_cmp);
- imx_epit_reload_compare_timer(s);
- ptimer_transaction_commit(s->timer_cmp);
+ case 2: /* LR */
+ imx_epit_write_lr(s, (uint32_t)value);
+ break;
+ case 3: /* CMP */
+ imx_epit_write_cmp(s, (uint32_t)value);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset);
-
break;
}
}
+
static void imx_epit_cmp(void *opaque)
{
IMXEPITState *s = IMX_EPIT(opaque);
- DPRINTF("sr was %d\n", s->sr);
+ /* The cmp ptimer can't be running when the peripheral is disabled */
+ assert(s->cr & CR_EN);
- s->sr = 1;
+ DPRINTF("sr was %d\n", s->sr);
+ /* Set interrupt status bit SR.OCIF and update the interrupt state */
+ s->sr |= SR_OCIF;
imx_epit_update_int(s);
}
@@ -325,15 +381,13 @@ static const MemoryRegionOps imx_epit_ops = {
static const VMStateDescription vmstate_imx_timer_epit = {
.name = TYPE_IMX_EPIT,
- .version_id = 2,
- .minimum_version_id = 2,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (VMStateField[]) {
VMSTATE_UINT32(cr, IMXEPITState),
VMSTATE_UINT32(sr, IMXEPITState),
VMSTATE_UINT32(lr, IMXEPITState),
VMSTATE_UINT32(cmp, IMXEPITState),
- VMSTATE_UINT32(cnt, IMXEPITState),
- VMSTATE_UINT32(freq, IMXEPITState),
VMSTATE_PTIMER(timer_reload, IMXEPITState),
VMSTATE_PTIMER(timer_cmp, IMXEPITState),
VMSTATE_END_OF_LIST()
@@ -352,17 +406,33 @@ static void imx_epit_realize(DeviceState *dev, Error **errp)
0x00001000);
sysbus_init_mmio(sbd, &s->iomem);
+ /*
+ * The reload timer keeps running when the peripheral is enabled. It is a
+ * kind of wall clock that does not generate any interrupts. The callback
+ * needs to be provided, but it does nothing as the ptimer already supports
+ * all necessary reloading functionality.
+ */
s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_LEGACY);
+ /*
+ * The compare timer is running only when the peripheral configuration is
+ * in a state that will generate compare interrupts.
+ */
s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_LEGACY);
}
+static void imx_epit_dev_reset(DeviceState *dev)
+{
+ IMXEPITState *s = IMX_EPIT(dev);
+ imx_epit_reset(s, true);
+}
+
static void imx_epit_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_epit_realize;
- dc->reset = imx_epit_reset;
+ dc->reset = imx_epit_dev_reset;
dc->vmsd = &vmstate_imx_timer_epit;
dc->desc = "i.MX periodic timer";
}
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index 80b8302..7222b1b 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -115,6 +115,17 @@ static const IMXClk imx6_gpt_clocks[] = {
CLK_HIGH, /* 111 reference clock */
};
+static const IMXClk imx6ul_gpt_clocks[] = {
+ CLK_NONE, /* 000 No clock source */
+ CLK_IPG, /* 001 ipg_clk, 532MHz*/
+ CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */
+ CLK_EXT, /* 011 External clock */
+ CLK_32k, /* 100 ipg_clk_32k */
+ CLK_NONE, /* 101 not defined */
+ CLK_NONE, /* 110 not defined */
+ CLK_NONE, /* 111 not defined */
+};
+
static const IMXClk imx7_gpt_clocks[] = {
CLK_NONE, /* 000 No clock source */
CLK_IPG, /* 001 ipg_clk, 532MHz*/
@@ -539,6 +550,13 @@ static void imx6_gpt_init(Object *obj)
s->clocks = imx6_gpt_clocks;
}
+static void imx6ul_gpt_init(Object *obj)
+{
+ IMXGPTState *s = IMX_GPT(obj);
+
+ s->clocks = imx6ul_gpt_clocks;
+}
+
static void imx7_gpt_init(Object *obj)
{
IMXGPTState *s = IMX_GPT(obj);
@@ -566,6 +584,12 @@ static const TypeInfo imx6_gpt_info = {
.instance_init = imx6_gpt_init,
};
+static const TypeInfo imx6ul_gpt_info = {
+ .name = TYPE_IMX6UL_GPT,
+ .parent = TYPE_IMX25_GPT,
+ .instance_init = imx6ul_gpt_init,
+};
+
static const TypeInfo imx7_gpt_info = {
.name = TYPE_IMX7_GPT,
.parent = TYPE_IMX25_GPT,
@@ -577,6 +601,7 @@ static void imx_gpt_register_types(void)
type_register_static(&imx25_gpt_info);
type_register_static(&imx31_gpt_info);
type_register_static(&imx6_gpt_info);
+ type_register_static(&imx6ul_gpt_info);
type_register_static(&imx7_gpt_info);
}