diff --git a/MAINTAINERS b/MAINTAINERS index dcedfaed1f..294c88ace9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -648,7 +648,7 @@ M: Peter Maydell L: qemu-arm@nongnu.org S: Odd Fixes F: hw/*/exynos* -F: include/hw/arm/exynos4210.h +F: include/hw/*/exynos* Calxeda Highbank M: Rob Herring diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index 1544632b67..1297dff522 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -96,9 +96,9 @@ gic-version Valid values are: ``2`` - GICv2 + GICv2. Note that this limits the number of CPUs to 8. ``3`` - GICv3 + GICv3. This allows up to 512 CPUs. ``host`` Use the same GIC version the host provides, when using KVM ``max`` diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 0299e81f85..8dafa2215b 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -101,6 +101,348 @@ #define EXYNOS4210_PL330_BASE1_ADDR 0x12690000 #define EXYNOS4210_PL330_BASE2_ADDR 0x12850000 +enum ExtGicId { + EXT_GIC_ID_MDMA_LCD0 = 66, + EXT_GIC_ID_PDMA0, + EXT_GIC_ID_PDMA1, + EXT_GIC_ID_TIMER0, + EXT_GIC_ID_TIMER1, + EXT_GIC_ID_TIMER2, + EXT_GIC_ID_TIMER3, + EXT_GIC_ID_TIMER4, + EXT_GIC_ID_MCT_L0, + EXT_GIC_ID_WDT, + EXT_GIC_ID_RTC_ALARM, + EXT_GIC_ID_RTC_TIC, + EXT_GIC_ID_GPIO_XB, + EXT_GIC_ID_GPIO_XA, + EXT_GIC_ID_MCT_L1, + EXT_GIC_ID_IEM_APC, + EXT_GIC_ID_IEM_IEC, + EXT_GIC_ID_NFC, + EXT_GIC_ID_UART0, + EXT_GIC_ID_UART1, + EXT_GIC_ID_UART2, + EXT_GIC_ID_UART3, + EXT_GIC_ID_UART4, + EXT_GIC_ID_MCT_G0, + EXT_GIC_ID_I2C0, + EXT_GIC_ID_I2C1, + EXT_GIC_ID_I2C2, + EXT_GIC_ID_I2C3, + EXT_GIC_ID_I2C4, + EXT_GIC_ID_I2C5, + EXT_GIC_ID_I2C6, + EXT_GIC_ID_I2C7, + EXT_GIC_ID_SPI0, + EXT_GIC_ID_SPI1, + EXT_GIC_ID_SPI2, + EXT_GIC_ID_MCT_G1, + EXT_GIC_ID_USB_HOST, + EXT_GIC_ID_USB_DEVICE, + EXT_GIC_ID_MODEMIF, + EXT_GIC_ID_HSMMC0, + EXT_GIC_ID_HSMMC1, + EXT_GIC_ID_HSMMC2, + EXT_GIC_ID_HSMMC3, + EXT_GIC_ID_SDMMC, + EXT_GIC_ID_MIPI_CSI_4LANE, + EXT_GIC_ID_MIPI_DSI_4LANE, + EXT_GIC_ID_MIPI_CSI_2LANE, + EXT_GIC_ID_MIPI_DSI_2LANE, + EXT_GIC_ID_ONENAND_AUDI, + EXT_GIC_ID_ROTATOR, + EXT_GIC_ID_FIMC0, + EXT_GIC_ID_FIMC1, + EXT_GIC_ID_FIMC2, + EXT_GIC_ID_FIMC3, + EXT_GIC_ID_JPEG, + EXT_GIC_ID_2D, + EXT_GIC_ID_PCIe, + EXT_GIC_ID_MIXER, + EXT_GIC_ID_HDMI, + EXT_GIC_ID_HDMI_I2C, + EXT_GIC_ID_MFC, + EXT_GIC_ID_TVENC, +}; + +enum ExtInt { + EXT_GIC_ID_EXTINT0 = 48, + EXT_GIC_ID_EXTINT1, + EXT_GIC_ID_EXTINT2, + EXT_GIC_ID_EXTINT3, + EXT_GIC_ID_EXTINT4, + EXT_GIC_ID_EXTINT5, + EXT_GIC_ID_EXTINT6, + EXT_GIC_ID_EXTINT7, + EXT_GIC_ID_EXTINT8, + EXT_GIC_ID_EXTINT9, + EXT_GIC_ID_EXTINT10, + EXT_GIC_ID_EXTINT11, + EXT_GIC_ID_EXTINT12, + EXT_GIC_ID_EXTINT13, + EXT_GIC_ID_EXTINT14, + EXT_GIC_ID_EXTINT15 +}; + +/* + * External GIC sources which are not from External Interrupt Combiner or + * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ, + * which is INTG16 in Internal Interrupt Combiner. + */ + +static const uint32_t +combiner_grp_to_gic_id[64 - EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { + /* int combiner groups 16-19 */ + { }, { }, { }, { }, + /* int combiner group 20 */ + { 0, EXT_GIC_ID_MDMA_LCD0 }, + /* int combiner group 21 */ + { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 }, + /* int combiner group 22 */ + { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2, + EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 }, + /* int combiner group 23 */ + { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC }, + /* int combiner group 24 */ + { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA }, + /* int combiner group 25 */ + { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC }, + /* int combiner group 26 */ + { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3, + EXT_GIC_ID_UART4 }, + /* int combiner group 27 */ + { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3, + EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6, + EXT_GIC_ID_I2C7 }, + /* int combiner group 28 */ + { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST}, + /* int combiner group 29 */ + { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2, + EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC }, + /* int combiner group 30 */ + { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE }, + /* int combiner group 31 */ + { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE }, + /* int combiner group 32 */ + { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 }, + /* int combiner group 33 */ + { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 }, + /* int combiner group 34 */ + { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC }, + /* int combiner group 35 */ + { 0, 0, 0, EXT_GIC_ID_MCT_L1 }, + /* int combiner group 36 */ + { EXT_GIC_ID_MIXER }, + /* int combiner group 37 */ + { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6, + EXT_GIC_ID_EXTINT7 }, + /* groups 38-50 */ + { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, + /* int combiner group 51 */ + { EXT_GIC_ID_MCT_L0 }, + /* group 52 */ + { }, + /* int combiner group 53 */ + { EXT_GIC_ID_WDT }, + /* groups 54-63 */ + { }, { }, { }, { }, { }, { }, { }, { }, { }, { } +}; + +#define EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit) ((grp) * 8 + (bit)) +#define EXYNOS4210_COMBINER_GET_GRP_NUM(irq) ((irq) / 8) +#define EXYNOS4210_COMBINER_GET_BIT_NUM(irq) \ + ((irq) - 8 * EXYNOS4210_COMBINER_GET_GRP_NUM(irq)) + +/* + * Some interrupt lines go to multiple combiner inputs. + * This data structure defines those: each array element is + * a list of combiner inputs which are connected together; + * the one with the smallest interrupt ID value must be first. + * As with combiner_grp_to_gic_id[], we rely on (0, 0) not being + * wired to anything so we can use 0 as a terminator. + */ +#define IRQNO(G, B) EXYNOS4210_COMBINER_GET_IRQ_NUM(G, B) +#define IRQNONE 0 + +#define COMBINERMAP_SIZE 16 + +static const int combinermap[COMBINERMAP_SIZE][6] = { + /* MDNIE_LCD1 */ + { IRQNO(0, 4), IRQNO(1, 0), IRQNONE }, + { IRQNO(0, 5), IRQNO(1, 1), IRQNONE }, + { IRQNO(0, 6), IRQNO(1, 2), IRQNONE }, + { IRQNO(0, 7), IRQNO(1, 3), IRQNONE }, + /* TMU */ + { IRQNO(2, 4), IRQNO(3, 4), IRQNONE }, + { IRQNO(2, 5), IRQNO(3, 5), IRQNONE }, + { IRQNO(2, 6), IRQNO(3, 6), IRQNONE }, + { IRQNO(2, 7), IRQNO(3, 7), IRQNONE }, + /* LCD1 */ + { IRQNO(11, 4), IRQNO(12, 0), IRQNONE }, + { IRQNO(11, 5), IRQNO(12, 1), IRQNONE }, + { IRQNO(11, 6), IRQNO(12, 2), IRQNONE }, + { IRQNO(11, 7), IRQNO(12, 3), IRQNONE }, + /* Multi-core timer */ + { IRQNO(1, 4), IRQNO(12, 4), IRQNO(35, 4), IRQNO(51, 4), IRQNO(53, 4), IRQNONE }, + { IRQNO(1, 5), IRQNO(12, 5), IRQNO(35, 5), IRQNO(51, 5), IRQNO(53, 5), IRQNONE }, + { IRQNO(1, 6), IRQNO(12, 6), IRQNO(35, 6), IRQNO(51, 6), IRQNO(53, 6), IRQNONE }, + { IRQNO(1, 7), IRQNO(12, 7), IRQNO(35, 7), IRQNO(51, 7), IRQNO(53, 7), IRQNONE }, +}; + +#undef IRQNO + +static const int *combinermap_entry(int irq) +{ + /* + * If the interrupt number passed in is the first entry in some + * line of the combinermap, return a pointer to that line; + * otherwise return NULL. + */ + int i; + for (i = 0; i < COMBINERMAP_SIZE; i++) { + if (combinermap[i][0] == irq) { + return combinermap[i]; + } + } + return NULL; +} + +static int mapline_size(const int *mapline) +{ + /* Return number of entries in this mapline in total */ + int i = 0; + + if (!mapline) { + /* Not in the map? IRQ goes to exactly one combiner input */ + return 1; + } + while (*mapline != IRQNONE) { + mapline++; + i++; + } + return i; +} + +/* + * Initialize board IRQs. + * These IRQs contain splitted Int/External Combiner and External Gic IRQs. + */ +static void exynos4210_init_board_irqs(Exynos4210State *s) +{ + uint32_t grp, bit, irq_id, n; + DeviceState *extgicdev = DEVICE(&s->ext_gic); + DeviceState *intcdev = DEVICE(&s->int_combiner); + DeviceState *extcdev = DEVICE(&s->ext_combiner); + int splitcount = 0; + DeviceState *splitter; + const int *mapline; + int numlines, splitin, in; + + for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) { + irq_id = 0; + if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4)) { + /* MCT_G0 is passed to External GIC */ + irq_id = EXT_GIC_ID_MCT_G0; + } + if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5)) { + /* MCT_G1 is passed to External and GIC */ + irq_id = EXT_GIC_ID_MCT_G1; + } + + if (s->irq_table[n]) { + /* + * This must be some non-first entry in a combinermap line, + * and we've already filled it in. + */ + continue; + } + mapline = combinermap_entry(n); + /* + * We need to connect the IRQ to multiple inputs on both combiners + * and possibly also to the external GIC. + */ + numlines = 2 * mapline_size(mapline); + if (irq_id) { + numlines++; + } + assert(splitcount < EXYNOS4210_NUM_SPLITTERS); + splitter = DEVICE(&s->splitter[splitcount]); + qdev_prop_set_uint16(splitter, "num-lines", numlines); + qdev_realize(splitter, NULL, &error_abort); + splitcount++; + + in = n; + splitin = 0; + for (;;) { + s->irq_table[in] = qdev_get_gpio_in(splitter, 0); + qdev_connect_gpio_out(splitter, splitin, + qdev_get_gpio_in(intcdev, in)); + qdev_connect_gpio_out(splitter, splitin + 1, + qdev_get_gpio_in(extcdev, in)); + splitin += 2; + if (!mapline) { + break; + } + mapline++; + in = *mapline; + if (in == IRQNONE) { + break; + } + } + if (irq_id) { + qdev_connect_gpio_out(splitter, splitin, + qdev_get_gpio_in(extgicdev, irq_id - 32)); + } + } + for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) { + /* these IDs are passed to Internal Combiner and External GIC */ + grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n); + bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n); + irq_id = combiner_grp_to_gic_id[grp - + EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit]; + + if (s->irq_table[n]) { + /* + * This must be some non-first entry in a combinermap line, + * and we've already filled it in. + */ + continue; + } + + if (irq_id) { + assert(splitcount < EXYNOS4210_NUM_SPLITTERS); + splitter = DEVICE(&s->splitter[splitcount]); + qdev_prop_set_uint16(splitter, "num-lines", 2); + qdev_realize(splitter, NULL, &error_abort); + splitcount++; + s->irq_table[n] = qdev_get_gpio_in(splitter, 0); + qdev_connect_gpio_out(splitter, 0, qdev_get_gpio_in(intcdev, n)); + qdev_connect_gpio_out(splitter, 1, + qdev_get_gpio_in(extgicdev, irq_id - 32)); + } else { + s->irq_table[n] = qdev_get_gpio_in(intcdev, n); + } + } + /* + * We check this here to avoid a more obscure assert later when + * qdev_assert_realized_properly() checks that we realized every + * child object we initialized. + */ + assert(splitcount == EXYNOS4210_NUM_SPLITTERS); +} + +/* + * Get IRQ number from exynos4210 IRQ subsystem stub. + * To identify IRQ source use internal combiner group and bit number + * grp - group number + * bit - bit number inside group + */ +uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit) +{ + return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit); +} + static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43, 0x09, 0x00, 0x00, 0x00 }; @@ -205,7 +547,6 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) { Exynos4210State *s = EXYNOS4210_SOC(socdev); MemoryRegion *system_mem = get_system_memory(); - qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS]; SysBusDevice *busdev; DeviceState *dev, *uart[4], *pl330[3]; int i, n; @@ -229,81 +570,63 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp) qdev_realize(DEVICE(cpuobj), NULL, &error_fatal); } - /*** IRQs ***/ - - s->irq_table = exynos4210_init_irq(&s->irqs); - /* IRQ Gate */ for (i = 0; i < EXYNOS4210_NCPUS; i++) { - dev = qdev_new("exynos4210.irq_gate"); - qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - /* Get IRQ Gate input in gate_irq */ - for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) { - gate_irq[i][n] = qdev_get_gpio_in(dev, n); - } - busdev = SYS_BUS_DEVICE(dev); - - /* Connect IRQ Gate output to CPU's IRQ line */ - sysbus_connect_irq(busdev, 0, - qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ)); + DeviceState *orgate = DEVICE(&s->cpu_irq_orgate[i]); + object_property_set_int(OBJECT(orgate), "num-lines", + EXYNOS4210_IRQ_GATE_NINPUTS, + &error_abort); + qdev_realize(orgate, NULL, &error_abort); + qdev_connect_gpio_out(orgate, 0, + qdev_get_gpio_in(DEVICE(s->cpu[i]), ARM_CPU_IRQ)); } /* Private memory region and Internal GIC */ - dev = qdev_new(TYPE_A9MPCORE_PRIV); - qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - busdev = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(busdev, &error_fatal); + qdev_prop_set_uint32(DEVICE(&s->a9mpcore), "num-cpu", EXYNOS4210_NCPUS); + busdev = SYS_BUS_DEVICE(&s->a9mpcore); + sysbus_realize(busdev, &error_fatal); sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR); for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, gate_irq[n][0]); - } - for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) { - s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n); + sysbus_connect_irq(busdev, n, + qdev_get_gpio_in(DEVICE(&s->cpu_irq_orgate[n]), 0)); } /* Cache controller */ sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL); /* External GIC */ - dev = qdev_new("exynos4210.gic"); - qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS); - busdev = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(busdev, &error_fatal); + qdev_prop_set_uint32(DEVICE(&s->ext_gic), "num-cpu", EXYNOS4210_NCPUS); + busdev = SYS_BUS_DEVICE(&s->ext_gic); + sysbus_realize(busdev, &error_fatal); /* Map CPU interface */ sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR); /* Map Distributer interface */ sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR); for (n = 0; n < EXYNOS4210_NCPUS; n++) { - sysbus_connect_irq(busdev, n, gate_irq[n][1]); - } - for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) { - s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n); + sysbus_connect_irq(busdev, n, + qdev_get_gpio_in(DEVICE(&s->cpu_irq_orgate[n]), 1)); } /* Internal Interrupt Combiner */ - dev = qdev_new("exynos4210.combiner"); - busdev = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(busdev, &error_fatal); + busdev = SYS_BUS_DEVICE(&s->int_combiner); + sysbus_realize(busdev, &error_fatal); for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { - sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]); + sysbus_connect_irq(busdev, n, + qdev_get_gpio_in(DEVICE(&s->a9mpcore), n)); } - exynos4210_combiner_get_gpioin(&s->irqs, dev, 0); sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR); /* External Interrupt Combiner */ - dev = qdev_new("exynos4210.combiner"); - qdev_prop_set_uint32(dev, "external", 1); - busdev = SYS_BUS_DEVICE(dev); - sysbus_realize_and_unref(busdev, &error_fatal); + qdev_prop_set_uint32(DEVICE(&s->ext_combiner), "external", 1); + busdev = SYS_BUS_DEVICE(&s->ext_combiner); + sysbus_realize(busdev, &error_fatal); for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) { - sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]); + sysbus_connect_irq(busdev, n, qdev_get_gpio_in(DEVICE(&s->ext_gic), n)); } - exynos4210_combiner_get_gpioin(&s->irqs, dev, 1); sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR); /* Initialize board IRQs. */ - exynos4210_init_board_irqs(&s->irqs); + exynos4210_init_board_irqs(s); /*** Memory ***/ @@ -488,6 +811,23 @@ static void exynos4210_init(Object *obj) object_initialize_child(obj, name, orgate, TYPE_OR_IRQ); g_free(name); } + + for (i = 0; i < ARRAY_SIZE(s->cpu_irq_orgate); i++) { + g_autofree char *name = g_strdup_printf("cpu-irq-orgate%d", i); + object_initialize_child(obj, name, &s->cpu_irq_orgate[i], TYPE_OR_IRQ); + } + + for (i = 0; i < ARRAY_SIZE(s->splitter); i++) { + g_autofree char *name = g_strdup_printf("irq-splitter%d", i); + object_initialize_child(obj, name, &s->splitter[i], TYPE_SPLIT_IRQ); + } + + object_initialize_child(obj, "a9mpcore", &s->a9mpcore, TYPE_A9MPCORE_PRIV); + object_initialize_child(obj, "ext-gic", &s->ext_gic, TYPE_EXYNOS4210_GIC); + object_initialize_child(obj, "int-combiner", &s->int_combiner, + TYPE_EXYNOS4210_COMBINER); + object_initialize_child(obj, "ext-combiner", &s->ext_combiner, + TYPE_EXYNOS4210_COMBINER); } static void exynos4210_class_init(ObjectClass *klass, void *data) diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index 0678a56156..6bc6f5d2fe 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -30,11 +30,25 @@ #include "sysemu/sysemu.h" #include "sysemu/block-backend.h" -#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7 -#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff -#define QUANTA_GBS_POWER_ON_STRAPS 0x000017ff -#define KUDO_BMC_POWER_ON_STRAPS 0x00001fff -#define MORI_BMC_POWER_ON_STRAPS 0x00001fff +#define NPCM7XX_POWER_ON_STRAPS_DEFAULT ( \ + NPCM7XX_PWRON_STRAP_SPI0F18 | \ + NPCM7XX_PWRON_STRAP_SFAB | \ + NPCM7XX_PWRON_STRAP_BSPA | \ + NPCM7XX_PWRON_STRAP_FUP(FUP_NORM_UART2) | \ + NPCM7XX_PWRON_STRAP_SECEN | \ + NPCM7XX_PWRON_STRAP_HIZ | \ + NPCM7XX_PWRON_STRAP_ECC | \ + NPCM7XX_PWRON_STRAP_RESERVE1 | \ + NPCM7XX_PWRON_STRAP_J2EN | \ + NPCM7XX_PWRON_STRAP_CKFRQ(CKFRQ_DEFAULT)) + +#define NPCM750_EVB_POWER_ON_STRAPS ( \ + NPCM7XX_POWER_ON_STRAPS_DEFAULT & ~NPCM7XX_PWRON_STRAP_J2EN) +#define QUANTA_GSJ_POWER_ON_STRAPS NPCM7XX_POWER_ON_STRAPS_DEFAULT +#define QUANTA_GBS_POWER_ON_STRAPS ( \ + NPCM7XX_POWER_ON_STRAPS_DEFAULT & ~NPCM7XX_PWRON_STRAP_SFAB) +#define KUDO_BMC_POWER_ON_STRAPS NPCM7XX_POWER_ON_STRAPS_DEFAULT +#define MORI_BMC_POWER_ON_STRAPS NPCM7XX_POWER_ON_STRAPS_DEFAULT static const char npcm7xx_default_bootrom[] = "npcm7xx_bootrom.bin"; diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 7b424e94a5..d2dc8a8952 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -13,9 +13,11 @@ #include "hw/sysbus.h" #include "hw/arm/boot.h" #include "hw/arm/primecell.h" +#include "hw/core/split-irq.h" #include "hw/net/lan9118.h" #include "hw/net/smc91c111.h" #include "hw/pci/pci.h" +#include "hw/qdev-core.h" #include "net/net.h" #include "sysemu/sysemu.h" #include "hw/boards.h" @@ -53,6 +55,20 @@ static const int realview_board_id[] = { 0x76d }; +static void split_irq_from_named(DeviceState *src, const char* outname, + qemu_irq out1, qemu_irq out2) { + DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); + + qdev_prop_set_uint32(splitter, "num-lines", 2); + + qdev_realize_and_unref(splitter, NULL, &error_fatal); + + qdev_connect_gpio_out(splitter, 0, out1); + qdev_connect_gpio_out(splitter, 1, out2); + qdev_connect_gpio_out_named(src, outname, 0, + qdev_get_gpio_in(splitter, 0)); +} + static void realview_init(MachineState *machine, enum realview_board_type board_type) { @@ -66,7 +82,6 @@ static void realview_init(MachineState *machine, DeviceState *dev, *sysctl, *gpio2, *pl041; SysBusDevice *busdev; qemu_irq pic[64]; - qemu_irq mmc_irq[2]; PCIBus *pci_bus = NULL; NICInfo *nd; DriveInfo *dinfo; @@ -229,14 +244,14 @@ static void realview_init(MachineState *machine, * and the PL061 has them the other way about. Also the card * detect line is inverted. */ - mmc_irq[0] = qemu_irq_split( - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT), - qdev_get_gpio_in(gpio2, 1)); - mmc_irq[1] = qemu_irq_split( - qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN), - qemu_irq_invert(qdev_get_gpio_in(gpio2, 0))); - qdev_connect_gpio_out_named(dev, "card-read-only", 0, mmc_irq[0]); - qdev_connect_gpio_out_named(dev, "card-inserted", 0, mmc_irq[1]); + split_irq_from_named(dev, "card-read-only", + qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT), + qdev_get_gpio_in(gpio2, 1)); + + split_irq_from_named(dev, "card-inserted", + qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN), + qemu_irq_invert(qdev_get_gpio_in(gpio2, 0))); + dinfo = drive_get(IF_SD, 0, 0); if (dinfo) { DeviceState *card; diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index b6c8a5d609..12c673c917 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "hw/core/split-irq.h" #include "hw/sysbus.h" #include "hw/sd/sd.h" #include "hw/ssi/ssi.h" @@ -1160,6 +1161,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) DeviceState *ssddev; DriveInfo *dinfo; DeviceState *carddev; + DeviceState *gpio_d_splitter; BlockBackend *blk; /* @@ -1237,9 +1239,18 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) &error_fatal); ssddev = ssi_create_peripheral(bus, "ssd0323"); - gpio_out[GPIO_D][0] = qemu_irq_split( - qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0), + + gpio_d_splitter = qdev_new(TYPE_SPLIT_IRQ); + qdev_prop_set_uint32(gpio_d_splitter, "num-lines", 2); + qdev_realize_and_unref(gpio_d_splitter, NULL, &error_fatal); + qdev_connect_gpio_out( + gpio_d_splitter, 0, + qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0)); + qdev_connect_gpio_out( + gpio_d_splitter, 1, qdev_get_gpio_in_named(ssddev, SSI_GPIO_CS, 0)); + gpio_out[GPIO_D][0] = qdev_get_gpio_in(gpio_d_splitter, 0); + gpio_out[GPIO_C][7] = qdev_get_gpio_in(ssddev, 0); /* Make sure the select pin is high. */ diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 9284f7d28e..bb6a2484d8 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -2048,6 +2048,13 @@ static void machvirt_init(MachineState *machine) exit(1); } + if (vms->secure && (kvm_enabled() || hvf_enabled())) { + error_report("mach-virt: %s does not support providing " + "Security extensions (TrustZone) to the guest CPU", + kvm_enabled() ? "KVM" : "HVF"); + exit(1); + } + if (vms->virt && (kvm_enabled() || hvf_enabled())) { error_report("mach-virt: %s does not support providing " "Virtualization extensions to the guest CPU", diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 7c7baff8b7..66a2de7e13 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -721,9 +721,9 @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data) mc->desc = "Xilinx Versal Virtual development board"; mc->init = versal_virt_init; - mc->min_cpus = XLNX_VERSAL_NR_ACPUS; - mc->max_cpus = XLNX_VERSAL_NR_ACPUS; - mc->default_cpus = XLNX_VERSAL_NR_ACPUS; + mc->min_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS; + mc->max_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS; + mc->default_cpus = XLNX_VERSAL_NR_ACPUS + XLNX_VERSAL_NR_RCPUS; mc->no_cdrom = true; mc->default_ram_id = "ddr"; } diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 2551dfc22d..57276e1506 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -25,6 +25,7 @@ #include "hw/sysbus.h" #define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72") +#define XLNX_VERSAL_RCPU_TYPE ARM_CPU_TYPE_NAME("cortex-r5f") #define GEM_REVISION 0x40070106 #define VERSAL_NUM_PMC_APB_IRQS 3 @@ -34,10 +35,15 @@ static void versal_create_apu_cpus(Versal *s) { int i; + object_initialize_child(OBJECT(s), "apu-cluster", &s->fpd.apu.cluster, + TYPE_CPU_CLUSTER); + qdev_prop_set_uint32(DEVICE(&s->fpd.apu.cluster), "cluster-id", 0); + for (i = 0; i < ARRAY_SIZE(s->fpd.apu.cpu); i++) { Object *obj; - object_initialize_child(OBJECT(s), "apu-cpu[*]", &s->fpd.apu.cpu[i], + object_initialize_child(OBJECT(&s->fpd.apu.cluster), + "apu-cpu[*]", &s->fpd.apu.cpu[i], XLNX_VERSAL_ACPU_TYPE); obj = OBJECT(&s->fpd.apu.cpu[i]); if (i) { @@ -52,6 +58,8 @@ static void versal_create_apu_cpus(Versal *s) &error_abort); qdev_realize(DEVICE(obj), NULL, &error_fatal); } + + qdev_realize(DEVICE(&s->fpd.apu.cluster), NULL, &error_fatal); } static void versal_create_apu_gic(Versal *s, qemu_irq *pic) @@ -123,6 +131,35 @@ static void versal_create_apu_gic(Versal *s, qemu_irq *pic) } } +static void versal_create_rpu_cpus(Versal *s) +{ + int i; + + object_initialize_child(OBJECT(s), "rpu-cluster", &s->lpd.rpu.cluster, + TYPE_CPU_CLUSTER); + qdev_prop_set_uint32(DEVICE(&s->lpd.rpu.cluster), "cluster-id", 1); + + for (i = 0; i < ARRAY_SIZE(s->lpd.rpu.cpu); i++) { + Object *obj; + + object_initialize_child(OBJECT(&s->lpd.rpu.cluster), + "rpu-cpu[*]", &s->lpd.rpu.cpu[i], + XLNX_VERSAL_RCPU_TYPE); + obj = OBJECT(&s->lpd.rpu.cpu[i]); + object_property_set_bool(obj, "start-powered-off", true, + &error_abort); + + object_property_set_int(obj, "mp-affinity", 0x100 | i, &error_abort); + object_property_set_int(obj, "core-count", ARRAY_SIZE(s->lpd.rpu.cpu), + &error_abort); + object_property_set_link(obj, "memory", OBJECT(&s->lpd.rpu.mr), + &error_abort); + qdev_realize(DEVICE(obj), NULL, &error_fatal); + } + + qdev_realize(DEVICE(&s->lpd.rpu.cluster), NULL, &error_fatal); +} + static void versal_create_uarts(Versal *s, qemu_irq *pic) { int i; @@ -502,6 +539,57 @@ static void versal_create_ospi(Versal *s, qemu_irq *pic) qdev_connect_gpio_out(orgate, 0, pic[VERSAL_OSPI_IRQ]); } +static void versal_create_crl(Versal *s, qemu_irq *pic) +{ + SysBusDevice *sbd; + int i; + + object_initialize_child(OBJECT(s), "crl", &s->lpd.crl, + TYPE_XLNX_VERSAL_CRL); + sbd = SYS_BUS_DEVICE(&s->lpd.crl); + + for (i = 0; i < ARRAY_SIZE(s->lpd.rpu.cpu); i++) { + g_autofree gchar *name = g_strdup_printf("cpu_r5[%d]", i); + + object_property_set_link(OBJECT(&s->lpd.crl), + name, OBJECT(&s->lpd.rpu.cpu[i]), + &error_abort); + } + + for (i = 0; i < ARRAY_SIZE(s->lpd.iou.gem); i++) { + g_autofree gchar *name = g_strdup_printf("gem[%d]", i); + + object_property_set_link(OBJECT(&s->lpd.crl), + name, OBJECT(&s->lpd.iou.gem[i]), + &error_abort); + } + + for (i = 0; i < ARRAY_SIZE(s->lpd.iou.adma); i++) { + g_autofree gchar *name = g_strdup_printf("adma[%d]", i); + + object_property_set_link(OBJECT(&s->lpd.crl), + name, OBJECT(&s->lpd.iou.adma[i]), + &error_abort); + } + + for (i = 0; i < ARRAY_SIZE(s->lpd.iou.uart); i++) { + g_autofree gchar *name = g_strdup_printf("uart[%d]", i); + + object_property_set_link(OBJECT(&s->lpd.crl), + name, OBJECT(&s->lpd.iou.uart[i]), + &error_abort); + } + + object_property_set_link(OBJECT(&s->lpd.crl), + "usb", OBJECT(&s->lpd.iou.usb), + &error_abort); + + sysbus_realize(sbd, &error_fatal); + memory_region_add_subregion(&s->mr_ps, MM_CRL, + sysbus_mmio_get_region(sbd, 0)); + sysbus_connect_irq(sbd, 0, pic[VERSAL_CRL_IRQ]); +} + /* This takes the board allocated linear DDR memory and creates aliases * for each split DDR range/aperture on the Versal address map. */ @@ -585,8 +673,6 @@ static void versal_unimp(Versal *s) 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, - MM_CRL, MM_CRL_SIZE); versal_unimp_area(s, "crf", &s->mr_ps, MM_FPD_CRF, MM_FPD_CRF_SIZE); versal_unimp_area(s, "apu", &s->mr_ps, @@ -631,6 +717,7 @@ static void versal_realize(DeviceState *dev, Error **errp) versal_create_apu_cpus(s); versal_create_apu_gic(s, pic); + versal_create_rpu_cpus(s); versal_create_uarts(s, pic); versal_create_usbs(s, pic); versal_create_gems(s, pic); @@ -643,6 +730,7 @@ static void versal_realize(DeviceState *dev, Error **errp) versal_create_efuse(s, pic); versal_create_pmc_iou_slcr(s, pic); versal_create_ospi(s, pic); + versal_create_crl(s, pic); versal_map_ddr(s); versal_unimp(s); @@ -652,6 +740,8 @@ static void versal_realize(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(&s->mr_ps, MM_OCM, &s->lpd.mr_ocm, 0); memory_region_add_subregion_overlap(&s->fpd.apu.mr, 0, &s->mr_ps, 0); + memory_region_add_subregion_overlap(&s->lpd.rpu.mr, 0, + &s->lpd.rpu.mr_ps_alias, 0); } static void versal_init(Object *obj) @@ -659,7 +749,10 @@ static void versal_init(Object *obj) Versal *s = XLNX_VERSAL(obj); memory_region_init(&s->fpd.apu.mr, obj, "mr-apu", UINT64_MAX); + memory_region_init(&s->lpd.rpu.mr, obj, "mr-rpu", UINT64_MAX); memory_region_init(&s->mr_ps, obj, "mr-ps-switch", UINT64_MAX); + memory_region_init_alias(&s->lpd.rpu.mr_ps_alias, OBJECT(s), + "mr-rpu-ps-alias", &s->mr_ps, 0, UINT64_MAX); } static Property versal_properties[] = { diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 5bfe285a19..375309e68e 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -68,6 +68,9 @@ #define APU_ADDR 0xfd5c0000 #define APU_IRQ 153 +#define TTC0_ADDR 0xFF110000 +#define TTC0_IRQ 36 + #define IPI_ADDR 0xFF300000 #define IPI_IRQ 64 @@ -316,6 +319,24 @@ static void xlnx_zynqmp_create_crf(XlnxZynqMPState *s, qemu_irq *gic) sysbus_connect_irq(sbd, 0, gic[CRF_IRQ]); } +static void xlnx_zynqmp_create_ttc(XlnxZynqMPState *s, qemu_irq *gic) +{ + SysBusDevice *sbd; + int i, irq; + + for (i = 0; i < XLNX_ZYNQMP_NUM_TTC; i++) { + object_initialize_child(OBJECT(s), "ttc[*]", &s->ttc[i], + TYPE_CADENCE_TTC); + sbd = SYS_BUS_DEVICE(&s->ttc[i]); + + sysbus_realize(sbd, &error_fatal); + sysbus_mmio_map(sbd, 0, TTC0_ADDR + i * 0x10000); + for (irq = 0; irq < 3; irq++) { + sysbus_connect_irq(sbd, irq, gic[TTC0_IRQ + i * 3 + irq]); + } + } +} + static void xlnx_zynqmp_create_unimp_mmio(XlnxZynqMPState *s) { static const struct UnimpInfo { @@ -721,6 +742,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) xlnx_zynqmp_create_efuse(s, gic_spi); xlnx_zynqmp_create_apu_ctrl(s, gic_spi); xlnx_zynqmp_create_crf(s, gic_spi); + xlnx_zynqmp_create_ttc(s, gic_spi); xlnx_zynqmp_create_unimp_mmio(s); for (i = 0; i < XLNX_ZYNQMP_NUM_GDMA_CH; i++) { diff --git a/hw/core/irq.c b/hw/core/irq.c index 741219277b..3623f711fe 100644 --- a/hw/core/irq.c +++ b/hw/core/irq.c @@ -106,21 +106,6 @@ qemu_irq qemu_irq_invert(qemu_irq irq) return qemu_allocate_irq(qemu_notirq, irq, 0); } -static void qemu_splitirq(void *opaque, int line, int level) -{ - struct IRQState **irq = opaque; - irq[0]->handler(irq[0]->opaque, irq[0]->n, level); - irq[1]->handler(irq[1]->opaque, irq[1]->n, level); -} - -qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2) -{ - qemu_irq *s = g_new0(qemu_irq, 2); - s[0] = irq1; - s[1] = irq2; - return qemu_allocate_irq(qemu_splitirq, s, 0); -} - void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n) { int i; diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c index 4534ee248d..a289510bdb 100644 --- a/hw/intc/exynos4210_combiner.c +++ b/hw/intc/exynos4210_combiner.c @@ -31,7 +31,7 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "qemu/module.h" - +#include "hw/intc/exynos4210_combiner.h" #include "hw/arm/exynos4210.h" #include "hw/hw.h" #include "hw/irq.h" @@ -48,36 +48,7 @@ #define DPRINTF(fmt, ...) do {} while (0) #endif -#define IIC_NGRP 64 /* Internal Interrupt Combiner - Groups number */ -#define IIC_NIRQ (IIC_NGRP * 8)/* Internal Interrupt Combiner - Interrupts number */ #define IIC_REGION_SIZE 0x108 /* Size of memory mapped region */ -#define IIC_REGSET_SIZE 0x41 - -/* - * State for each output signal of internal combiner - */ -typedef struct CombinerGroupState { - uint8_t src_mask; /* 1 - source enabled, 0 - disabled */ - uint8_t src_pending; /* Pending source interrupts before masking */ -} CombinerGroupState; - -#define TYPE_EXYNOS4210_COMBINER "exynos4210.combiner" -OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210CombinerState, EXYNOS4210_COMBINER) - -struct Exynos4210CombinerState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - - struct CombinerGroupState group[IIC_NGRP]; - uint32_t reg_set[IIC_REGSET_SIZE]; - uint32_t icipsr[2]; - uint32_t external; /* 1 means that this combiner is external */ - - qemu_irq output_irq[IIC_NGRP]; -}; static const VMStateDescription vmstate_exynos4210_combiner_group_state = { .name = "exynos4210.combiner.groupstate", @@ -105,83 +76,6 @@ static const VMStateDescription vmstate_exynos4210_combiner = { } }; -/* - * Get Combiner input GPIO into irqs structure - */ -void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev, - int ext) -{ - int n; - int bit; - int max; - qemu_irq *irq; - - max = ext ? EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ : - EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; - irq = ext ? irqs->ext_combiner_irq : irqs->int_combiner_irq; - - /* - * Some IRQs of Int/External Combiner are going to two Combiners groups, - * so let split them. - */ - for (n = 0; n < max; n++) { - - bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n); - - switch (n) { - /* MDNIE_LCD1 INTG1 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 0) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 3): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(0, bit + 4)]); - continue; - - /* TMU INTG3 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(3, 4): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(2, bit)]); - continue; - - /* LCD1 INTG12 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 0) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 3): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(11, bit + 4)]); - continue; - - /* Multi-Core Timer INTG12 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 8): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); - continue; - - /* Multi-Core Timer INTG35 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 4) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 8): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); - continue; - - /* Multi-Core Timer INTG51 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 4) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 8): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); - continue; - - /* Multi-Core Timer INTG53 */ - case EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 4) ... - EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 8): - irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), - irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); - continue; - } - - irq[n] = qdev_get_gpio_in(dev, n); - } -} - static uint64_t exynos4210_combiner_read(void *opaque, hwaddr offset, unsigned size) { diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index bc73d1f115..71a88c86bc 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -27,157 +27,10 @@ #include "qemu/module.h" #include "hw/irq.h" #include "hw/qdev-properties.h" +#include "hw/intc/exynos4210_gic.h" #include "hw/arm/exynos4210.h" #include "qom/object.h" -enum ExtGicId { - EXT_GIC_ID_MDMA_LCD0 = 66, - EXT_GIC_ID_PDMA0, - EXT_GIC_ID_PDMA1, - EXT_GIC_ID_TIMER0, - EXT_GIC_ID_TIMER1, - EXT_GIC_ID_TIMER2, - EXT_GIC_ID_TIMER3, - EXT_GIC_ID_TIMER4, - EXT_GIC_ID_MCT_L0, - EXT_GIC_ID_WDT, - EXT_GIC_ID_RTC_ALARM, - EXT_GIC_ID_RTC_TIC, - EXT_GIC_ID_GPIO_XB, - EXT_GIC_ID_GPIO_XA, - EXT_GIC_ID_MCT_L1, - EXT_GIC_ID_IEM_APC, - EXT_GIC_ID_IEM_IEC, - EXT_GIC_ID_NFC, - EXT_GIC_ID_UART0, - EXT_GIC_ID_UART1, - EXT_GIC_ID_UART2, - EXT_GIC_ID_UART3, - EXT_GIC_ID_UART4, - EXT_GIC_ID_MCT_G0, - EXT_GIC_ID_I2C0, - EXT_GIC_ID_I2C1, - EXT_GIC_ID_I2C2, - EXT_GIC_ID_I2C3, - EXT_GIC_ID_I2C4, - EXT_GIC_ID_I2C5, - EXT_GIC_ID_I2C6, - EXT_GIC_ID_I2C7, - EXT_GIC_ID_SPI0, - EXT_GIC_ID_SPI1, - EXT_GIC_ID_SPI2, - EXT_GIC_ID_MCT_G1, - EXT_GIC_ID_USB_HOST, - EXT_GIC_ID_USB_DEVICE, - EXT_GIC_ID_MODEMIF, - EXT_GIC_ID_HSMMC0, - EXT_GIC_ID_HSMMC1, - EXT_GIC_ID_HSMMC2, - EXT_GIC_ID_HSMMC3, - EXT_GIC_ID_SDMMC, - EXT_GIC_ID_MIPI_CSI_4LANE, - EXT_GIC_ID_MIPI_DSI_4LANE, - EXT_GIC_ID_MIPI_CSI_2LANE, - EXT_GIC_ID_MIPI_DSI_2LANE, - EXT_GIC_ID_ONENAND_AUDI, - EXT_GIC_ID_ROTATOR, - EXT_GIC_ID_FIMC0, - EXT_GIC_ID_FIMC1, - EXT_GIC_ID_FIMC2, - EXT_GIC_ID_FIMC3, - EXT_GIC_ID_JPEG, - EXT_GIC_ID_2D, - EXT_GIC_ID_PCIe, - EXT_GIC_ID_MIXER, - EXT_GIC_ID_HDMI, - EXT_GIC_ID_HDMI_I2C, - EXT_GIC_ID_MFC, - EXT_GIC_ID_TVENC, -}; - -enum ExtInt { - EXT_GIC_ID_EXTINT0 = 48, - EXT_GIC_ID_EXTINT1, - EXT_GIC_ID_EXTINT2, - EXT_GIC_ID_EXTINT3, - EXT_GIC_ID_EXTINT4, - EXT_GIC_ID_EXTINT5, - EXT_GIC_ID_EXTINT6, - EXT_GIC_ID_EXTINT7, - EXT_GIC_ID_EXTINT8, - EXT_GIC_ID_EXTINT9, - EXT_GIC_ID_EXTINT10, - EXT_GIC_ID_EXTINT11, - EXT_GIC_ID_EXTINT12, - EXT_GIC_ID_EXTINT13, - EXT_GIC_ID_EXTINT14, - EXT_GIC_ID_EXTINT15 -}; - -/* - * External GIC sources which are not from External Interrupt Combiner or - * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ, - * which is INTG16 in Internal Interrupt Combiner. - */ - -static const uint32_t -combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { - /* int combiner groups 16-19 */ - { }, { }, { }, { }, - /* int combiner group 20 */ - { 0, EXT_GIC_ID_MDMA_LCD0 }, - /* int combiner group 21 */ - { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 }, - /* int combiner group 22 */ - { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2, - EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 }, - /* int combiner group 23 */ - { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC }, - /* int combiner group 24 */ - { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA }, - /* int combiner group 25 */ - { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC }, - /* int combiner group 26 */ - { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3, - EXT_GIC_ID_UART4 }, - /* int combiner group 27 */ - { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3, - EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6, - EXT_GIC_ID_I2C7 }, - /* int combiner group 28 */ - { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST}, - /* int combiner group 29 */ - { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2, - EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC }, - /* int combiner group 30 */ - { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE }, - /* int combiner group 31 */ - { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE }, - /* int combiner group 32 */ - { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 }, - /* int combiner group 33 */ - { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 }, - /* int combiner group 34 */ - { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC }, - /* int combiner group 35 */ - { 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, - /* int combiner group 36 */ - { EXT_GIC_ID_MIXER }, - /* int combiner group 37 */ - { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6, - EXT_GIC_ID_EXTINT7 }, - /* groups 38-50 */ - { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, - /* int combiner group 51 */ - { EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, - /* group 52 */ - { }, - /* int combiner group 53 */ - { EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, - /* groups 54-63 */ - { }, { }, { }, { }, { }, { }, { }, { }, { }, { } -}; - #define EXYNOS4210_GIC_NIRQ 160 #define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000 @@ -192,92 +45,6 @@ combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { #define EXYNOS4210_GIC_CPU_REGION_SIZE 0x100 #define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000 -static void exynos4210_irq_handler(void *opaque, int irq, int level) -{ - Exynos4210Irq *s = (Exynos4210Irq *)opaque; - - /* Bypass */ - qemu_set_irq(s->board_irqs[irq], level); -} - -/* - * Initialize exynos4210 IRQ subsystem stub. - */ -qemu_irq *exynos4210_init_irq(Exynos4210Irq *s) -{ - return qemu_allocate_irqs(exynos4210_irq_handler, s, - EXYNOS4210_MAX_INT_COMBINER_IN_IRQ); -} - -/* - * Initialize board IRQs. - * These IRQs contain splitted Int/External Combiner and External Gic IRQs. - */ -void exynos4210_init_board_irqs(Exynos4210Irq *s) -{ - uint32_t grp, bit, irq_id, n; - - for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) { - irq_id = 0; - if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) || - n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) { - /* MCT_G0 is passed to External GIC */ - irq_id = EXT_GIC_ID_MCT_G0; - } - if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) || - n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) { - /* MCT_G1 is passed to External and GIC */ - irq_id = EXT_GIC_ID_MCT_G1; - } - if (irq_id) { - s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], - s->ext_gic_irq[irq_id-32]); - } else { - s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], - s->ext_combiner_irq[n]); - } - } - for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) { - /* these IDs are passed to Internal Combiner and External GIC */ - grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n); - bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n); - irq_id = combiner_grp_to_gic_id[grp - - EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit]; - - if (irq_id) { - s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], - s->ext_gic_irq[irq_id-32]); - } - } -} - -/* - * Get IRQ number from exynos4210 IRQ subsystem stub. - * To identify IRQ source use internal combiner group and bit number - * grp - group number - * bit - bit number inside group - */ -uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit) -{ - return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit); -} - -/********* GIC part *********/ - -#define TYPE_EXYNOS4210_GIC "exynos4210.gic" -OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210GicState, EXYNOS4210_GIC) - -struct Exynos4210GicState { - SysBusDevice parent_obj; - - MemoryRegion cpu_container; - MemoryRegion dist_container; - MemoryRegion cpu_alias[EXYNOS4210_NCPUS]; - MemoryRegion dist_alias[EXYNOS4210_NCPUS]; - uint32_t num_cpu; - DeviceState *gic; -}; - static void exynos4210_gic_set_irq(void *opaque, int irq, int level) { Exynos4210GicState *s = (Exynos4210GicState *)opaque; @@ -320,7 +87,7 @@ static void exynos4210_gic_realize(DeviceState *dev, Error **errp) * enough room for the cpu numbers. gcc 9.2.1 on 32-bit x86 * doesn't figure this out, otherwise and gives spurious warnings. */ - assert(n <= EXYNOS4210_NCPUS); + assert(n <= EXYNOS4210_GIC_NCPUS); for (i = 0; i < n; i++) { /* Map CPU interface per SMP Core */ sprintf(cpu_alias_name, "%s%x", cpu_prefix, i); @@ -373,110 +140,3 @@ static void exynos4210_gic_register_types(void) } type_init(exynos4210_gic_register_types) - -/* IRQ OR Gate struct. - * - * This device models an OR gate. There are n_in input qdev gpio lines and one - * output sysbus IRQ line. The output IRQ level is formed as OR between all - * gpio inputs. - */ - -#define TYPE_EXYNOS4210_IRQ_GATE "exynos4210.irq_gate" -OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210IRQGateState, EXYNOS4210_IRQ_GATE) - -struct Exynos4210IRQGateState { - SysBusDevice parent_obj; - - uint32_t n_in; /* inputs amount */ - uint32_t *level; /* input levels */ - qemu_irq out; /* output IRQ */ -}; - -static Property exynos4210_irq_gate_properties[] = { - DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1), - DEFINE_PROP_END_OF_LIST(), -}; - -static const VMStateDescription vmstate_exynos4210_irq_gate = { - .name = "exynos4210.irq_gate", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, n_in), - VMSTATE_END_OF_LIST() - } -}; - -/* Process a change in IRQ input. */ -static void exynos4210_irq_gate_handler(void *opaque, int irq, int level) -{ - Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque; - uint32_t i; - - assert(irq < s->n_in); - - s->level[irq] = level; - - for (i = 0; i < s->n_in; i++) { - if (s->level[i] >= 1) { - qemu_irq_raise(s->out); - return; - } - } - - qemu_irq_lower(s->out); -} - -static void exynos4210_irq_gate_reset(DeviceState *d) -{ - Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(d); - - memset(s->level, 0, s->n_in * sizeof(*s->level)); -} - -/* - * IRQ Gate initialization. - */ -static void exynos4210_irq_gate_init(Object *obj) -{ - Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(obj); - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - - sysbus_init_irq(sbd, &s->out); -} - -static void exynos4210_irq_gate_realize(DeviceState *dev, Error **errp) -{ - Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(dev); - - /* Allocate general purpose input signals and connect a handler to each of - * them */ - qdev_init_gpio_in(dev, exynos4210_irq_gate_handler, s->n_in); - - s->level = g_malloc0(s->n_in * sizeof(*s->level)); -} - -static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->reset = exynos4210_irq_gate_reset; - dc->vmsd = &vmstate_exynos4210_irq_gate; - device_class_set_props(dc, exynos4210_irq_gate_properties); - dc->realize = exynos4210_irq_gate_realize; -} - -static const TypeInfo exynos4210_irq_gate_info = { - .name = TYPE_EXYNOS4210_IRQ_GATE, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(Exynos4210IRQGateState), - .instance_init = exynos4210_irq_gate_init, - .class_init = exynos4210_irq_gate_class_init, -}; - -static void exynos4210_irq_gate_register_types(void) -{ - type_register_static(&exynos4210_irq_gate_info); -} - -type_init(exynos4210_irq_gate_register_types) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 6fb69612e0..2ff05c7afa 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -86,6 +86,7 @@ softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c')) softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c')) specific_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-crf.c')) specific_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-apu-ctrl.c')) +specific_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-crl.c')) softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files( 'xlnx-versal-xramc.c', 'xlnx-versal-pmc-iou-slcr.c', diff --git a/hw/misc/xlnx-versal-crl.c b/hw/misc/xlnx-versal-crl.c new file mode 100644 index 0000000000..767106b7a3 --- /dev/null +++ b/hw/misc/xlnx-versal-crl.c @@ -0,0 +1,421 @@ +/* + * QEMU model of the Clock-Reset-LPD (CRL). + * + * Copyright (c) 2022 Advanced Micro Devices, Inc. + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Written by Edgar E. Iglesias + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "qemu/bitops.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/register.h" +#include "hw/resettable.h" + +#include "target/arm/arm-powerctl.h" +#include "hw/misc/xlnx-versal-crl.h" + +#ifndef XLNX_VERSAL_CRL_ERR_DEBUG +#define XLNX_VERSAL_CRL_ERR_DEBUG 0 +#endif + +static void crl_update_irq(XlnxVersalCRL *s) +{ + bool pending = s->regs[R_IR_STATUS] & ~s->regs[R_IR_MASK]; + qemu_set_irq(s->irq, pending); +} + +static void crl_status_postw(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + crl_update_irq(s); +} + +static uint64_t crl_enable_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + uint32_t val = val64; + + s->regs[R_IR_MASK] &= ~val; + crl_update_irq(s); + return 0; +} + +static uint64_t crl_disable_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + uint32_t val = val64; + + s->regs[R_IR_MASK] |= val; + crl_update_irq(s); + return 0; +} + +static void crl_reset_dev(XlnxVersalCRL *s, DeviceState *dev, + bool rst_old, bool rst_new) +{ + device_cold_reset(dev); +} + +static void crl_reset_cpu(XlnxVersalCRL *s, ARMCPU *armcpu, + bool rst_old, bool rst_new) +{ + if (rst_new) { + arm_set_cpu_off(armcpu->mp_affinity); + } else { + arm_set_cpu_on_and_reset(armcpu->mp_affinity); + } +} + +#define REGFIELD_RESET(type, s, reg, f, new_val, dev) { \ + bool old_f = ARRAY_FIELD_EX32((s)->regs, reg, f); \ + bool new_f = FIELD_EX32(new_val, reg, f); \ + \ + /* Detect edges. */ \ + if (dev && old_f != new_f) { \ + crl_reset_ ## type(s, dev, old_f, new_f); \ + } \ +} + +static uint64_t crl_rst_r5_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(cpu, s, RST_CPU_R5, RESET_CPU0, val64, s->cfg.cpu_r5[0]); + REGFIELD_RESET(cpu, s, RST_CPU_R5, RESET_CPU1, val64, s->cfg.cpu_r5[1]); + return val64; +} + +static uint64_t crl_rst_adma_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + int i; + + /* A single register fans out to all ADMA reset inputs. */ + for (i = 0; i < ARRAY_SIZE(s->cfg.adma); i++) { + REGFIELD_RESET(dev, s, RST_ADMA, RESET, val64, s->cfg.adma[i]); + } + return val64; +} + +static uint64_t crl_rst_uart0_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(dev, s, RST_UART0, RESET, val64, s->cfg.uart[0]); + return val64; +} + +static uint64_t crl_rst_uart1_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(dev, s, RST_UART1, RESET, val64, s->cfg.uart[1]); + return val64; +} + +static uint64_t crl_rst_gem0_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(dev, s, RST_GEM0, RESET, val64, s->cfg.gem[0]); + return val64; +} + +static uint64_t crl_rst_gem1_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(dev, s, RST_GEM1, RESET, val64, s->cfg.gem[1]); + return val64; +} + +static uint64_t crl_rst_usb_prew(RegisterInfo *reg, uint64_t val64) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(reg->opaque); + + REGFIELD_RESET(dev, s, RST_USB0, RESET, val64, s->cfg.usb); + return val64; +} + +static const RegisterAccessInfo crl_regs_info[] = { + { .name = "ERR_CTRL", .addr = A_ERR_CTRL, + },{ .name = "IR_STATUS", .addr = A_IR_STATUS, + .w1c = 0x1, + .post_write = crl_status_postw, + },{ .name = "IR_MASK", .addr = A_IR_MASK, + .reset = 0x1, + .ro = 0x1, + },{ .name = "IR_ENABLE", .addr = A_IR_ENABLE, + .pre_write = crl_enable_prew, + },{ .name = "IR_DISABLE", .addr = A_IR_DISABLE, + .pre_write = crl_disable_prew, + },{ .name = "WPROT", .addr = A_WPROT, + },{ .name = "PLL_CLK_OTHER_DMN", .addr = A_PLL_CLK_OTHER_DMN, + .reset = 0x1, + .rsvd = 0xe, + },{ .name = "RPLL_CTRL", .addr = A_RPLL_CTRL, + .reset = 0x24809, + .rsvd = 0xf88c00f6, + },{ .name = "RPLL_CFG", .addr = A_RPLL_CFG, + .reset = 0x2000000, + .rsvd = 0x1801210, + },{ .name = "RPLL_FRAC_CFG", .addr = A_RPLL_FRAC_CFG, + .rsvd = 0x7e330000, + },{ .name = "PLL_STATUS", .addr = A_PLL_STATUS, + .reset = R_PLL_STATUS_RPLL_STABLE_MASK | + R_PLL_STATUS_RPLL_LOCK_MASK, + .rsvd = 0xfa, + .ro = 0x5, + },{ .name = "RPLL_TO_XPD_CTRL", .addr = A_RPLL_TO_XPD_CTRL, + .reset = 0x2000100, + .rsvd = 0xfdfc00ff, + },{ .name = "LPD_TOP_SWITCH_CTRL", .addr = A_LPD_TOP_SWITCH_CTRL, + .reset = 0x6000300, + .rsvd = 0xf9fc00f8, + },{ .name = "LPD_LSBUS_CTRL", .addr = A_LPD_LSBUS_CTRL, + .reset = 0x2000800, + .rsvd = 0xfdfc00f8, + },{ .name = "CPU_R5_CTRL", .addr = A_CPU_R5_CTRL, + .reset = 0xe000300, + .rsvd = 0xe1fc00f8, + },{ .name = "IOU_SWITCH_CTRL", .addr = A_IOU_SWITCH_CTRL, + .reset = 0x2000500, + .rsvd = 0xfdfc00f8, + },{ .name = "GEM0_REF_CTRL", .addr = A_GEM0_REF_CTRL, + .reset = 0xe000a00, + .rsvd = 0xf1fc00f8, + },{ .name = "GEM1_REF_CTRL", .addr = A_GEM1_REF_CTRL, + .reset = 0xe000a00, + .rsvd = 0xf1fc00f8, + },{ .name = "GEM_TSU_REF_CTRL", .addr = A_GEM_TSU_REF_CTRL, + .reset = 0x300, + .rsvd = 0xfdfc00f8, + },{ .name = "USB0_BUS_REF_CTRL", .addr = A_USB0_BUS_REF_CTRL, + .reset = 0x2001900, + .rsvd = 0xfdfc00f8, + },{ .name = "UART0_REF_CTRL", .addr = A_UART0_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "UART1_REF_CTRL", .addr = A_UART1_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "SPI0_REF_CTRL", .addr = A_SPI0_REF_CTRL, + .reset = 0x600, + .rsvd = 0xfdfc00f8, + },{ .name = "SPI1_REF_CTRL", .addr = A_SPI1_REF_CTRL, + .reset = 0x600, + .rsvd = 0xfdfc00f8, + },{ .name = "CAN0_REF_CTRL", .addr = A_CAN0_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "CAN1_REF_CTRL", .addr = A_CAN1_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "I2C0_REF_CTRL", .addr = A_I2C0_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "I2C1_REF_CTRL", .addr = A_I2C1_REF_CTRL, + .reset = 0xc00, + .rsvd = 0xfdfc00f8, + },{ .name = "DBG_LPD_CTRL", .addr = A_DBG_LPD_CTRL, + .reset = 0x300, + .rsvd = 0xfdfc00f8, + },{ .name = "TIMESTAMP_REF_CTRL", .addr = A_TIMESTAMP_REF_CTRL, + .reset = 0x2000c00, + .rsvd = 0xfdfc00f8, + },{ .name = "CRL_SAFETY_CHK", .addr = A_CRL_SAFETY_CHK, + },{ .name = "PSM_REF_CTRL", .addr = A_PSM_REF_CTRL, + .reset = 0xf04, + .rsvd = 0xfffc00f8, + },{ .name = "DBG_TSTMP_CTRL", .addr = A_DBG_TSTMP_CTRL, + .reset = 0x300, + .rsvd = 0xfdfc00f8, + },{ .name = "CPM_TOPSW_REF_CTRL", .addr = A_CPM_TOPSW_REF_CTRL, + .reset = 0x300, + .rsvd = 0xfdfc00f8, + },{ .name = "USB3_DUAL_REF_CTRL", .addr = A_USB3_DUAL_REF_CTRL, + .reset = 0x3c00, + .rsvd = 0xfdfc00f8, + },{ .name = "RST_CPU_R5", .addr = A_RST_CPU_R5, + .reset = 0x17, + .rsvd = 0x8, + .pre_write = crl_rst_r5_prew, + },{ .name = "RST_ADMA", .addr = A_RST_ADMA, + .reset = 0x1, + .pre_write = crl_rst_adma_prew, + },{ .name = "RST_GEM0", .addr = A_RST_GEM0, + .reset = 0x1, + .pre_write = crl_rst_gem0_prew, + },{ .name = "RST_GEM1", .addr = A_RST_GEM1, + .reset = 0x1, + .pre_write = crl_rst_gem1_prew, + },{ .name = "RST_SPARE", .addr = A_RST_SPARE, + .reset = 0x1, + },{ .name = "RST_USB0", .addr = A_RST_USB0, + .reset = 0x1, + .pre_write = crl_rst_usb_prew, + },{ .name = "RST_UART0", .addr = A_RST_UART0, + .reset = 0x1, + .pre_write = crl_rst_uart0_prew, + },{ .name = "RST_UART1", .addr = A_RST_UART1, + .reset = 0x1, + .pre_write = crl_rst_uart1_prew, + },{ .name = "RST_SPI0", .addr = A_RST_SPI0, + .reset = 0x1, + },{ .name = "RST_SPI1", .addr = A_RST_SPI1, + .reset = 0x1, + },{ .name = "RST_CAN0", .addr = A_RST_CAN0, + .reset = 0x1, + },{ .name = "RST_CAN1", .addr = A_RST_CAN1, + .reset = 0x1, + },{ .name = "RST_I2C0", .addr = A_RST_I2C0, + .reset = 0x1, + },{ .name = "RST_I2C1", .addr = A_RST_I2C1, + .reset = 0x1, + },{ .name = "RST_DBG_LPD", .addr = A_RST_DBG_LPD, + .reset = 0x33, + .rsvd = 0xcc, + },{ .name = "RST_GPIO", .addr = A_RST_GPIO, + .reset = 0x1, + },{ .name = "RST_TTC", .addr = A_RST_TTC, + .reset = 0xf, + },{ .name = "RST_TIMESTAMP", .addr = A_RST_TIMESTAMP, + .reset = 0x1, + },{ .name = "RST_SWDT", .addr = A_RST_SWDT, + .reset = 0x1, + },{ .name = "RST_OCM", .addr = A_RST_OCM, + },{ .name = "RST_IPI", .addr = A_RST_IPI, + },{ .name = "RST_FPD", .addr = A_RST_FPD, + .reset = 0x3, + },{ .name = "PSM_RST_MODE", .addr = A_PSM_RST_MODE, + .reset = 0x1, + .rsvd = 0xf8, + } +}; + +static void crl_reset_enter(Object *obj, ResetType type) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { + register_reset(&s->regs_info[i]); + } +} + +static void crl_reset_hold(Object *obj) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj); + + crl_update_irq(s); +} + +static const MemoryRegionOps crl_ops = { + .read = register_read_memory, + .write = register_write_memory, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static void crl_init(Object *obj) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + int i; + + s->reg_array = + register_init_block32(DEVICE(obj), crl_regs_info, + ARRAY_SIZE(crl_regs_info), + s->regs_info, s->regs, + &crl_ops, + XLNX_VERSAL_CRL_ERR_DEBUG, + CRL_R_MAX * 4); + sysbus_init_mmio(sbd, &s->reg_array->mem); + sysbus_init_irq(sbd, &s->irq); + + for (i = 0; i < ARRAY_SIZE(s->cfg.cpu_r5); ++i) { + object_property_add_link(obj, "cpu_r5[*]", TYPE_ARM_CPU, + (Object **)&s->cfg.cpu_r5[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + } + + for (i = 0; i < ARRAY_SIZE(s->cfg.adma); ++i) { + object_property_add_link(obj, "adma[*]", TYPE_DEVICE, + (Object **)&s->cfg.adma[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + } + + for (i = 0; i < ARRAY_SIZE(s->cfg.uart); ++i) { + object_property_add_link(obj, "uart[*]", TYPE_DEVICE, + (Object **)&s->cfg.uart[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + } + + for (i = 0; i < ARRAY_SIZE(s->cfg.gem); ++i) { + object_property_add_link(obj, "gem[*]", TYPE_DEVICE, + (Object **)&s->cfg.gem[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + } + + object_property_add_link(obj, "usb", TYPE_DEVICE, + (Object **)&s->cfg.gem[i], + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); +} + +static void crl_finalize(Object *obj) +{ + XlnxVersalCRL *s = XLNX_VERSAL_CRL(obj); + register_finalize_block(s->reg_array); +} + +static const VMStateDescription vmstate_crl = { + .name = TYPE_XLNX_VERSAL_CRL, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, XlnxVersalCRL, CRL_R_MAX), + VMSTATE_END_OF_LIST(), + } +}; + +static void crl_class_init(ObjectClass *klass, void *data) +{ + ResettableClass *rc = RESETTABLE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->vmsd = &vmstate_crl; + + rc->phases.enter = crl_reset_enter; + rc->phases.hold = crl_reset_hold; +} + +static const TypeInfo crl_info = { + .name = TYPE_XLNX_VERSAL_CRL, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XlnxVersalCRL), + .class_init = crl_class_init, + .instance_init = crl_init, + .instance_finalize = crl_finalize, +}; + +static void crl_register_types(void) +{ + type_register_static(&crl_info); +} + +type_init(crl_register_types) diff --git a/hw/timer/cadence_ttc.c b/hw/timer/cadence_ttc.c index 64108241ba..e57a0f5f09 100644 --- a/hw/timer/cadence_ttc.c +++ b/hw/timer/cadence_ttc.c @@ -24,6 +24,8 @@ #include "qemu/timer.h" #include "qom/object.h" +#include "hw/timer/cadence_ttc.h" + #ifdef CADENCE_TTC_ERR_DEBUG #define DB_PRINT(...) do { \ fprintf(stderr, ": %s: ", __func__); \ @@ -49,36 +51,6 @@ #define CLOCK_CTRL_PS_EN 0x00000001 #define CLOCK_CTRL_PS_V 0x0000001e -typedef struct { - QEMUTimer *timer; - int freq; - - uint32_t reg_clock; - uint32_t reg_count; - uint32_t reg_value; - uint16_t reg_interval; - uint16_t reg_match[3]; - uint32_t reg_intr; - uint32_t reg_intr_en; - uint32_t reg_event_ctrl; - uint32_t reg_event; - - uint64_t cpu_time; - unsigned int cpu_time_valid; - - qemu_irq irq; -} CadenceTimerState; - -#define TYPE_CADENCE_TTC "cadence_ttc" -OBJECT_DECLARE_SIMPLE_TYPE(CadenceTTCState, CADENCE_TTC) - -struct CadenceTTCState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - CadenceTimerState timer[3]; -}; - static void cadence_timer_update(CadenceTimerState *s) { qemu_set_irq(s->irq, !!(s->reg_intr & s->reg_intr_en)); diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h index 60b9e126f5..97353f1c02 100644 --- a/include/hw/arm/exynos4210.h +++ b/include/hw/arm/exynos4210.h @@ -26,6 +26,10 @@ #include "hw/or-irq.h" #include "hw/sysbus.h" +#include "hw/cpu/a9mpcore.h" +#include "hw/intc/exynos4210_gic.h" +#include "hw/intc/exynos4210_combiner.h" +#include "hw/core/split-irq.h" #include "target/arm/cpu-qom.h" #include "qom/object.h" @@ -65,34 +69,25 @@ #define EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ \ (EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ * 8) -#define EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit) ((grp)*8 + (bit)) -#define EXYNOS4210_COMBINER_GET_GRP_NUM(irq) ((irq) / 8) -#define EXYNOS4210_COMBINER_GET_BIT_NUM(irq) \ - ((irq) - 8 * EXYNOS4210_COMBINER_GET_GRP_NUM(irq)) - -/* IRQs number for external and internal GIC */ -#define EXYNOS4210_EXT_GIC_NIRQ (160-32) -#define EXYNOS4210_INT_GIC_NIRQ 64 - #define EXYNOS4210_I2C_NUMBER 9 #define EXYNOS4210_NUM_DMA 3 -typedef struct Exynos4210Irq { - qemu_irq int_combiner_irq[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ]; - qemu_irq ext_combiner_irq[EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ]; - qemu_irq int_gic_irq[EXYNOS4210_INT_GIC_NIRQ]; - qemu_irq ext_gic_irq[EXYNOS4210_EXT_GIC_NIRQ]; - qemu_irq board_irqs[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ]; -} Exynos4210Irq; +/* + * We need one splitter for every external combiner input, plus + * one for every non-zero entry in combiner_grp_to_gic_id[], + * minus one for every external combiner ID in second or later + * places in a combinermap[] line. + * We'll assert in exynos4210_init_board_irqs() if this is wrong. + */ +#define EXYNOS4210_NUM_SPLITTERS (EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ + 38) struct Exynos4210State { /*< private >*/ SysBusDevice parent_obj; /*< public >*/ ARMCPU *cpu[EXYNOS4210_NCPUS]; - Exynos4210Irq irqs; - qemu_irq *irq_table; + qemu_irq irq_table[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ]; MemoryRegion chipid_mem; MemoryRegion iram_mem; @@ -102,6 +97,12 @@ struct Exynos4210State { MemoryRegion bootreg_mem; I2CBus *i2c_if[EXYNOS4210_I2C_NUMBER]; qemu_or_irq pl330_irq_orgate[EXYNOS4210_NUM_DMA]; + qemu_or_irq cpu_irq_orgate[EXYNOS4210_NCPUS]; + A9MPPrivState a9mpcore; + Exynos4210GicState ext_gic; + Exynos4210CombinerState int_combiner; + Exynos4210CombinerState ext_combiner; + SplitIRQ splitter[EXYNOS4210_NUM_SPLITTERS]; }; #define TYPE_EXYNOS4210_SOC "exynos4210" @@ -110,25 +111,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210State, EXYNOS4210_SOC) void exynos4210_write_secondary(ARMCPU *cpu, const struct arm_boot_info *info); -/* Initialize exynos4210 IRQ subsystem stub */ -qemu_irq *exynos4210_init_irq(Exynos4210Irq *env); - -/* Initialize board IRQs. - * These IRQs contain splitted Int/External Combiner and External Gic IRQs */ -void exynos4210_init_board_irqs(Exynos4210Irq *s); - /* Get IRQ number from exynos4210 IRQ subsystem stub. * To identify IRQ source use internal combiner group and bit number * grp - group number * bit - bit number inside group */ uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit); -/* - * Get Combiner input GPIO into irqs structure - */ -void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev, - int ext); - /* * exynos4210 UART */ diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 0728316ec7..cbe8a19c10 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -14,6 +14,7 @@ #include "hw/sysbus.h" #include "hw/arm/boot.h" +#include "hw/cpu/cluster.h" #include "hw/or-irq.h" #include "hw/sd/sdhci.h" #include "hw/intc/arm_gicv3.h" @@ -28,12 +29,14 @@ #include "hw/nvram/xlnx-versal-efuse.h" #include "hw/ssi/xlnx-versal-ospi.h" #include "hw/dma/xlnx_csu_dma.h" +#include "hw/misc/xlnx-versal-crl.h" #include "hw/misc/xlnx-versal-pmc-iou-slcr.h" #define TYPE_XLNX_VERSAL "xlnx-versal" OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL) #define XLNX_VERSAL_NR_ACPUS 2 +#define XLNX_VERSAL_NR_RCPUS 2 #define XLNX_VERSAL_NR_UARTS 2 #define XLNX_VERSAL_NR_GEMS 2 #define XLNX_VERSAL_NR_ADMAS 8 @@ -49,6 +52,7 @@ struct Versal { struct { struct { MemoryRegion mr; + CPUClusterState cluster; ARMCPU cpu[XLNX_VERSAL_NR_ACPUS]; GICv3State gic; } apu; @@ -71,10 +75,21 @@ struct Versal { VersalUsb2 usb; } iou; + /* Real-time Processing Unit. */ + struct { + MemoryRegion mr; + MemoryRegion mr_ps_alias; + + CPUClusterState cluster; + ARMCPU cpu[XLNX_VERSAL_NR_RCPUS]; + } rpu; + struct { qemu_or_irq irq_orgate; XlnxXramCtrl ctrl[XLNX_VERSAL_NR_XRAM]; } xram; + + XlnxVersalCRL crl; } lpd; /* The Platform Management Controller subsystem. */ @@ -115,6 +130,7 @@ struct Versal { #define VERSAL_TIMER_NS_EL1_IRQ 14 #define VERSAL_TIMER_NS_EL2_IRQ 10 +#define VERSAL_CRL_IRQ 10 #define VERSAL_UART0_IRQ_0 18 #define VERSAL_UART1_IRQ_0 19 #define VERSAL_USB0_IRQ_0 22 diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h index 9d9a9d0bf9..85fd9f53da 100644 --- a/include/hw/arm/xlnx-zynqmp.h +++ b/include/hw/arm/xlnx-zynqmp.h @@ -41,6 +41,7 @@ #include "hw/or-irq.h" #include "hw/misc/xlnx-zynqmp-apu-ctrl.h" #include "hw/misc/xlnx-zynqmp-crf.h" +#include "hw/timer/cadence_ttc.h" #define TYPE_XLNX_ZYNQMP "xlnx-zynqmp" OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP) @@ -84,6 +85,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(XlnxZynqMPState, XLNX_ZYNQMP) #define XLNX_ZYNQMP_MAX_RAM_SIZE (XLNX_ZYNQMP_MAX_LOW_RAM_SIZE + \ XLNX_ZYNQMP_MAX_HIGH_RAM_SIZE) +#define XLNX_ZYNQMP_NUM_TTC 4 + /* * Unimplemented mmio regions needed to boot some images. */ @@ -128,6 +131,7 @@ struct XlnxZynqMPState { qemu_or_irq qspi_irq_orgate; XlnxZynqMPAPUCtrl apu_ctrl; XlnxZynqMPCRF crf; + CadenceTTCState ttc[XLNX_ZYNQMP_NUM_TTC]; char *boot_cpu; ARMCPU *boot_cpu_ptr; diff --git a/include/hw/intc/exynos4210_combiner.h b/include/hw/intc/exynos4210_combiner.h new file mode 100644 index 0000000000..429844fed4 --- /dev/null +++ b/include/hw/intc/exynos4210_combiner.h @@ -0,0 +1,57 @@ +/* + * Samsung exynos4210 Interrupt Combiner + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. + * All rights reserved. + * + * Evgeny Voevodin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef HW_INTC_EXYNOS4210_COMBINER +#define HW_INTC_EXYNOS4210_COMBINER + +#include "hw/sysbus.h" + +/* + * State for each output signal of internal combiner + */ +typedef struct CombinerGroupState { + uint8_t src_mask; /* 1 - source enabled, 0 - disabled */ + uint8_t src_pending; /* Pending source interrupts before masking */ +} CombinerGroupState; + +#define TYPE_EXYNOS4210_COMBINER "exynos4210.combiner" +OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210CombinerState, EXYNOS4210_COMBINER) + +/* Number of groups and total number of interrupts for the internal combiner */ +#define IIC_NGRP 64 +#define IIC_NIRQ (IIC_NGRP * 8) +#define IIC_REGSET_SIZE 0x41 + +struct Exynos4210CombinerState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + + struct CombinerGroupState group[IIC_NGRP]; + uint32_t reg_set[IIC_REGSET_SIZE]; + uint32_t icipsr[2]; + uint32_t external; /* 1 means that this combiner is external */ + + qemu_irq output_irq[IIC_NGRP]; +}; + +#endif diff --git a/include/hw/intc/exynos4210_gic.h b/include/hw/intc/exynos4210_gic.h new file mode 100644 index 0000000000..f64c4069c6 --- /dev/null +++ b/include/hw/intc/exynos4210_gic.h @@ -0,0 +1,43 @@ +/* + * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. + * All rights reserved. + * + * Evgeny Voevodin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#ifndef HW_INTC_EXYNOS4210_GIC_H +#define HW_INTC_EXYNOS4210_GIC_H + +#include "hw/sysbus.h" + +#define TYPE_EXYNOS4210_GIC "exynos4210.gic" +OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210GicState, EXYNOS4210_GIC) + +#define EXYNOS4210_GIC_NCPUS 2 + +struct Exynos4210GicState { + SysBusDevice parent_obj; + + MemoryRegion cpu_container; + MemoryRegion dist_container; + MemoryRegion cpu_alias[EXYNOS4210_GIC_NCPUS]; + MemoryRegion dist_alias[EXYNOS4210_GIC_NCPUS]; + uint32_t num_cpu; + DeviceState *gic; +}; + +#endif diff --git a/include/hw/irq.h b/include/hw/irq.h index dc7abf199e..645b73d251 100644 --- a/include/hw/irq.h +++ b/include/hw/irq.h @@ -46,11 +46,6 @@ void qemu_free_irq(qemu_irq irq); /* Returns a new IRQ with opposite polarity. */ qemu_irq qemu_irq_invert(qemu_irq irq); -/* Returns a new IRQ which feeds into both the passed IRQs. - * It's probably better to use the TYPE_SPLIT_IRQ device instead. - */ -qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2); - /* For internal use in qtest. Similar to qemu_irq_split, but operating on an existing vector of qemu_irq. */ void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n); diff --git a/include/hw/misc/npcm7xx_gcr.h b/include/hw/misc/npcm7xx_gcr.h index 13109d9d32..9419e0a7d2 100644 --- a/include/hw/misc/npcm7xx_gcr.h +++ b/include/hw/misc/npcm7xx_gcr.h @@ -19,6 +19,36 @@ #include "exec/memory.h" #include "hw/sysbus.h" +/* + * NPCM7XX PWRON STRAP bit fields + * 12: SPI0 powered by VSBV3 at 1.8V + * 11: System flash attached to BMC + * 10: BSP alternative pins. + * 9:8: Flash UART command route enabled. + * 7: Security enabled. + * 6: HI-Z state control. + * 5: ECC disabled. + * 4: Reserved + * 3: JTAG2 enabled. + * 2:0: CPU and DRAM clock frequency. + */ +#define NPCM7XX_PWRON_STRAP_SPI0F18 BIT(12) +#define NPCM7XX_PWRON_STRAP_SFAB BIT(11) +#define NPCM7XX_PWRON_STRAP_BSPA BIT(10) +#define NPCM7XX_PWRON_STRAP_FUP(x) ((x) << 8) +#define FUP_NORM_UART2 3 +#define FUP_PROG_UART3 2 +#define FUP_PROG_UART2 1 +#define FUP_NORM_UART3 0 +#define NPCM7XX_PWRON_STRAP_SECEN BIT(7) +#define NPCM7XX_PWRON_STRAP_HIZ BIT(6) +#define NPCM7XX_PWRON_STRAP_ECC BIT(5) +#define NPCM7XX_PWRON_STRAP_RESERVE1 BIT(4) +#define NPCM7XX_PWRON_STRAP_J2EN BIT(3) +#define NPCM7XX_PWRON_STRAP_CKFRQ(x) (x) +#define CKFRQ_SKIPINIT 0x000 +#define CKFRQ_DEFAULT 0x111 + /* * Number of registers in our device state structure. Don't change this without * incrementing the version_id in the vmstate. diff --git a/include/hw/misc/xlnx-versal-crl.h b/include/hw/misc/xlnx-versal-crl.h new file mode 100644 index 0000000000..2857f4169a --- /dev/null +++ b/include/hw/misc/xlnx-versal-crl.h @@ -0,0 +1,235 @@ +/* + * QEMU model of the Clock-Reset-LPD (CRL). + * + * Copyright (c) 2022 Xilinx Inc. + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Written by Edgar E. Iglesias + */ +#ifndef HW_MISC_XLNX_VERSAL_CRL_H +#define HW_MISC_XLNX_VERSAL_CRL_H + +#include "hw/sysbus.h" +#include "hw/register.h" +#include "target/arm/cpu.h" + +#define TYPE_XLNX_VERSAL_CRL "xlnx,versal-crl" +OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersalCRL, XLNX_VERSAL_CRL) + +REG32(ERR_CTRL, 0x0) + FIELD(ERR_CTRL, SLVERR_ENABLE, 0, 1) +REG32(IR_STATUS, 0x4) + FIELD(IR_STATUS, ADDR_DECODE_ERR, 0, 1) +REG32(IR_MASK, 0x8) + FIELD(IR_MASK, ADDR_DECODE_ERR, 0, 1) +REG32(IR_ENABLE, 0xc) + FIELD(IR_ENABLE, ADDR_DECODE_ERR, 0, 1) +REG32(IR_DISABLE, 0x10) + FIELD(IR_DISABLE, ADDR_DECODE_ERR, 0, 1) +REG32(WPROT, 0x1c) + FIELD(WPROT, ACTIVE, 0, 1) +REG32(PLL_CLK_OTHER_DMN, 0x20) + FIELD(PLL_CLK_OTHER_DMN, APLL_BYPASS, 0, 1) +REG32(RPLL_CTRL, 0x40) + FIELD(RPLL_CTRL, POST_SRC, 24, 3) + FIELD(RPLL_CTRL, PRE_SRC, 20, 3) + FIELD(RPLL_CTRL, CLKOUTDIV, 16, 2) + FIELD(RPLL_CTRL, FBDIV, 8, 8) + FIELD(RPLL_CTRL, BYPASS, 3, 1) + FIELD(RPLL_CTRL, RESET, 0, 1) +REG32(RPLL_CFG, 0x44) + FIELD(RPLL_CFG, LOCK_DLY, 25, 7) + FIELD(RPLL_CFG, LOCK_CNT, 13, 10) + FIELD(RPLL_CFG, LFHF, 10, 2) + FIELD(RPLL_CFG, CP, 5, 4) + FIELD(RPLL_CFG, RES, 0, 4) +REG32(RPLL_FRAC_CFG, 0x48) + FIELD(RPLL_FRAC_CFG, ENABLED, 31, 1) + FIELD(RPLL_FRAC_CFG, SEED, 22, 3) + FIELD(RPLL_FRAC_CFG, ALGRTHM, 19, 1) + FIELD(RPLL_FRAC_CFG, ORDER, 18, 1) + FIELD(RPLL_FRAC_CFG, DATA, 0, 16) +REG32(PLL_STATUS, 0x50) + FIELD(PLL_STATUS, RPLL_STABLE, 2, 1) + FIELD(PLL_STATUS, RPLL_LOCK, 0, 1) +REG32(RPLL_TO_XPD_CTRL, 0x100) + FIELD(RPLL_TO_XPD_CTRL, CLKACT, 25, 1) + FIELD(RPLL_TO_XPD_CTRL, DIVISOR0, 8, 10) +REG32(LPD_TOP_SWITCH_CTRL, 0x104) + FIELD(LPD_TOP_SWITCH_CTRL, CLKACT_ADMA, 26, 1) + FIELD(LPD_TOP_SWITCH_CTRL, CLKACT, 25, 1) + FIELD(LPD_TOP_SWITCH_CTRL, DIVISOR0, 8, 10) + FIELD(LPD_TOP_SWITCH_CTRL, SRCSEL, 0, 3) +REG32(LPD_LSBUS_CTRL, 0x108) + FIELD(LPD_LSBUS_CTRL, CLKACT, 25, 1) + FIELD(LPD_LSBUS_CTRL, DIVISOR0, 8, 10) + FIELD(LPD_LSBUS_CTRL, SRCSEL, 0, 3) +REG32(CPU_R5_CTRL, 0x10c) + FIELD(CPU_R5_CTRL, CLKACT_OCM2, 28, 1) + FIELD(CPU_R5_CTRL, CLKACT_OCM, 27, 1) + FIELD(CPU_R5_CTRL, CLKACT_CORE, 26, 1) + FIELD(CPU_R5_CTRL, CLKACT, 25, 1) + FIELD(CPU_R5_CTRL, DIVISOR0, 8, 10) + FIELD(CPU_R5_CTRL, SRCSEL, 0, 3) +REG32(IOU_SWITCH_CTRL, 0x114) + FIELD(IOU_SWITCH_CTRL, CLKACT, 25, 1) + FIELD(IOU_SWITCH_CTRL, DIVISOR0, 8, 10) + FIELD(IOU_SWITCH_CTRL, SRCSEL, 0, 3) +REG32(GEM0_REF_CTRL, 0x118) + FIELD(GEM0_REF_CTRL, CLKACT_RX, 27, 1) + FIELD(GEM0_REF_CTRL, CLKACT_TX, 26, 1) + FIELD(GEM0_REF_CTRL, CLKACT, 25, 1) + FIELD(GEM0_REF_CTRL, DIVISOR0, 8, 10) + FIELD(GEM0_REF_CTRL, SRCSEL, 0, 3) +REG32(GEM1_REF_CTRL, 0x11c) + FIELD(GEM1_REF_CTRL, CLKACT_RX, 27, 1) + FIELD(GEM1_REF_CTRL, CLKACT_TX, 26, 1) + FIELD(GEM1_REF_CTRL, CLKACT, 25, 1) + FIELD(GEM1_REF_CTRL, DIVISOR0, 8, 10) + FIELD(GEM1_REF_CTRL, SRCSEL, 0, 3) +REG32(GEM_TSU_REF_CTRL, 0x120) + FIELD(GEM_TSU_REF_CTRL, CLKACT, 25, 1) + FIELD(GEM_TSU_REF_CTRL, DIVISOR0, 8, 10) + FIELD(GEM_TSU_REF_CTRL, SRCSEL, 0, 3) +REG32(USB0_BUS_REF_CTRL, 0x124) + FIELD(USB0_BUS_REF_CTRL, CLKACT, 25, 1) + FIELD(USB0_BUS_REF_CTRL, DIVISOR0, 8, 10) + FIELD(USB0_BUS_REF_CTRL, SRCSEL, 0, 3) +REG32(UART0_REF_CTRL, 0x128) + FIELD(UART0_REF_CTRL, CLKACT, 25, 1) + FIELD(UART0_REF_CTRL, DIVISOR0, 8, 10) + FIELD(UART0_REF_CTRL, SRCSEL, 0, 3) +REG32(UART1_REF_CTRL, 0x12c) + FIELD(UART1_REF_CTRL, CLKACT, 25, 1) + FIELD(UART1_REF_CTRL, DIVISOR0, 8, 10) + FIELD(UART1_REF_CTRL, SRCSEL, 0, 3) +REG32(SPI0_REF_CTRL, 0x130) + FIELD(SPI0_REF_CTRL, CLKACT, 25, 1) + FIELD(SPI0_REF_CTRL, DIVISOR0, 8, 10) + FIELD(SPI0_REF_CTRL, SRCSEL, 0, 3) +REG32(SPI1_REF_CTRL, 0x134) + FIELD(SPI1_REF_CTRL, CLKACT, 25, 1) + FIELD(SPI1_REF_CTRL, DIVISOR0, 8, 10) + FIELD(SPI1_REF_CTRL, SRCSEL, 0, 3) +REG32(CAN0_REF_CTRL, 0x138) + FIELD(CAN0_REF_CTRL, CLKACT, 25, 1) + FIELD(CAN0_REF_CTRL, DIVISOR0, 8, 10) + FIELD(CAN0_REF_CTRL, SRCSEL, 0, 3) +REG32(CAN1_REF_CTRL, 0x13c) + FIELD(CAN1_REF_CTRL, CLKACT, 25, 1) + FIELD(CAN1_REF_CTRL, DIVISOR0, 8, 10) + FIELD(CAN1_REF_CTRL, SRCSEL, 0, 3) +REG32(I2C0_REF_CTRL, 0x140) + FIELD(I2C0_REF_CTRL, CLKACT, 25, 1) + FIELD(I2C0_REF_CTRL, DIVISOR0, 8, 10) + FIELD(I2C0_REF_CTRL, SRCSEL, 0, 3) +REG32(I2C1_REF_CTRL, 0x144) + FIELD(I2C1_REF_CTRL, CLKACT, 25, 1) + FIELD(I2C1_REF_CTRL, DIVISOR0, 8, 10) + FIELD(I2C1_REF_CTRL, SRCSEL, 0, 3) +REG32(DBG_LPD_CTRL, 0x148) + FIELD(DBG_LPD_CTRL, CLKACT, 25, 1) + FIELD(DBG_LPD_CTRL, DIVISOR0, 8, 10) + FIELD(DBG_LPD_CTRL, SRCSEL, 0, 3) +REG32(TIMESTAMP_REF_CTRL, 0x14c) + FIELD(TIMESTAMP_REF_CTRL, CLKACT, 25, 1) + FIELD(TIMESTAMP_REF_CTRL, DIVISOR0, 8, 10) + FIELD(TIMESTAMP_REF_CTRL, SRCSEL, 0, 3) +REG32(CRL_SAFETY_CHK, 0x150) +REG32(PSM_REF_CTRL, 0x154) + FIELD(PSM_REF_CTRL, DIVISOR0, 8, 10) + FIELD(PSM_REF_CTRL, SRCSEL, 0, 3) +REG32(DBG_TSTMP_CTRL, 0x158) + FIELD(DBG_TSTMP_CTRL, CLKACT, 25, 1) + FIELD(DBG_TSTMP_CTRL, DIVISOR0, 8, 10) + FIELD(DBG_TSTMP_CTRL, SRCSEL, 0, 3) +REG32(CPM_TOPSW_REF_CTRL, 0x15c) + FIELD(CPM_TOPSW_REF_CTRL, CLKACT, 25, 1) + FIELD(CPM_TOPSW_REF_CTRL, DIVISOR0, 8, 10) + FIELD(CPM_TOPSW_REF_CTRL, SRCSEL, 0, 3) +REG32(USB3_DUAL_REF_CTRL, 0x160) + FIELD(USB3_DUAL_REF_CTRL, CLKACT, 25, 1) + FIELD(USB3_DUAL_REF_CTRL, DIVISOR0, 8, 10) + FIELD(USB3_DUAL_REF_CTRL, SRCSEL, 0, 3) +REG32(RST_CPU_R5, 0x300) + FIELD(RST_CPU_R5, RESET_PGE, 4, 1) + FIELD(RST_CPU_R5, RESET_AMBA, 2, 1) + FIELD(RST_CPU_R5, RESET_CPU1, 1, 1) + FIELD(RST_CPU_R5, RESET_CPU0, 0, 1) +REG32(RST_ADMA, 0x304) + FIELD(RST_ADMA, RESET, 0, 1) +REG32(RST_GEM0, 0x308) + FIELD(RST_GEM0, RESET, 0, 1) +REG32(RST_GEM1, 0x30c) + FIELD(RST_GEM1, RESET, 0, 1) +REG32(RST_SPARE, 0x310) + FIELD(RST_SPARE, RESET, 0, 1) +REG32(RST_USB0, 0x314) + FIELD(RST_USB0, RESET, 0, 1) +REG32(RST_UART0, 0x318) + FIELD(RST_UART0, RESET, 0, 1) +REG32(RST_UART1, 0x31c) + FIELD(RST_UART1, RESET, 0, 1) +REG32(RST_SPI0, 0x320) + FIELD(RST_SPI0, RESET, 0, 1) +REG32(RST_SPI1, 0x324) + FIELD(RST_SPI1, RESET, 0, 1) +REG32(RST_CAN0, 0x328) + FIELD(RST_CAN0, RESET, 0, 1) +REG32(RST_CAN1, 0x32c) + FIELD(RST_CAN1, RESET, 0, 1) +REG32(RST_I2C0, 0x330) + FIELD(RST_I2C0, RESET, 0, 1) +REG32(RST_I2C1, 0x334) + FIELD(RST_I2C1, RESET, 0, 1) +REG32(RST_DBG_LPD, 0x338) + FIELD(RST_DBG_LPD, RPU_DBG1_RESET, 5, 1) + FIELD(RST_DBG_LPD, RPU_DBG0_RESET, 4, 1) + FIELD(RST_DBG_LPD, RESET_HSDP, 1, 1) + FIELD(RST_DBG_LPD, RESET, 0, 1) +REG32(RST_GPIO, 0x33c) + FIELD(RST_GPIO, RESET, 0, 1) +REG32(RST_TTC, 0x344) + FIELD(RST_TTC, TTC3_RESET, 3, 1) + FIELD(RST_TTC, TTC2_RESET, 2, 1) + FIELD(RST_TTC, TTC1_RESET, 1, 1) + FIELD(RST_TTC, TTC0_RESET, 0, 1) +REG32(RST_TIMESTAMP, 0x348) + FIELD(RST_TIMESTAMP, RESET, 0, 1) +REG32(RST_SWDT, 0x34c) + FIELD(RST_SWDT, RESET, 0, 1) +REG32(RST_OCM, 0x350) + FIELD(RST_OCM, RESET, 0, 1) +REG32(RST_IPI, 0x354) + FIELD(RST_IPI, RESET, 0, 1) +REG32(RST_SYSMON, 0x358) + FIELD(RST_SYSMON, SEQ_RST, 1, 1) + FIELD(RST_SYSMON, CFG_RST, 0, 1) +REG32(RST_FPD, 0x360) + FIELD(RST_FPD, SRST, 1, 1) + FIELD(RST_FPD, POR, 0, 1) +REG32(PSM_RST_MODE, 0x370) + FIELD(PSM_RST_MODE, WAKEUP, 2, 1) + FIELD(PSM_RST_MODE, RST_MODE, 0, 2) + +#define CRL_R_MAX (R_PSM_RST_MODE + 1) + +#define RPU_MAX_CPU 2 + +struct XlnxVersalCRL { + SysBusDevice parent_obj; + qemu_irq irq; + + struct { + ARMCPU *cpu_r5[RPU_MAX_CPU]; + DeviceState *adma[8]; + DeviceState *uart[2]; + DeviceState *gem[2]; + DeviceState *usb; + } cfg; + + RegisterInfoArray *reg_array; + uint32_t regs[CRL_R_MAX]; + RegisterInfo regs_info[CRL_R_MAX]; +}; +#endif diff --git a/include/hw/timer/cadence_ttc.h b/include/hw/timer/cadence_ttc.h new file mode 100644 index 0000000000..e1251383f2 --- /dev/null +++ b/include/hw/timer/cadence_ttc.h @@ -0,0 +1,54 @@ +/* + * Xilinx Zynq cadence TTC model + * + * Copyright (c) 2011 Xilinx Inc. + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com) + * Copyright (c) 2012 PetaLogix Pty Ltd. + * Written By Haibing Ma + * M. Habib + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ +#ifndef HW_TIMER_CADENCE_TTC_H +#define HW_TIMER_CADENCE_TTC_H + +#include "hw/sysbus.h" +#include "qemu/timer.h" + +typedef struct { + QEMUTimer *timer; + int freq; + + uint32_t reg_clock; + uint32_t reg_count; + uint32_t reg_value; + uint16_t reg_interval; + uint16_t reg_match[3]; + uint32_t reg_intr; + uint32_t reg_intr_en; + uint32_t reg_event_ctrl; + uint32_t reg_event; + + uint64_t cpu_time; + unsigned int cpu_time_valid; + + qemu_irq irq; +} CadenceTimerState; + +#define TYPE_CADENCE_TTC "cadence_ttc" +OBJECT_DECLARE_SIMPLE_TYPE(CadenceTTCState, CADENCE_TTC) + +struct CadenceTTCState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + CadenceTimerState timer[3]; +}; + +#endif