Map the WDT2 registers in the AST2600 FMC memory region by creating a local address space on top of WDT2 memory region.
The model only implements the enable bit of the control register. The reload register uses a 0.1s unit instead of a 1us. Values are converted on the fly when doing the accesses. The restart register is the same. Cc: Peter Delevoryas <p...@fb.com> Signed-off-by: Cédric Le Goater <c...@kaod.org> --- include/hw/ssi/aspeed_smc.h | 3 ++ hw/arm/aspeed_ast2600.c | 2 + hw/ssi/aspeed_smc.c | 78 ++++++++++++++++++++++++++++++++++++- hw/ssi/trace-events | 1 + 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index 75bc793bd269..ad3c80f2d809 100644 --- a/include/hw/ssi/aspeed_smc.h +++ b/include/hw/ssi/aspeed_smc.h @@ -76,6 +76,9 @@ struct AspeedSMCState { MemoryRegion *dram_mr; AddressSpace dram_as; + AddressSpace wdt2_as; + MemoryRegion *wdt2_mr; + AspeedSMCFlash flashes[ASPEED_SMC_CS_MAX]; uint8_t snoop_index; diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 3a7aa910b157..4abb0bb91e92 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -366,6 +366,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } /* FMC, The number of CS is set at the board level */ + object_property_set_link(OBJECT(&s->fmc), "wdt2", OBJECT(&s->wdt[2].iomem), + &error_abort); object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), &error_abort); if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 8a988c167604..1770985230b0 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -130,6 +130,8 @@ #define FMC_WDT2_CTRL_SINGLE_BOOT_MODE BIT(5) #define FMC_WDT2_CTRL_BOOT_SOURCE BIT(4) /* O: primary 1: alternate */ #define FMC_WDT2_CTRL_EN BIT(0) +#define R_FMC_WDT2_RELOAD (0x68 / 4) +#define R_FMC_WDT2_RESTART (0x6C / 4) /* DMA Control/Status Register */ #define R_DMA_CTRL (0x80 / 4) @@ -704,6 +706,54 @@ static void aspeed_smc_reset(DeviceState *d) s->snoop_dummies = 0; } +#define ASPEED_WDT_RELOAD 0x04 +#define ASPEED_WDT_RESTART 0x08 +#define ASPEED_WDT_CTRL 0x0C + +static void aspeed_smc_wdt2_write(AspeedSMCState *s, uint32_t offset, + uint32_t value) +{ + MemTxResult result; + + address_space_stl_le(&s->wdt2_as, offset, value, MEMTXATTRS_UNSPECIFIED, + &result); + if (result != MEMTX_OK) { + aspeed_smc_error("WDT2 write failed @%08x", offset); + return; + } +} + +static uint64_t aspeed_smc_wdt2_read(AspeedSMCState *s, uint32_t offset) +{ + MemTxResult result; + uint32_t value; + + value = address_space_ldl_le(&s->wdt2_as, offset, MEMTXATTRS_UNSPECIFIED, + &result); + if (result != MEMTX_OK) { + aspeed_smc_error("WDT2 read failed @%08x", offset); + return -1; + } + return value; +} + +static void aspeed_smc_wdt2_enable(AspeedSMCState *s, bool enable) +{ + uint32_t value; + + value = aspeed_smc_wdt2_read(s, ASPEED_WDT_CTRL); + if (value == -1) { + return; + } + + value &= ~BIT(0); + value |= enable; + + aspeed_smc_wdt2_write(s, ASPEED_WDT_CTRL, value); + + trace_aspeed_smc_wdt2_enable(enable ? "en" : "dis"); +} + static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) { AspeedSMCState *s = ASPEED_SMC(opaque); @@ -718,7 +768,6 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) addr == R_CE_CMD_CTRL || addr == R_INTR_CTRL || addr == R_DUMMY_DATA || - (aspeed_smc_has_wdt_control(asc) && addr == R_FMC_WDT2_CTRL) || (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) || (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR) || (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR) || @@ -731,6 +780,10 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) trace_aspeed_smc_read(addr << 2, size, s->regs[addr]); return s->regs[addr]; + } else if (aspeed_smc_has_wdt_control(asc) && addr == R_FMC_WDT2_CTRL) { + return aspeed_smc_wdt2_read(s, ASPEED_WDT_CTRL); + } else if (aspeed_smc_has_wdt_control(asc) && addr == R_FMC_WDT2_RELOAD) { + return aspeed_smc_wdt2_read(s, ASPEED_WDT_RELOAD) / 100000; } else { qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n", __func__, addr); @@ -1053,7 +1106,11 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, } else if (addr == R_DUMMY_DATA) { s->regs[addr] = value & 0xff; } else if (aspeed_smc_has_wdt_control(asc) && addr == R_FMC_WDT2_CTRL) { - s->regs[addr] = value & FMC_WDT2_CTRL_EN; + aspeed_smc_wdt2_enable(s, !!(value & FMC_WDT2_CTRL_EN)); + } else if (aspeed_smc_has_wdt_control(asc) && addr == R_FMC_WDT2_RELOAD) { + aspeed_smc_wdt2_write(s, ASPEED_WDT_RELOAD, value * 100000); + } else if (aspeed_smc_has_wdt_control(asc) && addr == R_FMC_WDT2_RESTART) { + aspeed_smc_wdt2_write(s, ASPEED_WDT_RESTART, value); } else if (addr == R_INTR_CTRL) { s->regs[addr] = value; } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) { @@ -1108,6 +1165,16 @@ static void aspeed_smc_dma_setup(AspeedSMCState *s, Error **errp) TYPE_ASPEED_SMC ".dma-dram"); } +static void aspeed_smc_wdt_setup(AspeedSMCState *s, Error **errp) +{ + if (!s->wdt2_mr) { + error_setg(errp, TYPE_ASPEED_SMC ": 'wdt2' link not set"); + return; + } + + address_space_init(&s->wdt2_as, s->wdt2_mr, TYPE_ASPEED_SMC ".wdt2"); +} + static void aspeed_smc_realize(DeviceState *dev, Error **errp) { SysBusDevice *sbd = SYS_BUS_DEVICE(dev); @@ -1189,6 +1256,11 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) if (aspeed_smc_has_dma(asc)) { aspeed_smc_dma_setup(s, errp); } + + /* WDT2 support */ + if (aspeed_smc_has_wdt_control(asc)) { + aspeed_smc_wdt_setup(s, errp); + } } static const VMStateDescription vmstate_aspeed_smc = { @@ -1208,6 +1280,8 @@ static Property aspeed_smc_properties[] = { DEFINE_PROP_BOOL("inject-failure", AspeedSMCState, inject_failure, false), DEFINE_PROP_LINK("dram", AspeedSMCState, dram_mr, TYPE_MEMORY_REGION, MemoryRegion *), + DEFINE_PROP_LINK("wdt2", AspeedSMCState, wdt2_mr, + TYPE_MEMORY_REGION, MemoryRegion *), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/ssi/trace-events b/hw/ssi/trace-events index 612d3d6087aa..0de79bf9c6a5 100644 --- a/hw/ssi/trace-events +++ b/hw/ssi/trace-events @@ -9,6 +9,7 @@ aspeed_smc_dma_checksum(uint32_t addr, uint32_t data) "0x%08x: 0x%08x" aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint32_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%08x size:0x%08x" aspeed_smc_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64 aspeed_smc_flash_select(int cs, const char *prefix) "CS%d %sselect" +aspeed_smc_wdt2_enable(const char *prefix) "WDT2 is %sabled" # npcm7xx_fiu.c -- 2.31.1