aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/arm/armv7m.c4
-rw-r--r--hw/arm/aspeed_ast2600.c2
-rw-r--r--hw/arm/omap1.c2
-rw-r--r--hw/arm/pxa2xx.c2
-rw-r--r--hw/arm/strongarm.c2
-rw-r--r--hw/arm/xlnx-versal-virt.c25
-rw-r--r--hw/arm/xlnx-versal.c190
-rw-r--r--hw/block/m25p80.c2
-rw-r--r--hw/char/exynos4210_uart.c2
-rw-r--r--hw/dma/xlnx_csu_dma.c17
-rw-r--r--hw/intc/arm_gicv3.c1
-rw-r--r--hw/intc/arm_gicv3_common.c9
-rw-r--r--hw/intc/arm_gicv3_its.c258
-rw-r--r--hw/intc/arm_gicv3_redist.c115
-rw-r--r--hw/intc/gicv3_internal.h43
-rw-r--r--hw/intc/trace-events8
-rw-r--r--hw/misc/mac_via.c2
-rw-r--r--hw/misc/macio/cuda.c2
-rw-r--r--hw/misc/macio/pmu.c2
-rw-r--r--hw/misc/meson.build5
-rw-r--r--hw/misc/xlnx-versal-pmc-iou-slcr.c1446
-rw-r--r--hw/ppc/spapr_rtc.c2
-rw-r--r--hw/rtc/allwinner-rtc.c2
-rw-r--r--hw/rtc/aspeed_rtc.c2
-rw-r--r--hw/rtc/ds1338.c2
-rw-r--r--hw/rtc/exynos4210_rtc.c2
-rw-r--r--hw/rtc/goldfish_rtc.c2
-rw-r--r--hw/rtc/m41t80.c2
-rw-r--r--hw/rtc/m48t59.c2
-rw-r--r--hw/rtc/mc146818rtc.c2
-rw-r--r--hw/rtc/pl031.c2
-rw-r--r--hw/rtc/twl92230.c2
-rw-r--r--hw/rtc/xlnx-zynqmp-rtc.c2
-rw-r--r--hw/s390x/tod-tcg.c2
-rw-r--r--hw/scsi/megasas.c2
-rw-r--r--hw/ssi/meson.build1
-rw-r--r--hw/ssi/xlnx-versal-ospi.c1853
37 files changed, 3967 insertions, 54 deletions
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index 8d08db80be..ceb76df3cd 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -520,8 +520,8 @@ static const VMStateDescription vmstate_armv7m = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
- VMSTATE_CLOCK(refclk, SysTickState),
- VMSTATE_CLOCK(cpuclk, SysTickState),
+ VMSTATE_CLOCK(refclk, ARMv7MState),
+ VMSTATE_CLOCK(cpuclk, ARMv7MState),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index 8f37bdb1d8..12f6edc081 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -29,7 +29,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
[ASPEED_DEV_PWM] = 0x1E610000,
[ASPEED_DEV_FMC] = 0x1E620000,
[ASPEED_DEV_SPI1] = 0x1E630000,
- [ASPEED_DEV_SPI2] = 0x1E641000,
+ [ASPEED_DEV_SPI2] = 0x1E631000,
[ASPEED_DEV_EHCI1] = 0x1E6A1000,
[ASPEED_DEV_EHCI2] = 0x1E6A3000,
[ASPEED_DEV_MII1] = 0x1E650000,
diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c
index 180d3788f8..9852c2a07e 100644
--- a/hw/arm/omap1.c
+++ b/hw/arm/omap1.c
@@ -21,7 +21,6 @@
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qapi/error.h"
-#include "qemu-common.h"
#include "cpu.h"
#include "exec/address-spaces.h"
#include "hw/hw.h"
@@ -35,6 +34,7 @@
#include "sysemu/qtest.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
+#include "sysemu/rtc.h"
#include "qemu/range.h"
#include "hw/sysbus.h"
#include "qemu/cutils.h"
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index 15a247efae..a6f938f115 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -8,7 +8,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "qapi/error.h"
@@ -27,6 +26,7 @@
#include "chardev/char-fe.h"
#include "sysemu/blockdev.h"
#include "sysemu/qtest.h"
+#include "sysemu/rtc.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
#include "qom/object.h"
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
index 939a57dda5..39b8f01ac4 100644
--- a/hw/arm/strongarm.c
+++ b/hw/arm/strongarm.c
@@ -28,7 +28,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "cpu.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
@@ -41,6 +40,7 @@
#include "chardev/char-fe.h"
#include "chardev/char-serial.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "hw/ssi/ssi.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
index 0c5edc898e..3f56ae28ee 100644
--- a/hw/arm/xlnx-versal-virt.c
+++ b/hw/arm/xlnx-versal-virt.c
@@ -25,6 +25,8 @@
#define TYPE_XLNX_VERSAL_VIRT_MACHINE MACHINE_TYPE_NAME("xlnx-versal-virt")
OBJECT_DECLARE_SIMPLE_TYPE(VersalVirt, XLNX_VERSAL_VIRT_MACHINE)
+#define XLNX_VERSAL_NUM_OSPI_FLASH 4
+
struct VersalVirt {
MachineState parent_obj;
@@ -365,7 +367,7 @@ static void fdt_add_bbram_node(VersalVirt *s)
qemu_fdt_add_subnode(s->fdt, name);
qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
- GIC_FDT_IRQ_TYPE_SPI, VERSAL_BBRAM_APB_IRQ_0,
+ GIC_FDT_IRQ_TYPE_SPI, VERSAL_PMC_APB_IRQ,
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
qemu_fdt_setprop(s->fdt, name, "interrupt-names",
interrupt_names, sizeof(interrupt_names));
@@ -691,6 +693,27 @@ static void versal_virt_init(MachineState *machine)
exit(EXIT_FAILURE);
}
}
+
+ for (i = 0; i < XLNX_VERSAL_NUM_OSPI_FLASH; i++) {
+ BusState *spi_bus;
+ DeviceState *flash_dev;
+ qemu_irq cs_line;
+ DriveInfo *dinfo = drive_get(IF_MTD, 0, i);
+
+ spi_bus = qdev_get_child_bus(DEVICE(&s->soc.pmc.iou.ospi), "spi0");
+
+ flash_dev = qdev_new("mt35xu01g");
+ if (dinfo) {
+ qdev_prop_set_drive_err(flash_dev, "drive",
+ blk_by_legacy_dinfo(dinfo), &error_fatal);
+ }
+ qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal);
+
+ cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.pmc.iou.ospi),
+ i + 1, cs_line);
+ }
}
static void versal_virt_machine_instance_init(Object *obj)
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
index b2705b6925..ab58bebfd2 100644
--- a/hw/arm/xlnx-versal.c
+++ b/hw/arm/xlnx-versal.c
@@ -21,10 +21,15 @@
#include "kvm_arm.h"
#include "hw/misc/unimp.h"
#include "hw/arm/xlnx-versal.h"
+#include "qemu/log.h"
+#include "hw/sysbus.h"
#define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72")
#define GEM_REVISION 0x40070106
+#define VERSAL_NUM_PMC_APB_IRQS 3
+#define NUM_OSPI_IRQ_LINES 3
+
static void versal_create_apu_cpus(Versal *s)
{
int i;
@@ -260,6 +265,26 @@ static void versal_create_sds(Versal *s, qemu_irq *pic)
}
}
+static void versal_create_pmc_apb_irq_orgate(Versal *s, qemu_irq *pic)
+{
+ DeviceState *orgate;
+
+ /*
+ * The VERSAL_PMC_APB_IRQ is an 'or' of the interrupts from the following
+ * models:
+ * - RTC
+ * - BBRAM
+ * - PMC SLCR
+ */
+ object_initialize_child(OBJECT(s), "pmc-apb-irq-orgate",
+ &s->pmc.apb_irq_orgate, TYPE_OR_IRQ);
+ orgate = DEVICE(&s->pmc.apb_irq_orgate);
+ object_property_set_int(OBJECT(orgate),
+ "num-lines", VERSAL_NUM_PMC_APB_IRQS, &error_fatal);
+ qdev_realize(orgate, NULL, &error_fatal);
+ qdev_connect_gpio_out(orgate, 0, pic[VERSAL_PMC_APB_IRQ]);
+}
+
static void versal_create_rtc(Versal *s, qemu_irq *pic)
{
SysBusDevice *sbd;
@@ -277,7 +302,8 @@ static void versal_create_rtc(Versal *s, qemu_irq *pic)
* TODO: Connect the ALARM and SECONDS interrupts once our RTC model
* supports them.
*/
- sysbus_connect_irq(sbd, 1, pic[VERSAL_RTC_APB_ERR_IRQ]);
+ sysbus_connect_irq(sbd, 1,
+ qdev_get_gpio_in(DEVICE(&s->pmc.apb_irq_orgate), 0));
}
static void versal_create_xrams(Versal *s, qemu_irq *pic)
@@ -328,7 +354,8 @@ static void versal_create_bbram(Versal *s, qemu_irq *pic)
sysbus_realize(sbd, &error_fatal);
memory_region_add_subregion(&s->mr_ps, MM_PMC_BBRAM_CTRL,
sysbus_mmio_get_region(sbd, 0));
- sysbus_connect_irq(sbd, 0, pic[VERSAL_BBRAM_APB_IRQ_0]);
+ sysbus_connect_irq(sbd, 0,
+ qdev_get_gpio_in(DEVICE(&s->pmc.apb_irq_orgate), 1));
}
static void versal_realize_efuse_part(Versal *s, Object *dev, hwaddr base)
@@ -369,6 +396,114 @@ static void versal_create_efuse(Versal *s, qemu_irq *pic)
sysbus_connect_irq(SYS_BUS_DEVICE(ctrl), 0, pic[VERSAL_EFUSE_IRQ]);
}
+static void versal_create_pmc_iou_slcr(Versal *s, qemu_irq *pic)
+{
+ SysBusDevice *sbd;
+
+ object_initialize_child(OBJECT(s), "versal-pmc-iou-slcr", &s->pmc.iou.slcr,
+ TYPE_XILINX_VERSAL_PMC_IOU_SLCR);
+
+ sbd = SYS_BUS_DEVICE(&s->pmc.iou.slcr);
+ sysbus_realize(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_PMC_IOU_SLCR,
+ sysbus_mmio_get_region(sbd, 0));
+
+ sysbus_connect_irq(sbd, 0,
+ qdev_get_gpio_in(DEVICE(&s->pmc.apb_irq_orgate), 2));
+}
+
+static void versal_create_ospi(Versal *s, qemu_irq *pic)
+{
+ SysBusDevice *sbd;
+ MemoryRegion *mr_dac;
+ qemu_irq ospi_mux_sel;
+ DeviceState *orgate;
+
+ memory_region_init(&s->pmc.iou.ospi.linear_mr, OBJECT(s),
+ "versal-ospi-linear-mr" , MM_PMC_OSPI_DAC_SIZE);
+
+ object_initialize_child(OBJECT(s), "versal-ospi", &s->pmc.iou.ospi.ospi,
+ TYPE_XILINX_VERSAL_OSPI);
+
+ mr_dac = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->pmc.iou.ospi.ospi), 1);
+ memory_region_add_subregion(&s->pmc.iou.ospi.linear_mr, 0x0, mr_dac);
+
+ /* Create the OSPI destination DMA */
+ object_initialize_child(OBJECT(s), "versal-ospi-dma-dst",
+ &s->pmc.iou.ospi.dma_dst,
+ TYPE_XLNX_CSU_DMA);
+
+ object_property_set_link(OBJECT(&s->pmc.iou.ospi.dma_dst),
+ "dma", OBJECT(get_system_memory()),
+ &error_abort);
+
+ sbd = SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_dst);
+ sysbus_realize(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI_DMA_DST,
+ sysbus_mmio_get_region(sbd, 0));
+
+ /* Create the OSPI source DMA */
+ object_initialize_child(OBJECT(s), "versal-ospi-dma-src",
+ &s->pmc.iou.ospi.dma_src,
+ TYPE_XLNX_CSU_DMA);
+
+ object_property_set_bool(OBJECT(&s->pmc.iou.ospi.dma_src), "is-dst",
+ false, &error_abort);
+
+ object_property_set_link(OBJECT(&s->pmc.iou.ospi.dma_src),
+ "dma", OBJECT(mr_dac), &error_abort);
+
+ object_property_set_link(OBJECT(&s->pmc.iou.ospi.dma_src),
+ "stream-connected-dma",
+ OBJECT(&s->pmc.iou.ospi.dma_dst),
+ &error_abort);
+
+ sbd = SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_src);
+ sysbus_realize(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI_DMA_SRC,
+ sysbus_mmio_get_region(sbd, 0));
+
+ /* Realize the OSPI */
+ object_property_set_link(OBJECT(&s->pmc.iou.ospi.ospi), "dma-src",
+ OBJECT(&s->pmc.iou.ospi.dma_src), &error_abort);
+
+ sbd = SYS_BUS_DEVICE(&s->pmc.iou.ospi.ospi);
+ sysbus_realize(sbd, &error_fatal);
+
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI,
+ sysbus_mmio_get_region(sbd, 0));
+
+ memory_region_add_subregion(&s->mr_ps, MM_PMC_OSPI_DAC,
+ &s->pmc.iou.ospi.linear_mr);
+
+ /* ospi_mux_sel */
+ ospi_mux_sel = qdev_get_gpio_in_named(DEVICE(&s->pmc.iou.ospi.ospi),
+ "ospi-mux-sel", 0);
+ qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr), "ospi-mux-sel", 0,
+ ospi_mux_sel);
+
+ /* OSPI irq */
+ object_initialize_child(OBJECT(s), "ospi-irq-orgate",
+ &s->pmc.iou.ospi.irq_orgate, TYPE_OR_IRQ);
+ object_property_set_int(OBJECT(&s->pmc.iou.ospi.irq_orgate),
+ "num-lines", NUM_OSPI_IRQ_LINES, &error_fatal);
+
+ orgate = DEVICE(&s->pmc.iou.ospi.irq_orgate);
+ qdev_realize(orgate, NULL, &error_fatal);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pmc.iou.ospi.ospi), 0,
+ qdev_get_gpio_in(orgate, 0));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_src), 0,
+ qdev_get_gpio_in(orgate, 1));
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->pmc.iou.ospi.dma_dst), 0,
+ qdev_get_gpio_in(orgate, 2));
+
+ qdev_connect_gpio_out(orgate, 0, pic[VERSAL_OSPI_IRQ]);
+}
+
/* This takes the board allocated linear DDR memory and creates aliases
* for each split DDR range/aperture on the Versal address map.
*/
@@ -425,8 +560,31 @@ static void versal_unimp_area(Versal *s, const char *name,
memory_region_add_subregion(mr, base, mr_dev);
}
+static void versal_unimp_sd_emmc_sel(void *opaque, int n, int level)
+{
+ qemu_log_mask(LOG_UNIMP,
+ "Selecting between enabling SD mode or eMMC mode on "
+ "controller %d is not yet implemented\n", n);
+}
+
+static void versal_unimp_qspi_ospi_mux_sel(void *opaque, int n, int level)
+{
+ qemu_log_mask(LOG_UNIMP,
+ "Selecting between enabling the QSPI or OSPI linear address "
+ "region is not yet implemented\n");
+}
+
+static void versal_unimp_irq_parity_imr(void *opaque, int n, int level)
+{
+ qemu_log_mask(LOG_UNIMP,
+ "PMC SLCR parity interrupt behaviour "
+ "is not yet implemented\n");
+}
+
static void versal_unimp(Versal *s)
{
+ qemu_irq gpio_in;
+
versal_unimp_area(s, "psm", &s->mr_ps,
MM_PSM_START, MM_PSM_END - MM_PSM_START);
versal_unimp_area(s, "crl", &s->mr_ps,
@@ -441,6 +599,31 @@ static void versal_unimp(Versal *s)
MM_IOU_SCNTR, MM_IOU_SCNTR_SIZE);
versal_unimp_area(s, "iou-scntr-seucre", &s->mr_ps,
MM_IOU_SCNTRS, MM_IOU_SCNTRS_SIZE);
+
+ qdev_init_gpio_in_named(DEVICE(s), versal_unimp_sd_emmc_sel,
+ "sd-emmc-sel-dummy", 2);
+ qdev_init_gpio_in_named(DEVICE(s), versal_unimp_qspi_ospi_mux_sel,
+ "qspi-ospi-mux-sel-dummy", 1);
+ qdev_init_gpio_in_named(DEVICE(s), versal_unimp_irq_parity_imr,
+ "irq-parity-imr-dummy", 1);
+
+ gpio_in = qdev_get_gpio_in_named(DEVICE(s), "sd-emmc-sel-dummy", 0);
+ qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr), "sd-emmc-sel", 0,
+ gpio_in);
+
+ gpio_in = qdev_get_gpio_in_named(DEVICE(s), "sd-emmc-sel-dummy", 1);
+ qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr), "sd-emmc-sel", 1,
+ gpio_in);
+
+ gpio_in = qdev_get_gpio_in_named(DEVICE(s), "qspi-ospi-mux-sel-dummy", 0);
+ qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr),
+ "qspi-ospi-mux-sel", 0,
+ gpio_in);
+
+ gpio_in = qdev_get_gpio_in_named(DEVICE(s), "irq-parity-imr-dummy", 0);
+ qdev_connect_gpio_out_named(DEVICE(&s->pmc.iou.slcr),
+ SYSBUS_DEVICE_GPIO_IRQ, 0,
+ gpio_in);
}
static void versal_realize(DeviceState *dev, Error **errp)
@@ -455,10 +638,13 @@ static void versal_realize(DeviceState *dev, Error **errp)
versal_create_gems(s, pic);
versal_create_admas(s, pic);
versal_create_sds(s, pic);
+ versal_create_pmc_apb_irq_orgate(s, pic);
versal_create_rtc(s, pic);
versal_create_xrams(s, pic);
versal_create_bbram(s, pic);
versal_create_efuse(s, pic);
+ versal_create_pmc_iou_slcr(s, pic);
+ versal_create_ospi(s, pic);
versal_map_ddr(s);
versal_unimp(s);
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index b77503dc84..c6bf3c6bfa 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -255,6 +255,8 @@ static const FlashPartInfo known_devices[] = {
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
{ INFO("n25q512ax3", 0x20ba20, 0x1000, 64 << 10, 1024, ER_4K) },
{ INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) },
+ { INFO_STACKED("mt35xu01g", 0x2c5b1b, 0x104100, 128 << 10, 1024,
+ ER_4K | ER_32K, 2) },
{ INFO_STACKED("n25q00", 0x20ba21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 80d401a379..addcd59b02 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -628,7 +628,6 @@ static const VMStateDescription vmstate_exynos4210_uart_fifo = {
.name = "exynos4210.uart.fifo",
.version_id = 1,
.minimum_version_id = 1,
- .post_load = exynos4210_uart_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32(sp, Exynos4210UartFIFO),
VMSTATE_UINT32(rp, Exynos4210UartFIFO),
@@ -641,6 +640,7 @@ static const VMStateDescription vmstate_exynos4210_uart = {
.name = "exynos4210.uart",
.version_id = 1,
.minimum_version_id = 1,
+ .post_load = exynos4210_uart_post_load,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(rx, Exynos4210UartState, 1,
vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO),
diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c
index 896bb3574d..095f954476 100644
--- a/hw/dma/xlnx_csu_dma.c
+++ b/hw/dma/xlnx_csu_dma.c
@@ -472,6 +472,20 @@ static uint64_t addr_msb_pre_write(RegisterInfo *reg, uint64_t val)
return val & R_ADDR_MSB_ADDR_MSB_MASK;
}
+static MemTxResult xlnx_csu_dma_class_read(XlnxCSUDMA *s, hwaddr addr,
+ uint32_t len)
+{
+ RegisterInfo *reg = &s->regs_info[R_SIZE];
+ uint64_t we = MAKE_64BIT_MASK(0, 4 * 8);
+
+ s->regs[R_ADDR] = addr;
+ s->regs[R_ADDR_MSB] = (uint64_t)addr >> 32;
+
+ register_write(reg, len, we, object_get_typename(OBJECT(s)), false);
+
+ return (s->regs[R_SIZE] == 0) ? MEMTX_OK : MEMTX_ERROR;
+}
+
static const RegisterAccessInfo *xlnx_csu_dma_regs_info[] = {
#define DMACH_REGINFO(NAME, snd) \
(const RegisterAccessInfo []) { \
@@ -696,6 +710,7 @@ static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
StreamSinkClass *ssc = STREAM_SINK_CLASS(klass);
+ XlnxCSUDMAClass *xcdc = XLNX_CSU_DMA_CLASS(klass);
dc->reset = xlnx_csu_dma_reset;
dc->realize = xlnx_csu_dma_realize;
@@ -704,6 +719,8 @@ static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data)
ssc->push = xlnx_csu_dma_stream_push;
ssc->can_push = xlnx_csu_dma_stream_can_push;
+
+ xcdc->read = xlnx_csu_dma_class_read;
}
static void xlnx_csu_dma_init(Object *obj)
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 715df5421d..6d3c8ee231 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -166,6 +166,7 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
}
if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable &&
+ (cs->gic->gicd_ctlr & GICD_CTLR_EN_GRP1NS) &&
(cs->hpplpi.prio != 0xff)) {
if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio)) {
cs->hppi.irq = cs->hpplpi.irq;
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
index 9884d2e39b..4ca5ae9bc5 100644
--- a/hw/intc/arm_gicv3_common.c
+++ b/hw/intc/arm_gicv3_common.c
@@ -357,6 +357,11 @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
return;
}
+ if (s->lpi_enable) {
+ address_space_init(&s->dma_as, s->dma,
+ "gicv3-its-sysmem");
+ }
+
s->cpu = g_new0(GICv3CPUState, s->num_cpu);
for (i = 0; i < s->num_cpu; i++) {
@@ -424,6 +429,10 @@ static void arm_gicv3_common_reset(DeviceState *dev)
cs->level = 0;
cs->gicr_ctlr = 0;
+ if (s->lpi_enable) {
+ /* Our implementation supports clearing GICR_CTLR.EnableLPIs */
+ cs->gicr_ctlr |= GICR_CTLR_CES;
+ }
cs->gicr_statusr[GICV3_S] = 0;
cs->gicr_statusr[GICV3_NS] = 0;
cs->gicr_waker = GICR_WAKER_ProcessorSleep | GICR_WAKER_ChildrenAsleep;
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index b2f6a8c7f0..51d9be4ae6 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "trace.h"
#include "hw/qdev-properties.h"
#include "hw/intc/arm_gicv3_its_common.h"
#include "gicv3_internal.h"
@@ -255,10 +256,10 @@ static ItsCmdResult process_its_cmd(GICv3ITSState *s, uint64_t value,
eventid = (value & EVENTID_MASK);
- if (devid >= s->dt.num_ids) {
+ if (devid >= s->dt.num_entries) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid command attributes: devid %d>=%d",
- __func__, devid, s->dt.num_ids);
+ __func__, devid, s->dt.num_entries);
return CMD_CONTINUE;
}
@@ -299,7 +300,7 @@ static ItsCmdResult process_its_cmd(GICv3ITSState *s, uint64_t value,
return CMD_CONTINUE;
}
- if (icid >= s->ct.num_ids) {
+ if (icid >= s->ct.num_entries) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid ICID 0x%x in ITE (table corrupted?)\n",
__func__, icid);
@@ -383,10 +384,10 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, uint64_t value,
icid = value & ICID_MASK;
- if (devid >= s->dt.num_ids) {
+ if (devid >= s->dt.num_entries) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid command attributes: devid %d>=%d",
- __func__, devid, s->dt.num_ids);
+ __func__, devid, s->dt.num_entries);
return CMD_CONTINUE;
}
@@ -399,7 +400,7 @@ static ItsCmdResult process_mapti(GICv3ITSState *s, uint64_t value,
num_eventids = 1ULL << (FIELD_EX64(dte, DTE, SIZE) + 1);
num_intids = 1ULL << (GICD_TYPER_IDBITS + 1);
- if ((icid >= s->ct.num_ids)
+ if ((icid >= s->ct.num_entries)
|| !dte_valid || (eventid >= num_eventids) ||
(((pIntid < GICV3_LPI_INTID_START) || (pIntid >= num_intids)) &&
(pIntid != INTID_SPURIOUS))) {
@@ -484,7 +485,7 @@ static ItsCmdResult process_mapc(GICv3ITSState *s, uint32_t offset)
valid = (value & CMD_FIELD_VALID_MASK);
- if ((icid >= s->ct.num_ids) || (rdbase >= s->gicv3->num_cpu)) {
+ if ((icid >= s->ct.num_entries) || (rdbase >= s->gicv3->num_cpu)) {
qemu_log_mask(LOG_GUEST_ERROR,
"ITS MAPC: invalid collection table attributes "
"icid %d rdbase %" PRIu64 "\n", icid, rdbase);
@@ -565,7 +566,7 @@ static ItsCmdResult process_mapd(GICv3ITSState *s, uint64_t value,
valid = (value & CMD_FIELD_VALID_MASK);
- if ((devid >= s->dt.num_ids) ||
+ if ((devid >= s->dt.num_entries) ||
(size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
qemu_log_mask(LOG_GUEST_ERROR,
"ITS MAPD: invalid device table attributes "
@@ -581,6 +582,201 @@ static ItsCmdResult process_mapd(GICv3ITSState *s, uint64_t value,
return update_dte(s, devid, valid, size, itt_addr) ? CMD_CONTINUE : CMD_STALL;
}
+static ItsCmdResult process_movall(GICv3ITSState *s, uint64_t value,
+ uint32_t offset)
+{
+ AddressSpace *as = &s->gicv3->dma_as;
+ MemTxResult res = MEMTX_OK;
+ uint64_t rd1, rd2;
+
+ /* No fields in dwords 0 or 1 */
+ offset += NUM_BYTES_IN_DW;
+ offset += NUM_BYTES_IN_DW;
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ rd1 = FIELD_EX64(value, MOVALL_2, RDBASE1);
+ if (rd1 >= s->gicv3->num_cpu) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: RDBASE1 %" PRId64
+ " out of range (must be less than %d)\n",
+ __func__, rd1, s->gicv3->num_cpu);
+ return CMD_CONTINUE;
+ }
+
+ offset += NUM_BYTES_IN_DW;
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ rd2 = FIELD_EX64(value, MOVALL_3, RDBASE2);
+ if (rd2 >= s->gicv3->num_cpu) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: RDBASE2 %" PRId64
+ " out of range (must be less than %d)\n",
+ __func__, rd2, s->gicv3->num_cpu);
+ return CMD_CONTINUE;
+ }
+
+ if (rd1 == rd2) {
+ /* Move to same target must succeed as a no-op */
+ return CMD_CONTINUE;
+ }
+
+ /* Move all pending LPIs from redistributor 1 to redistributor 2 */
+ gicv3_redist_movall_lpis(&s->gicv3->cpu[rd1], &s->gicv3->cpu[rd2]);
+
+ return CMD_CONTINUE;
+}
+
+static ItsCmdResult process_movi(GICv3ITSState *s, uint64_t value,
+ uint32_t offset)
+{
+ AddressSpace *as = &s->gicv3->dma_as;
+ MemTxResult res = MEMTX_OK;
+ uint32_t devid, eventid, intid;
+ uint16_t old_icid, new_icid;
+ uint64_t old_cte, new_cte;
+ uint64_t old_rdbase, new_rdbase;
+ uint64_t dte;
+ bool dte_valid, ite_valid, cte_valid;
+ uint64_t num_eventids;
+ IteEntry ite = {};
+
+ devid = FIELD_EX64(value, MOVI_0, DEVICEID);
+
+ offset += NUM_BYTES_IN_DW;
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+ eventid = FIELD_EX64(value, MOVI_1, EVENTID);
+
+ offset += NUM_BYTES_IN_DW;
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
+ MEMTXATTRS_UNSPECIFIED, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+ new_icid = FIELD_EX64(value, MOVI_2, ICID);
+
+ if (devid >= s->dt.num_entries) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: devid %d>=%d",
+ __func__, devid, s->dt.num_entries);
+ return CMD_CONTINUE;
+ }
+ dte = get_dte(s, devid, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ dte_valid = FIELD_EX64(dte, DTE, VALID);
+ if (!dte_valid) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: "
+ "invalid dte: %"PRIx64" for %d\n",
+ __func__, dte, devid);
+ return CMD_CONTINUE;
+ }
+
+ num_eventids = 1ULL << (FIELD_EX64(dte, DTE, SIZE) + 1);
+ if (eventid >= num_eventids) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: eventid %d >= %"
+ PRId64 "\n",
+ __func__, eventid, num_eventids);
+ return CMD_CONTINUE;
+ }
+
+ ite_valid = get_ite(s, eventid, dte, &old_icid, &intid, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+
+ if (!ite_valid) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: invalid ITE\n",
+ __func__);
+ return CMD_CONTINUE;
+ }
+
+ if (old_icid >= s->ct.num_entries) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid ICID 0x%x in ITE (table corrupted?)\n",
+ __func__, old_icid);
+ return CMD_CONTINUE;
+ }
+
+ if (new_icid >= s->ct.num_entries) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: ICID 0x%x\n",
+ __func__, new_icid);
+ return CMD_CONTINUE;
+ }
+
+ cte_valid = get_cte(s, old_icid, &old_cte, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+ if (!cte_valid) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: "
+ "invalid cte: %"PRIx64"\n",
+ __func__, old_cte);
+ return CMD_CONTINUE;
+ }
+
+ cte_valid = get_cte(s, new_icid, &new_cte, &res);
+ if (res != MEMTX_OK) {
+ return CMD_STALL;
+ }
+ if (!cte_valid) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid command attributes: "
+ "invalid cte: %"PRIx64"\n",
+ __func__, new_cte);
+ return CMD_CONTINUE;
+ }
+
+ old_rdbase = FIELD_EX64(old_cte, CTE, RDBASE);
+ if (old_rdbase >= s->gicv3->num_cpu) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: CTE has invalid rdbase 0x%"PRIx64"\n",
+ __func__, old_rdbase);
+ return CMD_CONTINUE;
+ }
+
+ new_rdbase = FIELD_EX64(new_cte, CTE, RDBASE);
+ if (new_rdbase >= s->gicv3->num_cpu) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: CTE has invalid rdbase 0x%"PRIx64"\n",
+ __func__, new_rdbase);
+ return CMD_CONTINUE;
+ }
+
+ if (old_rdbase != new_rdbase) {
+ /* Move the LPI from the old redistributor to the new one */
+ gicv3_redist_mov_lpi(&s->gicv3->cpu[old_rdbase],
+ &s->gicv3->cpu[new_rdbase],
+ intid);
+ }
+
+ /* Update the ICID field in the interrupt translation table entry */
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, VALID, 1);
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, INTTYPE, ITE_INTTYPE_PHYSICAL);
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, INTID, intid);
+ ite.itel = FIELD_DP64(ite.itel, ITE_L, DOORBELL, INTID_SPURIOUS);
+ ite.iteh = FIELD_DP32(ite.iteh, ITE_H, ICID, new_icid);
+ return update_ite(s, eventid, dte, ite) ? CMD_CONTINUE : CMD_STALL;
+}
+
/*
* Current implementation blocks until all
* commands are processed
@@ -634,6 +830,8 @@ static void process_cmdq(GICv3ITSState *s)
cmd = (data & CMD_MASK);
+ trace_gicv3_its_process_command(rd_offset, cmd);
+
switch (cmd) {
case GITS_CMD_INT:
result = process_its_cmd(s, data, cq_offset, INTERRUPT);
@@ -676,6 +874,12 @@ static void process_cmdq(GICv3ITSState *s)
gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
}
break;
+ case GITS_CMD_MOVI:
+ result = process_movi(s, data, cq_offset);
+ break;
+ case GITS_CMD_MOVALL:
+ result = process_movall(s, data, cq_offset);
+ break;
default:
break;
}
@@ -788,7 +992,7 @@ static void extract_table_params(GICv3ITSState *s)
L1TABLE_ENTRY_SIZE) *
(page_sz / td->entry_sz));
}
- td->num_ids = 1ULL << idbits;
+ td->num_entries = MIN(td->num_entries, 1ULL << idbits);
}
}
@@ -810,6 +1014,18 @@ static void extract_cmdq_params(GICv3ITSState *s)
}
}
+static MemTxResult gicv3_its_translation_read(void *opaque, hwaddr offset,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ /*
+ * GITS_TRANSLATER is write-only, and all other addresses
+ * in the interrupt translation space frame are RES0.
+ */
+ *data = 0;
+ return MEMTX_OK;
+}
+
static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
uint64_t data, unsigned size,
MemTxAttrs attrs)
@@ -818,6 +1034,8 @@ static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
bool result = true;
uint32_t devid = 0;
+ trace_gicv3_its_translation_write(offset, data, size, attrs.requester_id);
+
switch (offset) {
case GITS_TRANSLATER:
if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
@@ -848,7 +1066,6 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
s->ctlr |= R_GITS_CTLR_ENABLED_MASK;
extract_table_params(s);
extract_cmdq_params(s);
- s->creadr = 0;
process_cmdq(s);
} else {
s->ctlr &= ~R_GITS_CTLR_ENABLED_MASK;
@@ -862,7 +1079,6 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
s->cbaser = deposit64(s->cbaser, 0, 32, value);
s->creadr = 0;
- s->cwriter = s->creadr;
}
break;
case GITS_CBASER + 4:
@@ -873,7 +1089,6 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
s->cbaser = deposit64(s->cbaser, 32, 32, value);
s->creadr = 0;
- s->cwriter = s->creadr;
}
break;
case GITS_CWRITER:
@@ -915,6 +1130,10 @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
index = (offset - GITS_BASER) / 8;
+ if (s->baser[index] == 0) {
+ /* Unimplemented GITS_BASERn: RAZ/WI */
+ break;
+ }
if (offset & 7) {
value <<= 32;
value &= ~GITS_BASER_RO_MASK;
@@ -1011,6 +1230,10 @@ static bool its_writell(GICv3ITSState *s, hwaddr offset,
*/
if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
index = (offset - GITS_BASER) / 8;
+ if (s->baser[index] == 0) {
+ /* Unimplemented GITS_BASERn: RAZ/WI */
+ break;
+ }
s->baser[index] &= GITS_BASER_RO_MASK;
s->baser[index] |= (value & ~GITS_BASER_RO_MASK);
}
@@ -1023,7 +1246,6 @@ static bool its_writell(GICv3ITSState *s, hwaddr offset,
if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
s->cbaser = value;
s->creadr = 0;
- s->cwriter = s->creadr;
}
break;
case GITS_CWRITER:
@@ -1107,6 +1329,7 @@ static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid guest read at offset " TARGET_FMT_plx
"size %u\n", __func__, offset, size);
+ trace_gicv3_its_badread(offset, size);
/*
* The spec requires that reserved registers are RAZ/WI;
* so use false returns from leaf functions as a way to
@@ -1114,6 +1337,8 @@ static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
* the caller, or we'll cause a spurious guest data abort.
*/
*data = 0;
+ } else {
+ trace_gicv3_its_read(offset, *data, size);
}
return MEMTX_OK;
}
@@ -1140,12 +1365,15 @@ static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid guest write at offset " TARGET_FMT_plx
"size %u\n", __func__, offset, size);
+ trace_gicv3_its_badwrite(offset, data, size);
/*
* The spec requires that reserved registers are RAZ/WI;
* so use false returns from leaf functions as a way to
* trigger the guest-error logging but don't return it to
* the caller, or we'll cause a spurious guest data abort.
*/
+ } else {
+ trace_gicv3_its_write(offset, data, size);
}
return MEMTX_OK;
}
@@ -1161,6 +1389,7 @@ static const MemoryRegionOps gicv3_its_control_ops = {
};
static const MemoryRegionOps gicv3_its_translation_ops = {
+ .read_with_attrs = gicv3_its_translation_read,
.write_with_attrs = gicv3_its_translation_write,
.valid.min_access_size = 2,
.valid.max_access_size = 4,
@@ -1183,9 +1412,6 @@ static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops);
- address_space_init(&s->gicv3->dma_as, s->gicv3->dma,
- "gicv3-its-sysmem");
-
/* set the ITS default features supported */
s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL, 1);
s->typer = FIELD_DP64(s->typer, GITS_TYPER, ITT_ENTRY_SIZE,
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index 99b11ca5ee..412a04f59c 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -591,8 +591,7 @@ void gicv3_redist_update_lpi_only(GICv3CPUState *cs)
idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
GICD_TYPER_IDBITS);
- if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
- !cs->gicr_pendbaser) {
+ if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {
return;
}
@@ -673,9 +672,8 @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
GICD_TYPER_IDBITS);
- if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
- !cs->gicr_pendbaser || (irq > (1ULL << (idbits + 1)) - 1) ||
- irq < GICV3_LPI_INTID_START) {
+ if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) ||
+ (irq > (1ULL << (idbits + 1)) - 1) || irq < GICV3_LPI_INTID_START) {
return;
}
@@ -683,6 +681,113 @@ void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
gicv3_redist_lpi_pending(cs, irq, level);
}
+void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq)
+{
+ /*
+ * Move the specified LPI's pending state from the source redistributor
+ * to the destination.
+ *
+ * If LPIs are disabled on dest this is CONSTRAINED UNPREDICTABLE:
+ * we choose to NOP. If LPIs are disabled on source there's nothing
+ * to be transferred anyway.
+ */
+ AddressSpace *as = &src->gic->dma_as;
+ uint64_t idbits;
+ uint32_t pendt_size;
+ uint64_t src_baddr;
+ uint8_t src_pend;
+
+ if (!(src->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) ||
+ !(dest->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {
+ return;
+ }
+
+ idbits = MIN(FIELD_EX64(src->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ GICD_TYPER_IDBITS);
+ idbits = MIN(FIELD_EX64(dest->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ idbits);
+
+ pendt_size = 1ULL << (idbits + 1);
+ if ((irq / 8) >= pendt_size) {
+ return;
+ }
+
+ src_baddr = src->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
+
+ address_space_read(as, src_baddr + (irq / 8),
+ MEMTXATTRS_UNSPECIFIED, &src_pend, sizeof(src_pend));
+ if (!extract32(src_pend, irq % 8, 1)) {
+ /* Not pending on source, nothing to do */
+ return;
+ }
+ src_pend &= ~(1 << (irq % 8));
+ address_space_write(as, src_baddr + (irq / 8),
+ MEMTXATTRS_UNSPECIFIED, &src_pend, sizeof(src_pend));
+ if (irq == src->hpplpi.irq) {
+ /*
+ * We just made this LPI not-pending so only need to update
+ * if it was previously the highest priority pending LPI
+ */
+ gicv3_redist_update_lpi(src);
+ }
+ /* Mark it pending on the destination */
+ gicv3_redist_lpi_pending(dest, irq, 1);
+}
+
+void gicv3_redist_movall_lpis(GICv3CPUState *src, GICv3CPUState *dest)
+{
+ /*
+ * We must move all pending LPIs from the source redistributor
+ * to the destination. That is, for every pending LPI X on
+ * src, we must set it not-pending on src and pending on dest.
+ * LPIs that are already pending on dest are not cleared.
+ *
+ * If LPIs are disabled on dest this is CONSTRAINED UNPREDICTABLE:
+ * we choose to NOP. If LPIs are disabled on source there's nothing
+ * to be transferred anyway.
+ */
+ AddressSpace *as = &src->gic->dma_as;
+ uint64_t idbits;
+ uint32_t pendt_size;
+ uint64_t src_baddr, dest_baddr;
+ int i;
+
+ if (!(src->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) ||
+ !(dest->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) {
+ return;
+ }
+
+ idbits = MIN(FIELD_EX64(src->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ GICD_TYPER_IDBITS);
+ idbits = MIN(FIELD_EX64(dest->gicr_propbaser, GICR_PROPBASER, IDBITS),
+ idbits);
+
+ pendt_size = 1ULL << (idbits + 1);
+ src_baddr = src->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
+ dest_baddr = dest->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
+
+ for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) {
+ uint8_t src_pend, dest_pend;
+
+ address_space_read(as, src_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &src_pend, sizeof(src_pend));
+ if (!src_pend) {
+ continue;
+ }
+ address_space_read(as, dest_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &dest_pend, sizeof(dest_pend));
+ dest_pend |= src_pend;
+ src_pend = 0;
+ address_space_write(as, src_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &src_pend, sizeof(src_pend));
+ address_space_write(as, dest_baddr + i, MEMTXATTRS_UNSPECIFIED,
+ &dest_pend, sizeof(dest_pend));
+ }
+
+ gicv3_redist_update_lpi(src);
+ gicv3_redist_update_lpi(dest);
+}
+
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
{
/* Update redistributor state for a change in an external PPI input line */
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index 1eeb99035d..b1af26df9f 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -110,6 +110,7 @@
#define GICR_NSACR (GICR_SGI_OFFSET + 0x0E00)
#define GICR_CTLR_ENABLE_LPIS (1U << 0)
+#define GICR_CTLR_CES (1U << 1)
#define GICR_CTLR_RWP (1U << 3)
#define GICR_CTLR_DPG0 (1U << 24)
#define GICR_CTLR_DPG1NS (1U << 25)
@@ -314,16 +315,18 @@ FIELD(GITS_TYPER, CIL, 36, 1)
#define CMD_MASK 0xff
/* ITS Commands */
-#define GITS_CMD_CLEAR 0x04
-#define GITS_CMD_DISCARD 0x0F
+#define GITS_CMD_MOVI 0x01
#define GITS_CMD_INT 0x03
-#define GITS_CMD_MAPC 0x09
+#define GITS_CMD_CLEAR 0x04
+#define GITS_CMD_SYNC 0x05
#define GITS_CMD_MAPD 0x08
-#define GITS_CMD_MAPI 0x0B
+#define GITS_CMD_MAPC 0x09
#define GITS_CMD_MAPTI 0x0A
+#define GITS_CMD_MAPI 0x0B
#define GITS_CMD_INV 0x0C
#define GITS_CMD_INVALL 0x0D
-#define GITS_CMD_SYNC 0x05
+#define GITS_CMD_MOVALL 0x0E
+#define GITS_CMD_DISCARD 0x0F
/* MAPC command fields */
#define ICID_LENGTH 16
@@ -354,6 +357,15 @@ FIELD(MAPC, RDBASE, 16, 32)
#define L2_TABLE_VALID_MASK CMD_FIELD_VALID_MASK
#define TABLE_ENTRY_VALID_MASK (1ULL << 0)
+/* MOVALL command fields */
+FIELD(MOVALL_2, RDBASE1, 16, 36)
+FIELD(MOVALL_3, RDBASE2, 16, 36)
+
+/* MOVI command fields */
+FIELD(MOVI_0, DEVICEID, 32, 32)
+FIELD(MOVI_1, EVENTID, 0, 32)
+FIELD(MOVI_2, ICID, 0, 16)
+
/*
* 12 bytes Interrupt translation Table Entry size
* as per Table 5.3 in GICv3 spec
@@ -496,6 +508,27 @@ void gicv3_redist_update_lpi(GICv3CPUState *cs);
* an incoming migration has loaded new state.
*/
void gicv3_redist_update_lpi_only(GICv3CPUState *cs);
+/**
+ * gicv3_redist_mov_lpi:
+ * @src: source redistributor
+ * @dest: destination redistributor
+ * @irq: LPI to update
+ *
+ * Move the pending state of the specified LPI from @src to @dest,
+ * as required by the ITS MOVI command.
+ */
+void gicv3_redist_mov_lpi(GICv3CPUState *src, GICv3CPUState *dest, int irq);
+/**
+ * gicv3_redist_movall_lpis:
+ * @src: source redistributor
+ * @dest: destination redistributor
+ *
+ * Scan the LPI pending table for @src, and for each pending LPI there
+ * mark it as not-pending for @src and pending for @dest, as required
+ * by the ITS MOVALL command.
+ */
+void gicv3_redist_movall_lpis(GICv3CPUState *src, GICv3CPUState *dest);
+
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns);
void gicv3_init_cpuif(GICv3State *s);
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 9aba7e3a7a..b28cda4e08 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -169,6 +169,14 @@ gicv3_redist_badwrite(uint32_t cpu, uint64_t offset, uint64_t data, unsigned siz
gicv3_redist_set_irq(uint32_t cpu, int irq, int level) "GICv3 redistributor 0x%x interrupt %d level changed to %d"
gicv3_redist_send_sgi(uint32_t cpu, int irq) "GICv3 redistributor 0x%x pending SGI %d"
+# arm_gicv3_its.c
+gicv3_its_read(uint64_t offset, uint64_t data, unsigned size) "GICv3 ITS read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+gicv3_its_badread(uint64_t offset, unsigned size) "GICv3 ITS read: offset 0x%" PRIx64 " size %u: error"
+gicv3_its_write(uint64_t offset, uint64_t data, unsigned size) "GICv3 ITS write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+gicv3_its_badwrite(uint64_t offset, uint64_t data, unsigned size) "GICv3 ITS write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u: error"
+gicv3_its_translation_write(uint64_t offset, uint64_t data, unsigned size, uint32_t requester_id) "GICv3 ITS TRANSLATER write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u requester_id 0x%x"
+gicv3_its_process_command(uint32_t rd_offset, uint8_t cmd) "GICv3 ITS: processing command at offset 0x%x: 0x%x"
+
# armv7m_nvic.c
nvic_recompute_state(int vectpending, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d vectpending_prio %d exception_prio %d"
nvic_recompute_state_secure(int vectpending, bool vectpending_is_s_banked, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d is_s_banked %d vectpending_prio %d exception_prio %d"
diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c
index b378e6b305..71b74c3372 100644
--- a/hw/misc/mac_via.c
+++ b/hw/misc/mac_via.c
@@ -16,7 +16,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "migration/vmstate.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
@@ -30,6 +29,7 @@
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "sysemu/block-backend.h"
+#include "sysemu/rtc.h"
#include "trace.h"
#include "qemu/log.h"
diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c
index e917a6a095..233daf1405 100644
--- a/hw/misc/macio/cuda.c
+++ b/hw/misc/macio/cuda.c
@@ -24,7 +24,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/ppc/mac.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
@@ -34,6 +33,7 @@
#include "qapi/error.h"
#include "qemu/timer.h"
#include "sysemu/runstate.h"
+#include "sysemu/rtc.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c
index eb39c64694..76c608ee19 100644
--- a/hw/misc/macio/pmu.c
+++ b/hw/misc/macio/pmu.c
@@ -29,7 +29,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/ppc/mac.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
@@ -41,6 +40,7 @@
#include "qapi/error.h"
#include "qemu/timer.h"
#include "sysemu/runstate.h"
+#include "sysemu/rtc.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index d1a1169108..6dcbe044f3 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -84,7 +84,10 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files(
))
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c'))
softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c'))
-softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-xramc.c'))
+softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files(
+ 'xlnx-versal-xramc.c',
+ 'xlnx-versal-pmc-iou-slcr.c',
+))
softmmu_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c'))
softmmu_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c'))
softmmu_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c'))
diff --git a/hw/misc/xlnx-versal-pmc-iou-slcr.c b/hw/misc/xlnx-versal-pmc-iou-slcr.c
new file mode 100644
index 0000000000..07b7ebc217
--- /dev/null
+++ b/hw/misc/xlnx-versal-pmc-iou-slcr.c
@@ -0,0 +1,1446 @@
+/*
+ * QEMU model of Versal's PMC IOU SLCR (system level control registers)
+ *
+ * Copyright (c) 2021 Xilinx Inc.
+ * Written by Edgar E. Iglesias <edgar.iglesias@xilinx.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/register.h"
+#include "hw/irq.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+#include "hw/misc/xlnx-versal-pmc-iou-slcr.h"
+
+#ifndef XILINX_VERSAL_PMC_IOU_SLCR_ERR_DEBUG
+#define XILINX_VERSAL_PMC_IOU_SLCR_ERR_DEBUG 0
+#endif
+
+REG32(MIO_PIN_0, 0x0)
+ FIELD(MIO_PIN_0, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_0, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_0, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_0, L0_SEL, 1, 2)
+REG32(MIO_PIN_1, 0x4)
+ FIELD(MIO_PIN_1, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_1, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_1, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_1, L0_SEL, 1, 2)
+REG32(MIO_PIN_2, 0x8)
+ FIELD(MIO_PIN_2, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_2, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_2, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_2, L0_SEL, 1, 2)
+REG32(MIO_PIN_3, 0xc)
+ FIELD(MIO_PIN_3, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_3, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_3, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_3, L0_SEL, 1, 2)
+REG32(MIO_PIN_4, 0x10)
+ FIELD(MIO_PIN_4, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_4, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_4, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_4, L0_SEL, 1, 2)
+REG32(MIO_PIN_5, 0x14)
+ FIELD(MIO_PIN_5, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_5, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_5, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_5, L0_SEL, 1, 2)
+REG32(MIO_PIN_6, 0x18)
+ FIELD(MIO_PIN_6, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_6, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_6, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_6, L0_SEL, 1, 2)
+REG32(MIO_PIN_7, 0x1c)
+ FIELD(MIO_PIN_7, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_7, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_7, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_7, L0_SEL, 1, 2)
+REG32(MIO_PIN_8, 0x20)
+ FIELD(MIO_PIN_8, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_8, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_8, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_8, L0_SEL, 1, 2)
+REG32(MIO_PIN_9, 0x24)
+ FIELD(MIO_PIN_9, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_9, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_9, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_9, L0_SEL, 1, 2)
+REG32(MIO_PIN_10, 0x28)
+ FIELD(MIO_PIN_10, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_10, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_10, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_10, L0_SEL, 1, 2)
+REG32(MIO_PIN_11, 0x2c)
+ FIELD(MIO_PIN_11, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_11, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_11, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_11, L0_SEL, 1, 2)
+REG32(MIO_PIN_12, 0x30)
+ FIELD(MIO_PIN_12, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_12, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_12, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_12, L0_SEL, 1, 2)
+REG32(MIO_PIN_13, 0x34)
+ FIELD(MIO_PIN_13, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_13, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_13, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_13, L0_SEL, 1, 2)
+REG32(MIO_PIN_14, 0x38)
+ FIELD(MIO_PIN_14, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_14, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_14, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_14, L0_SEL, 1, 2)
+REG32(MIO_PIN_15, 0x3c)
+ FIELD(MIO_PIN_15, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_15, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_15, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_15, L0_SEL, 1, 2)
+REG32(MIO_PIN_16, 0x40)
+ FIELD(MIO_PIN_16, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_16, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_16, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_16, L0_SEL, 1, 2)
+REG32(MIO_PIN_17, 0x44)
+ FIELD(MIO_PIN_17, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_17, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_17, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_17, L0_SEL, 1, 2)
+REG32(MIO_PIN_18, 0x48)
+ FIELD(MIO_PIN_18, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_18, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_18, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_18, L0_SEL, 1, 2)
+REG32(MIO_PIN_19, 0x4c)
+ FIELD(MIO_PIN_19, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_19, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_19, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_19, L0_SEL, 1, 2)
+REG32(MIO_PIN_20, 0x50)
+ FIELD(MIO_PIN_20, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_20, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_20, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_20, L0_SEL, 1, 2)
+REG32(MIO_PIN_21, 0x54)
+ FIELD(MIO_PIN_21, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_21, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_21, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_21, L0_SEL, 1, 2)
+REG32(MIO_PIN_22, 0x58)
+ FIELD(MIO_PIN_22, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_22, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_22, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_22, L0_SEL, 1, 2)
+REG32(MIO_PIN_23, 0x5c)
+ FIELD(MIO_PIN_23, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_23, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_23, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_23, L0_SEL, 1, 2)
+REG32(MIO_PIN_24, 0x60)
+ FIELD(MIO_PIN_24, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_24, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_24, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_24, L0_SEL, 1, 2)
+REG32(MIO_PIN_25, 0x64)
+ FIELD(MIO_PIN_25, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_25, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_25, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_25, L0_SEL, 1, 2)
+REG32(MIO_PIN_26, 0x68)
+ FIELD(MIO_PIN_26, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_26, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_26, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_26, L0_SEL, 1, 2)
+REG32(MIO_PIN_27, 0x6c)
+ FIELD(MIO_PIN_27, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_27, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_27, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_27, L0_SEL, 1, 2)
+REG32(MIO_PIN_28, 0x70)
+ FIELD(MIO_PIN_28, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_28, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_28, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_28, L0_SEL, 1, 2)
+REG32(MIO_PIN_29, 0x74)
+ FIELD(MIO_PIN_29, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_29, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_29, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_29, L0_SEL, 1, 2)
+REG32(MIO_PIN_30, 0x78)
+ FIELD(MIO_PIN_30, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_30, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_30, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_30, L0_SEL, 1, 2)
+REG32(MIO_PIN_31, 0x7c)
+ FIELD(MIO_PIN_31, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_31, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_31, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_31, L0_SEL, 1, 2)
+REG32(MIO_PIN_32, 0x80)
+ FIELD(MIO_PIN_32, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_32, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_32, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_32, L0_SEL, 1, 2)
+REG32(MIO_PIN_33, 0x84)
+ FIELD(MIO_PIN_33, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_33, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_33, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_33, L0_SEL, 1, 2)
+REG32(MIO_PIN_34, 0x88)
+ FIELD(MIO_PIN_34, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_34, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_34, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_34, L0_SEL, 1, 2)
+REG32(MIO_PIN_35, 0x8c)
+ FIELD(MIO_PIN_35, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_35, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_35, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_35, L0_SEL, 1, 2)
+REG32(MIO_PIN_36, 0x90)
+ FIELD(MIO_PIN_36, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_36, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_36, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_36, L0_SEL, 1, 2)
+REG32(MIO_PIN_37, 0x94)
+ FIELD(MIO_PIN_37, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_37, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_37, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_37, L0_SEL, 1, 2)
+REG32(MIO_PIN_38, 0x98)
+ FIELD(MIO_PIN_38, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_38, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_38, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_38, L0_SEL, 1, 2)
+REG32(MIO_PIN_39, 0x9c)
+ FIELD(MIO_PIN_39, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_39, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_39, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_39, L0_SEL, 1, 2)
+REG32(MIO_PIN_40, 0xa0)
+ FIELD(MIO_PIN_40, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_40, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_40, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_40, L0_SEL, 1, 2)
+REG32(MIO_PIN_41, 0xa4)
+ FIELD(MIO_PIN_41, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_41, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_41, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_41, L0_SEL, 1, 2)
+REG32(MIO_PIN_42, 0xa8)
+ FIELD(MIO_PIN_42, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_42, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_42, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_42, L0_SEL, 1, 2)
+REG32(MIO_PIN_43, 0xac)
+ FIELD(MIO_PIN_43, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_43, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_43, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_43, L0_SEL, 1, 2)
+REG32(MIO_PIN_44, 0xb0)
+ FIELD(MIO_PIN_44, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_44, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_44, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_44, L0_SEL, 1, 2)
+REG32(MIO_PIN_45, 0xb4)
+ FIELD(MIO_PIN_45, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_45, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_45, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_45, L0_SEL, 1, 2)
+REG32(MIO_PIN_46, 0xb8)
+ FIELD(MIO_PIN_46, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_46, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_46, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_46, L0_SEL, 1, 2)
+REG32(MIO_PIN_47, 0xbc)
+ FIELD(MIO_PIN_47, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_47, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_47, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_47, L0_SEL, 1, 2)
+REG32(MIO_PIN_48, 0xc0)
+ FIELD(MIO_PIN_48, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_48, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_48, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_48, L0_SEL, 1, 2)
+REG32(MIO_PIN_49, 0xc4)
+ FIELD(MIO_PIN_49, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_49, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_49, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_49, L0_SEL, 1, 2)
+REG32(MIO_PIN_50, 0xc8)
+ FIELD(MIO_PIN_50, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_50, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_50, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_50, L0_SEL, 1, 2)
+REG32(MIO_PIN_51, 0xcc)
+ FIELD(MIO_PIN_51, L3_SEL, 7, 3)
+ FIELD(MIO_PIN_51, L2_SEL, 5, 2)
+ FIELD(MIO_PIN_51, L1_SEL, 3, 2)
+ FIELD(MIO_PIN_51, L0_SEL, 1, 2)
+REG32(BNK0_EN_RX, 0x100)
+ FIELD(BNK0_EN_RX, BNK0_EN_RX, 0, 26)
+REG32(BNK0_SEL_RX0, 0x104)
+REG32(BNK0_SEL_RX1, 0x108)
+ FIELD(BNK0_SEL_RX1, BNK0_SEL_RX, 0, 20)
+REG32(BNK0_EN_RX_SCHMITT_HYST, 0x10c)
+ FIELD(BNK0_EN_RX_SCHMITT_HYST, BNK0_EN_RX_SCHMITT_HYST, 0, 26)
+REG32(BNK0_EN_WK_PD, 0x110)
+ FIELD(BNK0_EN_WK_PD, BNK0_EN_WK_PD, 0, 26)
+REG32(BNK0_EN_WK_PU, 0x114)
+ FIELD(BNK0_EN_WK_PU, BNK0_EN_WK_PU, 0, 26)
+REG32(BNK0_SEL_DRV0, 0x118)
+REG32(BNK0_SEL_DRV1, 0x11c)
+ FIELD(BNK0_SEL_DRV1, BNK0_SEL_DRV, 0, 20)
+REG32(BNK0_SEL_SLEW, 0x120)
+ FIELD(BNK0_SEL_SLEW, BNK0_SEL_SLEW, 0, 26)
+REG32(BNK0_EN_DFT_OPT_INV, 0x124)
+ FIELD(BNK0_EN_DFT_OPT_INV, BNK0_EN_DFT_OPT_INV, 0, 26)
+REG32(BNK0_EN_PAD2PAD_LOOPBACK, 0x128)
+ FIELD(BNK0_EN_PAD2PAD_LOOPBACK, BNK0_EN_PAD2PAD_LOOPBACK, 0, 13)
+REG32(BNK0_RX_SPARE0, 0x12c)
+REG32(BNK0_RX_SPARE1, 0x130)
+ FIELD(BNK0_RX_SPARE1, BNK0_RX_SPARE, 0, 20)
+REG32(BNK0_TX_SPARE0, 0x134)
+REG32(BNK0_TX_SPARE1, 0x138)
+ FIELD(BNK0_TX_SPARE1, BNK0_TX_SPARE, 0, 20)
+REG32(BNK0_SEL_EN1P8, 0x13c)
+ FIELD(BNK0_SEL_EN1P8, BNK0_SEL_EN1P8, 0, 1)
+REG32(BNK0_EN_B_POR_DETECT, 0x140)
+ FIELD(BNK0_EN_B_POR_DETECT, BNK0_EN_B_POR_DETECT, 0, 1)
+REG32(BNK0_LPF_BYP_POR_DETECT, 0x144)
+ FIELD(BNK0_LPF_BYP_POR_DETECT, BNK0_LPF_BYP_POR_DETECT, 0, 1)
+REG32(BNK0_EN_LATCH, 0x148)
+ FIELD(BNK0_EN_LATCH, BNK0_EN_LATCH, 0, 1)
+REG32(BNK0_VBG_LPF_BYP_B, 0x14c)
+ FIELD(BNK0_VBG_LPF_BYP_B, BNK0_VBG_LPF_BYP_B, 0, 1)
+REG32(BNK0_EN_AMP_B, 0x150)
+ FIELD(BNK0_EN_AMP_B, BNK0_EN_AMP_B, 0, 2)
+REG32(BNK0_SPARE_BIAS, 0x154)
+ FIELD(BNK0_SPARE_BIAS, BNK0_SPARE_BIAS, 0, 4)
+REG32(BNK0_DRIVER_BIAS, 0x158)
+ FIELD(BNK0_DRIVER_BIAS, BNK0_DRIVER_BIAS, 0, 15)
+REG32(BNK0_VMODE, 0x15c)
+ FIELD(BNK0_VMODE, BNK0_VMODE, 0, 1)
+REG32(BNK0_SEL_AUX_IO_RX, 0x160)
+ FIELD(BNK0_SEL_AUX_IO_RX, BNK0_SEL_AUX_IO_RX, 0, 26)
+REG32(BNK0_EN_TX_HS_MODE, 0x164)
+ FIELD(BNK0_EN_TX_HS_MODE, BNK0_EN_TX_HS_MODE, 0, 26)
+REG32(MIO_MST_TRI0, 0x200)
+ FIELD(MIO_MST_TRI0, PIN_25_TRI, 25, 1)
+ FIELD(MIO_MST_TRI0, PIN_24_TRI, 24, 1)
+ FIELD(MIO_MST_TRI0, PIN_23_TRI, 23, 1)
+ FIELD(MIO_MST_TRI0, PIN_22_TRI, 22, 1)
+ FIELD(MIO_MST_TRI0, PIN_21_TRI, 21, 1)
+ FIELD(MIO_MST_TRI0, PIN_20_TRI, 20, 1)
+ FIELD(MIO_MST_TRI0, PIN_19_TRI, 19, 1)
+ FIELD(MIO_MST_TRI0, PIN_18_TRI, 18, 1)
+ FIELD(MIO_MST_TRI0, PIN_17_TRI, 17, 1)
+ FIELD(MIO_MST_TRI0, PIN_16_TRI, 16, 1)
+ FIELD(MIO_MST_TRI0, PIN_15_TRI, 15, 1)
+ FIELD(MIO_MST_TRI0, PIN_14_TRI, 14, 1)
+ FIELD(MIO_MST_TRI0, PIN_13_TRI, 13, 1)
+ FIELD(MIO_MST_TRI0, PIN_12_TRI, 12, 1)
+ FIELD(MIO_MST_TRI0, PIN_11_TRI, 11, 1)
+ FIELD(MIO_MST_TRI0, PIN_10_TRI, 10, 1)
+ FIELD(MIO_MST_TRI0, PIN_09_TRI, 9, 1)
+ FIELD(MIO_MST_TRI0, PIN_08_TRI, 8, 1)
+ FIELD(MIO_MST_TRI0, PIN_07_TRI, 7, 1)
+ FIELD(MIO_MST_TRI0, PIN_06_TRI, 6, 1)
+ FIELD(MIO_MST_TRI0, PIN_05_TRI, 5, 1)
+ FIELD(MIO_MST_TRI0, PIN_04_TRI, 4, 1)
+ FIELD(MIO_MST_TRI0, PIN_03_TRI, 3, 1)
+ FIELD(MIO_MST_TRI0, PIN_02_TRI, 2, 1)
+ FIELD(MIO_MST_TRI0, PIN_01_TRI, 1, 1)
+ FIELD(MIO_MST_TRI0, PIN_00_TRI, 0, 1)
+REG32(MIO_MST_TRI1, 0x204)
+ FIELD(MIO_MST_TRI1, PIN_51_TRI, 25, 1)
+ FIELD(MIO_MST_TRI1, PIN_50_TRI, 24, 1)
+ FIELD(MIO_MST_TRI1, PIN_49_TRI, 23, 1)
+ FIELD(MIO_MST_TRI1, PIN_48_TRI, 22, 1)
+ FIELD(MIO_MST_TRI1, PIN_47_TRI, 21, 1)
+ FIELD(MIO_MST_TRI1, PIN_46_TRI, 20, 1)
+ FIELD(MIO_MST_TRI1, PIN_45_TRI, 19, 1)
+ FIELD(MIO_MST_TRI1, PIN_44_TRI, 18, 1)
+ FIELD(MIO_MST_TRI1, PIN_43_TRI, 17, 1)
+ FIELD(MIO_MST_TRI1, PIN_42_TRI, 16, 1)
+ FIELD(MIO_MST_TRI1, PIN_41_TRI, 15, 1)
+ FIELD(MIO_MST_TRI1, PIN_40_TRI, 14, 1)
+ FIELD(MIO_MST_TRI1, PIN_39_TRI, 13, 1)
+ FIELD(MIO_MST_TRI1, PIN_38_TRI, 12, 1)
+ FIELD(MIO_MST_TRI1, PIN_37_TRI, 11, 1)
+ FIELD(MIO_MST_TRI1, PIN_36_TRI, 10, 1)
+ FIELD(MIO_MST_TRI1, PIN_35_TRI, 9, 1)
+ FIELD(MIO_MST_TRI1, PIN_34_TRI, 8, 1)
+ FIELD(MIO_MST_TRI1, PIN_33_TRI, 7, 1)
+ FIELD(MIO_MST_TRI1, PIN_32_TRI, 6, 1)
+ FIELD(MIO_MST_TRI1, PIN_31_TRI, 5, 1)
+ FIELD(MIO_MST_TRI1, PIN_30_TRI, 4, 1)
+ FIELD(MIO_MST_TRI1, PIN_29_TRI, 3, 1)
+ FIELD(MIO_MST_TRI1, PIN_28_TRI, 2, 1)
+ FIELD(MIO_MST_TRI1, PIN_27_TRI, 1, 1)
+ FIELD(MIO_MST_TRI1, PIN_26_TRI, 0, 1)
+REG32(BNK1_EN_RX, 0x300)
+ FIELD(BNK1_EN_RX, BNK1_EN_RX, 0, 26)
+REG32(BNK1_SEL_RX0, 0x304)
+REG32(BNK1_SEL_RX1, 0x308)
+ FIELD(BNK1_SEL_RX1, BNK1_SEL_RX, 0, 20)
+REG32(BNK1_EN_RX_SCHMITT_HYST, 0x30c)
+ FIELD(BNK1_EN_RX_SCHMITT_HYST, BNK1_EN_RX_SCHMITT_HYST, 0, 26)
+REG32(BNK1_EN_WK_PD, 0x310)
+ FIELD(BNK1_EN_WK_PD, BNK1_EN_WK_PD, 0, 26)
+REG32(BNK1_EN_WK_PU, 0x314)
+ FIELD(BNK1_EN_WK_PU, BNK1_EN_WK_PU, 0, 26)
+REG32(BNK1_SEL_DRV0, 0x318)
+REG32(BNK1_SEL_DRV1, 0x31c)
+ FIELD(BNK1_SEL_DRV1, BNK1_SEL_DRV, 0, 20)
+REG32(BNK1_SEL_SLEW, 0x320)
+ FIELD(BNK1_SEL_SLEW, BNK1_SEL_SLEW, 0, 26)
+REG32(BNK1_EN_DFT_OPT_INV, 0x324)
+ FIELD(BNK1_EN_DFT_OPT_INV, BNK1_EN_DFT_OPT_INV, 0, 26)
+REG32(BNK1_EN_PAD2PAD_LOOPBACK, 0x328)
+ FIELD(BNK1_EN_PAD2PAD_LOOPBACK, BNK1_EN_PAD2PAD_LOOPBACK, 0, 13)
+REG32(BNK1_RX_SPARE0, 0x32c)
+REG32(BNK1_RX_SPARE1, 0x330)
+ FIELD(BNK1_RX_SPARE1, BNK1_RX_SPARE, 0, 20)
+REG32(BNK1_TX_SPARE0, 0x334)
+REG32(BNK1_TX_SPARE1, 0x338)
+ FIELD(BNK1_TX_SPARE1, BNK1_TX_SPARE, 0, 20)
+REG32(BNK1_SEL_EN1P8, 0x33c)
+ FIELD(BNK1_SEL_EN1P8, BNK1_SEL_EN1P8, 0, 1)
+REG32(BNK1_EN_B_POR_DETECT, 0x340)
+ FIELD(BNK1_EN_B_POR_DETECT, BNK1_EN_B_POR_DETECT, 0, 1)
+REG32(BNK1_LPF_BYP_POR_DETECT, 0x344)
+ FIELD(BNK1_LPF_BYP_POR_DETECT, BNK1_LPF_BYP_POR_DETECT, 0, 1)
+REG32(BNK1_EN_LATCH, 0x348)
+ FIELD(BNK1_EN_LATCH, BNK1_EN_LATCH, 0, 1)
+REG32(BNK1_VBG_LPF_BYP_B, 0x34c)
+ FIELD(BNK1_VBG_LPF_BYP_B, BNK1_VBG_LPF_BYP_B, 0, 1)
+REG32(BNK1_EN_AMP_B, 0x350)
+ FIELD(BNK1_EN_AMP_B, BNK1_EN_AMP_B, 0, 2)
+REG32(BNK1_SPARE_BIAS, 0x354)
+ FIELD(BNK1_SPARE_BIAS, BNK1_SPARE_BIAS, 0, 4)
+REG32(BNK1_DRIVER_BIAS, 0x358)
+ FIELD(BNK1_DRIVER_BIAS, BNK1_DRIVER_BIAS, 0, 15)
+REG32(BNK1_VMODE, 0x35c)
+ FIELD(BNK1_VMODE, BNK1_VMODE, 0, 1)
+REG32(BNK1_SEL_AUX_IO_RX, 0x360)
+ FIELD(BNK1_SEL_AUX_IO_RX, BNK1_SEL_AUX_IO_RX, 0, 26)
+REG32(BNK1_EN_TX_HS_MODE, 0x364)
+ FIELD(BNK1_EN_TX_HS_MODE, BNK1_EN_TX_HS_MODE, 0, 26)
+REG32(SD0_CLK_CTRL, 0x400)
+ FIELD(SD0_CLK_CTRL, SDIO0_FBCLK_SEL, 2, 1)
+ FIELD(SD0_CLK_CTRL, SDIO0_RX_SRC_SEL, 0, 2)
+REG32(SD0_CTRL_REG, 0x404)
+ FIELD(SD0_CTRL_REG, SD0_EMMC_SEL, 0, 1)
+REG32(SD0_CONFIG_REG1, 0x410)
+ FIELD(SD0_CONFIG_REG1, SD0_BASECLK, 7, 8)
+ FIELD(SD0_CONFIG_REG1, SD0_TUNIGCOUNT, 1, 6)
+ FIELD(SD0_CONFIG_REG1, SD0_ASYNCWKPENA, 0, 1)
+REG32(SD0_CONFIG_REG2, 0x414)
+ FIELD(SD0_CONFIG_REG2, SD0_SLOTTYPE, 12, 2)
+ FIELD(SD0_CONFIG_REG2, SD0_ASYCINTR, 11, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_64BIT, 10, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_1P8V, 9, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_3P0V, 8, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_3P3V, 7, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_SUSPRES, 6, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_SDMA, 5, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_HIGHSPEED, 4, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_ADMA2, 3, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_8BIT, 2, 1)
+ FIELD(SD0_CONFIG_REG2, SD0_MAXBLK, 0, 2)
+REG32(SD0_CONFIG_REG3, 0x418)
+ FIELD(SD0_CONFIG_REG3, SD0_TUNINGSDR50, 10, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_RETUNETMR, 6, 4)
+ FIELD(SD0_CONFIG_REG3, SD0_DDRIVER, 5, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_CDRIVER, 4, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_ADRIVER, 3, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_DDR50, 2, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_SDR104, 1, 1)
+ FIELD(SD0_CONFIG_REG3, SD0_SDR50, 0, 1)
+REG32(SD0_INITPRESET, 0x41c)
+ FIELD(SD0_INITPRESET, SD0_INITPRESET, 0, 13)
+REG32(SD0_DSPPRESET, 0x420)
+ FIELD(SD0_DSPPRESET, SD0_DSPPRESET, 0, 13)
+REG32(SD0_HSPDPRESET, 0x424)
+ FIELD(SD0_HSPDPRESET, SD0_HSPDPRESET, 0, 13)
+REG32(SD0_SDR12PRESET, 0x428)
+ FIELD(SD0_SDR12PRESET, SD0_SDR12PRESET, 0, 13)
+REG32(SD0_SDR25PRESET, 0x42c)
+ FIELD(SD0_SDR25PRESET, SD0_SDR25PRESET, 0, 13)
+REG32(SD0_SDR50PRSET, 0x430)
+ FIELD(SD0_SDR50PRSET, SD0_SDR50PRESET, 0, 13)
+REG32(SD0_SDR104PRST, 0x434)
+ FIELD(SD0_SDR104PRST, SD0_SDR104PRESET, 0, 13)
+REG32(SD0_DDR50PRESET, 0x438)
+ FIELD(SD0_DDR50PRESET, SD0_DDR50PRESET, 0, 13)
+REG32(SD0_MAXCUR1P8, 0x43c)
+ FIELD(SD0_MAXCUR1P8, SD0_MAXCUR1P8, 0, 8)
+REG32(SD0_MAXCUR3P0, 0x440)
+ FIELD(SD0_MAXCUR3P0, SD0_MAXCUR3P0, 0, 8)
+REG32(SD0_MAXCUR3P3, 0x444)
+ FIELD(SD0_MAXCUR3P3, SD0_MAXCUR3P3, 0, 8)
+REG32(SD0_DLL_CTRL, 0x448)
+ FIELD(SD0_DLL_CTRL, SD0_CLKSTABLE_CFG, 9, 1)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_CFG, 5, 4)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_PSDONE, 4, 1)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_OVF, 3, 1)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_RST, 2, 1)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_TESTMODE, 1, 1)
+ FIELD(SD0_DLL_CTRL, SD0_DLL_LOCK, 0, 1)
+REG32(SD0_CDN_CTRL, 0x44c)
+ FIELD(SD0_CDN_CTRL, SD0_CDN_CTRL, 0, 1)
+REG32(SD0_DLL_TEST, 0x450)
+ FIELD(SD0_DLL_TEST, DLL_DIV, 16, 8)
+ FIELD(SD0_DLL_TEST, DLL_TX_SEL, 9, 7)
+ FIELD(SD0_DLL_TEST, DLL_RX_SEL, 0, 9)
+REG32(SD0_RX_TUNING_SEL, 0x454)
+ FIELD(SD0_RX_TUNING_SEL, SD0_RX_SEL, 0, 9)
+REG32(SD0_DLL_DIV_MAP0, 0x458)
+ FIELD(SD0_DLL_DIV_MAP0, DIV_3, 24, 8)
+ FIELD(SD0_DLL_DIV_MAP0, DIV_2, 16, 8)
+ FIELD(SD0_DLL_DIV_MAP0, DIV_1, 8, 8)
+ FIELD(SD0_DLL_DIV_MAP0, DIV_0, 0, 8)
+REG32(SD0_DLL_DIV_MAP1, 0x45c)
+ FIELD(SD0_DLL_DIV_MAP1, DIV_7, 24, 8)
+ FIELD(SD0_DLL_DIV_MAP1, DIV_6, 16, 8)
+ FIELD(SD0_DLL_DIV_MAP1, DIV_5, 8, 8)
+ FIELD(SD0_DLL_DIV_MAP1, DIV_4, 0, 8)
+REG32(SD0_IOU_COHERENT_CTRL, 0x460)
+ FIELD(SD0_IOU_COHERENT_CTRL, SD0_AXI_COH, 0, 4)
+REG32(SD0_IOU_INTERCONNECT_ROUTE, 0x464)
+ FIELD(SD0_IOU_INTERCONNECT_ROUTE, SD0, 0, 1)
+REG32(SD0_IOU_RAM, 0x468)
+ FIELD(SD0_IOU_RAM, EMASA0, 6, 1)
+ FIELD(SD0_IOU_RAM, EMAB0, 3, 3)
+ FIELD(SD0_IOU_RAM, EMAA0, 0, 3)
+REG32(SD0_IOU_INTERCONNECT_QOS, 0x46c)
+ FIELD(SD0_IOU_INTERCONNECT_QOS, SD0_QOS, 0, 4)
+REG32(SD1_CLK_CTRL, 0x480)
+ FIELD(SD1_CLK_CTRL, SDIO1_FBCLK_SEL, 1, 1)
+ FIELD(SD1_CLK_CTRL, SDIO1_RX_SRC_SEL, 0, 1)
+REG32(SD1_CTRL_REG, 0x484)
+ FIELD(SD1_CTRL_REG, SD1_EMMC_SEL, 0, 1)
+REG32(SD1_CONFIG_REG1, 0x490)
+ FIELD(SD1_CONFIG_REG1, SD1_BASECLK, 7, 8)
+ FIELD(SD1_CONFIG_REG1, SD1_TUNIGCOUNT, 1, 6)
+ FIELD(SD1_CONFIG_REG1, SD1_ASYNCWKPENA, 0, 1)
+REG32(SD1_CONFIG_REG2, 0x494)
+ FIELD(SD1_CONFIG_REG2, SD1_SLOTTYPE, 12, 2)
+ FIELD(SD1_CONFIG_REG2, SD1_ASYCINTR, 11, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_64BIT, 10, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_1P8V, 9, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_3P0V, 8, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_3P3V, 7, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_SUSPRES, 6, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_SDMA, 5, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_HIGHSPEED, 4, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_ADMA2, 3, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_8BIT, 2, 1)
+ FIELD(SD1_CONFIG_REG2, SD1_MAXBLK, 0, 2)
+REG32(SD1_CONFIG_REG3, 0x498)
+ FIELD(SD1_CONFIG_REG3, SD1_TUNINGSDR50, 10, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_RETUNETMR, 6, 4)
+ FIELD(SD1_CONFIG_REG3, SD1_DDRIVER, 5, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_CDRIVER, 4, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_ADRIVER, 3, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_DDR50, 2, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_SDR104, 1, 1)
+ FIELD(SD1_CONFIG_REG3, SD1_SDR50, 0, 1)
+REG32(SD1_INITPRESET, 0x49c)
+ FIELD(SD1_INITPRESET, SD1_INITPRESET, 0, 13)
+REG32(SD1_DSPPRESET, 0x4a0)
+ FIELD(SD1_DSPPRESET, SD1_DSPPRESET, 0, 13)
+REG32(SD1_HSPDPRESET, 0x4a4)
+ FIELD(SD1_HSPDPRESET, SD1_HSPDPRESET, 0, 13)
+REG32(SD1_SDR12PRESET, 0x4a8)
+ FIELD(SD1_SDR12PRESET, SD1_SDR12PRESET, 0, 13)
+REG32(SD1_SDR25PRESET, 0x4ac)
+ FIELD(SD1_SDR25PRESET, SD1_SDR25PRESET, 0, 13)
+REG32(SD1_SDR50PRSET, 0x4b0)
+ FIELD(SD1_SDR50PRSET, SD1_SDR50PRESET, 0, 13)
+REG32(SD1_SDR104PRST, 0x4b4)
+ FIELD(SD1_SDR104PRST, SD1_SDR104PRESET, 0, 13)
+REG32(SD1_DDR50PRESET, 0x4b8)
+ FIELD(SD1_DDR50PRESET, SD1_DDR50PRESET, 0, 13)
+REG32(SD1_MAXCUR1P8, 0x4bc)
+ FIELD(SD1_MAXCUR1P8, SD1_MAXCUR1P8, 0, 8)
+REG32(SD1_MAXCUR3P0, 0x4c0)
+ FIELD(SD1_MAXCUR3P0, SD1_MAXCUR3P0, 0, 8)
+REG32(SD1_MAXCUR3P3, 0x4c4)
+ FIELD(SD1_MAXCUR3P3, SD1_MAXCUR3P3, 0, 8)
+REG32(SD1_DLL_CTRL, 0x4c8)
+ FIELD(SD1_DLL_CTRL, SD1_CLKSTABLE_CFG, 9, 1)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_CFG, 5, 4)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_PSDONE, 4, 1)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_OVF, 3, 1)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_RST, 2, 1)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_TESTMODE, 1, 1)
+ FIELD(SD1_DLL_CTRL, SD1_DLL_LOCK, 0, 1)
+REG32(SD1_CDN_CTRL, 0x4cc)
+ FIELD(SD1_CDN_CTRL, SD1_CDN_CTRL, 0, 1)
+REG32(SD1_DLL_TEST, 0x4d0)
+ FIELD(SD1_DLL_TEST, DLL_DIV, 16, 8)
+ FIELD(SD1_DLL_TEST, DLL_TX_SEL, 9, 7)
+ FIELD(SD1_DLL_TEST, DLL_RX_SEL, 0, 9)
+REG32(SD1_RX_TUNING_SEL, 0x4d4)
+ FIELD(SD1_RX_TUNING_SEL, SD1_RX_SEL, 0, 9)
+REG32(SD1_DLL_DIV_MAP0, 0x4d8)
+ FIELD(SD1_DLL_DIV_MAP0, DIV_3, 24, 8)
+ FIELD(SD1_DLL_DIV_MAP0, DIV_2, 16, 8)
+ FIELD(SD1_DLL_DIV_MAP0, DIV_1, 8, 8)
+ FIELD(SD1_DLL_DIV_MAP0, DIV_0, 0, 8)
+REG32(SD1_DLL_DIV_MAP1, 0x4dc)
+ FIELD(SD1_DLL_DIV_MAP1, DIV_7, 24, 8)
+ FIELD(SD1_DLL_DIV_MAP1, DIV_6, 16, 8)
+ FIELD(SD1_DLL_DIV_MAP1, DIV_5, 8, 8)
+ FIELD(SD1_DLL_DIV_MAP1, DIV_4, 0, 8)
+REG32(SD1_IOU_COHERENT_CTRL, 0x4e0)
+ FIELD(SD1_IOU_COHERENT_CTRL, SD1_AXI_COH, 0, 4)
+REG32(SD1_IOU_INTERCONNECT_ROUTE, 0x4e4)
+ FIELD(SD1_IOU_INTERCONNECT_ROUTE, SD1, 0, 1)
+REG32(SD1_IOU_RAM, 0x4e8)
+ FIELD(SD1_IOU_RAM, EMASA0, 6, 1)
+ FIELD(SD1_IOU_RAM, EMAB0, 3, 3)
+ FIELD(SD1_IOU_RAM, EMAA0, 0, 3)
+REG32(SD1_IOU_INTERCONNECT_QOS, 0x4ec)
+ FIELD(SD1_IOU_INTERCONNECT_QOS, SD1_QOS, 0, 4)
+REG32(OSPI_QSPI_IOU_AXI_MUX_SEL, 0x504)
+ FIELD(OSPI_QSPI_IOU_AXI_MUX_SEL, OSPI_MUX_SEL, 1, 1)
+ FIELD(OSPI_QSPI_IOU_AXI_MUX_SEL, QSPI_OSPI_MUX_SEL, 0, 1)
+REG32(QSPI_IOU_COHERENT_CTRL, 0x508)
+ FIELD(QSPI_IOU_COHERENT_CTRL, QSPI_AXI_COH, 0, 4)
+REG32(QSPI_IOU_INTERCONNECT_ROUTE, 0x50c)
+ FIELD(QSPI_IOU_INTERCONNECT_ROUTE, QSPI, 0, 1)
+REG32(QSPI_IOU_RAM, 0x510)
+ FIELD(QSPI_IOU_RAM, EMASA1, 13, 1)
+ FIELD(QSPI_IOU_RAM, EMAB1, 10, 3)
+ FIELD(QSPI_IOU_RAM, EMAA1, 7, 3)
+ FIELD(QSPI_IOU_RAM, EMASA0, 6, 1)
+ FIELD(QSPI_IOU_RAM, EMAB0, 3, 3)
+ FIELD(QSPI_IOU_RAM, EMAA0, 0, 3)
+REG32(QSPI_IOU_INTERCONNECT_QOS, 0x514)
+ FIELD(QSPI_IOU_INTERCONNECT_QOS, QSPI_QOS, 0, 4)
+REG32(OSPI_IOU_COHERENT_CTRL, 0x530)
+ FIELD(OSPI_IOU_COHERENT_CTRL, OSPI_AXI_COH, 0, 4)
+REG32(OSPI_IOU_INTERCONNECT_ROUTE, 0x534)
+ FIELD(OSPI_IOU_INTERCONNECT_ROUTE, OSPI, 0, 1)
+REG32(OSPI_IOU_RAM, 0x538)
+ FIELD(OSPI_IOU_RAM, EMAS0, 5, 1)
+ FIELD(OSPI_IOU_RAM, EMAW0, 3, 2)
+ FIELD(OSPI_IOU_RAM, EMA0, 0, 3)
+REG32(OSPI_IOU_INTERCONNECT_QOS, 0x53c)
+ FIELD(OSPI_IOU_INTERCONNECT_QOS, OSPI_QOS, 0, 4)
+REG32(OSPI_REFCLK_DLY_CTRL, 0x540)
+ FIELD(OSPI_REFCLK_DLY_CTRL, DLY1, 3, 2)
+ FIELD(OSPI_REFCLK_DLY_CTRL, DLY0, 0, 3)
+REG32(CUR_PWR_ST, 0x600)
+ FIELD(CUR_PWR_ST, U2PMU, 0, 2)
+REG32(CONNECT_ST, 0x604)
+ FIELD(CONNECT_ST, U2PMU, 0, 1)
+REG32(PW_STATE_REQ, 0x608)
+ FIELD(PW_STATE_REQ, BIT_1_0, 0, 2)
+REG32(HOST_U2_PORT_DISABLE, 0x60c)
+ FIELD(HOST_U2_PORT_DISABLE, BIT_0, 0, 1)
+REG32(DBG_U2PMU, 0x610)
+REG32(DBG_U2PMU_EXT1, 0x614)
+REG32(DBG_U2PMU_EXT2, 0x618)
+ FIELD(DBG_U2PMU_EXT2, BIT_67_64, 0, 4)
+REG32(PME_GEN_U2PMU, 0x61c)
+ FIELD(PME_GEN_U2PMU, BIT_0, 0, 1)
+REG32(PWR_CONFIG_USB2, 0x620)
+ FIELD(PWR_CONFIG_USB2, STRAP, 0, 30)
+REG32(PHY_HUB, 0x624)
+ FIELD(PHY_HUB, VBUS_CTRL, 1, 1)
+ FIELD(PHY_HUB, OVER_CURRENT, 0, 1)
+REG32(CTRL, 0x700)
+ FIELD(CTRL, SLVERR_ENABLE, 0, 1)
+REG32(ISR, 0x800)
+ FIELD(ISR, ADDR_DECODE_ERR, 0, 1)
+REG32(IMR, 0x804)
+ FIELD(IMR, ADDR_DECODE_ERR, 0, 1)
+REG32(IER, 0x808)
+ FIELD(IER, ADDR_DECODE_ERR, 0, 1)
+REG32(IDR, 0x80c)
+ FIELD(IDR, ADDR_DECODE_ERR, 0, 1)
+REG32(ITR, 0x810)
+ FIELD(ITR, ADDR_DECODE_ERR, 0, 1)
+REG32(PARITY_ISR, 0x814)
+ FIELD(PARITY_ISR, PERR_AXI_SD1_IOU, 12, 1)
+ FIELD(PARITY_ISR, PERR_AXI_SD0_IOU, 11, 1)
+ FIELD(PARITY_ISR, PERR_AXI_QSPI_IOU, 10, 1)
+ FIELD(PARITY_ISR, PERR_AXI_OSPI_IOU, 9, 1)
+ FIELD(PARITY_ISR, PERR_IOU_SD1, 8, 1)
+ FIELD(PARITY_ISR, PERR_IOU_SD0, 7, 1)
+ FIELD(PARITY_ISR, PERR_IOU_QSPI1, 6, 1)
+ FIELD(PARITY_ISR, PERR_IOUSLCR_SECURE_APB, 5, 1)
+ FIELD(PARITY_ISR, PERR_IOUSLCR_APB, 4, 1)
+ FIELD(PARITY_ISR, PERR_QSPI0_APB, 3, 1)
+ FIELD(PARITY_ISR, PERR_OSPI_APB, 2, 1)
+ FIELD(PARITY_ISR, PERR_I2C_APB, 1, 1)
+ FIELD(PARITY_ISR, PERR_GPIO_APB, 0, 1)
+REG32(PARITY_IMR, 0x818)
+ FIELD(PARITY_IMR, PERR_AXI_SD1_IOU, 12, 1)
+ FIELD(PARITY_IMR, PERR_AXI_SD0_IOU, 11, 1)
+ FIELD(PARITY_IMR, PERR_AXI_QSPI_IOU, 10, 1)
+ FIELD(PARITY_IMR, PERR_AXI_OSPI_IOU, 9, 1)
+ FIELD(PARITY_IMR, PERR_IOU_SD1, 8, 1)
+ FIELD(PARITY_IMR, PERR_IOU_SD0, 7, 1)
+ FIELD(PARITY_IMR, PERR_IOU_QSPI1, 6, 1)
+ FIELD(PARITY_IMR, PERR_IOUSLCR_SECURE_APB, 5, 1)
+ FIELD(PARITY_IMR, PERR_IOUSLCR_APB, 4, 1)
+ FIELD(PARITY_IMR, PERR_QSPI0_APB, 3, 1)
+ FIELD(PARITY_IMR, PERR_OSPI_APB, 2, 1)
+ FIELD(PARITY_IMR, PERR_I2C_APB, 1, 1)
+ FIELD(PARITY_IMR, PERR_GPIO_APB, 0, 1)
+REG32(PARITY_IER, 0x81c)
+ FIELD(PARITY_IER, PERR_AXI_SD1_IOU, 12, 1)
+ FIELD(PARITY_IER, PERR_AXI_SD0_IOU, 11, 1)
+ FIELD(PARITY_IER, PERR_AXI_QSPI_IOU, 10, 1)
+ FIELD(PARITY_IER, PERR_AXI_OSPI_IOU, 9, 1)
+ FIELD(PARITY_IER, PERR_IOU_SD1, 8, 1)
+ FIELD(PARITY_IER, PERR_IOU_SD0, 7, 1)
+ FIELD(PARITY_IER, PERR_IOU_QSPI1, 6, 1)
+ FIELD(PARITY_IER, PERR_IOUSLCR_SECURE_APB, 5, 1)
+ FIELD(PARITY_IER, PERR_IOUSLCR_APB, 4, 1)
+ FIELD(PARITY_IER, PERR_QSPI0_APB, 3, 1)
+ FIELD(PARITY_IER, PERR_OSPI_APB, 2, 1)
+ FIELD(PARITY_IER, PERR_I2C_APB, 1, 1)
+ FIELD(PARITY_IER, PERR_GPIO_APB, 0, 1)
+REG32(PARITY_IDR, 0x820)
+ FIELD(PARITY_IDR, PERR_AXI_SD1_IOU, 12, 1)
+ FIELD(PARITY_IDR, PERR_AXI_SD0_IOU, 11, 1)
+ FIELD(PARITY_IDR, PERR_AXI_QSPI_IOU, 10, 1)
+ FIELD(PARITY_IDR, PERR_AXI_OSPI_IOU, 9, 1)
+ FIELD(PARITY_IDR, PERR_IOU_SD1, 8, 1)
+ FIELD(PARITY_IDR, PERR_IOU_SD0, 7, 1)
+ FIELD(PARITY_IDR, PERR_IOU_QSPI1, 6, 1)
+ FIELD(PARITY_IDR, PERR_IOUSLCR_SECURE_APB, 5, 1)
+ FIELD(PARITY_IDR, PERR_IOUSLCR_APB, 4, 1)
+ FIELD(PARITY_IDR, PERR_QSPI0_APB, 3, 1)
+ FIELD(PARITY_IDR, PERR_OSPI_APB, 2, 1)
+ FIELD(PARITY_IDR, PERR_I2C_APB, 1, 1)
+ FIELD(PARITY_IDR, PERR_GPIO_APB, 0, 1)
+REG32(PARITY_ITR, 0x824)
+ FIELD(PARITY_ITR, PERR_AXI_SD1_IOU, 12, 1)
+ FIELD(PARITY_ITR, PERR_AXI_SD0_IOU, 11, 1)
+ FIELD(PARITY_ITR, PERR_AXI_QSPI_IOU, 10, 1)
+ FIELD(PARITY_ITR, PERR_AXI_OSPI_IOU, 9, 1)
+ FIELD(PARITY_ITR, PERR_IOU_SD1, 8, 1)
+ FIELD(PARITY_ITR, PERR_IOU_SD0, 7, 1)
+ FIELD(PARITY_ITR, PERR_IOU_QSPI1, 6, 1)
+ FIELD(PARITY_ITR, PERR_IOUSLCR_SECURE_APB, 5, 1)
+ FIELD(PARITY_ITR, PERR_IOUSLCR_APB, 4, 1)
+ FIELD(PARITY_ITR, PERR_QSPI0_APB, 3, 1)
+ FIELD(PARITY_ITR, PERR_OSPI_APB, 2, 1)
+ FIELD(PARITY_ITR, PERR_I2C_APB, 1, 1)
+ FIELD(PARITY_ITR, PERR_GPIO_APB, 0, 1)
+REG32(WPROT0, 0x828)
+ FIELD(WPROT0, ACTIVE, 0, 1)
+
+static void parity_imr_update_irq(XlnxVersalPmcIouSlcr *s)
+{
+ bool pending = s->regs[R_PARITY_ISR] & ~s->regs[R_PARITY_IMR];
+ qemu_set_irq(s->irq_parity_imr, pending);
+}
+
+static void parity_isr_postw(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ parity_imr_update_irq(s);
+}
+
+static uint64_t parity_ier_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_PARITY_IMR] &= ~val;
+ parity_imr_update_irq(s);
+ return 0;
+}
+
+static uint64_t parity_idr_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_PARITY_IMR] |= val;
+ parity_imr_update_irq(s);
+ return 0;
+}
+
+static uint64_t parity_itr_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_PARITY_ISR] |= val;
+ parity_imr_update_irq(s);
+ return 0;
+}
+
+static void imr_update_irq(XlnxVersalPmcIouSlcr *s)
+{
+ bool pending = s->regs[R_ISR] & ~s->regs[R_IMR];
+ qemu_set_irq(s->irq_imr, pending);
+}
+
+static void isr_postw(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ imr_update_irq(s);
+}
+
+static uint64_t ier_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_IMR] &= ~val;
+ imr_update_irq(s);
+ return 0;
+}
+
+static uint64_t idr_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_IMR] |= val;
+ imr_update_irq(s);
+ return 0;
+}
+
+static uint64_t itr_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val = val64;
+
+ s->regs[R_ISR] |= val;
+ imr_update_irq(s);
+ return 0;
+}
+
+static uint64_t sd0_ctrl_reg_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t prev = ARRAY_FIELD_EX32(s->regs, SD0_CTRL_REG, SD0_EMMC_SEL);
+
+ if (prev != (val64 & R_SD0_CTRL_REG_SD0_EMMC_SEL_MASK)) {
+ qemu_set_irq(s->sd_emmc_sel[0], !!val64);
+ }
+
+ return val64;
+}
+
+static uint64_t sd1_ctrl_reg_prew(RegisterInfo *reg, uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t prev = ARRAY_FIELD_EX32(s->regs, SD1_CTRL_REG, SD1_EMMC_SEL);
+
+ if (prev != (val64 & R_SD1_CTRL_REG_SD1_EMMC_SEL_MASK)) {
+ qemu_set_irq(s->sd_emmc_sel[1], !!val64);
+ }
+
+ return val64;
+}
+
+static uint64_t ospi_qspi_iou_axi_mux_sel_prew(RegisterInfo *reg,
+ uint64_t val64)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(reg->opaque);
+ uint32_t val32 = (uint32_t) val64;
+ uint8_t ospi_mux_sel = FIELD_EX32(val32, OSPI_QSPI_IOU_AXI_MUX_SEL,
+ OSPI_MUX_SEL);
+ uint8_t qspi_ospi_mux_sel = FIELD_EX32(val32, OSPI_QSPI_IOU_AXI_MUX_SEL,
+ QSPI_OSPI_MUX_SEL);
+
+ if (ospi_mux_sel !=
+ ARRAY_FIELD_EX32(s->regs, OSPI_QSPI_IOU_AXI_MUX_SEL, OSPI_MUX_SEL)) {
+ qemu_set_irq(s->ospi_mux_sel, !!ospi_mux_sel);
+ }
+
+ if (qspi_ospi_mux_sel !=
+ ARRAY_FIELD_EX32(s->regs, OSPI_QSPI_IOU_AXI_MUX_SEL,
+ QSPI_OSPI_MUX_SEL)) {
+ qemu_set_irq(s->qspi_ospi_mux_sel, !!qspi_ospi_mux_sel);
+ }
+
+ return val64;
+}
+
+static RegisterAccessInfo pmc_iou_slcr_regs_info[] = {
+ { .name = "MIO_PIN_0", .addr = A_MIO_PIN_0,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_1", .addr = A_MIO_PIN_1,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_2", .addr = A_MIO_PIN_2,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_3", .addr = A_MIO_PIN_3,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_4", .addr = A_MIO_PIN_4,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_5", .addr = A_MIO_PIN_5,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_6", .addr = A_MIO_PIN_6,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_7", .addr = A_MIO_PIN_7,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_8", .addr = A_MIO_PIN_8,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_9", .addr = A_MIO_PIN_9,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_10", .addr = A_MIO_PIN_10,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_11", .addr = A_MIO_PIN_11,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_12", .addr = A_MIO_PIN_12,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_13", .addr = A_MIO_PIN_13,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_14", .addr = A_MIO_PIN_14,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_15", .addr = A_MIO_PIN_15,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_16", .addr = A_MIO_PIN_16,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_17", .addr = A_MIO_PIN_17,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_18", .addr = A_MIO_PIN_18,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_19", .addr = A_MIO_PIN_19,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_20", .addr = A_MIO_PIN_20,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_21", .addr = A_MIO_PIN_21,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_22", .addr = A_MIO_PIN_22,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_23", .addr = A_MIO_PIN_23,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_24", .addr = A_MIO_PIN_24,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_25", .addr = A_MIO_PIN_25,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_26", .addr = A_MIO_PIN_26,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_27", .addr = A_MIO_PIN_27,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_28", .addr = A_MIO_PIN_28,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_29", .addr = A_MIO_PIN_29,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_30", .addr = A_MIO_PIN_30,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_31", .addr = A_MIO_PIN_31,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_32", .addr = A_MIO_PIN_32,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_33", .addr = A_MIO_PIN_33,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_34", .addr = A_MIO_PIN_34,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_35", .addr = A_MIO_PIN_35,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_36", .addr = A_MIO_PIN_36,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_37", .addr = A_MIO_PIN_37,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_38", .addr = A_MIO_PIN_38,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_39", .addr = A_MIO_PIN_39,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_40", .addr = A_MIO_PIN_40,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_41", .addr = A_MIO_PIN_41,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_42", .addr = A_MIO_PIN_42,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_43", .addr = A_MIO_PIN_43,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_44", .addr = A_MIO_PIN_44,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_45", .addr = A_MIO_PIN_45,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_46", .addr = A_MIO_PIN_46,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_47", .addr = A_MIO_PIN_47,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_48", .addr = A_MIO_PIN_48,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_49", .addr = A_MIO_PIN_49,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_50", .addr = A_MIO_PIN_50,
+ .rsvd = 0xfffffc01,
+ },{ .name = "MIO_PIN_51", .addr = A_MIO_PIN_51,
+ .rsvd = 0xfffffc01,
+ },{ .name = "BNK0_EN_RX", .addr = A_BNK0_EN_RX,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_SEL_RX0", .addr = A_BNK0_SEL_RX0,
+ .reset = 0xffffffff,
+ },{ .name = "BNK0_SEL_RX1", .addr = A_BNK0_SEL_RX1,
+ .reset = 0xfffff,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK0_EN_RX_SCHMITT_HYST", .addr = A_BNK0_EN_RX_SCHMITT_HYST,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_EN_WK_PD", .addr = A_BNK0_EN_WK_PD,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_EN_WK_PU", .addr = A_BNK0_EN_WK_PU,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_SEL_DRV0", .addr = A_BNK0_SEL_DRV0,
+ .reset = 0xffffffff,
+ },{ .name = "BNK0_SEL_DRV1", .addr = A_BNK0_SEL_DRV1,
+ .reset = 0xfffff,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK0_SEL_SLEW", .addr = A_BNK0_SEL_SLEW,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_EN_DFT_OPT_INV", .addr = A_BNK0_EN_DFT_OPT_INV,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_EN_PAD2PAD_LOOPBACK",
+ .addr = A_BNK0_EN_PAD2PAD_LOOPBACK,
+ .rsvd = 0xffffe000,
+ },{ .name = "BNK0_RX_SPARE0", .addr = A_BNK0_RX_SPARE0,
+ },{ .name = "BNK0_RX_SPARE1", .addr = A_BNK0_RX_SPARE1,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK0_TX_SPARE0", .addr = A_BNK0_TX_SPARE0,
+ },{ .name = "BNK0_TX_SPARE1", .addr = A_BNK0_TX_SPARE1,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK0_SEL_EN1P8", .addr = A_BNK0_SEL_EN1P8,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK0_EN_B_POR_DETECT", .addr = A_BNK0_EN_B_POR_DETECT,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK0_LPF_BYP_POR_DETECT", .addr = A_BNK0_LPF_BYP_POR_DETECT,
+ .reset = 0x1,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK0_EN_LATCH", .addr = A_BNK0_EN_LATCH,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK0_VBG_LPF_BYP_B", .addr = A_BNK0_VBG_LPF_BYP_B,
+ .reset = 0x1,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK0_EN_AMP_B", .addr = A_BNK0_EN_AMP_B,
+ .rsvd = 0xfffffffc,
+ },{ .name = "BNK0_SPARE_BIAS", .addr = A_BNK0_SPARE_BIAS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "BNK0_DRIVER_BIAS", .addr = A_BNK0_DRIVER_BIAS,
+ .rsvd = 0xffff8000,
+ },{ .name = "BNK0_VMODE", .addr = A_BNK0_VMODE,
+ .rsvd = 0xfffffffe,
+ .ro = 0x1,
+ },{ .name = "BNK0_SEL_AUX_IO_RX", .addr = A_BNK0_SEL_AUX_IO_RX,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK0_EN_TX_HS_MODE", .addr = A_BNK0_EN_TX_HS_MODE,
+ .rsvd = 0xfc000000,
+ },{ .name = "MIO_MST_TRI0", .addr = A_MIO_MST_TRI0,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "MIO_MST_TRI1", .addr = A_MIO_MST_TRI1,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_RX", .addr = A_BNK1_EN_RX,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_SEL_RX0", .addr = A_BNK1_SEL_RX0,
+ .reset = 0xffffffff,
+ },{ .name = "BNK1_SEL_RX1", .addr = A_BNK1_SEL_RX1,
+ .reset = 0xfffff,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK1_EN_RX_SCHMITT_HYST", .addr = A_BNK1_EN_RX_SCHMITT_HYST,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_WK_PD", .addr = A_BNK1_EN_WK_PD,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_WK_PU", .addr = A_BNK1_EN_WK_PU,
+ .reset = 0x3ffffff,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_SEL_DRV0", .addr = A_BNK1_SEL_DRV0,
+ .reset = 0xffffffff,
+ },{ .name = "BNK1_SEL_DRV1", .addr = A_BNK1_SEL_DRV1,
+ .reset = 0xfffff,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK1_SEL_SLEW", .addr = A_BNK1_SEL_SLEW,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_DFT_OPT_INV", .addr = A_BNK1_EN_DFT_OPT_INV,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_PAD2PAD_LOOPBACK",
+ .addr = A_BNK1_EN_PAD2PAD_LOOPBACK,
+ .rsvd = 0xffffe000,
+ },{ .name = "BNK1_RX_SPARE0", .addr = A_BNK1_RX_SPARE0,
+ },{ .name = "BNK1_RX_SPARE1", .addr = A_BNK1_RX_SPARE1,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK1_TX_SPARE0", .addr = A_BNK1_TX_SPARE0,
+ },{ .name = "BNK1_TX_SPARE1", .addr = A_BNK1_TX_SPARE1,
+ .rsvd = 0xfff00000,
+ },{ .name = "BNK1_SEL_EN1P8", .addr = A_BNK1_SEL_EN1P8,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK1_EN_B_POR_DETECT", .addr = A_BNK1_EN_B_POR_DETECT,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK1_LPF_BYP_POR_DETECT", .addr = A_BNK1_LPF_BYP_POR_DETECT,
+ .reset = 0x1,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK1_EN_LATCH", .addr = A_BNK1_EN_LATCH,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK1_VBG_LPF_BYP_B", .addr = A_BNK1_VBG_LPF_BYP_B,
+ .reset = 0x1,
+ .rsvd = 0xfffffffe,
+ },{ .name = "BNK1_EN_AMP_B", .addr = A_BNK1_EN_AMP_B,
+ .rsvd = 0xfffffffc,
+ },{ .name = "BNK1_SPARE_BIAS", .addr = A_BNK1_SPARE_BIAS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "BNK1_DRIVER_BIAS", .addr = A_BNK1_DRIVER_BIAS,
+ .rsvd = 0xffff8000,
+ },{ .name = "BNK1_VMODE", .addr = A_BNK1_VMODE,
+ .rsvd = 0xfffffffe,
+ .ro = 0x1,
+ },{ .name = "BNK1_SEL_AUX_IO_RX", .addr = A_BNK1_SEL_AUX_IO_RX,
+ .rsvd = 0xfc000000,
+ },{ .name = "BNK1_EN_TX_HS_MODE", .addr = A_BNK1_EN_TX_HS_MODE,
+ .rsvd = 0xfc000000,
+ },{ .name = "SD0_CLK_CTRL", .addr = A_SD0_CLK_CTRL,
+ .rsvd = 0xfffffff8,
+ },{ .name = "SD0_CTRL_REG", .addr = A_SD0_CTRL_REG,
+ .rsvd = 0xfffffffe,
+ .pre_write = sd0_ctrl_reg_prew,
+ },{ .name = "SD0_CONFIG_REG1", .addr = A_SD0_CONFIG_REG1,
+ .reset = 0x3250,
+ .rsvd = 0xffff8000,
+ },{ .name = "SD0_CONFIG_REG2", .addr = A_SD0_CONFIG_REG2,
+ .reset = 0xffc,
+ .rsvd = 0xffffc000,
+ },{ .name = "SD0_CONFIG_REG3", .addr = A_SD0_CONFIG_REG3,
+ .reset = 0x407,
+ .rsvd = 0xfffff800,
+ },{ .name = "SD0_INITPRESET", .addr = A_SD0_INITPRESET,
+ .reset = 0x100,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_DSPPRESET", .addr = A_SD0_DSPPRESET,
+ .reset = 0x4,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_HSPDPRESET", .addr = A_SD0_HSPDPRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_SDR12PRESET", .addr = A_SD0_SDR12PRESET,
+ .reset = 0x4,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_SDR25PRESET", .addr = A_SD0_SDR25PRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_SDR50PRSET", .addr = A_SD0_SDR50PRSET,
+ .reset = 0x1,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_SDR104PRST", .addr = A_SD0_SDR104PRST,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_DDR50PRESET", .addr = A_SD0_DDR50PRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD0_MAXCUR1P8", .addr = A_SD0_MAXCUR1P8,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD0_MAXCUR3P0", .addr = A_SD0_MAXCUR3P0,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD0_MAXCUR3P3", .addr = A_SD0_MAXCUR3P3,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD0_DLL_CTRL", .addr = A_SD0_DLL_CTRL,
+ .reset = 0x1,
+ .rsvd = 0xfffffc00,
+ .ro = 0x19,
+ },{ .name = "SD0_CDN_CTRL", .addr = A_SD0_CDN_CTRL,
+ .rsvd = 0xfffffffe,
+ },{ .name = "SD0_DLL_TEST", .addr = A_SD0_DLL_TEST,
+ .rsvd = 0xff000000,
+ },{ .name = "SD0_RX_TUNING_SEL", .addr = A_SD0_RX_TUNING_SEL,
+ .rsvd = 0xfffffe00,
+ .ro = 0x1ff,
+ },{ .name = "SD0_DLL_DIV_MAP0", .addr = A_SD0_DLL_DIV_MAP0,
+ .reset = 0x50505050,
+ },{ .name = "SD0_DLL_DIV_MAP1", .addr = A_SD0_DLL_DIV_MAP1,
+ .reset = 0x50505050,
+ },{ .name = "SD0_IOU_COHERENT_CTRL", .addr = A_SD0_IOU_COHERENT_CTRL,
+ .rsvd = 0xfffffff0,
+ },{ .name = "SD0_IOU_INTERCONNECT_ROUTE",
+ .addr = A_SD0_IOU_INTERCONNECT_ROUTE,
+ .rsvd = 0xfffffffe,
+ },{ .name = "SD0_IOU_RAM", .addr = A_SD0_IOU_RAM,
+ .reset = 0x24,
+ .rsvd = 0xffffff80,
+ },{ .name = "SD0_IOU_INTERCONNECT_QOS",
+ .addr = A_SD0_IOU_INTERCONNECT_QOS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "SD1_CLK_CTRL", .addr = A_SD1_CLK_CTRL,
+ .rsvd = 0xfffffffc,
+ },{ .name = "SD1_CTRL_REG", .addr = A_SD1_CTRL_REG,
+ .rsvd = 0xfffffffe,
+ .pre_write = sd1_ctrl_reg_prew,
+ },{ .name = "SD1_CONFIG_REG1", .addr = A_SD1_CONFIG_REG1,
+ .reset = 0x3250,
+ .rsvd = 0xffff8000,
+ },{ .name = "SD1_CONFIG_REG2", .addr = A_SD1_CONFIG_REG2,
+ .reset = 0xffc,
+ .rsvd = 0xffffc000,
+ },{ .name = "SD1_CONFIG_REG3", .addr = A_SD1_CONFIG_REG3,
+ .reset = 0x407,
+ .rsvd = 0xfffff800,
+ },{ .name = "SD1_INITPRESET", .addr = A_SD1_INITPRESET,
+ .reset = 0x100,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_DSPPRESET", .addr = A_SD1_DSPPRESET,
+ .reset = 0x4,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_HSPDPRESET", .addr = A_SD1_HSPDPRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_SDR12PRESET", .addr = A_SD1_SDR12PRESET,
+ .reset = 0x4,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_SDR25PRESET", .addr = A_SD1_SDR25PRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_SDR50PRSET", .addr = A_SD1_SDR50PRSET,
+ .reset = 0x1,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_SDR104PRST", .addr = A_SD1_SDR104PRST,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_DDR50PRESET", .addr = A_SD1_DDR50PRESET,
+ .reset = 0x2,
+ .rsvd = 0xffffe000,
+ },{ .name = "SD1_MAXCUR1P8", .addr = A_SD1_MAXCUR1P8,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD1_MAXCUR3P0", .addr = A_SD1_MAXCUR3P0,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD1_MAXCUR3P3", .addr = A_SD1_MAXCUR3P3,
+ .rsvd = 0xffffff00,
+ },{ .name = "SD1_DLL_CTRL", .addr = A_SD1_DLL_CTRL,
+ .reset = 0x1,
+ .rsvd = 0xfffffc00,
+ .ro = 0x19,
+ },{ .name = "SD1_CDN_CTRL", .addr = A_SD1_CDN_CTRL,
+ .rsvd = 0xfffffffe,
+ },{ .name = "SD1_DLL_TEST", .addr = A_SD1_DLL_TEST,
+ .rsvd = 0xff000000,
+ },{ .name = "SD1_RX_TUNING_SEL", .addr = A_SD1_RX_TUNING_SEL,
+ .rsvd = 0xfffffe00,
+ .ro = 0x1ff,
+ },{ .name = "SD1_DLL_DIV_MAP0", .addr = A_SD1_DLL_DIV_MAP0,
+ .reset = 0x50505050,
+ },{ .name = "SD1_DLL_DIV_MAP1", .addr = A_SD1_DLL_DIV_MAP1,
+ .reset = 0x50505050,
+ },{ .name = "SD1_IOU_COHERENT_CTRL", .addr = A_SD1_IOU_COHERENT_CTRL,
+ .rsvd = 0xfffffff0,
+ },{ .name = "SD1_IOU_INTERCONNECT_ROUTE",
+ .addr = A_SD1_IOU_INTERCONNECT_ROUTE,
+ .rsvd = 0xfffffffe,
+ },{ .name = "SD1_IOU_RAM", .addr = A_SD1_IOU_RAM,
+ .reset = 0x24,
+ .rsvd = 0xffffff80,
+ },{ .name = "SD1_IOU_INTERCONNECT_QOS",
+ .addr = A_SD1_IOU_INTERCONNECT_QOS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "OSPI_QSPI_IOU_AXI_MUX_SEL",
+ .addr = A_OSPI_QSPI_IOU_AXI_MUX_SEL,
+ .reset = 0x1,
+ .rsvd = 0xfffffffc,
+ .pre_write = ospi_qspi_iou_axi_mux_sel_prew,
+ },{ .name = "QSPI_IOU_COHERENT_CTRL", .addr = A_QSPI_IOU_COHERENT_CTRL,
+ .rsvd = 0xfffffff0,
+ },{ .name = "QSPI_IOU_INTERCONNECT_ROUTE",
+ .addr = A_QSPI_IOU_INTERCONNECT_ROUTE,
+ .rsvd = 0xfffffffe,
+ },{ .name = "QSPI_IOU_RAM", .addr = A_QSPI_IOU_RAM,
+ .reset = 0x1224,
+ .rsvd = 0xffffc000,
+ },{ .name = "QSPI_IOU_INTERCONNECT_QOS",
+ .addr = A_QSPI_IOU_INTERCONNECT_QOS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "OSPI_IOU_COHERENT_CTRL", .addr = A_OSPI_IOU_COHERENT_CTRL,
+ .rsvd = 0xfffffff0,
+ },{ .name = "OSPI_IOU_INTERCONNECT_ROUTE",
+ .addr = A_OSPI_IOU_INTERCONNECT_ROUTE,
+ .rsvd = 0xfffffffe,
+ },{ .name = "OSPI_IOU_RAM", .addr = A_OSPI_IOU_RAM,
+ .reset = 0xa,
+ .rsvd = 0xffffffc0,
+ },{ .name = "OSPI_IOU_INTERCONNECT_QOS",
+ .addr = A_OSPI_IOU_INTERCONNECT_QOS,
+ .rsvd = 0xfffffff0,
+ },{ .name = "OSPI_REFCLK_DLY_CTRL", .addr = A_OSPI_REFCLK_DLY_CTRL,
+ .reset = 0x13,
+ .rsvd = 0xffffffe0,
+ },{ .name = "CUR_PWR_ST", .addr = A_CUR_PWR_ST,
+ .rsvd = 0xfffffffc,
+ .ro = 0x3,
+ },{ .name = "CONNECT_ST", .addr = A_CONNECT_ST,
+ .rsvd = 0xfffffffe,
+ .ro = 0x1,
+ },{ .name = "PW_STATE_REQ", .addr = A_PW_STATE_REQ,
+ .rsvd = 0xfffffffc,
+ },{ .name = "HOST_U2_PORT_DISABLE", .addr = A_HOST_U2_PORT_DISABLE,
+ .rsvd = 0xfffffffe,
+ },{ .name = "DBG_U2PMU", .addr = A_DBG_U2PMU,
+ .ro = 0xffffffff,
+ },{ .name = "DBG_U2PMU_EXT1", .addr = A_DBG_U2PMU_EXT1,
+ .ro = 0xffffffff,
+ },{ .name = "DBG_U2PMU_EXT2", .addr = A_DBG_U2PMU_EXT2,
+ .rsvd = 0xfffffff0,
+ .ro = 0xf,
+ },{ .name = "PME_GEN_U2PMU", .addr = A_PME_GEN_U2PMU,
+ .rsvd = 0xfffffffe,
+ .ro = 0x1,
+ },{ .name = "PWR_CONFIG_USB2", .addr = A_PWR_CONFIG_USB2,
+ .rsvd = 0xc0000000,
+ },{ .name = "PHY_HUB", .addr = A_PHY_HUB,
+ .rsvd = 0xfffffffc,
+ .ro = 0x2,
+ },{ .name = "CTRL", .addr = A_CTRL,
+ },{ .name = "ISR", .addr = A_ISR,
+ .w1c = 0x1,
+ .post_write = isr_postw,
+ },{ .name = "IMR", .addr = A_IMR,
+ .reset = 0x1,
+ .ro = 0x1,
+ },{ .name = "IER", .addr = A_IER,
+ .pre_write = ier_prew,
+ },{ .name = "IDR", .addr = A_IDR,
+ .pre_write = idr_prew,
+ },{ .name = "ITR", .addr = A_ITR,
+ .pre_write = itr_prew,
+ },{ .name = "PARITY_ISR", .addr = A_PARITY_ISR,
+ .w1c = 0x1fff,
+ .post_write = parity_isr_postw,
+ },{ .name = "PARITY_IMR", .addr = A_PARITY_IMR,
+ .reset = 0x1fff,
+ .ro = 0x1fff,
+ },{ .name = "PARITY_IER", .addr = A_PARITY_IER,
+ .pre_write = parity_ier_prew,
+ },{ .name = "PARITY_IDR", .addr = A_PARITY_IDR,
+ .pre_write = parity_idr_prew,
+ },{ .name = "PARITY_ITR", .addr = A_PARITY_ITR,
+ .pre_write = parity_itr_prew,
+ },{ .name = "WPROT0", .addr = A_WPROT0,
+ .reset = 0x1,
+ }
+};
+
+static void xlnx_versal_pmc_iou_slcr_reset_init(Object *obj, ResetType type)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(obj);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
+ register_reset(&s->regs_info[i]);
+ }
+}
+
+static void xlnx_versal_pmc_iou_slcr_reset_hold(Object *obj)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(obj);
+
+ parity_imr_update_irq(s);
+ imr_update_irq(s);
+
+ /*
+ * Setup OSPI_QSPI mux
+ * By default axi slave interface is enabled for ospi-dma
+ */
+ qemu_set_irq(s->ospi_mux_sel, 0);
+ qemu_set_irq(s->qspi_ospi_mux_sel, 1);
+}
+
+static const MemoryRegionOps pmc_iou_slcr_ops = {
+ .read = register_read_memory,
+ .write = register_write_memory,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void xlnx_versal_pmc_iou_slcr_realize(DeviceState *dev, Error **errp)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(dev);
+
+ qdev_init_gpio_out_named(dev, s->sd_emmc_sel, "sd-emmc-sel", 2);
+ qdev_init_gpio_out_named(dev, &s->qspi_ospi_mux_sel,
+ "qspi-ospi-mux-sel", 1);
+ qdev_init_gpio_out_named(dev, &s->ospi_mux_sel, "ospi-mux-sel", 1);
+}
+
+static void xlnx_versal_pmc_iou_slcr_init(Object *obj)
+{
+ XlnxVersalPmcIouSlcr *s = XILINX_VERSAL_PMC_IOU_SLCR(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ RegisterInfoArray *reg_array;
+
+ memory_region_init(&s->iomem, obj, TYPE_XILINX_VERSAL_PMC_IOU_SLCR,
+ XILINX_VERSAL_PMC_IOU_SLCR_R_MAX * 4);
+ reg_array =
+ register_init_block32(DEVICE(obj), pmc_iou_slcr_regs_info,
+ ARRAY_SIZE(pmc_iou_slcr_regs_info),
+ s->regs_info, s->regs,
+ &pmc_iou_slcr_ops,
+ XILINX_VERSAL_PMC_IOU_SLCR_ERR_DEBUG,
+ XILINX_VERSAL_PMC_IOU_SLCR_R_MAX * 4);
+ memory_region_add_subregion(&s->iomem,
+ 0x0,
+ &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->iomem);
+ sysbus_init_irq(sbd, &s->irq_parity_imr);
+ sysbus_init_irq(sbd, &s->irq_imr);
+}
+
+static const VMStateDescription vmstate_pmc_iou_slcr = {
+ .name = TYPE_XILINX_VERSAL_PMC_IOU_SLCR,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, XlnxVersalPmcIouSlcr,
+ XILINX_VERSAL_PMC_IOU_SLCR_R_MAX),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static void xlnx_versal_pmc_iou_slcr_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ dc->realize = xlnx_versal_pmc_iou_slcr_realize;
+ dc->vmsd = &vmstate_pmc_iou_slcr;
+ rc->phases.enter = xlnx_versal_pmc_iou_slcr_reset_init;
+ rc->phases.hold = xlnx_versal_pmc_iou_slcr_reset_hold;
+}
+
+static const TypeInfo xlnx_versal_pmc_iou_slcr_info = {
+ .name = TYPE_XILINX_VERSAL_PMC_IOU_SLCR,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(XlnxVersalPmcIouSlcr),
+ .class_init = xlnx_versal_pmc_iou_slcr_class_init,
+ .instance_init = xlnx_versal_pmc_iou_slcr_init,
+};
+
+static void xlnx_versal_pmc_iou_slcr_register_types(void)
+{
+ type_register_static(&xlnx_versal_pmc_iou_slcr_info);
+}
+
+type_init(xlnx_versal_pmc_iou_slcr_register_types)
diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c
index fba4dfca35..94a5510e4e 100644
--- a/hw/ppc/spapr_rtc.c
+++ b/hw/ppc/spapr_rtc.c
@@ -26,9 +26,9 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "hw/ppc/spapr.h"
#include "migration/vmstate.h"
#include "qapi/error.h"
diff --git a/hw/rtc/allwinner-rtc.c b/hw/rtc/allwinner-rtc.c
index 5606a51d5c..7e493f0e79 100644
--- a/hw/rtc/allwinner-rtc.c
+++ b/hw/rtc/allwinner-rtc.c
@@ -23,9 +23,9 @@
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/module.h"
-#include "qemu-common.h"
#include "hw/qdev-properties.h"
#include "hw/rtc/allwinner-rtc.h"
+#include "sysemu/rtc.h"
#include "trace.h"
/* RTC registers */
diff --git a/hw/rtc/aspeed_rtc.c b/hw/rtc/aspeed_rtc.c
index 3ca1183558..f6da7b666d 100644
--- a/hw/rtc/aspeed_rtc.c
+++ b/hw/rtc/aspeed_rtc.c
@@ -7,11 +7,11 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/rtc/aspeed_rtc.h"
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/timer.h"
+#include "sysemu/rtc.h"
#include "trace.h"
diff --git a/hw/rtc/ds1338.c b/hw/rtc/ds1338.c
index bc5ce1a9f4..36d8121ddd 100644
--- a/hw/rtc/ds1338.c
+++ b/hw/rtc/ds1338.c
@@ -11,12 +11,12 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/i2c/i2c.h"
#include "migration/vmstate.h"
#include "qemu/bcd.h"
#include "qemu/module.h"
#include "qom/object.h"
+#include "sysemu/rtc.h"
/* Size of NVRAM including both the user-accessible area and the
* secondary register area.
diff --git a/hw/rtc/exynos4210_rtc.c b/hw/rtc/exynos4210_rtc.c
index 45c0a951c4..ae67641de6 100644
--- a/hw/rtc/exynos4210_rtc.c
+++ b/hw/rtc/exynos4210_rtc.c
@@ -26,7 +26,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/sysbus.h"
@@ -39,6 +38,7 @@
#include "hw/arm/exynos4210.h"
#include "qom/object.h"
+#include "sysemu/rtc.h"
#define DEBUG_RTC 0
diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c
index e07ff0164e..35e493be31 100644
--- a/hw/rtc/goldfish_rtc.c
+++ b/hw/rtc/goldfish_rtc.c
@@ -20,7 +20,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/rtc/goldfish_rtc.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
@@ -29,6 +28,7 @@
#include "qemu/bitops.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
diff --git a/hw/rtc/m41t80.c b/hw/rtc/m41t80.c
index 396d110ba2..a00971a67e 100644
--- a/hw/rtc/m41t80.c
+++ b/hw/rtc/m41t80.c
@@ -8,13 +8,13 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/timer.h"
#include "qemu/bcd.h"
#include "hw/i2c/i2c.h"
#include "qom/object.h"
+#include "sysemu/rtc.h"
#define TYPE_M41T80 "m41t80"
OBJECT_DECLARE_SIMPLE_TYPE(M41t80State, M41T80)
diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c
index 690f4e071a..74345d9d90 100644
--- a/hw/rtc/m48t59.c
+++ b/hw/rtc/m48t59.c
@@ -24,12 +24,12 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/rtc/m48t59.h"
#include "qemu/timer.h"
#include "sysemu/runstate.h"
+#include "sysemu/rtc.h"
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
#include "qapi/error.h"
diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c
index 4fbafddb22..e61a0cced4 100644
--- a/hw/rtc/mc146818rtc.c
+++ b/hw/rtc/mc146818rtc.c
@@ -23,7 +23,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/cutils.h"
#include "qemu/module.h"
#include "qemu/bcd.h"
@@ -36,6 +35,7 @@
#include "sysemu/replay.h"
#include "sysemu/reset.h"
#include "sysemu/runstate.h"
+#include "sysemu/rtc.h"
#include "hw/rtc/mc146818rtc.h"
#include "hw/rtc/mc146818rtc_regs.h"
#include "migration/vmstate.h"
diff --git a/hw/rtc/pl031.c b/hw/rtc/pl031.c
index e7ced90b02..38d9d3c2f3 100644
--- a/hw/rtc/pl031.c
+++ b/hw/rtc/pl031.c
@@ -12,7 +12,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/rtc/pl031.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
@@ -20,6 +19,7 @@
#include "hw/sysbus.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "qemu/cutils.h"
#include "qemu/log.h"
#include "qemu/module.h"
diff --git a/hw/rtc/twl92230.c b/hw/rtc/twl92230.c
index 0922df5ad3..e8d5eda3fc 100644
--- a/hw/rtc/twl92230.c
+++ b/hw/rtc/twl92230.c
@@ -20,13 +20,13 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/timer.h"
#include "hw/i2c/i2c.h"
#include "hw/irq.h"
#include "migration/qemu-file-types.h"
#include "migration/vmstate.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "qemu/bcd.h"
#include "qemu/module.h"
#include "qom/object.h"
diff --git a/hw/rtc/xlnx-zynqmp-rtc.c b/hw/rtc/xlnx-zynqmp-rtc.c
index 2bcd14d779..3e7d61a41c 100644
--- a/hw/rtc/xlnx-zynqmp-rtc.c
+++ b/hw/rtc/xlnx-zynqmp-rtc.c
@@ -25,7 +25,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/sysbus.h"
#include "hw/register.h"
#include "qemu/bitops.h"
@@ -34,6 +33,7 @@
#include "hw/irq.h"
#include "qemu/cutils.h"
#include "sysemu/sysemu.h"
+#include "sysemu/rtc.h"
#include "trace.h"
#include "hw/rtc/xlnx-zynqmp-rtc.h"
#include "migration/vmstate.h"
diff --git a/hw/s390x/tod-tcg.c b/hw/s390x/tod-tcg.c
index 9bb94ff72b..7646b4aa38 100644
--- a/hw/s390x/tod-tcg.c
+++ b/hw/s390x/tod-tcg.c
@@ -9,7 +9,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qapi/error.h"
#include "hw/s390x/tod.h"
#include "qemu/timer.h"
@@ -17,6 +16,7 @@
#include "qemu/module.h"
#include "cpu.h"
#include "tcg/tcg_s390x.h"
+#include "sysemu/rtc.h"
static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod,
Error **errp)
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index c9da5ce0b5..f638ff8831 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -19,11 +19,11 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "hw/pci/pci.h"
#include "hw/qdev-properties.h"
#include "sysemu/dma.h"
#include "sysemu/block-backend.h"
+#include "sysemu/rtc.h"
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "qemu/iov.h"
diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build
index 3d6bc82ab1..0ded9cd092 100644
--- a/hw/ssi/meson.build
+++ b/hw/ssi/meson.build
@@ -7,5 +7,6 @@ softmmu_ss.add(when: 'CONFIG_SSI', if_true: files('ssi.c'))
softmmu_ss.add(when: 'CONFIG_STM32F2XX_SPI', if_true: files('stm32f2xx_spi.c'))
softmmu_ss.add(when: 'CONFIG_XILINX_SPI', if_true: files('xilinx_spi.c'))
softmmu_ss.add(when: 'CONFIG_XILINX_SPIPS', if_true: files('xilinx_spips.c'))
+softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-ospi.c'))
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_spi.c'))
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_spi.c'))
diff --git a/hw/ssi/xlnx-versal-ospi.c b/hw/ssi/xlnx-versal-ospi.c
new file mode 100644
index 0000000000..7ecd148fdf
--- /dev/null
+++ b/hw/ssi/xlnx-versal-ospi.c
@@ -0,0 +1,1853 @@
+/*
+ * QEMU model of Xilinx Versal's OSPI controller.
+ *
+ * Copyright (c) 2021 Xilinx Inc.
+ * Written by Francisco Iglesias <francisco.iglesias@xilinx.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "hw/qdev-properties.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "hw/irq.h"
+#include "hw/ssi/xlnx-versal-ospi.h"
+
+#ifndef XILINX_VERSAL_OSPI_ERR_DEBUG
+#define XILINX_VERSAL_OSPI_ERR_DEBUG 0
+#endif
+
+REG32(CONFIG_REG, 0x0)
+ FIELD(CONFIG_REG, IDLE_FLD, 31, 1)
+ FIELD(CONFIG_REG, DUAL_BYTE_OPCODE_EN_FLD, 30, 1)
+ FIELD(CONFIG_REG, CRC_ENABLE_FLD, 29, 1)
+ FIELD(CONFIG_REG, CONFIG_RESV2_FLD, 26, 3)
+ FIELD(CONFIG_REG, PIPELINE_PHY_FLD, 25, 1)
+ FIELD(CONFIG_REG, ENABLE_DTR_PROTOCOL_FLD, 24, 1)
+ FIELD(CONFIG_REG, ENABLE_AHB_DECODER_FLD, 23, 1)
+ FIELD(CONFIG_REG, MSTR_BAUD_DIV_FLD, 19, 4)
+ FIELD(CONFIG_REG, ENTER_XIP_MODE_IMM_FLD, 18, 1)
+ FIELD(CONFIG_REG, ENTER_XIP_MODE_FLD, 17, 1)
+ FIELD(CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD, 16, 1)
+ FIELD(CONFIG_REG, ENB_DMA_IF_FLD, 15, 1)
+ FIELD(CONFIG_REG, WR_PROT_FLASH_FLD, 14, 1)
+ FIELD(CONFIG_REG, PERIPH_CS_LINES_FLD, 10, 4)
+ FIELD(CONFIG_REG, PERIPH_SEL_DEC_FLD, 9, 1)
+ FIELD(CONFIG_REG, ENB_LEGACY_IP_MODE_FLD, 8, 1)
+ FIELD(CONFIG_REG, ENB_DIR_ACC_CTLR_FLD, 7, 1)
+ FIELD(CONFIG_REG, RESET_CFG_FLD, 6, 1)
+ FIELD(CONFIG_REG, RESET_PIN_FLD, 5, 1)
+ FIELD(CONFIG_REG, HOLD_PIN_FLD, 4, 1)
+ FIELD(CONFIG_REG, PHY_MODE_ENABLE_FLD, 3, 1)
+ FIELD(CONFIG_REG, SEL_CLK_PHASE_FLD, 2, 1)
+ FIELD(CONFIG_REG, SEL_CLK_POL_FLD, 1, 1)
+ FIELD(CONFIG_REG, ENB_SPI_FLD, 0, 1)
+REG32(DEV_INSTR_RD_CONFIG_REG, 0x4)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV5_FLD, 29, 3)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, DUMMY_RD_CLK_CYCLES_FLD, 24, 5)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV4_FLD, 21, 3)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, MODE_BIT_ENABLE_FLD, 20, 1)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV3_FLD, 18, 2)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, DATA_XFER_TYPE_EXT_MODE_FLD, 16, 2)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, RD_INSTR_RESV2_FLD, 14, 2)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, ADDR_XFER_TYPE_STD_MODE_FLD, 12, 2)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, PRED_DIS_FLD, 11, 1)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, DDR_EN_FLD, 10, 1)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, INSTR_TYPE_FLD, 8, 2)
+ FIELD(DEV_INSTR_RD_CONFIG_REG, RD_OPCODE_NON_XIP_FLD, 0, 8)
+REG32(DEV_INSTR_WR_CONFIG_REG, 0x8)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV4_FLD, 29, 3)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, DUMMY_WR_CLK_CYCLES_FLD, 24, 5)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV3_FLD, 18, 6)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, DATA_XFER_TYPE_EXT_MODE_FLD, 16, 2)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV2_FLD, 14, 2)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, ADDR_XFER_TYPE_STD_MODE_FLD, 12, 2)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WR_INSTR_RESV1_FLD, 9, 3)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD, 8, 1)
+ FIELD(DEV_INSTR_WR_CONFIG_REG, WR_OPCODE_FLD, 0, 8)
+REG32(DEV_DELAY_REG, 0xc)
+ FIELD(DEV_DELAY_REG, D_NSS_FLD, 24, 8)
+ FIELD(DEV_DELAY_REG, D_BTWN_FLD, 16, 8)
+ FIELD(DEV_DELAY_REG, D_AFTER_FLD, 8, 8)
+ FIELD(DEV_DELAY_REG, D_INIT_FLD, 0, 8)
+REG32(RD_DATA_CAPTURE_REG, 0x10)
+ FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV3_FLD, 20, 12)
+ FIELD(RD_DATA_CAPTURE_REG, DDR_READ_DELAY_FLD, 16, 4)
+ FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV2_FLD, 9, 7)
+ FIELD(RD_DATA_CAPTURE_REG, DQS_ENABLE_FLD, 8, 1)
+ FIELD(RD_DATA_CAPTURE_REG, RD_DATA_RESV1_FLD, 6, 2)
+ FIELD(RD_DATA_CAPTURE_REG, SAMPLE_EDGE_SEL_FLD, 5, 1)
+ FIELD(RD_DATA_CAPTURE_REG, DELAY_FLD, 1, 4)
+ FIELD(RD_DATA_CAPTURE_REG, BYPASS_FLD, 0, 1)
+REG32(DEV_SIZE_CONFIG_REG, 0x14)
+ FIELD(DEV_SIZE_CONFIG_REG, DEV_SIZE_RESV_FLD, 29, 3)
+ FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS3_FLD, 27, 2)
+ FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS2_FLD, 25, 2)
+ FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS1_FLD, 23, 2)
+ FIELD(DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS0_FLD, 21, 2)
+ FIELD(DEV_SIZE_CONFIG_REG, BYTES_PER_SUBSECTOR_FLD, 16, 5)
+ FIELD(DEV_SIZE_CONFIG_REG, BYTES_PER_DEVICE_PAGE_FLD, 4, 12)
+ FIELD(DEV_SIZE_CONFIG_REG, NUM_ADDR_BYTES_FLD, 0, 4)
+REG32(SRAM_PARTITION_CFG_REG, 0x18)
+ FIELD(SRAM_PARTITION_CFG_REG, SRAM_PARTITION_RESV_FLD, 8, 24)
+ FIELD(SRAM_PARTITION_CFG_REG, ADDR_FLD, 0, 8)
+REG32(IND_AHB_ADDR_TRIGGER_REG, 0x1c)
+REG32(DMA_PERIPH_CONFIG_REG, 0x20)
+ FIELD(DMA_PERIPH_CONFIG_REG, DMA_PERIPH_RESV2_FLD, 12, 20)
+ FIELD(DMA_PERIPH_CONFIG_REG, NUM_BURST_REQ_BYTES_FLD, 8, 4)
+ FIELD(DMA_PERIPH_CONFIG_REG, DMA_PERIPH_RESV1_FLD, 4, 4)
+ FIELD(DMA_PERIPH_CONFIG_REG, NUM_SINGLE_REQ_BYTES_FLD, 0, 4)
+REG32(REMAP_ADDR_REG, 0x24)
+REG32(MODE_BIT_CONFIG_REG, 0x28)
+ FIELD(MODE_BIT_CONFIG_REG, RX_CRC_DATA_LOW_FLD, 24, 8)
+ FIELD(MODE_BIT_CONFIG_REG, RX_CRC_DATA_UP_FLD, 16, 8)
+ FIELD(MODE_BIT_CONFIG_REG, CRC_OUT_ENABLE_FLD, 15, 1)
+ FIELD(MODE_BIT_CONFIG_REG, MODE_BIT_RESV1_FLD, 11, 4)
+ FIELD(MODE_BIT_CONFIG_REG, CHUNK_SIZE_FLD, 8, 3)
+ FIELD(MODE_BIT_CONFIG_REG, MODE_FLD, 0, 8)
+REG32(SRAM_FILL_REG, 0x2c)
+ FIELD(SRAM_FILL_REG, SRAM_FILL_INDAC_WRITE_FLD, 16, 16)
+ FIELD(SRAM_FILL_REG, SRAM_FILL_INDAC_READ_FLD, 0, 16)
+REG32(TX_THRESH_REG, 0x30)
+ FIELD(TX_THRESH_REG, TX_THRESH_RESV_FLD, 5, 27)
+ FIELD(TX_THRESH_REG, LEVEL_FLD, 0, 5)
+REG32(RX_THRESH_REG, 0x34)
+ FIELD(RX_THRESH_REG, RX_THRESH_RESV_FLD, 5, 27)
+ FIELD(RX_THRESH_REG, LEVEL_FLD, 0, 5)
+REG32(WRITE_COMPLETION_CTRL_REG, 0x38)
+ FIELD(WRITE_COMPLETION_CTRL_REG, POLL_REP_DELAY_FLD, 24, 8)
+ FIELD(WRITE_COMPLETION_CTRL_REG, POLL_COUNT_FLD, 16, 8)
+ FIELD(WRITE_COMPLETION_CTRL_REG, ENABLE_POLLING_EXP_FLD, 15, 1)
+ FIELD(WRITE_COMPLETION_CTRL_REG, DISABLE_POLLING_FLD, 14, 1)
+ FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_POLARITY_FLD, 13, 1)
+ FIELD(WRITE_COMPLETION_CTRL_REG, WR_COMP_CTRL_RESV1_FLD, 12, 1)
+ FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_ADDR_EN_FLD, 11, 1)
+ FIELD(WRITE_COMPLETION_CTRL_REG, POLLING_BIT_INDEX_FLD, 8, 3)
+ FIELD(WRITE_COMPLETION_CTRL_REG, OPCODE_FLD, 0, 8)
+REG32(NO_OF_POLLS_BEF_EXP_REG, 0x3c)
+REG32(IRQ_STATUS_REG, 0x40)
+ FIELD(IRQ_STATUS_REG, IRQ_STAT_RESV_FLD, 20, 12)
+ FIELD(IRQ_STATUS_REG, ECC_FAIL_FLD, 19, 1)
+ FIELD(IRQ_STATUS_REG, TX_CRC_CHUNK_BRK_FLD, 18, 1)
+ FIELD(IRQ_STATUS_REG, RX_CRC_DATA_VAL_FLD, 17, 1)
+ FIELD(IRQ_STATUS_REG, RX_CRC_DATA_ERR_FLD, 16, 1)
+ FIELD(IRQ_STATUS_REG, IRQ_STAT_RESV1_FLD, 15, 1)
+ FIELD(IRQ_STATUS_REG, STIG_REQ_INT_FLD, 14, 1)
+ FIELD(IRQ_STATUS_REG, POLL_EXP_INT_FLD, 13, 1)
+ FIELD(IRQ_STATUS_REG, INDRD_SRAM_FULL_FLD, 12, 1)
+ FIELD(IRQ_STATUS_REG, RX_FIFO_FULL_FLD, 11, 1)
+ FIELD(IRQ_STATUS_REG, RX_FIFO_NOT_EMPTY_FLD, 10, 1)
+ FIELD(IRQ_STATUS_REG, TX_FIFO_FULL_FLD, 9, 1)
+ FIELD(IRQ_STATUS_REG, TX_FIFO_NOT_FULL_FLD, 8, 1)
+ FIELD(IRQ_STATUS_REG, RECV_OVERFLOW_FLD, 7, 1)
+ FIELD(IRQ_STATUS_REG, INDIRECT_XFER_LEVEL_BREACH_FLD, 6, 1)
+ FIELD(IRQ_STATUS_REG, ILLEGAL_ACCESS_DET_FLD, 5, 1)
+ FIELD(IRQ_STATUS_REG, PROT_WR_ATTEMPT_FLD, 4, 1)
+ FIELD(IRQ_STATUS_REG, INDIRECT_TRANSFER_REJECT_FLD, 3, 1)
+ FIELD(IRQ_STATUS_REG, INDIRECT_OP_DONE_FLD, 2, 1)
+ FIELD(IRQ_STATUS_REG, UNDERFLOW_DET_FLD, 1, 1)
+ FIELD(IRQ_STATUS_REG, MODE_M_FAIL_FLD, 0, 1)
+REG32(IRQ_MASK_REG, 0x44)
+ FIELD(IRQ_MASK_REG, IRQ_MASK_RESV_FLD, 20, 12)
+ FIELD(IRQ_MASK_REG, ECC_FAIL_MASK_FLD, 19, 1)
+ FIELD(IRQ_MASK_REG, TX_CRC_CHUNK_BRK_MASK_FLD, 18, 1)
+ FIELD(IRQ_MASK_REG, RX_CRC_DATA_VAL_MASK_FLD, 17, 1)
+ FIELD(IRQ_MASK_REG, RX_CRC_DATA_ERR_MASK_FLD, 16, 1)
+ FIELD(IRQ_MASK_REG, IRQ_MASK_RESV1_FLD, 15, 1)
+ FIELD(IRQ_MASK_REG, STIG_REQ_MASK_FLD, 14, 1)
+ FIELD(IRQ_MASK_REG, POLL_EXP_INT_MASK_FLD, 13, 1)
+ FIELD(IRQ_MASK_REG, INDRD_SRAM_FULL_MASK_FLD, 12, 1)
+ FIELD(IRQ_MASK_REG, RX_FIFO_FULL_MASK_FLD, 11, 1)
+ FIELD(IRQ_MASK_REG, RX_FIFO_NOT_EMPTY_MASK_FLD, 10, 1)
+ FIELD(IRQ_MASK_REG, TX_FIFO_FULL_MASK_FLD, 9, 1)
+ FIELD(IRQ_MASK_REG, TX_FIFO_NOT_FULL_MASK_FLD, 8, 1)
+ FIELD(IRQ_MASK_REG, RECV_OVERFLOW_MASK_FLD, 7, 1)
+ FIELD(IRQ_MASK_REG, INDIRECT_XFER_LEVEL_BREACH_MASK_FLD, 6, 1)
+ FIELD(IRQ_MASK_REG, ILLEGAL_ACCESS_DET_MASK_FLD, 5, 1)
+ FIELD(IRQ_MASK_REG, PROT_WR_ATTEMPT_MASK_FLD, 4, 1)
+ FIELD(IRQ_MASK_REG, INDIRECT_TRANSFER_REJECT_MASK_FLD, 3, 1)
+ FIELD(IRQ_MASK_REG, INDIRECT_OP_DONE_MASK_FLD, 2, 1)
+ FIELD(IRQ_MASK_REG, UNDERFLOW_DET_MASK_FLD, 1, 1)
+ FIELD(IRQ_MASK_REG, MODE_M_FAIL_MASK_FLD, 0, 1)
+REG32(LOWER_WR_PROT_REG, 0x50)
+REG32(UPPER_WR_PROT_REG, 0x54)
+REG32(WR_PROT_CTRL_REG, 0x58)
+ FIELD(WR_PROT_CTRL_REG, WR_PROT_CTRL_RESV_FLD, 2, 30)
+ FIELD(WR_PROT_CTRL_REG, ENB_FLD, 1, 1)
+ FIELD(WR_PROT_CTRL_REG, INV_FLD, 0, 1)
+REG32(INDIRECT_READ_XFER_CTRL_REG, 0x60)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, INDIR_RD_XFER_RESV_FLD, 8, 24)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, NUM_IND_OPS_DONE_FLD, 6, 2)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, IND_OPS_DONE_STATUS_FLD, 5, 1)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, RD_QUEUED_FLD, 4, 1)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, SRAM_FULL_FLD, 3, 1)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, RD_STATUS_FLD, 2, 1)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD, 1, 1)
+ FIELD(INDIRECT_READ_XFER_CTRL_REG, START_FLD, 0, 1)
+REG32(INDIRECT_READ_XFER_WATERMARK_REG, 0x64)
+REG32(INDIRECT_READ_XFER_START_REG, 0x68)
+REG32(INDIRECT_READ_XFER_NUM_BYTES_REG, 0x6c)
+REG32(INDIRECT_WRITE_XFER_CTRL_REG, 0x70)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, INDIR_WR_XFER_RESV2_FLD, 8, 24)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, NUM_IND_OPS_DONE_FLD, 6, 2)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, IND_OPS_DONE_STATUS_FLD, 5, 1)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, WR_QUEUED_FLD, 4, 1)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, INDIR_WR_XFER_RESV1_FLD, 3, 1)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, WR_STATUS_FLD, 2, 1)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD, 1, 1)
+ FIELD(INDIRECT_WRITE_XFER_CTRL_REG, START_FLD, 0, 1)
+REG32(INDIRECT_WRITE_XFER_WATERMARK_REG, 0x74)
+REG32(INDIRECT_WRITE_XFER_START_REG, 0x78)
+REG32(INDIRECT_WRITE_XFER_NUM_BYTES_REG, 0x7c)
+REG32(INDIRECT_TRIGGER_ADDR_RANGE_REG, 0x80)
+ FIELD(INDIRECT_TRIGGER_ADDR_RANGE_REG, IND_RANGE_RESV1_FLD, 4, 28)
+ FIELD(INDIRECT_TRIGGER_ADDR_RANGE_REG, IND_RANGE_WIDTH_FLD, 0, 4)
+REG32(FLASH_COMMAND_CTRL_MEM_REG, 0x8c)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV1_FLD, 29, 3)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_ADDR_FLD, 20, 9)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV2_FLD, 19, 1)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, NB_OF_STIG_READ_BYTES_FLD, 16, 3)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_READ_DATA_FLD, 8, 8)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, FLASH_COMMAND_CTRL_MEM_RESV3_FLD, 2, 6)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_REQ_IN_PROGRESS_FLD, 1, 1)
+ FIELD(FLASH_COMMAND_CTRL_MEM_REG, TRIGGER_MEM_BANK_REQ_FLD, 0, 1)
+REG32(FLASH_CMD_CTRL_REG, 0x90)
+ FIELD(FLASH_CMD_CTRL_REG, CMD_OPCODE_FLD, 24, 8)
+ FIELD(FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD, 23, 1)
+ FIELD(FLASH_CMD_CTRL_REG, NUM_RD_DATA_BYTES_FLD, 20, 3)
+ FIELD(FLASH_CMD_CTRL_REG, ENB_COMD_ADDR_FLD, 19, 1)
+ FIELD(FLASH_CMD_CTRL_REG, ENB_MODE_BIT_FLD, 18, 1)
+ FIELD(FLASH_CMD_CTRL_REG, NUM_ADDR_BYTES_FLD, 16, 2)
+ FIELD(FLASH_CMD_CTRL_REG, ENB_WRITE_DATA_FLD, 15, 1)
+ FIELD(FLASH_CMD_CTRL_REG, NUM_WR_DATA_BYTES_FLD, 12, 3)
+ FIELD(FLASH_CMD_CTRL_REG, NUM_DUMMY_CYCLES_FLD, 7, 5)
+ FIELD(FLASH_CMD_CTRL_REG, FLASH_CMD_CTRL_RESV1_FLD, 3, 4)
+ FIELD(FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD, 2, 1)
+ FIELD(FLASH_CMD_CTRL_REG, CMD_EXEC_STATUS_FLD, 1, 1)
+ FIELD(FLASH_CMD_CTRL_REG, CMD_EXEC_FLD, 0, 1)
+REG32(FLASH_CMD_ADDR_REG, 0x94)
+REG32(FLASH_RD_DATA_LOWER_REG, 0xa0)
+REG32(FLASH_RD_DATA_UPPER_REG, 0xa4)
+REG32(FLASH_WR_DATA_LOWER_REG, 0xa8)
+REG32(FLASH_WR_DATA_UPPER_REG, 0xac)
+REG32(POLLING_FLASH_STATUS_REG, 0xb0)
+ FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_RSVD_FLD2, 21, 11)
+ FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_NB_DUMMY, 16, 5)
+ FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_RSVD_FLD1, 9, 7)
+ FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_VALID_FLD, 8, 1)
+ FIELD(POLLING_FLASH_STATUS_REG, DEVICE_STATUS_FLD, 0, 8)
+REG32(PHY_CONFIGURATION_REG, 0xb4)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESYNC_FLD, 31, 1)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESET_FLD, 30, 1)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RX_DLL_BYPASS_FLD, 29, 1)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESV2_FLD, 23, 6)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_TX_DLL_DELAY_FLD, 16, 7)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RESV1_FLD, 7, 9)
+ FIELD(PHY_CONFIGURATION_REG, PHY_CONFIG_RX_DLL_DELAY_FLD, 0, 7)
+REG32(PHY_MASTER_CONTROL_REG, 0xb8)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV3_FLD, 25, 7)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_LOCK_MODE_FLD, 24, 1)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_BYPASS_MODE_FLD, 23, 1)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_PHASE_DETECT_SELECTOR_FLD, 20, 3)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV2_FLD, 19, 1)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_NB_INDICATIONS_FLD, 16, 3)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_CONTROL_RESV1_FLD, 7, 9)
+ FIELD(PHY_MASTER_CONTROL_REG, PHY_MASTER_INITIAL_DELAY_FLD, 0, 7)
+REG32(DLL_OBSERVABLE_LOWER_REG, 0xbc)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_DLL_LOCK_INC_FLD, 24, 8)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_DLL_LOCK_DEC_FLD, 16, 8)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD, 15, 1)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_LOCK_VALUE_FLD, 8, 7)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_UNLOCK_COUNTER_FLD, 3, 5)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_LOCK_MODE_FLD, 1, 2)
+ FIELD(DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD, 0, 1)
+REG32(DLL_OBSERVABLE_UPPER_REG, 0xc0)
+ FIELD(DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE_UPPER_RESV2_FLD, 23, 9)
+ FIELD(DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE_UPPER_TX_DECODER_OUTPUT_FLD, 16, 7)
+ FIELD(DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE_UPPER_RESV1_FLD, 7, 9)
+ FIELD(DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD, 0, 7)
+REG32(OPCODE_EXT_LOWER_REG, 0xe0)
+ FIELD(OPCODE_EXT_LOWER_REG, EXT_READ_OPCODE_FLD, 24, 8)
+ FIELD(OPCODE_EXT_LOWER_REG, EXT_WRITE_OPCODE_FLD, 16, 8)
+ FIELD(OPCODE_EXT_LOWER_REG, EXT_POLL_OPCODE_FLD, 8, 8)
+ FIELD(OPCODE_EXT_LOWER_REG, EXT_STIG_OPCODE_FLD, 0, 8)
+REG32(OPCODE_EXT_UPPER_REG, 0xe4)
+ FIELD(OPCODE_EXT_UPPER_REG, WEL_OPCODE_FLD, 24, 8)
+ FIELD(OPCODE_EXT_UPPER_REG, EXT_WEL_OPCODE_FLD, 16, 8)
+ FIELD(OPCODE_EXT_UPPER_REG, OPCODE_EXT_UPPER_RESV1_FLD, 0, 16)
+REG32(MODULE_ID_REG, 0xfc)
+ FIELD(MODULE_ID_REG, FIX_PATCH_FLD, 24, 8)
+ FIELD(MODULE_ID_REG, MODULE_ID_FLD, 8, 16)
+ FIELD(MODULE_ID_REG, MODULE_ID_RESV_FLD, 2, 6)
+ FIELD(MODULE_ID_REG, CONF_FLD, 0, 2)
+
+#define RXFF_SZ 1024
+#define TXFF_SZ 1024
+
+#define MAX_RX_DEC_OUT 8
+
+#define SZ_512MBIT (512 * 1024 * 1024)
+#define SZ_1GBIT (1024 * 1024 * 1024)
+#define SZ_2GBIT (2ULL * SZ_1GBIT)
+#define SZ_4GBIT (4ULL * SZ_1GBIT)
+
+#define IS_IND_DMA_START(op) (op->done_bytes == 0)
+/*
+ * Bit field size of R_INDIRECT_WRITE_XFER_CTRL_REG_NUM_IND_OPS_DONE_FLD
+ * is 2 bits, which can record max of 3 indac operations.
+ */
+#define IND_OPS_DONE_MAX 3
+
+typedef enum {
+ WREN = 0x6,
+} FlashCMD;
+
+static unsigned int ospi_stig_addr_len(XlnxVersalOspi *s)
+{
+ /* Num address bytes is NUM_ADDR_BYTES_FLD + 1 */
+ return ARRAY_FIELD_EX32(s->regs,
+ FLASH_CMD_CTRL_REG, NUM_ADDR_BYTES_FLD) + 1;
+}
+
+static unsigned int ospi_stig_wr_data_len(XlnxVersalOspi *s)
+{
+ /* Num write data bytes is NUM_WR_DATA_BYTES_FLD + 1 */
+ return ARRAY_FIELD_EX32(s->regs,
+ FLASH_CMD_CTRL_REG, NUM_WR_DATA_BYTES_FLD) + 1;
+}
+
+static unsigned int ospi_stig_rd_data_len(XlnxVersalOspi *s)
+{
+ /* Num read data bytes is NUM_RD_DATA_BYTES_FLD + 1 */
+ return ARRAY_FIELD_EX32(s->regs,
+ FLASH_CMD_CTRL_REG, NUM_RD_DATA_BYTES_FLD) + 1;
+}
+
+/*
+ * Status bits in R_IRQ_STATUS_REG are set when the event occurs and the
+ * interrupt is enabled in the mask register ([1] Section 2.3.17)
+ */
+static void set_irq(XlnxVersalOspi *s, uint32_t set_mask)
+{
+ s->regs[R_IRQ_STATUS_REG] |= s->regs[R_IRQ_MASK_REG] & set_mask;
+}
+
+static void ospi_update_irq_line(XlnxVersalOspi *s)
+{
+ qemu_set_irq(s->irq, !!(s->regs[R_IRQ_STATUS_REG] &
+ s->regs[R_IRQ_MASK_REG]));
+}
+
+static uint8_t ospi_get_wr_opcode(XlnxVersalOspi *s)
+{
+ return ARRAY_FIELD_EX32(s->regs,
+ DEV_INSTR_WR_CONFIG_REG, WR_OPCODE_FLD);
+}
+
+static uint8_t ospi_get_rd_opcode(XlnxVersalOspi *s)
+{
+ return ARRAY_FIELD_EX32(s->regs,
+ DEV_INSTR_RD_CONFIG_REG, RD_OPCODE_NON_XIP_FLD);
+}
+
+static uint32_t ospi_get_num_addr_bytes(XlnxVersalOspi *s)
+{
+ /* Num address bytes is NUM_ADDR_BYTES_FLD + 1 */
+ return ARRAY_FIELD_EX32(s->regs,
+ DEV_SIZE_CONFIG_REG, NUM_ADDR_BYTES_FLD) + 1;
+}
+
+static void ospi_stig_membank_req(XlnxVersalOspi *s)
+{
+ int idx = ARRAY_FIELD_EX32(s->regs,
+ FLASH_COMMAND_CTRL_MEM_REG, MEM_BANK_ADDR_FLD);
+
+ ARRAY_FIELD_DP32(s->regs, FLASH_COMMAND_CTRL_MEM_REG,
+ MEM_BANK_READ_DATA_FLD, s->stig_membank[idx]);
+}
+
+static int ospi_stig_membank_rd_bytes(XlnxVersalOspi *s)
+{
+ int rd_data_fld = ARRAY_FIELD_EX32(s->regs, FLASH_COMMAND_CTRL_MEM_REG,
+ NB_OF_STIG_READ_BYTES_FLD);
+ static const int sizes[6] = { 16, 32, 64, 128, 256, 512 };
+ return (rd_data_fld < 6) ? sizes[rd_data_fld] : 0;
+}
+
+static uint32_t ospi_get_page_sz(XlnxVersalOspi *s)
+{
+ return ARRAY_FIELD_EX32(s->regs,
+ DEV_SIZE_CONFIG_REG, BYTES_PER_DEVICE_PAGE_FLD);
+}
+
+static bool ospi_ind_rd_watermark_enabled(XlnxVersalOspi *s)
+{
+ return s->regs[R_INDIRECT_READ_XFER_WATERMARK_REG];
+}
+
+static void ind_op_advance(IndOp *op, unsigned int len)
+{
+ op->done_bytes += len;
+ assert(op->done_bytes <= op->num_bytes);
+ if (op->done_bytes == op->num_bytes) {
+ op->completed = true;
+ }
+}
+
+static uint32_t ind_op_next_byte(IndOp *op)
+{
+ return op->flash_addr + op->done_bytes;
+}
+
+static uint32_t ind_op_end_byte(IndOp *op)
+{
+ return op->flash_addr + op->num_bytes;
+}
+
+static void ospi_ind_op_next(IndOp *op)
+{
+ op[0] = op[1];
+ op[1].completed = true;
+}
+
+static void ind_op_setup(IndOp *op, uint32_t flash_addr, uint32_t num_bytes)
+{
+ if (num_bytes & 0x3) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI indirect op num bytes not word aligned\n");
+ }
+ op->flash_addr = flash_addr;
+ op->num_bytes = num_bytes;
+ op->done_bytes = 0;
+ op->completed = false;
+}
+
+static bool ospi_ind_op_completed(IndOp *op)
+{
+ return op->completed;
+}
+
+static bool ospi_ind_op_all_completed(XlnxVersalOspi *s)
+{
+ return s->rd_ind_op[0].completed && s->wr_ind_op[0].completed;
+}
+
+static void ospi_ind_op_cancel(IndOp *op)
+{
+ op[0].completed = true;
+ op[1].completed = true;
+}
+
+static bool ospi_ind_op_add(IndOp *op, Fifo8 *fifo,
+ uint32_t flash_addr, uint32_t num_bytes)
+{
+ /* Check if first indirect op has been completed */
+ if (op->completed) {
+ fifo8_reset(fifo);
+ ind_op_setup(op, flash_addr, num_bytes);
+ return false;
+ }
+
+ /* Check if second indirect op has been completed */
+ op++;
+ if (op->completed) {
+ ind_op_setup(op, flash_addr, num_bytes);
+ return false;
+ }
+ return true;
+}
+
+static void ospi_ind_op_queue_up_rd(XlnxVersalOspi *s)
+{
+ uint32_t num_bytes = s->regs[R_INDIRECT_READ_XFER_NUM_BYTES_REG];
+ uint32_t flash_addr = s->regs[R_INDIRECT_READ_XFER_START_REG];
+ bool failed;
+
+ failed = ospi_ind_op_add(s->rd_ind_op, &s->rx_sram, flash_addr, num_bytes);
+ /* If two already queued set rd reject interrupt */
+ if (failed) {
+ set_irq(s, R_IRQ_STATUS_REG_INDIRECT_TRANSFER_REJECT_FLD_MASK);
+ }
+}
+
+static void ospi_ind_op_queue_up_wr(XlnxVersalOspi *s)
+{
+ uint32_t num_bytes = s->regs[R_INDIRECT_WRITE_XFER_NUM_BYTES_REG];
+ uint32_t flash_addr = s->regs[R_INDIRECT_WRITE_XFER_START_REG];
+ bool failed;
+
+ failed = ospi_ind_op_add(s->wr_ind_op, &s->tx_sram, flash_addr, num_bytes);
+ /* If two already queued set rd reject interrupt */
+ if (failed) {
+ set_irq(s, R_IRQ_STATUS_REG_INDIRECT_TRANSFER_REJECT_FLD_MASK);
+ }
+}
+
+static uint64_t flash_sz(XlnxVersalOspi *s, unsigned int cs)
+{
+ /* Flash sizes in MB */
+ static const uint64_t sizes[4] = { SZ_512MBIT / 8, SZ_1GBIT / 8,
+ SZ_2GBIT / 8, SZ_4GBIT / 8 };
+ uint32_t v = s->regs[R_DEV_SIZE_CONFIG_REG];
+
+ v >>= cs * R_DEV_SIZE_CONFIG_REG_MEM_SIZE_ON_CS0_FLD_LENGTH;
+ return sizes[FIELD_EX32(v, DEV_SIZE_CONFIG_REG, MEM_SIZE_ON_CS0_FLD)];
+}
+
+static unsigned int ospi_get_block_sz(XlnxVersalOspi *s)
+{
+ unsigned int block_fld = ARRAY_FIELD_EX32(s->regs,
+ DEV_SIZE_CONFIG_REG,
+ BYTES_PER_SUBSECTOR_FLD);
+ return 1 << block_fld;
+}
+
+static unsigned int flash_blocks(XlnxVersalOspi *s, unsigned int cs)
+{
+ unsigned int b_sz = ospi_get_block_sz(s);
+ unsigned int f_sz = flash_sz(s, cs);
+
+ return f_sz / b_sz;
+}
+
+static int ospi_ahb_decoder_cs(XlnxVersalOspi *s, hwaddr addr)
+{
+ uint64_t end_addr = 0;
+ int cs;
+
+ for (cs = 0; cs < s->num_cs; cs++) {
+ end_addr += flash_sz(s, cs);
+ if (addr < end_addr) {
+ break;
+ }
+ }
+
+ if (cs == s->num_cs) {
+ /* Address is out of range */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI flash address does not fit in configuration\n");
+ return -1;
+ }
+ return cs;
+}
+
+static void ospi_ahb_decoder_enable_cs(XlnxVersalOspi *s, hwaddr addr)
+{
+ int cs = ospi_ahb_decoder_cs(s, addr);
+
+ if (cs >= 0) {
+ for (int i = 0; i < s->num_cs; i++) {
+ qemu_set_irq(s->cs_lines[i], cs != i);
+ }
+ }
+}
+
+static unsigned int single_cs(XlnxVersalOspi *s)
+{
+ unsigned int field = ARRAY_FIELD_EX32(s->regs,
+ CONFIG_REG, PERIPH_CS_LINES_FLD);
+
+ /*
+ * Below one liner is a trick that finds the rightmost zero and makes sure
+ * all other bits are turned to 1. It is a variant of the 'Isolate the
+ * rightmost 0-bit' trick found below at the time of writing:
+ *
+ * https://emre.me/computer-science/bit-manipulation-tricks/
+ *
+ * 4'bXXX0 -> 4'b1110
+ * 4'bXX01 -> 4'b1101
+ * 4'bX011 -> 4'b1011
+ * 4'b0111 -> 4'b0111
+ * 4'b1111 -> 4'b1111
+ */
+ return (field | ~(field + 1)) & 0xf;
+}
+
+static void ospi_update_cs_lines(XlnxVersalOspi *s)
+{
+ unsigned int all_cs;
+ int i;
+
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, PERIPH_SEL_DEC_FLD)) {
+ all_cs = ARRAY_FIELD_EX32(s->regs, CONFIG_REG, PERIPH_CS_LINES_FLD);
+ } else {
+ all_cs = single_cs(s);
+ }
+
+ for (i = 0; i < s->num_cs; i++) {
+ bool cs = (all_cs >> i) & 1;
+
+ qemu_set_irq(s->cs_lines[i], cs);
+ }
+}
+
+static void ospi_dac_cs(XlnxVersalOspi *s, hwaddr addr)
+{
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENABLE_AHB_DECODER_FLD)) {
+ ospi_ahb_decoder_enable_cs(s, addr);
+ } else {
+ ospi_update_cs_lines(s);
+ }
+}
+
+static void ospi_disable_cs(XlnxVersalOspi *s)
+{
+ int i;
+
+ for (i = 0; i < s->num_cs; i++) {
+ qemu_set_irq(s->cs_lines[i], 1);
+ }
+}
+
+static void ospi_flush_txfifo(XlnxVersalOspi *s)
+{
+ while (!fifo8_is_empty(&s->tx_fifo)) {
+ uint32_t tx_rx = fifo8_pop(&s->tx_fifo);
+
+ tx_rx = ssi_transfer(s->spi, tx_rx);
+ fifo8_push(&s->rx_fifo, tx_rx);
+ }
+}
+
+static void ospi_tx_fifo_push_address_raw(XlnxVersalOspi *s,
+ uint32_t flash_addr,
+ unsigned int addr_bytes)
+{
+ /* Push write address */
+ if (addr_bytes == 4) {
+ fifo8_push(&s->tx_fifo, flash_addr >> 24);
+ }
+ if (addr_bytes >= 3) {
+ fifo8_push(&s->tx_fifo, flash_addr >> 16);
+ }
+ if (addr_bytes >= 2) {
+ fifo8_push(&s->tx_fifo, flash_addr >> 8);
+ }
+ fifo8_push(&s->tx_fifo, flash_addr);
+}
+
+static void ospi_tx_fifo_push_address(XlnxVersalOspi *s, uint32_t flash_addr)
+{
+ /* Push write address */
+ int addr_bytes = ospi_get_num_addr_bytes(s);
+
+ ospi_tx_fifo_push_address_raw(s, flash_addr, addr_bytes);
+}
+
+static void ospi_tx_fifo_push_stig_addr(XlnxVersalOspi *s)
+{
+ uint32_t flash_addr = s->regs[R_FLASH_CMD_ADDR_REG];
+ unsigned int addr_bytes = ospi_stig_addr_len(s);
+
+ ospi_tx_fifo_push_address_raw(s, flash_addr, addr_bytes);
+}
+
+static void ospi_tx_fifo_push_rd_op_addr(XlnxVersalOspi *s, uint32_t flash_addr)
+{
+ uint8_t inst_code = ospi_get_rd_opcode(s);
+
+ fifo8_reset(&s->tx_fifo);
+
+ /* Push read opcode */
+ fifo8_push(&s->tx_fifo, inst_code);
+
+ /* Push read address */
+ ospi_tx_fifo_push_address(s, flash_addr);
+}
+
+static void ospi_tx_fifo_push_stig_wr_data(XlnxVersalOspi *s)
+{
+ uint64_t data = s->regs[R_FLASH_WR_DATA_LOWER_REG];
+ int wr_data_len = ospi_stig_wr_data_len(s);
+ int i;
+
+ data |= (uint64_t) s->regs[R_FLASH_WR_DATA_UPPER_REG] << 32;
+ for (i = 0; i < wr_data_len; i++) {
+ int shift = i * 8;
+ fifo8_push(&s->tx_fifo, data >> shift);
+ }
+}
+
+static void ospi_tx_fifo_push_stig_rd_data(XlnxVersalOspi *s)
+{
+ int rd_data_len;
+ int i;
+
+ if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD)) {
+ rd_data_len = ospi_stig_membank_rd_bytes(s);
+ } else {
+ rd_data_len = ospi_stig_rd_data_len(s);
+ }
+
+ /* transmit second part (data) */
+ for (i = 0; i < rd_data_len; ++i) {
+ fifo8_push(&s->tx_fifo, 0);
+ }
+}
+
+static void ospi_rx_fifo_pop_stig_rd_data(XlnxVersalOspi *s)
+{
+ int size = ospi_stig_rd_data_len(s);
+ uint8_t bytes[8] = {};
+ int i;
+
+ size = MIN(fifo8_num_used(&s->rx_fifo), size);
+
+ assert(size <= 8);
+
+ for (i = 0; i < size; i++) {
+ bytes[i] = fifo8_pop(&s->rx_fifo);
+ }
+
+ s->regs[R_FLASH_RD_DATA_LOWER_REG] = ldl_le_p(bytes);
+ s->regs[R_FLASH_RD_DATA_UPPER_REG] = ldl_le_p(bytes + 4);
+}
+
+static void ospi_ind_read(XlnxVersalOspi *s, uint32_t flash_addr, uint32_t len)
+{
+ int i;
+
+ /* Create first section of read cmd */
+ ospi_tx_fifo_push_rd_op_addr(s, flash_addr);
+
+ /* transmit first part */
+ ospi_update_cs_lines(s);
+ ospi_flush_txfifo(s);
+
+ fifo8_reset(&s->rx_fifo);
+
+ /* transmit second part (data) */
+ for (i = 0; i < len; ++i) {
+ fifo8_push(&s->tx_fifo, 0);
+ }
+ ospi_flush_txfifo(s);
+
+ for (i = 0; i < len; ++i) {
+ fifo8_push(&s->rx_sram, fifo8_pop(&s->rx_fifo));
+ }
+
+ /* done */
+ ospi_disable_cs(s);
+}
+
+static unsigned int ospi_dma_burst_size(XlnxVersalOspi *s)
+{
+ return 1 << ARRAY_FIELD_EX32(s->regs,
+ DMA_PERIPH_CONFIG_REG,
+ NUM_BURST_REQ_BYTES_FLD);
+}
+
+static unsigned int ospi_dma_single_size(XlnxVersalOspi *s)
+{
+ return 1 << ARRAY_FIELD_EX32(s->regs,
+ DMA_PERIPH_CONFIG_REG,
+ NUM_SINGLE_REQ_BYTES_FLD);
+}
+
+static void ind_rd_inc_num_done(XlnxVersalOspi *s)
+{
+ unsigned int done = ARRAY_FIELD_EX32(s->regs,
+ INDIRECT_READ_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD);
+ if (done < IND_OPS_DONE_MAX) {
+ done++;
+ }
+ done &= 0x3;
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD, done);
+}
+
+static void ospi_ind_rd_completed(XlnxVersalOspi *s)
+{
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG,
+ IND_OPS_DONE_STATUS_FLD, 1);
+
+ ind_rd_inc_num_done(s);
+ ospi_ind_op_next(s->rd_ind_op);
+ if (ospi_ind_op_all_completed(s)) {
+ set_irq(s, R_IRQ_STATUS_REG_INDIRECT_OP_DONE_FLD_MASK);
+ }
+}
+
+static void ospi_dma_read(XlnxVersalOspi *s)
+{
+ IndOp *op = s->rd_ind_op;
+ uint32_t dma_len = op->num_bytes;
+ uint32_t burst_sz = ospi_dma_burst_size(s);
+ uint32_t single_sz = ospi_dma_single_size(s);
+ uint32_t ind_trig_range;
+ uint32_t remainder;
+ XlnxCSUDMAClass *xcdc = XLNX_CSU_DMA_GET_CLASS(s->dma_src);
+
+ ind_trig_range = (1 << ARRAY_FIELD_EX32(s->regs,
+ INDIRECT_TRIGGER_ADDR_RANGE_REG,
+ IND_RANGE_WIDTH_FLD));
+ remainder = dma_len % burst_sz;
+ remainder = remainder % single_sz;
+ if (burst_sz > ind_trig_range || single_sz > ind_trig_range ||
+ remainder != 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI DMA burst size / single size config error\n");
+ }
+
+ s->src_dma_inprog = true;
+ if (xcdc->read(s->dma_src, 0, dma_len) != MEMTX_OK) {
+ qemu_log_mask(LOG_GUEST_ERROR, "OSPI DMA configuration error\n");
+ }
+ s->src_dma_inprog = false;
+}
+
+static void ospi_do_ind_read(XlnxVersalOspi *s)
+{
+ IndOp *op = s->rd_ind_op;
+ uint32_t next_b;
+ uint32_t end_b;
+ uint32_t len;
+ bool start_dma = IS_IND_DMA_START(op) && !s->src_dma_inprog;
+
+ /* Continue to read flash until we run out of space in sram */
+ while (!ospi_ind_op_completed(op) &&
+ !fifo8_is_full(&s->rx_sram)) {
+ /* Read reqested number of bytes, max bytes limited to size of sram */
+ next_b = ind_op_next_byte(op);
+ end_b = next_b + fifo8_num_free(&s->rx_sram);
+ end_b = MIN(end_b, ind_op_end_byte(op));
+
+ len = end_b - next_b;
+ ospi_ind_read(s, next_b, len);
+ ind_op_advance(op, len);
+
+ if (ospi_ind_rd_watermark_enabled(s)) {
+ ARRAY_FIELD_DP32(s->regs, IRQ_STATUS_REG,
+ INDIRECT_XFER_LEVEL_BREACH_FLD, 1);
+ set_irq(s,
+ R_IRQ_STATUS_REG_INDIRECT_XFER_LEVEL_BREACH_FLD_MASK);
+ }
+
+ if (!s->src_dma_inprog &&
+ ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD)) {
+ ospi_dma_read(s);
+ }
+ }
+
+ /* Set sram full */
+ if (fifo8_num_used(&s->rx_sram) == RXFF_SZ) {
+ ARRAY_FIELD_DP32(s->regs,
+ INDIRECT_READ_XFER_CTRL_REG, SRAM_FULL_FLD, 1);
+ set_irq(s, R_IRQ_STATUS_REG_INDRD_SRAM_FULL_FLD_MASK);
+ }
+
+ /* Signal completion if done, unless inside recursion via ospi_dma_read */
+ if (!ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD) || start_dma) {
+ if (ospi_ind_op_completed(op)) {
+ ospi_ind_rd_completed(s);
+ }
+ }
+}
+
+/* Transmit write enable instruction */
+static void ospi_transmit_wel(XlnxVersalOspi *s, bool ahb_decoder_cs,
+ hwaddr addr)
+{
+ fifo8_reset(&s->tx_fifo);
+ fifo8_push(&s->tx_fifo, WREN);
+
+ if (ahb_decoder_cs) {
+ ospi_ahb_decoder_enable_cs(s, addr);
+ } else {
+ ospi_update_cs_lines(s);
+ }
+
+ ospi_flush_txfifo(s);
+ ospi_disable_cs(s);
+
+ fifo8_reset(&s->rx_fifo);
+}
+
+static void ospi_ind_write(XlnxVersalOspi *s, uint32_t flash_addr, uint32_t len)
+{
+ bool ahb_decoder_cs = false;
+ uint8_t inst_code;
+ int i;
+
+ assert(fifo8_num_used(&s->tx_sram) >= len);
+
+ if (!ARRAY_FIELD_EX32(s->regs, DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD)) {
+ ospi_transmit_wel(s, ahb_decoder_cs, 0);
+ }
+
+ /* reset fifos */
+ fifo8_reset(&s->tx_fifo);
+ fifo8_reset(&s->rx_fifo);
+
+ /* Push write opcode */
+ inst_code = ospi_get_wr_opcode(s);
+ fifo8_push(&s->tx_fifo, inst_code);
+
+ /* Push write address */
+ ospi_tx_fifo_push_address(s, flash_addr);
+
+ /* data */
+ for (i = 0; i < len; i++) {
+ fifo8_push(&s->tx_fifo, fifo8_pop(&s->tx_sram));
+ }
+
+ /* transmit */
+ ospi_update_cs_lines(s);
+ ospi_flush_txfifo(s);
+
+ /* done */
+ ospi_disable_cs(s);
+ fifo8_reset(&s->rx_fifo);
+}
+
+static void ind_wr_inc_num_done(XlnxVersalOspi *s)
+{
+ unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD);
+ if (done < IND_OPS_DONE_MAX) {
+ done++;
+ }
+ done &= 0x3;
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD, done);
+}
+
+static void ospi_ind_wr_completed(XlnxVersalOspi *s)
+{
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,
+ IND_OPS_DONE_STATUS_FLD, 1);
+ ind_wr_inc_num_done(s);
+ ospi_ind_op_next(s->wr_ind_op);
+ /* Set indirect op done interrupt if enabled */
+ if (ospi_ind_op_all_completed(s)) {
+ set_irq(s, R_IRQ_STATUS_REG_INDIRECT_OP_DONE_FLD_MASK);
+ }
+}
+
+static void ospi_do_indirect_write(XlnxVersalOspi *s)
+{
+ uint32_t write_watermark = s->regs[R_INDIRECT_WRITE_XFER_WATERMARK_REG];
+ uint32_t pagesz = ospi_get_page_sz(s);
+ uint32_t page_mask = ~(pagesz - 1);
+ IndOp *op = s->wr_ind_op;
+ uint32_t next_b;
+ uint32_t end_b;
+ uint32_t len;
+
+ /* Write out tx_fifo in maximum page sz chunks */
+ while (!ospi_ind_op_completed(op) && fifo8_num_used(&s->tx_sram) > 0) {
+ next_b = ind_op_next_byte(op);
+ end_b = next_b + MIN(fifo8_num_used(&s->tx_sram), pagesz);
+
+ /* Dont cross page boundary */
+ if ((end_b & page_mask) > next_b) {
+ end_b &= page_mask;
+ }
+
+ len = end_b - next_b;
+ len = MIN(len, op->num_bytes - op->done_bytes);
+ ospi_ind_write(s, next_b, len);
+ ind_op_advance(op, len);
+ }
+
+ /*
+ * Always set indirect transfer level breached interrupt if enabled
+ * (write watermark > 0) since the tx_sram always will be emptied
+ */
+ if (write_watermark > 0) {
+ set_irq(s, R_IRQ_STATUS_REG_INDIRECT_XFER_LEVEL_BREACH_FLD_MASK);
+ }
+
+ /* Signal completions if done */
+ if (ospi_ind_op_completed(op)) {
+ ospi_ind_wr_completed(s);
+ }
+}
+
+static void ospi_stig_fill_membank(XlnxVersalOspi *s)
+{
+ int num_rd_bytes = ospi_stig_membank_rd_bytes(s);
+ int idx = num_rd_bytes - 8; /* first of last 8 */
+ int i;
+
+ for (i = 0; i < num_rd_bytes; i++) {
+ s->stig_membank[i] = fifo8_pop(&s->rx_fifo);
+ }
+
+ g_assert((idx + 4) < ARRAY_SIZE(s->stig_membank));
+
+ /* Fill in lower upper regs */
+ s->regs[R_FLASH_RD_DATA_LOWER_REG] = ldl_le_p(&s->stig_membank[idx]);
+ s->regs[R_FLASH_RD_DATA_UPPER_REG] = ldl_le_p(&s->stig_membank[idx + 4]);
+}
+
+static void ospi_stig_cmd_exec(XlnxVersalOspi *s)
+{
+ uint8_t inst_code;
+
+ /* Reset fifos */
+ fifo8_reset(&s->tx_fifo);
+ fifo8_reset(&s->rx_fifo);
+
+ /* Push write opcode */
+ inst_code = ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, CMD_OPCODE_FLD);
+ fifo8_push(&s->tx_fifo, inst_code);
+
+ /* Push address if enabled */
+ if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_COMD_ADDR_FLD)) {
+ ospi_tx_fifo_push_stig_addr(s);
+ }
+
+ /* Enable cs */
+ ospi_update_cs_lines(s);
+
+ /* Data */
+ if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_WRITE_DATA_FLD)) {
+ ospi_tx_fifo_push_stig_wr_data(s);
+ } else if (ARRAY_FIELD_EX32(s->regs,
+ FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD)) {
+ /* transmit first part */
+ ospi_flush_txfifo(s);
+ fifo8_reset(&s->rx_fifo);
+ ospi_tx_fifo_push_stig_rd_data(s);
+ }
+
+ /* Transmit */
+ ospi_flush_txfifo(s);
+ ospi_disable_cs(s);
+
+ if (ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, ENB_READ_DATA_FLD)) {
+ if (ARRAY_FIELD_EX32(s->regs,
+ FLASH_CMD_CTRL_REG, STIG_MEM_BANK_EN_FLD)) {
+ ospi_stig_fill_membank(s);
+ } else {
+ ospi_rx_fifo_pop_stig_rd_data(s);
+ }
+ }
+}
+
+static uint32_t ospi_block_address(XlnxVersalOspi *s, unsigned int block)
+{
+ unsigned int block_sz = ospi_get_block_sz(s);
+ unsigned int cs = 0;
+ uint32_t addr = 0;
+
+ while (cs < s->num_cs && block >= flash_blocks(s, cs)) {
+ block -= flash_blocks(s, 0);
+ addr += flash_sz(s, cs);
+ }
+ addr += block * block_sz;
+ return addr;
+}
+
+static uint32_t ospi_get_wr_prot_addr_low(XlnxVersalOspi *s)
+{
+ unsigned int block = s->regs[R_LOWER_WR_PROT_REG];
+
+ return ospi_block_address(s, block);
+}
+
+static uint32_t ospi_get_wr_prot_addr_upper(XlnxVersalOspi *s)
+{
+ unsigned int block = s->regs[R_UPPER_WR_PROT_REG];
+
+ /* Get address of first block out of defined range */
+ return ospi_block_address(s, block + 1);
+}
+
+static bool ospi_is_write_protected(XlnxVersalOspi *s, hwaddr addr)
+{
+ uint32_t wr_prot_addr_upper = ospi_get_wr_prot_addr_upper(s);
+ uint32_t wr_prot_addr_low = ospi_get_wr_prot_addr_low(s);
+ bool in_range = false;
+
+ if (addr >= wr_prot_addr_low && addr < wr_prot_addr_upper) {
+ in_range = true;
+ }
+
+ if (ARRAY_FIELD_EX32(s->regs, WR_PROT_CTRL_REG, INV_FLD)) {
+ in_range = !in_range;
+ }
+ return in_range;
+}
+
+static uint64_t ospi_rx_sram_read(XlnxVersalOspi *s, unsigned int size)
+{
+ uint8_t bytes[8] = {};
+ int i;
+
+ if (size < 4 && fifo8_num_used(&s->rx_sram) >= 4) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI only last read of internal "
+ "sram is allowed to be < 32 bits\n");
+ }
+
+ size = MIN(fifo8_num_used(&s->rx_sram), size);
+
+ assert(size <= 8);
+
+ for (i = 0; i < size; i++) {
+ bytes[i] = fifo8_pop(&s->rx_sram);
+ }
+
+ return ldq_le_p(bytes);
+}
+
+static void ospi_tx_sram_write(XlnxVersalOspi *s, uint64_t value,
+ unsigned int size)
+{
+ int i;
+ for (i = 0; i < size && !fifo8_is_full(&s->tx_sram); i++) {
+ fifo8_push(&s->tx_sram, value >> 8 * i);
+ }
+}
+
+static uint64_t ospi_do_dac_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+ uint8_t bytes[8] = {};
+ int i;
+
+ /* Create first section of read cmd */
+ ospi_tx_fifo_push_rd_op_addr(s, (uint32_t) addr);
+
+ /* Enable cs and transmit first part */
+ ospi_dac_cs(s, addr);
+ ospi_flush_txfifo(s);
+
+ fifo8_reset(&s->rx_fifo);
+
+ /* transmit second part (data) */
+ for (i = 0; i < size; ++i) {
+ fifo8_push(&s->tx_fifo, 0);
+ }
+ ospi_flush_txfifo(s);
+
+ /* fill in result */
+ size = MIN(fifo8_num_used(&s->rx_fifo), size);
+
+ assert(size <= 8);
+
+ for (i = 0; i < size; i++) {
+ bytes[i] = fifo8_pop(&s->rx_fifo);
+ }
+
+ /* done */
+ ospi_disable_cs(s);
+
+ return ldq_le_p(bytes);
+}
+
+static void ospi_do_dac_write(void *opaque,
+ hwaddr addr,
+ uint64_t value,
+ unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+ bool ahb_decoder_cs = ARRAY_FIELD_EX32(s->regs, CONFIG_REG,
+ ENABLE_AHB_DECODER_FLD);
+ uint8_t inst_code;
+ unsigned int i;
+
+ if (!ARRAY_FIELD_EX32(s->regs, DEV_INSTR_WR_CONFIG_REG, WEL_DIS_FLD)) {
+ ospi_transmit_wel(s, ahb_decoder_cs, addr);
+ }
+
+ /* reset fifos */
+ fifo8_reset(&s->tx_fifo);
+ fifo8_reset(&s->rx_fifo);
+
+ /* Push write opcode */
+ inst_code = ospi_get_wr_opcode(s);
+ fifo8_push(&s->tx_fifo, inst_code);
+
+ /* Push write address */
+ ospi_tx_fifo_push_address(s, addr);
+
+ /* data */
+ for (i = 0; i < size; i++) {
+ fifo8_push(&s->tx_fifo, value >> 8 * i);
+ }
+
+ /* Enable cs and transmit */
+ ospi_dac_cs(s, addr);
+ ospi_flush_txfifo(s);
+ ospi_disable_cs(s);
+
+ fifo8_reset(&s->rx_fifo);
+}
+
+static void flash_cmd_ctrl_mem_reg_post_write(RegisterInfo *reg,
+ uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) {
+ if (ARRAY_FIELD_EX32(s->regs,
+ FLASH_COMMAND_CTRL_MEM_REG,
+ TRIGGER_MEM_BANK_REQ_FLD)) {
+ ospi_stig_membank_req(s);
+ ARRAY_FIELD_DP32(s->regs, FLASH_COMMAND_CTRL_MEM_REG,
+ TRIGGER_MEM_BANK_REQ_FLD, 0);
+ }
+ }
+}
+
+static void flash_cmd_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD) &&
+ ARRAY_FIELD_EX32(s->regs, FLASH_CMD_CTRL_REG, CMD_EXEC_FLD)) {
+ ospi_stig_cmd_exec(s);
+ set_irq(s, R_IRQ_STATUS_REG_STIG_REQ_INT_FLD_MASK);
+ ARRAY_FIELD_DP32(s->regs, FLASH_CMD_CTRL_REG, CMD_EXEC_FLD, 0);
+ }
+}
+
+static uint64_t ind_wr_dec_num_done(XlnxVersalOspi *s, uint64_t val)
+{
+ unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD);
+ done--;
+ done &= 0x3;
+ val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD, done);
+ return val;
+}
+
+static bool ind_wr_clearing_op_done(XlnxVersalOspi *s, uint64_t new_val)
+{
+ bool set_in_reg = ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG,
+ IND_OPS_DONE_STATUS_FLD);
+ bool set_in_new_val = FIELD_EX32(new_val, INDIRECT_WRITE_XFER_CTRL_REG,
+ IND_OPS_DONE_STATUS_FLD);
+ /* return true if clearing bit */
+ return set_in_reg && !set_in_new_val;
+}
+
+static uint64_t ind_wr_xfer_ctrl_reg_pre_write(RegisterInfo *reg,
+ uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+
+ if (ind_wr_clearing_op_done(s, val)) {
+ val = ind_wr_dec_num_done(s, val);
+ }
+ return val;
+}
+
+static void ind_wr_xfer_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+
+ if (s->ind_write_disabled) {
+ return;
+ }
+
+ if (ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, START_FLD)) {
+ ospi_ind_op_queue_up_wr(s);
+ ospi_do_indirect_write(s);
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, START_FLD, 0);
+ }
+
+ if (ARRAY_FIELD_EX32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD)) {
+ ospi_ind_op_cancel(s->wr_ind_op);
+ fifo8_reset(&s->tx_sram);
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_WRITE_XFER_CTRL_REG, CANCEL_FLD, 0);
+ }
+}
+
+static uint64_t ind_wr_xfer_ctrl_reg_post_read(RegisterInfo *reg,
+ uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+ IndOp *op = s->wr_ind_op;
+
+ /* Check if ind ops is ongoing */
+ if (!ospi_ind_op_completed(&op[0])) {
+ /* Check if two ind ops are queued */
+ if (!ospi_ind_op_completed(&op[1])) {
+ val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG,
+ WR_QUEUED_FLD, 1);
+ }
+ val = FIELD_DP32(val, INDIRECT_WRITE_XFER_CTRL_REG, WR_STATUS_FLD, 1);
+ }
+ return val;
+}
+
+static uint64_t ind_rd_dec_num_done(XlnxVersalOspi *s, uint64_t val)
+{
+ unsigned int done = ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD);
+ done--;
+ done &= 0x3;
+ val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG,
+ NUM_IND_OPS_DONE_FLD, done);
+ return val;
+}
+
+static uint64_t ind_rd_xfer_ctrl_reg_pre_write(RegisterInfo *reg,
+ uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+
+ if (FIELD_EX32(val, INDIRECT_READ_XFER_CTRL_REG,
+ IND_OPS_DONE_STATUS_FLD)) {
+ val = ind_rd_dec_num_done(s, val);
+ val &= ~R_INDIRECT_READ_XFER_CTRL_REG_IND_OPS_DONE_STATUS_FLD_MASK;
+ }
+ return val;
+}
+
+static void ind_rd_xfer_ctrl_reg_post_write(RegisterInfo *reg, uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+
+ if (ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG, START_FLD)) {
+ ospi_ind_op_queue_up_rd(s);
+ ospi_do_ind_read(s);
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG, START_FLD, 0);
+ }
+
+ if (ARRAY_FIELD_EX32(s->regs, INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD)) {
+ ospi_ind_op_cancel(s->rd_ind_op);
+ fifo8_reset(&s->rx_sram);
+ ARRAY_FIELD_DP32(s->regs, INDIRECT_READ_XFER_CTRL_REG, CANCEL_FLD, 0);
+ }
+}
+
+static uint64_t ind_rd_xfer_ctrl_reg_post_read(RegisterInfo *reg,
+ uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+ IndOp *op = s->rd_ind_op;
+
+ /* Check if ind ops is ongoing */
+ if (!ospi_ind_op_completed(&op[0])) {
+ /* Check if two ind ops are queued */
+ if (!ospi_ind_op_completed(&op[1])) {
+ val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG,
+ RD_QUEUED_FLD, 1);
+ }
+ val = FIELD_DP32(val, INDIRECT_READ_XFER_CTRL_REG, RD_STATUS_FLD, 1);
+ }
+ return val;
+}
+
+static uint64_t sram_fill_reg_post_read(RegisterInfo *reg, uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+ val = ((fifo8_num_used(&s->tx_sram) & 0xFFFF) << 16) |
+ (fifo8_num_used(&s->rx_sram) & 0xFFFF);
+ return val;
+}
+
+static uint64_t dll_obs_upper_reg_post_read(RegisterInfo *reg, uint64_t val)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(reg->opaque);
+ uint32_t rx_dec_out;
+
+ rx_dec_out = FIELD_EX32(val, DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD);
+
+ if (rx_dec_out < MAX_RX_DEC_OUT) {
+ ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_UPPER_REG,
+ DLL_OBSERVABLE__UPPER_RX_DECODER_OUTPUT_FLD,
+ rx_dec_out + 1);
+ }
+
+ return val;
+}
+
+
+static void xlnx_versal_ospi_reset(DeviceState *dev)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(dev);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
+ register_reset(&s->regs_info[i]);
+ }
+
+ fifo8_reset(&s->rx_fifo);
+ fifo8_reset(&s->tx_fifo);
+ fifo8_reset(&s->rx_sram);
+ fifo8_reset(&s->tx_sram);
+
+ s->rd_ind_op[0].completed = true;
+ s->rd_ind_op[1].completed = true;
+ s->wr_ind_op[0].completed = true;
+ s->wr_ind_op[1].completed = true;
+ ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD, 1);
+ ARRAY_FIELD_DP32(s->regs, DLL_OBSERVABLE_LOWER_REG,
+ DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD, 1);
+}
+
+static RegisterAccessInfo ospi_regs_info[] = {
+ { .name = "CONFIG_REG",
+ .addr = A_CONFIG_REG,
+ .reset = 0x80780081,
+ .ro = 0x9c000000,
+ },{ .name = "DEV_INSTR_RD_CONFIG_REG",
+ .addr = A_DEV_INSTR_RD_CONFIG_REG,
+ .reset = 0x3,
+ .ro = 0xe0ecc800,
+ },{ .name = "DEV_INSTR_WR_CONFIG_REG",
+ .addr = A_DEV_INSTR_WR_CONFIG_REG,
+ .reset = 0x2,
+ .ro = 0xe0fcce00,
+ },{ .name = "DEV_DELAY_REG",
+ .addr = A_DEV_DELAY_REG,
+ },{ .name = "RD_DATA_CAPTURE_REG",
+ .addr = A_RD_DATA_CAPTURE_REG,
+ .reset = 0x1,
+ .ro = 0xfff0fec0,
+ },{ .name = "DEV_SIZE_CONFIG_REG",
+ .addr = A_DEV_SIZE_CONFIG_REG,
+ .reset = 0x101002,
+ .ro = 0xe0000000,
+ },{ .name = "SRAM_PARTITION_CFG_REG",
+ .addr = A_SRAM_PARTITION_CFG_REG,
+ .reset = 0x80,
+ .ro = 0xffffff00,
+ },{ .name = "IND_AHB_ADDR_TRIGGER_REG",
+ .addr = A_IND_AHB_ADDR_TRIGGER_REG,
+ },{ .name = "DMA_PERIPH_CONFIG_REG",
+ .addr = A_DMA_PERIPH_CONFIG_REG,
+ .ro = 0xfffff0f0,
+ },{ .name = "REMAP_ADDR_REG",
+ .addr = A_REMAP_ADDR_REG,
+ },{ .name = "MODE_BIT_CONFIG_REG",
+ .addr = A_MODE_BIT_CONFIG_REG,
+ .reset = 0x200,
+ .ro = 0xffff7800,
+ },{ .name = "SRAM_FILL_REG",
+ .addr = A_SRAM_FILL_REG,
+ .ro = 0xffffffff,
+ .post_read = sram_fill_reg_post_read,
+ },{ .name = "TX_THRESH_REG",
+ .addr = A_TX_THRESH_REG,
+ .reset = 0x1,
+ .ro = 0xffffffe0,
+ },{ .name = "RX_THRESH_REG",
+ .addr = A_RX_THRESH_REG,
+ .reset = 0x1,
+ .ro = 0xffffffe0,
+ },{ .name = "WRITE_COMPLETION_CTRL_REG",
+ .addr = A_WRITE_COMPLETION_CTRL_REG,
+ .reset = 0x10005,
+ .ro = 0x1800,
+ },{ .name = "NO_OF_POLLS_BEF_EXP_REG",
+ .addr = A_NO_OF_POLLS_BEF_EXP_REG,
+ .reset = 0xffffffff,
+ },{ .name = "IRQ_STATUS_REG",
+ .addr = A_IRQ_STATUS_REG,
+ .ro = 0xfff08000,
+ .w1c = 0xf7fff,
+ },{ .name = "IRQ_MASK_REG",
+ .addr = A_IRQ_MASK_REG,
+ .ro = 0xfff08000,
+ },{ .name = "LOWER_WR_PROT_REG",
+ .addr = A_LOWER_WR_PROT_REG,
+ },{ .name = "UPPER_WR_PROT_REG",
+ .addr = A_UPPER_WR_PROT_REG,
+ },{ .name = "WR_PROT_CTRL_REG",
+ .addr = A_WR_PROT_CTRL_REG,
+ .ro = 0xfffffffc,
+ },{ .name = "INDIRECT_READ_XFER_CTRL_REG",
+ .addr = A_INDIRECT_READ_XFER_CTRL_REG,
+ .ro = 0xffffffd4,
+ .w1c = 0x08,
+ .pre_write = ind_rd_xfer_ctrl_reg_pre_write,
+ .post_write = ind_rd_xfer_ctrl_reg_post_write,
+ .post_read = ind_rd_xfer_ctrl_reg_post_read,
+ },{ .name = "INDIRECT_READ_XFER_WATERMARK_REG",
+ .addr = A_INDIRECT_READ_XFER_WATERMARK_REG,
+ },{ .name = "INDIRECT_READ_XFER_START_REG",
+ .addr = A_INDIRECT_READ_XFER_START_REG,
+ },{ .name = "INDIRECT_READ_XFER_NUM_BYTES_REG",
+ .addr = A_INDIRECT_READ_XFER_NUM_BYTES_REG,
+ },{ .name = "INDIRECT_WRITE_XFER_CTRL_REG",
+ .addr = A_INDIRECT_WRITE_XFER_CTRL_REG,
+ .ro = 0xffffffdc,
+ .w1c = 0x20,
+ .pre_write = ind_wr_xfer_ctrl_reg_pre_write,
+ .post_write = ind_wr_xfer_ctrl_reg_post_write,
+ .post_read = ind_wr_xfer_ctrl_reg_post_read,
+ },{ .name = "INDIRECT_WRITE_XFER_WATERMARK_REG",
+ .addr = A_INDIRECT_WRITE_XFER_WATERMARK_REG,
+ .reset = 0xffffffff,
+ },{ .name = "INDIRECT_WRITE_XFER_START_REG",
+ .addr = A_INDIRECT_WRITE_XFER_START_REG,
+ },{ .name = "INDIRECT_WRITE_XFER_NUM_BYTES_REG",
+ .addr = A_INDIRECT_WRITE_XFER_NUM_BYTES_REG,
+ },{ .name = "INDIRECT_TRIGGER_ADDR_RANGE_REG",
+ .addr = A_INDIRECT_TRIGGER_ADDR_RANGE_REG,
+ .reset = 0x4,
+ .ro = 0xfffffff0,
+ },{ .name = "FLASH_COMMAND_CTRL_MEM_REG",
+ .addr = A_FLASH_COMMAND_CTRL_MEM_REG,
+ .ro = 0xe008fffe,
+ .post_write = flash_cmd_ctrl_mem_reg_post_write,
+ },{ .name = "FLASH_CMD_CTRL_REG",
+ .addr = A_FLASH_CMD_CTRL_REG,
+ .ro = 0x7a,
+ .post_write = flash_cmd_ctrl_reg_post_write,
+ },{ .name = "FLASH_CMD_ADDR_REG",
+ .addr = A_FLASH_CMD_ADDR_REG,
+ },{ .name = "FLASH_RD_DATA_LOWER_REG",
+ .addr = A_FLASH_RD_DATA_LOWER_REG,
+ .ro = 0xffffffff,
+ },{ .name = "FLASH_RD_DATA_UPPER_REG",
+ .addr = A_FLASH_RD_DATA_UPPER_REG,
+ .ro = 0xffffffff,
+ },{ .name = "FLASH_WR_DATA_LOWER_REG",
+ .addr = A_FLASH_WR_DATA_LOWER_REG,
+ },{ .name = "FLASH_WR_DATA_UPPER_REG",
+ .addr = A_FLASH_WR_DATA_UPPER_REG,
+ },{ .name = "POLLING_FLASH_STATUS_REG",
+ .addr = A_POLLING_FLASH_STATUS_REG,
+ .ro = 0xfff0ffff,
+ },{ .name = "PHY_CONFIGURATION_REG",
+ .addr = A_PHY_CONFIGURATION_REG,
+ .reset = 0x40000000,
+ .ro = 0x1f80ff80,
+ },{ .name = "PHY_MASTER_CONTROL_REG",
+ .addr = A_PHY_MASTER_CONTROL_REG,
+ .reset = 0x800000,
+ .ro = 0xfe08ff80,
+ },{ .name = "DLL_OBSERVABLE_LOWER_REG",
+ .addr = A_DLL_OBSERVABLE_LOWER_REG,
+ .ro = 0xffffffff,
+ },{ .name = "DLL_OBSERVABLE_UPPER_REG",
+ .addr = A_DLL_OBSERVABLE_UPPER_REG,
+ .ro = 0xffffffff,
+ .post_read = dll_obs_upper_reg_post_read,
+ },{ .name = "OPCODE_EXT_LOWER_REG",
+ .addr = A_OPCODE_EXT_LOWER_REG,
+ .reset = 0x13edfa00,
+ },{ .name = "OPCODE_EXT_UPPER_REG",
+ .addr = A_OPCODE_EXT_UPPER_REG,
+ .reset = 0x6f90000,
+ .ro = 0xffff,
+ },{ .name = "MODULE_ID_REG",
+ .addr = A_MODULE_ID_REG,
+ .reset = 0x300,
+ .ro = 0xffffffff,
+ }
+};
+
+/* Return dev-obj from reg-region created by register_init_block32 */
+static XlnxVersalOspi *xilinx_ospi_of_mr(void *mr_accessor)
+{
+ RegisterInfoArray *reg_array = mr_accessor;
+ Object *dev;
+
+ dev = reg_array->mem.owner;
+ assert(dev);
+
+ return XILINX_VERSAL_OSPI(dev);
+}
+
+static void ospi_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned int size)
+{
+ XlnxVersalOspi *s = xilinx_ospi_of_mr(opaque);
+
+ register_write_memory(opaque, addr, value, size);
+ ospi_update_irq_line(s);
+}
+
+static const MemoryRegionOps ospi_ops = {
+ .read = register_read_memory,
+ .write = ospi_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static uint64_t ospi_indac_read(void *opaque, unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+ uint64_t ret = ospi_rx_sram_read(s, size);
+
+ if (!ospi_ind_op_completed(s->rd_ind_op)) {
+ ospi_do_ind_read(s);
+ }
+ return ret;
+}
+
+static void ospi_indac_write(void *opaque, uint64_t value, unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+
+ g_assert(!s->ind_write_disabled);
+
+ if (!ospi_ind_op_completed(s->wr_ind_op)) {
+ ospi_tx_sram_write(s, value, size);
+ ospi_do_indirect_write(s);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI wr into indac area while no ongoing indac wr\n");
+ }
+}
+
+static bool is_inside_indac_range(XlnxVersalOspi *s, hwaddr addr)
+{
+ uint32_t range_start;
+ uint32_t range_end;
+
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DMA_IF_FLD)) {
+ return true;
+ }
+
+ range_start = s->regs[R_IND_AHB_ADDR_TRIGGER_REG];
+ range_end = range_start +
+ (1 << ARRAY_FIELD_EX32(s->regs,
+ INDIRECT_TRIGGER_ADDR_RANGE_REG,
+ IND_RANGE_WIDTH_FLD));
+
+ addr += s->regs[R_IND_AHB_ADDR_TRIGGER_REG] & 0xF0000000;
+
+ return addr >= range_start && addr < range_end;
+}
+
+static bool ospi_is_indac_active(XlnxVersalOspi *s)
+{
+ /*
+ * When dac and indac cannot be active at the same time,
+ * return true when dac is disabled.
+ */
+ return s->dac_with_indac || !s->dac_enable;
+}
+
+static uint64_t ospi_dac_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) {
+ if (ospi_is_indac_active(s) &&
+ is_inside_indac_range(s, addr)) {
+ return ospi_indac_read(s, size);
+ }
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DIR_ACC_CTLR_FLD)
+ && s->dac_enable) {
+ if (ARRAY_FIELD_EX32(s->regs,
+ CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD)) {
+ addr += s->regs[R_REMAP_ADDR_REG];
+ }
+ return ospi_do_dac_read(opaque, addr, size);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB rd while DAC disabled\n");
+ }
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB rd while OSPI disabled\n");
+ }
+
+ return 0;
+}
+
+static void ospi_dac_write(void *opaque, hwaddr addr, uint64_t value,
+ unsigned int size)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_SPI_FLD)) {
+ if (ospi_is_indac_active(s) &&
+ !s->ind_write_disabled &&
+ is_inside_indac_range(s, addr)) {
+ return ospi_indac_write(s, value, size);
+ }
+ if (ARRAY_FIELD_EX32(s->regs, CONFIG_REG, ENB_DIR_ACC_CTLR_FLD) &&
+ s->dac_enable) {
+ if (ARRAY_FIELD_EX32(s->regs,
+ CONFIG_REG, ENB_AHB_ADDR_REMAP_FLD)) {
+ addr += s->regs[R_REMAP_ADDR_REG];
+ }
+ /* Check if addr is write protected */
+ if (ARRAY_FIELD_EX32(s->regs, WR_PROT_CTRL_REG, ENB_FLD) &&
+ ospi_is_write_protected(s, addr)) {
+ set_irq(s, R_IRQ_STATUS_REG_PROT_WR_ATTEMPT_FLD_MASK);
+ ospi_update_irq_line(s);
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "OSPI writing into write protected area\n");
+ return;
+ }
+ ospi_do_dac_write(opaque, addr, value, size);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB wr while DAC disabled\n");
+ }
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "OSPI AHB wr while OSPI disabled\n");
+ }
+}
+
+static const MemoryRegionOps ospi_dac_ops = {
+ .read = ospi_dac_read,
+ .write = ospi_dac_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void ospi_update_dac_status(void *opaque, int n, int level)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(opaque);
+
+ s->dac_enable = level;
+}
+
+static void xlnx_versal_ospi_realize(DeviceState *dev, Error **errp)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ s->num_cs = 4;
+ s->spi = ssi_create_bus(dev, "spi0");
+ s->cs_lines = g_new0(qemu_irq, s->num_cs);
+ for (int i = 0; i < s->num_cs; ++i) {
+ sysbus_init_irq(sbd, &s->cs_lines[i]);
+ }
+
+ fifo8_create(&s->rx_fifo, RXFF_SZ);
+ fifo8_create(&s->tx_fifo, TXFF_SZ);
+ fifo8_create(&s->rx_sram, RXFF_SZ);
+ fifo8_create(&s->tx_sram, TXFF_SZ);
+}
+
+static void xlnx_versal_ospi_init(Object *obj)
+{
+ XlnxVersalOspi *s = XILINX_VERSAL_OSPI(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ DeviceState *dev = DEVICE(obj);
+ RegisterInfoArray *reg_array;
+
+ memory_region_init(&s->iomem, obj, TYPE_XILINX_VERSAL_OSPI,
+ XILINX_VERSAL_OSPI_R_MAX * 4);
+ reg_array =
+ register_init_block32(DEVICE(obj), ospi_regs_info,
+ ARRAY_SIZE(ospi_regs_info),
+ s->regs_info, s->regs,
+ &ospi_ops,
+ XILINX_VERSAL_OSPI_ERR_DEBUG,
+ XILINX_VERSAL_OSPI_R_MAX * 4);
+ memory_region_add_subregion(&s->iomem, 0x0, &reg_array->mem);
+ sysbus_init_mmio(sbd, &s->iomem);
+
+ memory_region_init_io(&s->iomem_dac, obj, &ospi_dac_ops, s,
+ TYPE_XILINX_VERSAL_OSPI "-dac", 0x20000000);
+ sysbus_init_mmio(sbd, &s->iomem_dac);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ object_property_add_link(obj, "dma-src", TYPE_XLNX_CSU_DMA,
+ (Object **)&s->dma_src,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_STRONG);
+
+ qdev_init_gpio_in_named(dev, ospi_update_dac_status, "ospi-mux-sel", 1);
+}
+
+static const VMStateDescription vmstate_ind_op = {
+ .name = "OSPIIndOp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(flash_addr, IndOp),
+ VMSTATE_UINT32(num_bytes, IndOp),
+ VMSTATE_UINT32(done_bytes, IndOp),
+ VMSTATE_BOOL(completed, IndOp),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_xlnx_versal_ospi = {
+ .name = TYPE_XILINX_VERSAL_OSPI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_FIFO8(rx_fifo, XlnxVersalOspi),
+ VMSTATE_FIFO8(tx_fifo, XlnxVersalOspi),
+ VMSTATE_FIFO8(rx_sram, XlnxVersalOspi),
+ VMSTATE_FIFO8(tx_sram, XlnxVersalOspi),
+ VMSTATE_BOOL(ind_write_disabled, XlnxVersalOspi),
+ VMSTATE_BOOL(dac_with_indac, XlnxVersalOspi),
+ VMSTATE_BOOL(dac_enable, XlnxVersalOspi),
+ VMSTATE_BOOL(src_dma_inprog, XlnxVersalOspi),
+ VMSTATE_STRUCT_ARRAY(rd_ind_op, XlnxVersalOspi, 2, 1,
+ vmstate_ind_op, IndOp),
+ VMSTATE_STRUCT_ARRAY(wr_ind_op, XlnxVersalOspi, 2, 1,
+ vmstate_ind_op, IndOp),
+ VMSTATE_UINT32_ARRAY(regs, XlnxVersalOspi, XILINX_VERSAL_OSPI_R_MAX),
+ VMSTATE_UINT8_ARRAY(stig_membank, XlnxVersalOspi, 512),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static Property xlnx_versal_ospi_properties[] = {
+ DEFINE_PROP_BOOL("dac-with-indac", XlnxVersalOspi, dac_with_indac, false),
+ DEFINE_PROP_BOOL("indac-write-disabled", XlnxVersalOspi,
+ ind_write_disabled, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xlnx_versal_ospi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = xlnx_versal_ospi_reset;
+ dc->realize = xlnx_versal_ospi_realize;
+ dc->vmsd = &vmstate_xlnx_versal_ospi;
+ device_class_set_props(dc, xlnx_versal_ospi_properties);
+}
+
+static const TypeInfo xlnx_versal_ospi_info = {
+ .name = TYPE_XILINX_VERSAL_OSPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(XlnxVersalOspi),
+ .class_init = xlnx_versal_ospi_class_init,
+ .instance_init = xlnx_versal_ospi_init,
+};
+
+static void xlnx_versal_ospi_register_types(void)
+{
+ type_register_static(&xlnx_versal_ospi_info);
+}
+
+type_init(xlnx_versal_ospi_register_types)