[PATCH v3 4/5] hw/riscv/k230: Route SSI interrupts to the PLIC
Kangjie Huang <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <[email protected]> |
Connect the nine interrupt outputs of each K230 DWC SSI controller to the documented PLIC source range. The TXU, DONE, and AXIE lines are wired to preserve the physical K230 interrupt topology, but remain inactive until their transfer engines are modelled. Extend qtests to cover TXE routing for all instances, RXU routing, and instance isolation. Signed-off-by: Kangjie Huang <[email protected]> --- hw/riscv/k230.c | 36 ++++++++++++++++++++ include/hw/riscv/k230.h | 3 ++ tests/qtest/k230-dwc-ssi-test.c | 59 ++++++++++++++++++++++++++++----- 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c index ea7eaa35a5..4911f2d1be 100644 --- a/hw/riscv/k230.c +++ b/hw/riscv/k230.c @@ -102,6 +102,21 @@ static const MemMapEntry memmap[] = { [K230_DEV_CLINT] = { 0xF04000000, 0x00400000 }, }; +typedef struct K230SsiRoute { + unsigned int ssi_index; + unsigned int irq_base; +} K230SsiRoute; + +/* + * SDK numbering follows the address map: spi0 is the SPI-OPI instance, + * while spi1 and spi2 are QSPI0 and QSPI1. + */ +static const K230SsiRoute k230_ssi_routes[] = { + { .ssi_index = 2, .irq_base = K230_SPI0_IRQ_BASE }, + { .ssi_index = 0, .irq_base = K230_SPI1_IRQ_BASE }, + { .ssi_index = 1, .irq_base = K230_SPI2_IRQ_BASE }, +}; + typedef struct K230DwcSsiProfile { uint32_t num_cs; uint32_t fifo_depth; @@ -191,6 +206,25 @@ static void k230_create_uart(MemoryRegion *sys_mem, DeviceState *plic, 399193, serial_hd(index), DEVICE_LITTLE_ENDIAN); } +static void k230_connect_ssi_irqs(K230SoCState *s) +{ + for (size_t route_idx = 0; + route_idx < ARRAY_SIZE(k230_ssi_routes); route_idx++) { + const K230SsiRoute *route = &k230_ssi_routes[route_idx]; + SysBusDevice *ssi; + + g_assert(route->ssi_index < ARRAY_SIZE(s->dwc_ssi)); + g_assert(route->irq_base + DWC_SSI_IRQ_COUNT <= + K230_PLIC_NUM_SOURCES); + + ssi = SYS_BUS_DEVICE(&s->dwc_ssi[route->ssi_index]); + for (unsigned int i = 0; i < DWC_SSI_IRQ_COUNT; i++) { + sysbus_connect_irq(ssi, i, + qdev_get_gpio_in(DEVICE(s->c908_plic), route->irq_base + i)); + } + } +} + static void k230_soc_realize(DeviceState *dev, Error **errp) { K230SoCState *s = RISCV_K230_SOC(dev); @@ -245,6 +279,8 @@ static void k230_soc_realize(DeviceState *dev, Error **errp) } } + k230_connect_ssi_irqs(s); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[0]), 0, memmap[K230_DEV_WDT0].base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[0]), 0, qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT0_IRQ)); diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h index cd30fd6aaa..4eee78ddec 100644 --- a/include/hw/riscv/k230.h +++ b/include/hw/riscv/k230.h @@ -131,6 +131,9 @@ enum { K230_UART4_IRQ = 20, K230_WDT0_IRQ = 107, K230_WDT1_IRQ = 108, + K230_SPI0_IRQ_BASE = 146, + K230_SPI1_IRQ_BASE = 155, + K230_SPI2_IRQ_BASE = 164, }; #define K230_UART_COUNT 5 diff --git a/tests/qtest/k230-dwc-ssi-test.c b/tests/qtest/k230-dwc-ssi-test.c index 126b73ea01..a522fc4973 100644 --- a/tests/qtest/k230-dwc-ssi-test.c +++ b/tests/qtest/k230-dwc-ssi-test.c @@ -14,6 +14,8 @@ #define K230_SPI0_BASE 0x91584000ULL #define K230_SPI1_BASE 0x91582000ULL #define K230_SPI2_BASE 0x91583000ULL +#define K230_PLIC_BASE 0xf00000000ULL +#define K230_PLIC_PENDING_BASE 0x1000 #define K230_SSI_CTRLR0 0x000 #define K230_SSI_CTRLR1 0x004 #define K230_SSI_SSIENR 0x008 @@ -63,6 +65,10 @@ #define K230_SSI_INT_RXF BIT(4) #define K230_SSI_INT_DONE BIT(11) #define K230_SSI_INT_AXIE BIT(8) +#define K230_SSI_IRQ_TXE 0 +#define K230_SSI_IRQ_RXU 5 +#define K230_SSI_IRQ_DONE 7 +#define K230_SSI_IRQ_AXIE 8 #define K230_SSI_RXFTLR 0x01c #define K230_SSI_RXOICR 0x03c @@ -77,6 +83,7 @@ typedef struct K230SsiInstance { uint64_t base; uint32_t num_cs; uint32_t imr_reset; + uint32_t first_irq; } K230SsiInstance; static const K230SsiInstance k230_ssi_instances[3] = { @@ -84,14 +91,17 @@ static const K230SsiInstance k230_ssi_instances[3] = { .base = K230_SPI0_BASE, .num_cs = 1, .imr_reset = 0x0000003fU, + .first_irq = 146, }, { .base = K230_SPI1_BASE, .num_cs = 5, .imr_reset = 0x0000001fU, + .first_irq = 155, }, { .base = K230_SPI2_BASE, .num_cs = 5, .imr_reset = 0x0000001fU, + .first_irq = 164, }, }; @@ -112,6 +122,14 @@ static void k230_ssi_writel(QTestState *qts, uint64_t base, qtest_writel(qts, base + offset, value); } +static bool k230_ssi_plic_pending(QTestState *qts, uint32_t irq) +{ + uint64_t addr = K230_PLIC_BASE + K230_PLIC_PENDING_BASE + + (irq / 32) * sizeof(uint32_t); + + return qtest_readl(qts, addr) & BIT(irq % 32); +} + static void k230_ssi_disable(QTestState *qts, uint64_t base) { k230_ssi_writel(qts, base, K230_SSI_SSIENR, 0); @@ -287,14 +305,38 @@ static void test_interrupt_controller(void) ==, 1); g_assert_cmphex(k230_ssi_readl(qts, K230_SPI1_BASE, K230_SSI_RISR) & K230_SSI_INT_RXU, ==, 0); - k230_ssi_writel(qts, K230_SPI1_BASE, K230_SSI_AXIECR, UINT32_MAX); - k230_ssi_writel(qts, K230_SPI1_BASE, K230_SSI_DONECR, UINT32_MAX); - g_assert_cmphex(k230_ssi_readl(qts, K230_SPI1_BASE, K230_SSI_AXIECR), - ==, 0); - g_assert_cmphex(k230_ssi_readl(qts, K230_SPI1_BASE, K230_SSI_DONECR), - ==, 0); - g_assert_cmphex(k230_ssi_readl(qts, K230_SPI1_BASE, K230_SSI_RISR) & - (K230_SSI_INT_DONE | K230_SSI_INT_AXIE), ==, 0); + qtest_quit(qts); +} + +static void test_plic_routing(void) +{ + QTestState *qts = k230_ssi_start(); + const K230SsiInstance *target = &k230_ssi_instances[1]; + + for (int i = 0; i < ARRAY_SIZE(k230_ssi_instances); i++) { + const K230SsiInstance *inst = &k230_ssi_instances[i]; + + g_assert_true(k230_ssi_plic_pending(qts, + inst->first_irq + + K230_SSI_IRQ_TXE)); + k230_ssi_writel(qts, inst->base, K230_SSI_IMR, 0); + g_assert_false(k230_ssi_plic_pending(qts, inst->first_irq + + K230_SSI_IRQ_DONE)); + g_assert_false(k230_ssi_plic_pending(qts, inst->first_irq + + K230_SSI_IRQ_AXIE)); + } + + k230_ssi_writel(qts, target->base, K230_SSI_IMR, K230_SSI_INT_RXU); + (void)k230_ssi_read_frame(qts, target->base); + g_assert_true(k230_ssi_plic_pending(qts, + target->first_irq + + K230_SSI_IRQ_RXU)); + for (int i = 0; i < ARRAY_SIZE(k230_ssi_instances); i++) { + if (&k230_ssi_instances[i] != target) { + g_assert_false(k230_ssi_plic_pending( + qts, k230_ssi_instances[i].first_irq + K230_SSI_IRQ_RXU)); + } + } qtest_quit(qts); } @@ -560,6 +602,7 @@ int main(int argc, char **argv) qtest_add_func("/k230-dwc-ssi/pio-data-path", test_pio_data_path); qtest_add_func("/k230-dwc-ssi/interrupt-controller", test_interrupt_controller); + qtest_add_func("/k230-dwc-ssi/plic-routing", test_plic_routing); qtest_add_func("/k230-dwc-ssi/tx-only-mode", test_tx_only_mode); qtest_add_func("/k230-dwc-ssi/eeprom-read-contract", test_eeprom_read_contract); -- 2.43.0