qemu/hw/watchdog/xlnx-versal-wwdt.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the WWDT Registers for the WWDT
   3 *
   4 * Copyright (c) 2020 Xilinx Inc.
   5 *
   6 * Autogenerated by xregqemu.py 2020-12-10.
   7 * Written by Joe Komlodi <komlodi@xilinx.com>
   8 *
   9 * Permission is hereby granted, free of charge, to any person obtaining a copy
  10 * of this software and associated documentation files (the "Software"), to deal
  11 * in the Software without restriction, including without limitation the rights
  12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13 * copies of the Software, and to permit persons to whom the Software is
  14 * furnished to do so, subject to the following conditions:
  15 *
  16 * The above copyright notice and this permission notice shall be included in
  17 * all copies or substantial portions of the Software.
  18 *
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25 * THE SOFTWARE.
  26 */
  27
  28#include "qemu/osdep.h"
  29#include "hw/sysbus.h"
  30#include "hw/register.h"
  31#include "qemu/bitops.h"
  32#include "qemu/log.h"
  33#include "qemu/timer.h"
  34#include "qapi/error.h"
  35#include "migration/vmstate.h"
  36#include "hw/qdev-properties.h"
  37#include "hw/fdt_generic_util.h"
  38
  39#ifndef XILINX_WWDT_ERR_DEBUG
  40#define XILINX_WWDT_ERR_DEBUG 0
  41#endif
  42
  43#define DB_PRINT_L(level, ...) do {         \
  44    if (XILINX_WWDT_ERR_DEBUG > (level)) {  \
  45        fprintf(stderr,  "%s: ", __func__); \
  46        fprintf(stderr, ## __VA_ARGS__);    \
  47    }                                       \
  48} while (0)
  49
  50#define TYPE_XILINX_WWDT "xlnx,versal-wwdt"
  51
  52/* Masks for LBE field in ENABLE_AND_STATUS_REG */
  53/* Basic WWDT mode */
  54#define LBE_BASIC_NO_BAD_EVENT_MASK 0x0
  55#define LBE_KICK_IN_FIRST_WINDOW_MASK 0x1
  56#define LBE_TSR_MISMATCH_MASK 0x2
  57#define LBE_SECOND_WINDOW_TIMEOUT_MASK 0x3
  58/* Q&A WWDT mode */
  59#define LBE_QA_NO_BAD_EVENT_MASK 0x4
  60#define LBE_TOKEN_EARLY_MASK 0x5
  61#define LBE_TOKEN_ERROR_MASK 0x6
  62#define LBE_TIMEOUT_MASK 0x7
  63
  64#define INC_AND_ROLLOVER(num, max) do { \
  65    if (num == max) {                   \
  66        num = 0;                        \
  67    } else {                            \
  68        ++num;                          \
  69    }                                   \
  70} while (0)
  71
  72#define XLNX_WWDT(obj) \
  73     OBJECT_CHECK(WWDT, (obj), TYPE_XILINX_WWDT)
  74
  75REG32(MASTER_WRITE_CONTROL_REG, 0x0)
  76    FIELD(MASTER_WRITE_CONTROL_REG, MWC, 0, 1)
  77REG32(ENABLE_AND_STATUS_REG, 0x4)
  78    FIELD(ENABLE_AND_STATUS_REG, LBE, 24, 3)
  79    FIELD(ENABLE_AND_STATUS_REG, FCV, 20, 3)
  80    FIELD(ENABLE_AND_STATUS_REG, WRP, 17, 1)
  81    FIELD(ENABLE_AND_STATUS_REG, WINT, 16, 1)
  82    FIELD(ENABLE_AND_STATUS_REG, ACNT, 14, 2)
  83    FIELD(ENABLE_AND_STATUS_REG, TOUT, 12, 1)
  84    FIELD(ENABLE_AND_STATUS_REG, SERR, 11, 1)
  85    FIELD(ENABLE_AND_STATUS_REG, TERR, 10, 1)
  86    FIELD(ENABLE_AND_STATUS_REG, TERL, 9, 1)
  87    FIELD(ENABLE_AND_STATUS_REG, WSW, 8, 1)
  88    FIELD(ENABLE_AND_STATUS_REG, TVAL, 2, 4)
  89    FIELD(ENABLE_AND_STATUS_REG, WCFG, 1, 1)
  90    FIELD(ENABLE_AND_STATUS_REG, WEN, 0, 1)
  91REG32(FUNCTION_CONTROL_REG, 0x8)
  92    FIELD(FUNCTION_CONTROL_REG, SBC, 8, 8)
  93    FIELD(FUNCTION_CONTROL_REG, BSS, 6, 2)
  94    FIELD(FUNCTION_CONTROL_REG, SSTE, 4, 1)
  95    FIELD(FUNCTION_CONTROL_REG, PSME, 3, 1)
  96    FIELD(FUNCTION_CONTROL_REG, FCE, 2, 1)
  97    FIELD(FUNCTION_CONTROL_REG, WM, 1, 1)
  98    FIELD(FUNCTION_CONTROL_REG, WDP, 0, 1)
  99REG32(FIRST_WINDOW_CONFIG_REG, 0xc)
 100REG32(SECOND_WINDOW_CONFIG_REG, 0x10)
 101REG32(SST_WINDOW_CONFIG_REG, 0x14)
 102REG32(TASK_SIGNATURE_REG0, 0x18)
 103REG32(TASK_SIGNATURE_REG1, 0x1c)
 104REG32(SECOND_SEQ_TIMER_REG, 0x20)
 105REG32(TOKEN_FEEDBACK_REG, 0x24)
 106    FIELD(TOKEN_FEEDBACK_REG, FDBK, 8, 4)
 107    FIELD(TOKEN_FEEDBACK_REG, SEED, 0, 4)
 108REG32(TOKEN_RESPONSE_REG, 0x28)
 109    FIELD(TOKEN_RESPONSE_REG, ANS, 0, 8)
 110REG32(INTERRUPT_ENABLE_REG, 0x30)
 111    FIELD(INTERRUPT_ENABLE_REG, GWIEN, 2, 1)
 112    FIELD(INTERRUPT_ENABLE_REG, WRPEN, 1, 1)
 113    FIELD(INTERRUPT_ENABLE_REG, WINTEN, 0, 1)
 114REG32(INTERRUPT_DISABLE_REG, 0x34)
 115    FIELD(INTERRUPT_DISABLE_REG, GWID, 2, 1)
 116    FIELD(INTERRUPT_DISABLE_REG, WRPD, 1, 1)
 117    FIELD(INTERRUPT_DISABLE_REG, WINTD, 0, 1)
 118REG32(INTERRUPT_MASK_REG, 0x38)
 119    FIELD(INTERRUPT_MASK_REG, GWIM, 2, 1)
 120    FIELD(INTERRUPT_MASK_REG, WRPM, 1, 1)
 121    FIELD(INTERRUPT_MASK_REG, WINTM, 0, 1)
 122REG32(ECO, 0x3c)
 123REG32(GWDT_REFRESH_REG, 0x1000)
 124    FIELD(GWDT_REFRESH_REG, GWRR, 0, 1)
 125REG32(GWDT_CNTRL_STATUS_REG, 0x2000)
 126    FIELD(GWDT_CNTRL_STATUS_REG, GWS, 1, 2)
 127    FIELD(GWDT_CNTRL_STATUS_REG, GWEN, 0, 1)
 128REG32(GWDT_OFFSET_REG, 0x2008)
 129REG32(GWDT_COMPARE_VALUE_REG0, 0x2010)
 130REG32(GWDT_COMPARE_VALUE_REG1, 0x2014)
 131REG32(GWDT_WARM_RESET_REG, 0x2fd0)
 132    FIELD(GWDT_WARM_RESET_REG, GWWRR, 0, 1)
 133
 134#define WWDT_R_MAX (R_GWDT_WARM_RESET_REG + 1)
 135
 136typedef struct WWDT {
 137    SysBusDevice parent_obj;
 138    MemoryRegion iomem;
 139
 140    /* GWDT */
 141    QEMUTimer *gwdt_timer;
 142    qemu_irq gwdt_ws0;
 143    qemu_irq gwdt_ws1;
 144
 145    /* WWDT */
 146    QEMUTimer *wwdt_timer;
 147    QEMUTimer *wwdt_irq_timer;
 148    QEMUTimer *sst_timer;
 149    qemu_irq wwdt_reset_pending;
 150    qemu_irq wwdt_irq;
 151
 152    /* Both WWDT and GWDT */
 153    qemu_irq wwdt_reset;
 154
 155    /* WWDT Q&A state */
 156    uint8_t lfsr;
 157    bool wwdt_qa_running;
 158    uint8_t token_cnt;
 159    /* WWDT and WWDT Q&A state */
 160    bool window_2;
 161    bool wen;
 162
 163    uint64_t pclk;
 164    uint32_t regs[WWDT_R_MAX];
 165    RegisterInfo regs_info[WWDT_R_MAX];
 166} WWDT;
 167
 168static void gwdt_update_irq(WWDT *s)
 169{
 170    bool irq;
 171
 172    irq = ARRAY_FIELD_EX32(s->regs, GWDT_CNTRL_STATUS_REG, GWS) & 0x1;
 173    irq &= !ARRAY_FIELD_EX32(s->regs, INTERRUPT_MASK_REG, GWIM);
 174    qemu_set_irq(s->gwdt_ws0, irq);
 175    irq = ARRAY_FIELD_EX32(s->regs, GWDT_CNTRL_STATUS_REG, GWS) & 0x2;
 176    qemu_set_irq(s->gwdt_ws1, irq);
 177}
 178
 179static uint32_t gwdt_reload_val(WWDT *s)
 180{
 181    return s->regs[R_GWDT_OFFSET_REG];
 182}
 183
 184static uint64_t gwdt_next_trigger(WWDT *s)
 185{
 186    uint64_t next = muldiv64(1000000000,
 187                             gwdt_reload_val(s),
 188                             s->pclk);
 189
 190    return next + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 191}
 192
 193static void gwdt_time_elapsed(void *opaque)
 194{
 195    WWDT *s = XLNX_WWDT(opaque);
 196    uint8_t window = ARRAY_FIELD_EX32(s->regs, GWDT_CNTRL_STATUS_REG, GWS);
 197
 198    switch (window) {
 199    case 0:
 200        ++window;
 201        ARRAY_FIELD_DP32(s->regs, GWDT_CNTRL_STATUS_REG, GWS, 1);
 202        gwdt_update_irq(s);
 203        break;
 204    case 1:
 205        ++window;
 206        ARRAY_FIELD_DP32(s->regs, GWDT_CNTRL_STATUS_REG, GWS, 3);
 207        gwdt_update_irq(s);
 208        /* Reset on second window timeout */
 209        qemu_set_irq(s->wwdt_reset, 1);
 210        break;
 211    case 2:
 212    case 3:
 213        /* Lines stay the same, value in GWS field stays the same */
 214        break;
 215    default:
 216        g_assert_not_reached();
 217    }
 218
 219    timer_mod(s->gwdt_timer, gwdt_next_trigger(s));
 220}
 221
 222static void gwdt_refresh_reg_postw(RegisterInfo *reg, uint64_t val64)
 223{
 224    WWDT *s = XLNX_WWDT(reg->opaque);
 225
 226    timer_mod(s->gwdt_timer, gwdt_next_trigger(s));
 227    /* Read as zero */
 228    s->regs[R_GWDT_REFRESH_REG] = 0;
 229
 230    ARRAY_FIELD_DP32(s->regs, GWDT_CNTRL_STATUS_REG, GWS, 0);
 231    gwdt_update_irq(s);
 232}
 233
 234static void gwdt_cntrl_status_reg_postw(RegisterInfo *reg, uint64_t val64)
 235{
 236    WWDT *s = XLNX_WWDT(reg->opaque);
 237
 238    if (FIELD_EX64(val64, GWDT_CNTRL_STATUS_REG, GWEN)) {
 239        timer_mod(s->gwdt_timer, gwdt_next_trigger(s));
 240    } else {
 241        timer_del(s->gwdt_timer);
 242        ARRAY_FIELD_DP32(s->regs, GWDT_CNTRL_STATUS_REG, GWS, 0);
 243        gwdt_update_irq(s);
 244    }
 245}
 246
 247static void gwdt_warm_reset_reg_postw(RegisterInfo *reg, uint64_t val64)
 248{
 249    WWDT *s = XLNX_WWDT(reg->opaque);
 250
 251    register_reset(&s->regs_info[R_GWDT_REFRESH_REG]);
 252    register_reset(&s->regs_info[R_GWDT_CNTRL_STATUS_REG]);
 253    register_reset(&s->regs_info[R_GWDT_OFFSET_REG]);
 254    register_reset(&s->regs_info[R_GWDT_COMPARE_VALUE_REG0]);
 255    register_reset(&s->regs_info[R_GWDT_COMPARE_VALUE_REG1]);
 256    /* Read as 0 */
 257    s->regs[R_GWDT_WARM_RESET_REG] = 0;
 258    gwdt_update_irq(s);
 259}
 260
 261static void wwdt_update_irq(WWDT *s)
 262{
 263    bool irq;
 264
 265    irq = ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, WINT);
 266    irq &= !ARRAY_FIELD_EX32(s->regs, INTERRUPT_MASK_REG, WINTM);
 267    qemu_set_irq(s->wwdt_irq, irq);
 268    irq = ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, WRP);
 269    irq &= !ARRAY_FIELD_EX32(s->regs, INTERRUPT_MASK_REG, WRPM);
 270    qemu_set_irq(s->wwdt_reset_pending, irq);
 271}
 272
 273static void wwdt_do_reset(WWDT *s)
 274{
 275    qemu_set_irq(s->wwdt_reset, 1);
 276     /* After generating wwdt_reset, WWDT stops running and WEN auto clears. */
 277    timer_del(s->wwdt_timer);
 278    ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WEN, 0);
 279}
 280
 281static void wwdt_sst_time_elapsed(void *opaque)
 282{
 283    WWDT *s = XLNX_WWDT(opaque);
 284    wwdt_do_reset(s);
 285}
 286static uint32_t wwdt_sst_reload_val(WWDT *s)
 287{
 288    return s->regs[R_SECOND_SEQ_TIMER_REG];
 289}
 290
 291static uint64_t wwdt_sst_next_trigger(WWDT *s)
 292{
 293    uint64_t next = muldiv64(1000000000,
 294                             wwdt_sst_reload_val(s),
 295                             s->pclk);
 296
 297    return next + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 298}
 299
 300static void wwdt_sst_start(WWDT *s)
 301{
 302    bool rp_en = !ARRAY_FIELD_EX32(s->regs, INTERRUPT_MASK_REG, WRPM);
 303    if (rp_en) {
 304        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WRP, 1);
 305        wwdt_update_irq(s);
 306    }
 307    timer_mod(s->sst_timer, wwdt_sst_next_trigger(s));
 308}
 309
 310static void wwdt_reset_event(WWDT *s)
 311{
 312    bool sst_en = ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, SSTE);
 313    if (sst_en) {
 314        wwdt_sst_start(s);
 315    } else {
 316        wwdt_do_reset(s);
 317    }
 318}
 319
 320static void wwdt_good_event(WWDT *s)
 321{
 322    bool count_en = ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, FCE);
 323    bool is_qa = ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, WM);
 324
 325    if (count_en || is_qa) {
 326        uint8_t count = ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, FCV);
 327        if (count) {
 328            --count;
 329            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, FCV, count);
 330        }
 331    }
 332}
 333
 334static void wwdt_bad_event(WWDT *s)
 335{
 336    bool count_en = ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, FCE);
 337    bool is_qa = ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, WM);
 338
 339    /* Fail counter is always enabled in Q&A mode */
 340    if (count_en || is_qa) {
 341        uint8_t count = ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, FCV);
 342        /* Bad event counter maxed out, do a reset */
 343        if (count == 7) {
 344            wwdt_reset_event(s);
 345        } else {
 346            ++count;
 347            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, FCV, count);
 348        }
 349    } else {
 350        wwdt_reset_event(s);
 351    }
 352}
 353
 354static void wwdt_irq_time_elapsed(void *opaque)
 355{
 356    WWDT *s = XLNX_WWDT(opaque);
 357
 358    DB_PRINT_L(0, "WWDT SBC and BSS mask matched, asserting IRQ.\n");
 359    ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WINT, 1);
 360    wwdt_update_irq(s);
 361}
 362
 363static uint32_t wwdt_irq_reload_val(WWDT *s, bool *success)
 364{
 365    uint32_t shift = 1 << (ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG,
 366                                            BSS) * 8);
 367    uint32_t val = ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, SBC) <<
 368                                    shift;
 369    /* Make sure WINT can actually trigger within the second window */
 370    if (val > s->regs[R_SECOND_WINDOW_CONFIG_REG]) {
 371        success = false;
 372        qemu_log_mask(LOG_GUEST_ERROR, "%s: WINT is set to trigger after "
 373                      "second window expires.\nSBC=0x%x BSS=0x%x window=0x%x\n",
 374                      object_get_canonical_path(OBJECT(s)),
 375                      ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, SBC),
 376                      ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, BSS),
 377                      s->regs[R_SECOND_WINDOW_CONFIG_REG]);
 378    } else {
 379        *success = true;
 380    }
 381
 382    return val;
 383}
 384
 385static uint64_t wwdt_irq_next_trigger(WWDT *s, bool *success)
 386{
 387    uint64_t next = muldiv64(1000000000,
 388                             wwdt_irq_reload_val(s, success),
 389                             s->pclk);
 390
 391    return next + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 392}
 393
 394/*
 395 * Hardware triggers WINT when the WWDT timer has a certain amount of bits
 396 * masked, specified by BSS and SBC.
 397 * An equivalent way to do this is to create another timer with the value of
 398 * SBC shifted by BSS.
 399 * We use another timer so the WWDT timer can continue to tick while WINT
 400 * is set and the IRQ is asserted.
 401 */
 402static void wwdt_irq_timer_start(WWDT *s)
 403{   uint64_t trigger;
 404    bool success;
 405
 406    trigger = wwdt_irq_next_trigger(s, &success);
 407    if (success) {
 408        DB_PRINT_L(0, "Starting interrupt timer\n");
 409        timer_mod(s->wwdt_irq_timer, trigger);
 410    }
 411}
 412
 413static uint32_t wwdt_reload_val(WWDT *s)
 414{
 415    if (s->window_2) {
 416        return s->regs[R_SECOND_WINDOW_CONFIG_REG];
 417    } else {
 418        return s->regs[R_FIRST_WINDOW_CONFIG_REG];
 419    }
 420}
 421
 422static uint64_t wwdt_next_trigger(WWDT *s)
 423{
 424    uint64_t next = muldiv64(1000000000,
 425                             wwdt_reload_val(s),
 426                             s->pclk);
 427
 428    return next + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 429}
 430
 431static void wwdt_qa_gen_token(WWDT *s)
 432{
 433    uint8_t fdbk = ARRAY_FIELD_EX32(s->regs, TOKEN_FEEDBACK_REG, FDBK);
 434    uint8_t token;
 435
 436    switch (fdbk & 0x3) {
 437    case 0x0:
 438    case 0x3:
 439        token = !!((s->lfsr & 0x2) ^ (s->token_cnt & 0x2));
 440        token |= ((s->lfsr & 0x8) ^ (s->token_cnt & 0x8)) >> 2;
 441        token |= ((s->lfsr & 0x1) ^ (s->token_cnt & 0x1)) << 2;
 442        token |= ((s->lfsr & 0x4) ^ (s->token_cnt & 0x4)) << 1;
 443        break;
 444    case 0x1:
 445        token = !!((s->lfsr & 0x8) ^ (s->token_cnt & 0x8));
 446        token |= ((s->lfsr & 0x4) ^ (s->token_cnt & 0x4)) >> 1;
 447        token |= ((s->lfsr & 0x2) ^ (s->token_cnt & 0x2)) << 1;
 448        token |= ((s->lfsr & 0x1) ^ (s->token_cnt & 0x1)) << 3;
 449        break;
 450    case 0x2:
 451        token = !!((s->lfsr & 0x4) ^ (s->token_cnt & 0x4));
 452        token |= ((s->lfsr & 0x8) ^ (s->token_cnt & 0x8)) >> 2;
 453        token |= ((s->lfsr & 0x1) ^ (s->token_cnt & 0x1)) << 2;
 454        token |= ((s->lfsr & 0x2) ^ (s->token_cnt & 0x2)) << 2;
 455        break;
 456    }
 457    DB_PRINT_L(0, "Generated question token 0x%x\n", token);
 458
 459    ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, TVAL, token);
 460}
 461
 462static void wwdt_qa_timer_start(WWDT *s)
 463{
 464    /* First time starting the timer, set initial values. */
 465    if (!s->wwdt_qa_running) {
 466        s->lfsr = ARRAY_FIELD_EX32(s->regs, TOKEN_FEEDBACK_REG, SEED);
 467        s->token_cnt = 1;
 468        s->wwdt_qa_running = true;
 469        wwdt_qa_gen_token(s);
 470    }
 471
 472    ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, ACNT, 3);
 473
 474    DB_PRINT_L(0, "Starting first window timer\n");
 475    timer_mod(s->wwdt_timer, wwdt_next_trigger(s));
 476}
 477
 478static void wwdt_qa_time_elapsed(WWDT *s)
 479{
 480    /* Second window timeout is always bad */
 481    if (s->window_2) {
 482        DB_PRINT_L(0, "Second window timeout\n");
 483        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 484                         LBE_TIMEOUT_MASK);
 485        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, TOUT, 1);
 486        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WSW, 0);
 487        s->window_2 = false;
 488
 489        wwdt_bad_event(s);
 490        wwdt_qa_timer_start(s);
 491    } else {
 492        /* Error if we didn't get 3 correct answers in the first window. */
 493        if (ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, ACNT) != 2) {
 494            DB_PRINT_L(0, "First window timeout\n");
 495            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 496                             LBE_TIMEOUT_MASK);
 497            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, TOUT, 1);
 498            wwdt_bad_event(s);
 499            wwdt_qa_timer_start(s);
 500        } else {
 501            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WSW, 1);
 502            s->window_2 = true;
 503
 504            wwdt_irq_timer_start(s);
 505            timer_mod(s->wwdt_timer, wwdt_next_trigger(s));
 506        }
 507    }
 508}
 509
 510static void wwdt_basic_time_elapsed(WWDT *s)
 511{
 512    if (s->window_2) {
 513        DB_PRINT_L(0, "Second window timeout\n");
 514        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 515                         LBE_SECOND_WINDOW_TIMEOUT_MASK);
 516        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, TOUT, 1);
 517        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WSW, 0);
 518        wwdt_bad_event(s);
 519        s->window_2 = false;
 520    } else {
 521        DB_PRINT_L(0, "Starting second window timer\n");
 522        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WSW, 1);
 523        s->window_2 = true;
 524
 525        wwdt_irq_timer_start(s);
 526    }
 527
 528    timer_mod(s->wwdt_timer, wwdt_next_trigger(s));
 529}
 530
 531static void wwdt_time_elapsed(void *opaque)
 532{
 533    WWDT *s = XLNX_WWDT(opaque);
 534    bool is_basic = !ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, WM);
 535
 536    DB_PRINT_L(0, "Time elapsed\n");
 537    if (is_basic) {
 538        wwdt_basic_time_elapsed(s);
 539    } else {
 540        wwdt_qa_time_elapsed(s);
 541    }
 542}
 543
 544static bool wwdt_basic_en(WWDT *s)
 545{
 546    bool success;
 547
 548    if (!s->regs[R_SECOND_WINDOW_CONFIG_REG]) {
 549        qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot run WWDT in basic mode "
 550                      "with second window set to 0\n",
 551                      object_get_canonical_path(OBJECT(s)));
 552        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WCFG, 1);
 553        success = false;
 554    } else {
 555        /* Block writes to WWDT when enabled. */
 556        ARRAY_FIELD_DP32(s->regs, MASTER_WRITE_CONTROL_REG, MWC, 0);
 557        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 558                         LBE_BASIC_NO_BAD_EVENT_MASK);
 559        DB_PRINT_L(0, "Starting first window timer\n");
 560        timer_mod(s->wwdt_timer, wwdt_next_trigger(s));
 561        s->wen = true;
 562        success = true;
 563    }
 564
 565    return success;
 566}
 567
 568static bool wwdt_qa_en(WWDT *s)
 569{
 570    bool success;
 571
 572    /*
 573     * Q&A mode timer isn't started until a separate write to TRR, however
 574     * we still block writes after WEN is set.
 575     */
 576    if (s->regs[R_SECOND_WINDOW_CONFIG_REG] &&
 577        s->regs[R_FIRST_WINDOW_CONFIG_REG]) {
 578        ARRAY_FIELD_DP32(s->regs, MASTER_WRITE_CONTROL_REG, MWC, 0);
 579        s->wen = true;
 580        success = true;
 581    } else {
 582        qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot run WWDT in Q&A mode "
 583                      "with either window set to 0\n",
 584                      object_get_canonical_path(OBJECT(s)));
 585        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WCFG, 1);
 586        success = false;
 587    }
 588
 589    return success;
 590}
 591
 592static bool wwdt_en(WWDT *s)
 593{
 594    bool is_basic = !ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, WM);
 595    bool success;
 596
 597    if (is_basic) {
 598        success = wwdt_basic_en(s);
 599    } else {
 600        success = wwdt_qa_en(s);
 601    }
 602    return success;
 603}
 604
 605static bool wwdt_tsr_check(WWDT *s)
 606{
 607    bool match = s->regs[R_TASK_SIGNATURE_REG0] ==
 608                 s->regs[R_TASK_SIGNATURE_REG1];
 609
 610    if (match) {
 611        wwdt_good_event(s);
 612    } else {
 613        wwdt_bad_event(s);
 614        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 615                         LBE_TSR_MISMATCH_MASK);
 616        qemu_log_mask(LOG_GUEST_ERROR, "%s: TSR mistmatch: TSR0=0x%x, "
 617                      "TSR1=0x%x\n", object_get_canonical_path(OBJECT(s)),
 618                      s->regs[R_TASK_SIGNATURE_REG0],
 619                      s->regs[R_TASK_SIGNATURE_REG1]);
 620    }
 621    return match;
 622}
 623
 624static void wwdt_basic_do_disable(WWDT *s)
 625{
 626    timer_del(s->wwdt_timer);
 627    s->wen = false;
 628    s->window_2 = false;
 629    ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WSW, 0);
 630}
 631
 632static bool wwdt_basic_disable(WWDT *s)
 633{
 634    bool success;
 635
 636    /* For basic WWDT, WEN can only be cleared in the second window */
 637    if (s->window_2) {
 638        bool psm_en = ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, PSME);
 639        if (psm_en) {
 640            if (wwdt_tsr_check(s)) {
 641                wwdt_basic_do_disable(s);
 642                success = true;
 643            } else {
 644                success = false;
 645            }
 646        } else {
 647            wwdt_basic_do_disable(s);
 648            success = true;
 649        }
 650    } else {
 651        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 652                         LBE_KICK_IN_FIRST_WINDOW_MASK);
 653        wwdt_bad_event(s);
 654        qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot clear WEN in first "
 655                      "window\n", object_get_canonical_path(OBJECT(s)));
 656        success = false;
 657    }
 658
 659    return success;
 660}
 661
 662static bool wwdt_qa_disable(WWDT *s)
 663{
 664    uint8_t fail_count = ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, FCV);
 665    bool success;
 666
 667    /* In Q&A WWDT, WEN can be cleared as long as FCV == 0 */
 668    if (!fail_count) {
 669        s->wwdt_qa_running = false;
 670        s->window_2 = false;
 671        timer_del(s->wwdt_timer);
 672        success = true;
 673        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WSW, 0);
 674    } else {
 675        wwdt_bad_event(s);
 676        qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot clear WEN if FCV is "
 677                      "non-zero\n", object_get_canonical_path(OBJECT(s)));
 678        success = false;
 679    }
 680    return success;
 681}
 682
 683static bool wwdt_disable(WWDT *s)
 684{
 685    bool is_basic = !ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, WM);
 686    bool success;
 687
 688    if (is_basic) {
 689        success = wwdt_basic_disable(s);
 690    } else {
 691        success = wwdt_qa_disable(s);
 692    }
 693    return success;
 694}
 695
 696static void wwdt_basic_do_kick(WWDT *s)
 697{
 698    DB_PRINT_L(0, "WDT kicked in second window\nRestarting in first window\n");
 699    wwdt_good_event(s);
 700    timer_mod(s->wwdt_timer, wwdt_next_trigger(s));
 701    s->window_2 = false;
 702    ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WSW, 0);
 703}
 704
 705static void wwdt_basic_kick(WWDT *s)
 706{
 707    bool wsw_set = ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, WSW);
 708
 709    /* Kick in first window */
 710    if (!s->window_2 && wsw_set) {
 711        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 712                         LBE_KICK_IN_FIRST_WINDOW_MASK);
 713        wwdt_bad_event(s);
 714
 715        qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot reset WDT in first "
 716                      "window\n", object_get_canonical_path(OBJECT(s)));
 717    /* Kick in second window */
 718    } else if (s->window_2 && !wsw_set) {
 719        bool psm_en = ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, PSME);
 720        if (psm_en) {
 721            if (wwdt_tsr_check(s)) {
 722                wwdt_basic_do_kick(s);
 723            }
 724        } else {
 725            wwdt_basic_do_kick(s);
 726        }
 727    }
 728}
 729
 730static uint8_t wwdt_qa_gen_ans(WWDT *s)
 731{
 732    uint8_t acnt = ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, ACNT);
 733    uint8_t token = ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, TVAL);
 734    uint8_t fdbk = ARRAY_FIELD_EX32(s->regs, TOKEN_FEEDBACK_REG, FDBK);
 735    uint8_t ans;
 736
 737    INC_AND_ROLLOVER(acnt, 3);
 738
 739    fdbk >>= 2;
 740    switch (fdbk) {
 741    case 0x0:
 742        ans = (token & 0x1) ^ !!(acnt & 0x2) ^ !!(token & 0x8);
 743        ans |= ((token & 0x1) ^ !!(acnt & 0x2) ^ !!(token & 0x4) ^
 744               !!(token & 0x2)) << 1;
 745        ans |= ((token & 0x1) ^ !!(acnt & 0x2) ^ !!(token & 0x8) ^
 746               !!(token & 0x2)) << 2;
 747        ans |= (!!(token & 0x4) ^ !!(acnt & 0x2) ^ (token & 0x1) ^
 748               !!(token & 0x8)) << 3;
 749        ans |= ((token & 0x2) ^ (acnt & 0x1)) << 4;
 750        ans |= (!!(token & 0x8) ^ (acnt & 0x1)) << 5;
 751        ans |= ((token & 0x1) ^ (acnt & 0x1)) << 6;
 752        ans |= (!!(token & 0x4) ^ (acnt & 0x1)) << 7;
 753        break;
 754    case 0x1:
 755        ans = !!(token & 0x2) ^ !!(acnt & 0x2) ^ (token & 0x1);
 756        ans |= (!!(token & 0x2) ^ !!(acnt & 0x2) ^ (token & 0x1) ^
 757               !!(token & 0x2)) << 1;
 758        ans |= (!!(token & 0x2) ^ !!(acnt & 0x2) ^ (token & 0x1) ^
 759               !!(token & 0x2)) << 2;
 760        ans |= ((token & 0x1) ^ !!(acnt & 0x2) ^ !!(token & 0x2) ^
 761              !!(token & 0x8)) << 3;
 762        ans |= ((token & 0x1) ^ (acnt & 0x1)) << 4;
 763        ans |= ((token & 0x1) ^ (acnt & 0x1)) << 5;
 764        ans |= (!!(token & 0x2) ^ (acnt & 0x1)) << 6;
 765        ans |= ((token & 0x1) ^ (acnt & 0x1)) << 7;
 766        break;
 767    case 0x2:
 768        ans = !!(token & 0x4) ^ !!(acnt & 0x2) ^ !!(token & 0x2);
 769        ans |= (!!(token & 0x4) ^ !!(acnt & 0x2) ^ !!(token & 0x2) ^
 770               !!(token & 0x2)) << 1;
 771        ans |= (!!(token & 0x4) ^ !!(acnt & 0x2) ^ !!(token & 0x2) ^
 772              !!(token & 0x2)) << 2;
 773        ans |= (!!(token & 0x2) ^ !!(acnt & 0x2) ^ !!(token & 0x4) ^
 774              !!(token & 0x8)) << 3;
 775        ans |= (!!(token & 0x4) ^ (acnt & 0x1)) << 4;
 776        ans |= (!!(token & 0x2) ^ (acnt & 0x1)) << 5;
 777        ans |= (!!(token & 0x4) ^ (acnt & 0x1)) << 6;
 778        ans |= (!!(token & 0x2) ^ (acnt & 0x1)) << 7;
 779        break;
 780    case 0x3:
 781        ans = !!(token & 0x8) ^ !!(acnt & 0x2) ^ !!(token & 0x4);
 782        ans |= (!!(token & 0x8) ^ !!(acnt & 0x2) ^ !!(token & 0x8) ^
 783               !!(token & 0x2)) << 1;
 784        ans |= (!!(token & 0x8) ^ !!(acnt & 0x2) ^ !!(token & 0x4) ^
 785               !!(token & 0x2)) << 2;
 786        ans |= (!!(token & 0x8) ^ !!(acnt & 0x2) ^ !!(token & 0x8) ^
 787               !!(token & 0x8)) << 3;
 788        ans |= (!!(token & 0x8) ^ (acnt & 0x1)) << 4;
 789        ans |= (!!(token & 0x4) ^ (acnt & 0x1)) << 5;
 790        ans |= (!!(token & 0x8) ^ (acnt & 0x1)) << 6;
 791        ans |= (!!(token & 0x4) ^ (acnt & 0x1)) << 7;
 792        break;
 793    }
 794
 795    DB_PRINT_L(0, "Generated answer 0x%x\n", ans);
 796
 797    return ans;
 798}
 799
 800static void wwdt_qa_next_token(WWDT *s)
 801{
 802    s->lfsr = ((!!((s->lfsr & 0x4) | (s->lfsr & 0x2))) |
 803              ((s->lfsr & 0x1) << 2) |
 804              (((s->lfsr & 0x8) ^ (s->lfsr & 0x4)) << 3));
 805    INC_AND_ROLLOVER(s->token_cnt, 0x0f);
 806    wwdt_qa_gen_token(s);
 807}
 808
 809static void wwdt_qa_answer_match(WWDT *s)
 810{
 811    uint8_t acnt = ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, ACNT);
 812
 813    ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, TERR, 0);
 814    /* If this is the 4th write, it's only valid in the 2nd window */
 815    if (acnt == 2) {
 816        if (s->window_2) {
 817            /* Restart WWDT to first window. LBE status is also reset. */
 818            s->window_2 = false;
 819            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WSW, 0);
 820            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, SERR, 0);
 821            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, TERL, 0);
 822            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 823                             LBE_QA_NO_BAD_EVENT_MASK);
 824            wwdt_good_event(s);
 825            wwdt_qa_next_token(s);
 826            wwdt_qa_timer_start(s);
 827        } else {
 828            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 829                             LBE_TOKEN_EARLY_MASK);
 830            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, SERR, 1);
 831            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, TERL, 1);
 832            wwdt_bad_event(s);
 833        }
 834    } else {
 835        INC_AND_ROLLOVER(acnt, 3);
 836
 837        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, ACNT, acnt);
 838        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, SERR, 0);
 839        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, TERL, 0);
 840    }
 841}
 842
 843static void wwdt_qa_answer_mismatch(WWDT *s)
 844{
 845    ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, SERR, 1);
 846    ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, TERR, 1);
 847    ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 848                     LBE_TOKEN_ERROR_MASK);
 849    wwdt_bad_event(s);
 850}
 851
 852static void wwdt_enable_and_status_reg_postw(RegisterInfo *reg, uint64_t val64)
 853{
 854    bool success;
 855    WWDT *s = XLNX_WWDT(reg->opaque);
 856    uint32_t val = (uint32_t)val64;
 857    bool wen_set = ARRAY_FIELD_EX32(s->regs, ENABLE_AND_STATUS_REG, WEN);
 858    bool is_basic = !ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, WM);
 859    bool wsw_clear = FIELD_EX32(val, ENABLE_AND_STATUS_REG, WSW);
 860
 861    /*
 862     * WSW is W1C, but the register API zeroes the write before prew or postw.
 863     * We need to know if the user is writing 1 or 0 to WSW to know if it's a
 864     * kick or not, so we make the field RW and W1C it manually.
 865     */
 866    if (wsw_clear) {
 867        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WSW, 0);
 868    } else {
 869        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WSW, s->window_2);
 870    }
 871
 872    if (!s->wen && wen_set) {
 873        success = wwdt_en(s);
 874        /* WEN is not set on a misconfiguration. */
 875        if (!success) {
 876            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WEN, 0);
 877        }
 878    } else if (s->wen && !wen_set) {
 879        success = wwdt_disable(s);
 880        /* WEN is not cleared if done in the wrong situation. */
 881        if (!success) {
 882            ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, WEN, 1);
 883        }
 884    }
 885
 886    if (is_basic && wsw_clear) {
 887        wwdt_basic_kick(s);
 888    } else if (wsw_clear) {
 889        qemu_log_mask(LOG_GUEST_ERROR, "%s: WSW is RO in Q&A mode.\n",
 890                      object_get_canonical_path(OBJECT(s)));
 891    }
 892
 893    wwdt_update_irq(s);
 894}
 895
 896static uint64_t wwdt_enable_and_status_reg_prew(RegisterInfo *reg,
 897                                                uint64_t val64)
 898{
 899    WWDT *s = XLNX_WWDT(reg->opaque);
 900    uint32_t val = (uint64_t)val64;
 901    bool wen_set = FIELD_EX32(val, ENABLE_AND_STATUS_REG, WEN);
 902    bool dis_prot = ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, WDP);
 903
 904    if (dis_prot) {
 905        if (s->wen && !wen_set) {
 906            qemu_log_mask(LOG_GUEST_ERROR, "%s: Cannot clear WEN when WDS is "
 907                          "set\n", object_get_canonical_path(OBJECT(s)));
 908            FIELD_DP32(val, ENABLE_AND_STATUS_REG, WEN, 1);
 909        }
 910    }
 911    return val;
 912}
 913
 914static void wwdt_token_response_reg_postw(RegisterInfo *reg, uint64_t val)
 915{
 916    WWDT *s = XLNX_WWDT(reg->opaque);
 917    bool is_basic = !ARRAY_FIELD_EX32(s->regs, FUNCTION_CONTROL_REG, WM);
 918    uint8_t expected_ans;
 919
 920    if (is_basic) {
 921        return;
 922    }
 923
 924    /* Start WWDT timer on first write. */
 925    if (!s->wwdt_qa_running) {
 926        ARRAY_FIELD_DP32(s->regs, ENABLE_AND_STATUS_REG, LBE,
 927                         LBE_QA_NO_BAD_EVENT_MASK);
 928        wwdt_qa_timer_start(s);
 929    /* Future writes to this register should be checked if they're correct. */
 930    } else {
 931        expected_ans = wwdt_qa_gen_ans(s);
 932        if (expected_ans == val) {
 933            wwdt_qa_answer_match(s);
 934        } else {
 935            wwdt_qa_answer_mismatch(s);
 936        }
 937    }
 938}
 939
 940static void wwdt_interrupt_enable_reg_postw(RegisterInfo *reg, uint64_t val64)
 941{
 942    WWDT *s = XLNX_WWDT(reg->opaque);
 943    uint32_t val = (uint32_t)val64;
 944
 945    val = ~val;
 946    s->regs[R_INTERRUPT_MASK_REG] &= ~val;
 947}
 948
 949static void wwdt_interrupt_disable_reg_postw(RegisterInfo *reg, uint64_t val64)
 950{
 951    WWDT *s = XLNX_WWDT(reg->opaque);
 952    uint32_t val = (uint32_t)val64;
 953
 954    s->regs[R_INTERRUPT_MASK_REG] |= val;
 955}
 956
 957static const RegisterAccessInfo wwdt_regs_info[] = {
 958    {   .name = "MASTER_WRITE_CONTROL_REG",  .addr = A_MASTER_WRITE_CONTROL_REG,
 959        .reset = 0x1,
 960        .rsvd = 0xfffffffe,
 961    },{ .name = "ENABLE_AND_STATUS_REG",  .addr = A_ENABLE_AND_STATUS_REG,
 962        .reset = 0x500000,
 963        .rsvd = 0xf88c20c0,
 964        .ro = 0x70de3c,
 965        .w1c = 0x7030002,
 966        .post_write = wwdt_enable_and_status_reg_postw,
 967        .pre_write = wwdt_enable_and_status_reg_prew,
 968    },{ .name = "FUNCTION_CONTROL_REG",  .addr = A_FUNCTION_CONTROL_REG,
 969        .rsvd = 0xffff0020,
 970    },{ .name = "FIRST_WINDOW_CONFIG_REG",  .addr = A_FIRST_WINDOW_CONFIG_REG,
 971    },{ .name = "SECOND_WINDOW_CONFIG_REG",  .addr = A_SECOND_WINDOW_CONFIG_REG,
 972    },{ .name = "SST_WINDOW_CONFIG_REG",  .addr = A_SST_WINDOW_CONFIG_REG,
 973    },{ .name = "TASK_SIGNATURE_REG0",  .addr = A_TASK_SIGNATURE_REG0,
 974    },{ .name = "TASK_SIGNATURE_REG1",  .addr = A_TASK_SIGNATURE_REG1,
 975    },{ .name = "SECOND_SEQ_TIMER_REG",  .addr = A_SECOND_SEQ_TIMER_REG,
 976        .ro = 0xffffffff,
 977    },{ .name = "TOKEN_FEEDBACK_REG",  .addr = A_TOKEN_FEEDBACK_REG,
 978        .rsvd = 0xfffff0f0,
 979    },{ .name = "TOKEN_RESPONSE_REG",  .addr = A_TOKEN_RESPONSE_REG,
 980        .rsvd = 0xffffff00,
 981        .post_write = wwdt_token_response_reg_postw,
 982    },{ .name = "INTERRUPT_ENABLE_REG",  .addr = A_INTERRUPT_ENABLE_REG,
 983        .rsvd = 0xfffffff8,
 984        .post_write = wwdt_interrupt_enable_reg_postw,
 985    },{ .name = "INTERRUPT_DISABLE_REG",  .addr = A_INTERRUPT_DISABLE_REG,
 986        .rsvd = 0xfffffff8,
 987        .post_write = wwdt_interrupt_disable_reg_postw,
 988    },{ .name = "INTERRUPT_MASK_REG",  .addr = A_INTERRUPT_MASK_REG,
 989        .reset = 0x2,
 990        .rsvd = 0xfffffff8,
 991        .ro = 0x7,
 992    },{ .name = "ECO",  .addr = A_ECO,
 993    },{ .name = "GWDT_REFRESH_REG",  .addr = A_GWDT_REFRESH_REG,
 994        .rsvd = 0xfffffffe,
 995        .post_write = gwdt_refresh_reg_postw,
 996    },{ .name = "GWDT_CNTRL_STATUS_REG",  .addr = A_GWDT_CNTRL_STATUS_REG,
 997        .rsvd = 0xfffffff8,
 998        .ro = 0x6,
 999        .post_write = gwdt_cntrl_status_reg_postw,
1000    },{ .name = "GWDT_OFFSET_REG",  .addr = A_GWDT_OFFSET_REG,
1001    },{ .name = "GWDT_COMPARE_VALUE_REG0",  .addr = A_GWDT_COMPARE_VALUE_REG0,
1002    },{ .name = "GWDT_COMPARE_VALUE_REG1",  .addr = A_GWDT_COMPARE_VALUE_REG1,
1003    },{ .name = "GWDT_WARM_RESET_REG",  .addr = A_GWDT_WARM_RESET_REG,
1004        .rsvd = 0xfffffffe,
1005        .post_write = gwdt_warm_reset_reg_postw,
1006    }
1007};
1008
1009static void wwdt_reset(DeviceState *dev)
1010{
1011    WWDT *s = XLNX_WWDT(dev);
1012    uint32_t i;
1013
1014    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
1015        register_reset(&s->regs_info[i]);
1016    }
1017    s->lfsr = 0;
1018    s->token_cnt = 0;
1019    s->wwdt_qa_running = false;
1020}
1021
1022static WWDT *wwdt_from_mr(void *mr_accessor)
1023{
1024    RegisterInfoArray *reg_array = mr_accessor;
1025    Object *obj;
1026
1027    assert(reg_array != NULL);
1028
1029    obj = reg_array->mem.owner;
1030    assert(obj);
1031
1032    return XLNX_WWDT(obj);
1033}
1034
1035static MemTxResult wwdt_write(void *opaque, hwaddr addr, uint64_t val,
1036                              unsigned size, MemTxAttrs attrs)
1037{
1038    WWDT *s = wwdt_from_mr(opaque);
1039    bool locked = !ARRAY_FIELD_EX32(s->regs, MASTER_WRITE_CONTROL_REG, MWC);
1040
1041    /* MWC reg and GWDT address space cannot be locked */
1042    if (locked && (addr > A_MASTER_WRITE_CONTROL_REG &&
1043                   addr < A_GWDT_REFRESH_REG)) {
1044        qemu_log_mask(LOG_GUEST_ERROR, "%s: Accessing locked register "
1045                      "0x%"HWADDR_PRIx"\n",
1046                      object_get_canonical_path(OBJECT(s)), addr);
1047        return MEMTX_ERROR;
1048    }
1049
1050    register_write_memory(opaque, addr, val, size);
1051    return MEMTX_OK;
1052}
1053
1054static const MemoryRegionOps wwdt_ops = {
1055    .read = register_read_memory,
1056    .write_with_attrs = wwdt_write,
1057    .endianness = DEVICE_LITTLE_ENDIAN,
1058    .valid = {
1059        .min_access_size = 4,
1060        .max_access_size = 4,
1061    },
1062};
1063
1064static void wwdt_realize(DeviceState *dev, Error **errp)
1065{
1066    WWDT *s = XLNX_WWDT(dev);
1067
1068    if (!s->pclk) {
1069        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "pclk");
1070    }
1071}
1072
1073static void wwdt_init(Object *obj)
1074{
1075    WWDT *s = XLNX_WWDT(obj);
1076    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1077    RegisterInfoArray *reg_array;
1078
1079    memory_region_init(&s->iomem, obj, TYPE_XILINX_WWDT, WWDT_R_MAX * 4);
1080    reg_array =
1081        register_init_block32(DEVICE(obj), wwdt_regs_info,
1082                              ARRAY_SIZE(wwdt_regs_info),
1083                              s->regs_info, s->regs,
1084                              &wwdt_ops,
1085                              XILINX_WWDT_ERR_DEBUG,
1086                              WWDT_R_MAX * 4);
1087    memory_region_add_subregion(&s->iomem,
1088                                0x0,
1089                                &reg_array->mem);
1090    sysbus_init_mmio(sbd, &s->iomem);
1091
1092    /* Order must match the order in DTS */
1093    sysbus_init_irq(sbd, &s->wwdt_irq);
1094    sysbus_init_irq(sbd, &s->wwdt_reset_pending);
1095    sysbus_init_irq(sbd, &s->gwdt_ws0);
1096    sysbus_init_irq(sbd, &s->gwdt_ws1);
1097
1098    qdev_init_gpio_out_named(DEVICE(obj), &s->wwdt_reset, "reset-out", 1);
1099
1100    s->gwdt_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, gwdt_time_elapsed, s);
1101    s->wwdt_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, wwdt_time_elapsed, s);
1102    s->wwdt_irq_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, wwdt_irq_time_elapsed,
1103                                     s);
1104    s->sst_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, wwdt_sst_time_elapsed, s);
1105}
1106
1107static Property wwdt_properties[] = {
1108    DEFINE_PROP_UINT64("pclk", WWDT, pclk, 0),
1109    DEFINE_PROP_END_OF_LIST(),
1110};
1111
1112static const FDTGenericGPIOSet wwdt_client_gpios[] = {
1113    {
1114        .names = &fdt_generic_gpio_name_set_gpio,
1115        .gpios = (FDTGenericGPIOConnection[]) {
1116            { .name = "reset-out", .fdt_index = 0, .range = 1 },
1117            { },
1118        }
1119    },
1120    { },
1121};
1122
1123static const VMStateDescription vmstate_wwdt = {
1124    .name = TYPE_XILINX_WWDT,
1125    .version_id = 1,
1126    .minimum_version_id = 1,
1127    .fields = (VMStateField[]) {
1128        VMSTATE_UINT32_ARRAY(regs, WWDT, WWDT_R_MAX),
1129        VMSTATE_END_OF_LIST(),
1130    }
1131};
1132
1133static void wwdt_class_init(ObjectClass *klass, void *data)
1134{
1135    DeviceClass *dc = DEVICE_CLASS(klass);
1136    FDTGenericGPIOClass *fggc = FDT_GENERIC_GPIO_CLASS(klass);
1137
1138    dc->reset = wwdt_reset;
1139    dc->realize = wwdt_realize;
1140    dc->vmsd = &vmstate_wwdt;
1141    device_class_set_props(dc, wwdt_properties);
1142    fggc->client_gpios = wwdt_client_gpios;
1143}
1144
1145static const TypeInfo wwdt_info = {
1146    .name          = TYPE_XILINX_WWDT,
1147    .parent        = TYPE_SYS_BUS_DEVICE,
1148    .instance_size = sizeof(WWDT),
1149    .class_init    = wwdt_class_init,
1150    .instance_init = wwdt_init,
1151    .interfaces = (InterfaceInfo[]) {
1152        { TYPE_FDT_GENERIC_GPIO },
1153        { }
1154    }
1155};
1156
1157static void wwdt_register_types(void)
1158{
1159    type_register_static(&wwdt_info);
1160}
1161
1162type_init(wwdt_register_types)
1163