qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

watchdog: wdt_aspeed: Add support for the reset width register

The reset width register controls how the pulse on the SoC's WDTRST{1,2}
pins behaves. A pulse is emitted if the external reset bit is set in
WDT_CTRL. On the AST2500 WDT_RESET_WIDTH can consume magic bit patterns
to configure push-pull/open-drain and active-high/active-low
behaviours and thus needs some special handling in the write path.

As some of the capabilities depend on the SoC version a silicon-rev
property is introduced, which is used to guard version-specific
behaviour.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Andrew Jeffery and committed by
Peter Maydell
f55d613b b2bfe9f7

+84 -11
+82 -11
hw/watchdog/wdt_aspeed.c
··· 8 8 */ 9 9 10 10 #include "qemu/osdep.h" 11 + 12 + #include "qapi/error.h" 11 13 #include "qemu/log.h" 14 + #include "qemu/timer.h" 12 15 #include "sysemu/watchdog.h" 16 + #include "hw/misc/aspeed_scu.h" 13 17 #include "hw/sysbus.h" 14 - #include "qemu/timer.h" 15 18 #include "hw/watchdog/wdt_aspeed.h" 16 19 17 - #define WDT_STATUS (0x00 / 4) 18 - #define WDT_RELOAD_VALUE (0x04 / 4) 19 - #define WDT_RESTART (0x08 / 4) 20 - #define WDT_CTRL (0x0C / 4) 20 + #define WDT_STATUS (0x00 / 4) 21 + #define WDT_RELOAD_VALUE (0x04 / 4) 22 + #define WDT_RESTART (0x08 / 4) 23 + #define WDT_CTRL (0x0C / 4) 21 24 #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5) 22 25 #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) 23 26 #define WDT_CTRL_1MHZ_CLK BIT(4) ··· 25 28 #define WDT_CTRL_WDT_INTR BIT(2) 26 29 #define WDT_CTRL_RESET_SYSTEM BIT(1) 27 30 #define WDT_CTRL_ENABLE BIT(0) 31 + #define WDT_RESET_WIDTH (0x18 / 4) 32 + #define WDT_RESET_WIDTH_ACTIVE_HIGH BIT(31) 33 + #define WDT_POLARITY_MASK (0xFF << 24) 34 + #define WDT_ACTIVE_HIGH_MAGIC (0xA5 << 24) 35 + #define WDT_ACTIVE_LOW_MAGIC (0x5A << 24) 36 + #define WDT_RESET_WIDTH_PUSH_PULL BIT(30) 37 + #define WDT_DRIVE_TYPE_MASK (0xFF << 24) 38 + #define WDT_PUSH_PULL_MAGIC (0xA8 << 24) 39 + #define WDT_OPEN_DRAIN_MAGIC (0x8A << 24) 28 40 29 - #define WDT_TIMEOUT_STATUS (0x10 / 4) 30 - #define WDT_TIMEOUT_CLEAR (0x14 / 4) 31 - #define WDT_RESET_WDITH (0x18 / 4) 41 + #define WDT_TIMEOUT_STATUS (0x10 / 4) 42 + #define WDT_TIMEOUT_CLEAR (0x14 / 4) 32 43 33 - #define WDT_RESTART_MAGIC 0x4755 44 + #define WDT_RESTART_MAGIC 0x4755 34 45 35 46 static bool aspeed_wdt_is_enabled(const AspeedWDTState *s) 36 47 { 37 48 return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE; 38 49 } 39 50 51 + static bool is_ast2500(const AspeedWDTState *s) 52 + { 53 + switch (s->silicon_rev) { 54 + case AST2500_A0_SILICON_REV: 55 + case AST2500_A1_SILICON_REV: 56 + return true; 57 + case AST2400_A0_SILICON_REV: 58 + case AST2400_A1_SILICON_REV: 59 + default: 60 + break; 61 + } 62 + 63 + return false; 64 + } 65 + 40 66 static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) 41 67 { 42 68 AspeedWDTState *s = ASPEED_WDT(opaque); ··· 55 81 return 0; 56 82 case WDT_CTRL: 57 83 return s->regs[WDT_CTRL]; 84 + case WDT_RESET_WIDTH: 85 + return s->regs[WDT_RESET_WIDTH]; 58 86 case WDT_TIMEOUT_STATUS: 59 87 case WDT_TIMEOUT_CLEAR: 60 - case WDT_RESET_WDITH: 61 88 qemu_log_mask(LOG_UNIMP, 62 89 "%s: uninmplemented read at offset 0x%" HWADDR_PRIx "\n", 63 90 __func__, offset); ··· 119 146 timer_del(s->timer); 120 147 } 121 148 break; 149 + case WDT_RESET_WIDTH: 150 + { 151 + uint32_t property = data & WDT_POLARITY_MASK; 152 + 153 + if (property && is_ast2500(s)) { 154 + if (property == WDT_ACTIVE_HIGH_MAGIC) { 155 + s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_ACTIVE_HIGH; 156 + } else if (property == WDT_ACTIVE_LOW_MAGIC) { 157 + s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_ACTIVE_HIGH; 158 + } else if (property == WDT_PUSH_PULL_MAGIC) { 159 + s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_PUSH_PULL; 160 + } else if (property == WDT_OPEN_DRAIN_MAGIC) { 161 + s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_PUSH_PULL; 162 + } 163 + } 164 + s->regs[WDT_RESET_WIDTH] &= ~s->ext_pulse_width_mask; 165 + s->regs[WDT_RESET_WIDTH] |= data & s->ext_pulse_width_mask; 166 + break; 167 + } 122 168 case WDT_TIMEOUT_STATUS: 123 169 case WDT_TIMEOUT_CLEAR: 124 - case WDT_RESET_WDITH: 125 170 qemu_log_mask(LOG_UNIMP, 126 171 "%s: uninmplemented write at offset 0x%" HWADDR_PRIx "\n", 127 172 __func__, offset); ··· 167 212 s->regs[WDT_RELOAD_VALUE] = 0x03EF1480; 168 213 s->regs[WDT_RESTART] = 0; 169 214 s->regs[WDT_CTRL] = 0; 215 + s->regs[WDT_RESET_WIDTH] = 0xFF; 170 216 171 217 timer_del(s->timer); 172 218 } ··· 187 233 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 188 234 AspeedWDTState *s = ASPEED_WDT(dev); 189 235 236 + if (!is_supported_silicon_rev(s->silicon_rev)) { 237 + error_setg(errp, "Unknown silicon revision: 0x%" PRIx32, 238 + s->silicon_rev); 239 + return; 240 + } 241 + 242 + switch (s->silicon_rev) { 243 + case AST2400_A0_SILICON_REV: 244 + case AST2400_A1_SILICON_REV: 245 + s->ext_pulse_width_mask = 0xff; 246 + break; 247 + case AST2500_A0_SILICON_REV: 248 + case AST2500_A1_SILICON_REV: 249 + s->ext_pulse_width_mask = 0xfffff; 250 + break; 251 + default: 252 + g_assert_not_reached(); 253 + } 254 + 190 255 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev); 191 256 192 257 /* FIXME: This setting should be derived from the SCU hw strapping ··· 199 264 sysbus_init_mmio(sbd, &s->iomem); 200 265 } 201 266 267 + static Property aspeed_wdt_properties[] = { 268 + DEFINE_PROP_UINT32("silicon-rev", AspeedWDTState, silicon_rev, 0), 269 + DEFINE_PROP_END_OF_LIST(), 270 + }; 271 + 202 272 static void aspeed_wdt_class_init(ObjectClass *klass, void *data) 203 273 { 204 274 DeviceClass *dc = DEVICE_CLASS(klass); ··· 207 277 dc->reset = aspeed_wdt_reset; 208 278 set_bit(DEVICE_CATEGORY_MISC, dc->categories); 209 279 dc->vmsd = &vmstate_aspeed_wdt; 280 + dc->props = aspeed_wdt_properties; 210 281 } 211 282 212 283 static const TypeInfo aspeed_wdt_info = {
+2
include/hw/watchdog/wdt_aspeed.h
··· 27 27 uint32_t regs[ASPEED_WDT_REGS_MAX]; 28 28 29 29 uint32_t pclk_freq; 30 + uint32_t silicon_rev; 31 + uint32_t ext_pulse_width_mask; 30 32 } AspeedWDTState; 31 33 32 34 #endif /* ASPEED_WDT_H */