/*
 * QEMU model of the ASU_GLOBAL This is the database for the ASU Global Register
 * Definitions.
 *
 * Copyright (c) 2023 Xilinx Inc.
 *
 * Autogenerated by xregqemu.py 2023-04-26.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/register.h"
#include "qemu/bitops.h"
#include "qemu/log.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
#include "hw/fdt_generic_util.h"

#ifndef XILINX_ASU_GLOBAL_ERR_DEBUG
#define XILINX_ASU_GLOBAL_ERR_DEBUG 0
#endif

#define TYPE_XILINX_ASU_GLOBAL "xlnx.asu_global"

#define XILINX_ASU_GLOBAL(obj) \
     OBJECT_CHECK(ASU_GLOBAL, (obj), TYPE_XILINX_ASU_GLOBAL)

REG32(GLOBAL_CNTRL, 0x0)
    FIELD(GLOBAL_CNTRL, MB_DBG_WAKE, 17, 1)
    FIELD(GLOBAL_CNTRL, MB_SLEEP, 16, 1)
    FIELD(GLOBAL_CNTRL, WRITE_QOS, 12, 4)
    FIELD(GLOBAL_CNTRL, READ_QOS, 8, 4)
    FIELD(GLOBAL_CNTRL, FW_IS_PRESENT, 4, 1)
    FIELD(GLOBAL_CNTRL, SLVERR_ENABLE, 1, 1)
REG32(ADDR_ERROR_STATUS, 0x10)
    FIELD(ADDR_ERROR_STATUS, STATUS, 0, 1)
REG32(ADDR_ERROR_INT_MASK, 0x14)
    FIELD(ADDR_ERROR_INT_MASK, MASK, 0, 1)
REG32(ADDR_ERROR_INT_EN, 0x18)
    FIELD(ADDR_ERROR_INT_EN, ENABLE, 0, 1)
REG32(ADDR_ERROR_INT_DIS, 0x1c)
    FIELD(ADDR_ERROR_INT_DIS, DISABLE, 0, 1)
REG32(GLOBAL_GEN_STORAGE0, 0x20)
REG32(GLOBAL_GEN_STORAGE1, 0x24)
REG32(GLOBAL_GEN_STORAGE2, 0x28)
REG32(GLOBAL_GEN_STORAGE3, 0x2c)
REG32(GLOBAL_GEN_STORAGE4, 0x30)
REG32(GLOBAL_GEN_STORAGE5, 0x34)
REG32(GLOBAL_GEN_STORAGE6, 0x38)
REG32(GLOBAL_GEN_STORAGE7, 0x3c)
REG32(PERS_GLOB_GEN_STORAGE0, 0x40)
REG32(PERS_GLOB_GEN_STORAGE1, 0x44)
REG32(PERS_GLOB_GEN_STORAGE2, 0x48)
REG32(PERS_GLOB_GEN_STORAGE3, 0x4c)
REG32(PERS_GLOB_GEN_STORAGE4, 0x50)
REG32(PERS_GLOB_GEN_STORAGE5, 0x54)
REG32(PERS_GLOB_GEN_STORAGE6, 0x58)
REG32(PERS_GLOB_GEN_STORAGE7, 0x5c)
REG32(ASU_INT_STATUS, 0x60)
    FIELD(ASU_INT_STATUS, ASU_INTERCONNECT_IRQ, 8, 1)
    FIELD(ASU_INT_STATUS, KEY_TRANSFER_DONE, 0, 1)
REG32(ASU_INT_MASK, 0x64)
    FIELD(ASU_INT_MASK, ASU_INTERCONNECT_IRQ, 8, 1)
    FIELD(ASU_INT_MASK, KEY_TRANSFER_DONE, 0, 1)
REG32(ASU_INT_ENABLE, 0x68)
    FIELD(ASU_INT_ENABLE, ASU_INTERCONNECT_IRQ, 8, 1)
    FIELD(ASU_INT_ENABLE, KEY_TRANSFER_DONE, 0, 1)
REG32(ASU_INT_DISABLE, 0x6c)
    FIELD(ASU_INT_DISABLE, ASU_INTERCONNECT_IRQ, 8, 1)
    FIELD(ASU_INT_DISABLE, KEY_TRANSFER_DONE, 0, 1)
REG32(ASU_INT_TRIGGER, 0x70)
    FIELD(ASU_INT_TRIGGER, ASU_INTERCONNECT_IRQ, 8, 1)
    FIELD(ASU_INT_TRIGGER, KEY_TRANSFER_DONE, 0, 1)
REG32(ASU_FATAL_ERROR_STATUS, 0x74)
    FIELD(ASU_FATAL_ERROR_STATUS, ASU_INT_UNCORR, 4, 1)
    FIELD(ASU_FATAL_ERROR_STATUS, MB_RISCV_LOCKSTEP_MISMATCH_1, 3, 1)
    FIELD(ASU_FATAL_ERROR_STATUS, MB_RISCV_LOCKSTEP_MISMATCH_0, 2, 1)
    FIELD(ASU_FATAL_ERROR_STATUS, INSTR_RAM_ECC, 1, 1)
    FIELD(ASU_FATAL_ERROR_STATUS, DATA_RAM_ECC, 0, 1)
REG32(ASU_FATAL_ERROR_MASK, 0x78)
    FIELD(ASU_FATAL_ERROR_MASK, ASU_INT_UNCORR, 4, 1)
    FIELD(ASU_FATAL_ERROR_MASK, MB_RISCV_LOCKSTEP_MISMATCH_1, 3, 1)
    FIELD(ASU_FATAL_ERROR_MASK, MB_RISCV_LOCKSTEP_MISMATCH_0, 2, 1)
    FIELD(ASU_FATAL_ERROR_MASK, INSTR_RAM_ECC, 1, 1)
    FIELD(ASU_FATAL_ERROR_MASK, DATA_RAM_ECC, 0, 1)
REG32(ASU_FATAL_ERROR_ENABLE, 0x7c)
    FIELD(ASU_FATAL_ERROR_ENABLE, ASU_INT_UNCORR, 4, 1)
    FIELD(ASU_FATAL_ERROR_ENABLE, MB_RISCV_LOCKSTEP_MISMATCH_1, 3, 1)
    FIELD(ASU_FATAL_ERROR_ENABLE, MB_RISCV_LOCKSTEP_MISMATCH_0, 2, 1)
    FIELD(ASU_FATAL_ERROR_ENABLE, INSTR_RAM_ECC, 1, 1)
    FIELD(ASU_FATAL_ERROR_ENABLE, DATA_RAM_ECC, 0, 1)
REG32(ASU_FATAL_ERROR_DISABLE, 0x80)
    FIELD(ASU_FATAL_ERROR_DISABLE, ASU_INT_UNCORR, 4, 1)
    FIELD(ASU_FATAL_ERROR_DISABLE, MB_RISCV_LOCKSTEP_MISMATCH_1, 3, 1)
    FIELD(ASU_FATAL_ERROR_DISABLE, MB_RISCV_LOCKSTEP_MISMATCH_0, 2, 1)
    FIELD(ASU_FATAL_ERROR_DISABLE, INSTR_RAM_ECC, 1, 1)
    FIELD(ASU_FATAL_ERROR_DISABLE, DATA_RAM_ECC, 0, 1)
REG32(ASU_FATAL_ERROR_TRIGGER, 0x84)
    FIELD(ASU_FATAL_ERROR_TRIGGER, ASU_INT_UNCORR, 4, 1)
    FIELD(ASU_FATAL_ERROR_TRIGGER, MB_RISCV_LOCKSTEP_MISMATCH_1, 3, 1)
    FIELD(ASU_FATAL_ERROR_TRIGGER, MB_RISCV_LOCKSTEP_MISMATCH_0, 2, 1)
    FIELD(ASU_FATAL_ERROR_TRIGGER, INSTR_RAM_ECC, 1, 1)
    FIELD(ASU_FATAL_ERROR_TRIGGER, DATA_RAM_ECC, 0, 1)
REG32(ASU_NON_FATAL_ERROR_STATUS, 0x88)
    FIELD(ASU_NON_FATAL_ERROR_STATUS, ASU_INT_CORR, 2, 1)
    FIELD(ASU_NON_FATAL_ERROR_STATUS, INSTR_RAM_ECC, 1, 1)
    FIELD(ASU_NON_FATAL_ERROR_STATUS, DATA_RAM_ECC, 0, 1)
REG32(ASU_NON_FATAL_ERROR_MASK, 0x8c)
    FIELD(ASU_NON_FATAL_ERROR_MASK, ASU_INT_CORR, 2, 1)
    FIELD(ASU_NON_FATAL_ERROR_MASK, INSTR_RAM_ECC, 1, 1)
    FIELD(ASU_NON_FATAL_ERROR_MASK, DATA_RAM_ECC, 0, 1)
REG32(ASU_NON_FATAL_ERROR_ENABLE, 0x90)
    FIELD(ASU_NON_FATAL_ERROR_ENABLE, ASU_INT_CORR, 2, 1)
    FIELD(ASU_NON_FATAL_ERROR_ENABLE, INSTR_RAM_ECC, 1, 1)
    FIELD(ASU_NON_FATAL_ERROR_ENABLE, DATA_RAM_ECC, 0, 1)
REG32(ASU_NON_FATAL_ERROR_DISABLE, 0x94)
    FIELD(ASU_NON_FATAL_ERROR_DISABLE, ASU_INT_CORR, 2, 1)
    FIELD(ASU_NON_FATAL_ERROR_DISABLE, INSTR_RAM_ECC, 1, 1)
    FIELD(ASU_NON_FATAL_ERROR_DISABLE, DATA_RAM_ECC, 0, 1)
REG32(ASU_NON_FATAL_ERROR_TRIGGER, 0x98)
    FIELD(ASU_NON_FATAL_ERROR_TRIGGER, ASU_INT_UNCORR, 2, 1)
    FIELD(ASU_NON_FATAL_ERROR_TRIGGER, INSTR_RAM_ECC, 1, 1)
    FIELD(ASU_NON_FATAL_ERROR_TRIGGER, DATA_RAM_ECC, 0, 1)
REG32(ASU_DEBUG_CTRL, 0x9c)
    FIELD(ASU_DEBUG_CTRL, EN, 0, 1)
REG32(SCAN_CLEAR_LOCK, 0x100)
    FIELD(SCAN_CLEAR_LOCK, LOCK, 0, 1)
REG32(ECO_1, 0x104)
REG32(ECO_2, 0x108)
REG32(GPI_STATUS, 0x10c)
    FIELD(GPI_STATUS, GPI_31, 31, 1)
    FIELD(GPI_STATUS, GPI_30, 30, 1)
    FIELD(GPI_STATUS, GPI_29, 29, 1)
    FIELD(GPI_STATUS, GPI_28, 28, 1)
    FIELD(GPI_STATUS, GPI_27, 27, 1)
    FIELD(GPI_STATUS, GPI_26, 26, 1)
    FIELD(GPI_STATUS, GPI_25, 25, 1)
    FIELD(GPI_STATUS, GPI_24, 24, 1)
    FIELD(GPI_STATUS, GPI_23, 23, 1)
    FIELD(GPI_STATUS, GPI_22, 22, 1)
    FIELD(GPI_STATUS, GPI_21, 21, 1)
    FIELD(GPI_STATUS, GPI_20, 20, 1)
    FIELD(GPI_STATUS, GPI_19, 19, 1)
    FIELD(GPI_STATUS, GPI_18, 18, 1)
    FIELD(GPI_STATUS, GPI_17, 17, 1)
    FIELD(GPI_STATUS, GPI_16, 16, 1)
    FIELD(GPI_STATUS, GPI_15, 15, 1)
    FIELD(GPI_STATUS, GPI_14, 14, 1)
    FIELD(GPI_STATUS, GPI_13, 13, 1)
    FIELD(GPI_STATUS, GPI_12, 12, 1)
    FIELD(GPI_STATUS, GPI_11, 11, 1)
    FIELD(GPI_STATUS, GPI_10, 10, 1)
    FIELD(GPI_STATUS, GPI_9, 9, 1)
    FIELD(GPI_STATUS, GPI_8, 8, 1)
    FIELD(GPI_STATUS, GPI_7, 7, 1)
    FIELD(GPI_STATUS, GPI_6, 6, 1)
    FIELD(GPI_STATUS, GPI_5, 5, 1)
    FIELD(GPI_STATUS, GPI_4, 4, 1)
    FIELD(GPI_STATUS, GPI_3, 3, 1)
    FIELD(GPI_STATUS, GPI_2, 2, 1)
    FIELD(GPI_STATUS, GPI_1, 1, 1)
    FIELD(GPI_STATUS, GPI_0, 0, 1)
REG32(GPI_MASK, 0x110)
    FIELD(GPI_MASK, GPI_31, 31, 1)
    FIELD(GPI_MASK, GPI_30, 30, 1)
    FIELD(GPI_MASK, GPI_29, 29, 1)
    FIELD(GPI_MASK, GPI_28, 28, 1)
    FIELD(GPI_MASK, GPI_27, 27, 1)
    FIELD(GPI_MASK, GPI_26, 26, 1)
    FIELD(GPI_MASK, GPI_25, 25, 1)
    FIELD(GPI_MASK, GPI_24, 24, 1)
    FIELD(GPI_MASK, GPI_23, 23, 1)
    FIELD(GPI_MASK, GPI_22, 22, 1)
    FIELD(GPI_MASK, GPI_21, 21, 1)
    FIELD(GPI_MASK, GPI_20, 20, 1)
    FIELD(GPI_MASK, GPI_19, 19, 1)
    FIELD(GPI_MASK, GPI_18, 18, 1)
    FIELD(GPI_MASK, GPI_17, 17, 1)
    FIELD(GPI_MASK, GPI_16, 16, 1)
    FIELD(GPI_MASK, GPI_15, 15, 1)
    FIELD(GPI_MASK, GPI_14, 14, 1)
    FIELD(GPI_MASK, GPI_13, 13, 1)
    FIELD(GPI_MASK, GPI_12, 12, 1)
    FIELD(GPI_MASK, GPI_11, 11, 1)
    FIELD(GPI_MASK, GPI_10, 10, 1)
    FIELD(GPI_MASK, GPI_9, 9, 1)
    FIELD(GPI_MASK, GPI_8, 8, 1)
    FIELD(GPI_MASK, GPI_7, 7, 1)
    FIELD(GPI_MASK, GPI_6, 6, 1)
    FIELD(GPI_MASK, GPI_5, 5, 1)
    FIELD(GPI_MASK, GPI_4, 4, 1)
    FIELD(GPI_MASK, GPI_3, 3, 1)
    FIELD(GPI_MASK, GPI_2, 2, 1)
    FIELD(GPI_MASK, GPI_1, 1, 1)
    FIELD(GPI_MASK, GPI_0, 0, 1)
REG32(GPI_EN, 0x114)
    FIELD(GPI_EN, GPI_31, 31, 1)
    FIELD(GPI_EN, GPI_30, 30, 1)
    FIELD(GPI_EN, GPI_29, 29, 1)
    FIELD(GPI_EN, GPI_28, 28, 1)
    FIELD(GPI_EN, GPI_27, 27, 1)
    FIELD(GPI_EN, GPI_26, 26, 1)
    FIELD(GPI_EN, GPI_25, 25, 1)
    FIELD(GPI_EN, GPI_24, 24, 1)
    FIELD(GPI_EN, GPI_23, 23, 1)
    FIELD(GPI_EN, GPI_22, 22, 1)
    FIELD(GPI_EN, GPI_21, 21, 1)
    FIELD(GPI_EN, GPI_20, 20, 1)
    FIELD(GPI_EN, GPI_19, 19, 1)
    FIELD(GPI_EN, GPI_18, 18, 1)
    FIELD(GPI_EN, GPI_17, 17, 1)
    FIELD(GPI_EN, GPI_16, 16, 1)
    FIELD(GPI_EN, GPI_15, 15, 1)
    FIELD(GPI_EN, GPI_14, 14, 1)
    FIELD(GPI_EN, GPI_13, 13, 1)
    FIELD(GPI_EN, GPI_12, 12, 1)
    FIELD(GPI_EN, GPI_11, 11, 1)
    FIELD(GPI_EN, GPI_10, 10, 1)
    FIELD(GPI_EN, GPI_9, 9, 1)
    FIELD(GPI_EN, GPI_8, 8, 1)
    FIELD(GPI_EN, GPI_7, 7, 1)
    FIELD(GPI_EN, GPI_6, 6, 1)
    FIELD(GPI_EN, GPI_5, 5, 1)
    FIELD(GPI_EN, GPI_4, 4, 1)
    FIELD(GPI_EN, GPI_3, 3, 1)
    FIELD(GPI_EN, GPI_2, 2, 1)
    FIELD(GPI_EN, GPI_1, 1, 1)
    FIELD(GPI_EN, GPI_0, 0, 1)
REG32(GPI_DIS, 0x118)
    FIELD(GPI_DIS, GPI_31, 31, 1)
    FIELD(GPI_DIS, GPI_30, 30, 1)
    FIELD(GPI_DIS, GPI_29, 29, 1)
    FIELD(GPI_DIS, GPI_28, 28, 1)
    FIELD(GPI_DIS, GPI_27, 27, 1)
    FIELD(GPI_DIS, GPI_26, 26, 1)
    FIELD(GPI_DIS, GPI_25, 25, 1)
    FIELD(GPI_DIS, GPI_24, 24, 1)
    FIELD(GPI_DIS, GPI_23, 23, 1)
    FIELD(GPI_DIS, GPI_22, 22, 1)
    FIELD(GPI_DIS, GPI_21, 21, 1)
    FIELD(GPI_DIS, GPI_20, 20, 1)
    FIELD(GPI_DIS, GPI_19, 19, 1)
    FIELD(GPI_DIS, GPI_18, 18, 1)
    FIELD(GPI_DIS, GPI_17, 17, 1)
    FIELD(GPI_DIS, GPI_16, 16, 1)
    FIELD(GPI_DIS, GPI_15, 15, 1)
    FIELD(GPI_DIS, GPI_14, 14, 1)
    FIELD(GPI_DIS, GPI_13, 13, 1)
    FIELD(GPI_DIS, GPI_12, 12, 1)
    FIELD(GPI_DIS, GPI_11, 11, 1)
    FIELD(GPI_DIS, GPI_10, 10, 1)
    FIELD(GPI_DIS, GPI_9, 9, 1)
    FIELD(GPI_DIS, GPI_8, 8, 1)
    FIELD(GPI_DIS, GPI_7, 7, 1)
    FIELD(GPI_DIS, GPI_6, 6, 1)
    FIELD(GPI_DIS, GPI_5, 5, 1)
    FIELD(GPI_DIS, GPI_4, 4, 1)
    FIELD(GPI_DIS, GPI_3, 3, 1)
    FIELD(GPI_DIS, GPI_2, 2, 1)
    FIELD(GPI_DIS, GPI_1, 1, 1)
    FIELD(GPI_DIS, GPI_0, 0, 1)
REG32(GPI_TRIG, 0x11c)
    FIELD(GPI_TRIG, GPI_31, 31, 1)
    FIELD(GPI_TRIG, GPI_30, 30, 1)
    FIELD(GPI_TRIG, GPI_29, 29, 1)
    FIELD(GPI_TRIG, GPI_28, 28, 1)
    FIELD(GPI_TRIG, GPI_27, 27, 1)
    FIELD(GPI_TRIG, GPI_26, 26, 1)
    FIELD(GPI_TRIG, GPI_25, 25, 1)
    FIELD(GPI_TRIG, GPI_24, 24, 1)
    FIELD(GPI_TRIG, GPI_23, 23, 1)
    FIELD(GPI_TRIG, GPI_22, 22, 1)
    FIELD(GPI_TRIG, GPI_21, 21, 1)
    FIELD(GPI_TRIG, GPI_20, 20, 1)
    FIELD(GPI_TRIG, GPI_19, 19, 1)
    FIELD(GPI_TRIG, GPI_18, 18, 1)
    FIELD(GPI_TRIG, GPI_17, 17, 1)
    FIELD(GPI_TRIG, GPI_16, 16, 1)
    FIELD(GPI_TRIG, GPI_15, 15, 1)
    FIELD(GPI_TRIG, GPI_14, 14, 1)
    FIELD(GPI_TRIG, GPI_13, 13, 1)
    FIELD(GPI_TRIG, GPI_12, 12, 1)
    FIELD(GPI_TRIG, GPI_11, 11, 1)
    FIELD(GPI_TRIG, GPI_10, 10, 1)
    FIELD(GPI_TRIG, GPI_9, 9, 1)
    FIELD(GPI_TRIG, GPI_8, 8, 1)
    FIELD(GPI_TRIG, GPI_7, 7, 1)
    FIELD(GPI_TRIG, GPI_6, 6, 1)
    FIELD(GPI_TRIG, GPI_5, 5, 1)
    FIELD(GPI_TRIG, GPI_4, 4, 1)
    FIELD(GPI_TRIG, GPI_3, 3, 1)
    FIELD(GPI_TRIG, GPI_2, 2, 1)
    FIELD(GPI_TRIG, GPI_1, 1, 1)
    FIELD(GPI_TRIG, GPI_0, 0, 1)

#define ASU_GLOBAL_R_MAX (R_GPI_TRIG + 1)

typedef struct ASU_GLOBAL {
    SysBusDevice parent_obj;
    MemoryRegion iomem;
    qemu_irq irq_asu_fatal_error;
    qemu_irq irq_asu_int;
    qemu_irq irq_asu_non_fatal_error;
    qemu_irq irq_addr_error_int;
    qemu_irq irq_gpi;

    uint32_t regs[ASU_GLOBAL_R_MAX];
    RegisterInfo regs_info[ASU_GLOBAL_R_MAX];
} ASU_GLOBAL;

static void asu_fatal_error_update_irq(ASU_GLOBAL *s)
{
    bool pending = s->regs[R_ASU_FATAL_ERROR_STATUS] &
                   ~s->regs[R_ASU_FATAL_ERROR_MASK];
    qemu_set_irq(s->irq_asu_fatal_error, pending);
}

static void asu_fatal_error_status_postw(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    asu_fatal_error_update_irq(s);
}

static uint64_t asu_fatal_error_enable_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ASU_FATAL_ERROR_MASK] &= ~val;
    asu_fatal_error_update_irq(s);
    return 0;
}

static uint64_t asu_fatal_error_disable_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ASU_FATAL_ERROR_MASK] |= val;
    asu_fatal_error_update_irq(s);
    return 0;
}

static uint64_t asu_fatal_error_trigger_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ASU_FATAL_ERROR_STATUS] |= val;
    asu_fatal_error_update_irq(s);
    return 0;
}

static void asu_int_update_irq(ASU_GLOBAL *s)
{
    bool pending = s->regs[R_ASU_INT_STATUS] & ~s->regs[R_ASU_INT_MASK];
    qemu_set_irq(s->irq_asu_int, pending);
}

static void asu_int_status_postw(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    asu_int_update_irq(s);
}

static uint64_t asu_int_enable_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ASU_INT_MASK] &= ~val;
    asu_int_update_irq(s);
    return 0;
}

static uint64_t asu_int_disable_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ASU_INT_MASK] |= val;
    asu_int_update_irq(s);
    return 0;
}

static uint64_t asu_int_trigger_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ASU_INT_STATUS] |= val;
    asu_int_update_irq(s);
    return 0;
}

static void asu_non_fatal_error_update_irq(ASU_GLOBAL *s)
{
    bool pending = s->regs[R_ASU_NON_FATAL_ERROR_STATUS] &
                   ~s->regs[R_ASU_NON_FATAL_ERROR_MASK];
    qemu_set_irq(s->irq_asu_non_fatal_error, pending);
}

static void asu_non_fatal_error_status_postw(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    asu_non_fatal_error_update_irq(s);
}

static uint64_t asu_non_fatal_error_enable_prew(RegisterInfo *reg,
                                                uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ASU_NON_FATAL_ERROR_MASK] &= ~val;
    asu_non_fatal_error_update_irq(s);
    return 0;
}

static uint64_t asu_non_fatal_error_disable_prew(RegisterInfo *reg,
                                                 uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ASU_NON_FATAL_ERROR_MASK] |= val;
    asu_non_fatal_error_update_irq(s);
    return 0;
}

static uint64_t asu_non_fatal_error_trigger_prew(RegisterInfo *reg,
                                                 uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ASU_NON_FATAL_ERROR_STATUS] |= val;
    asu_non_fatal_error_update_irq(s);
    return 0;
}

static void addr_error_int_update_irq(ASU_GLOBAL *s)
{
    bool pending = s->regs[R_ADDR_ERROR_STATUS] &
                    ~s->regs[R_ADDR_ERROR_INT_MASK];
    qemu_set_irq(s->irq_addr_error_int, pending);
}

static void addr_error_status_postw(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    addr_error_int_update_irq(s);
}

static uint64_t addr_error_int_en_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ADDR_ERROR_INT_MASK] &= ~val;
    addr_error_int_update_irq(s);
    return 0;
}

static uint64_t addr_error_int_dis_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_ADDR_ERROR_INT_MASK] |= val;
    addr_error_int_update_irq(s);
    return 0;
}

static void gpi_update_irq(ASU_GLOBAL *s)
{
    bool pending = s->regs[R_GPI_STATUS] & ~s->regs[R_GPI_MASK];
    qemu_set_irq(s->irq_gpi, pending);
}

static void gpi_status_postw(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    gpi_update_irq(s);
}

static uint64_t gpi_en_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_GPI_MASK] &= ~val;
    gpi_update_irq(s);
    return 0;
}

static uint64_t gpi_dis_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_GPI_MASK] |= val;
    gpi_update_irq(s);
    return 0;
}

static uint64_t gpi_trig_prew(RegisterInfo *reg, uint64_t val64)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(reg->opaque);
    uint32_t val = val64;

    s->regs[R_GPI_STATUS] |= val;
    gpi_update_irq(s);
    return 0;
}

static const RegisterAccessInfo asu_global_regs_info[] = {
    {   .name = "GLOBAL_CNTRL",  .addr = A_GLOBAL_CNTRL,
        .reset = 0x8800,
        .rsvd = 0xed,
        .ro = 0x300ed,
    },{ .name = "ADDR_ERROR_STATUS",  .addr = A_ADDR_ERROR_STATUS,
        .rsvd = 0xfffffffe,
        .ro = 0xfffffffe,
        .w1c = 0x1,
        .post_write = addr_error_status_postw,
    },{ .name = "ADDR_ERROR_INT_MASK",  .addr = A_ADDR_ERROR_INT_MASK,
        .reset = 0x1,
        .rsvd = 0xfffffffe,
        .ro = 0xffffffff,
    },{ .name = "ADDR_ERROR_INT_EN",  .addr = A_ADDR_ERROR_INT_EN,
        .pre_write = addr_error_int_en_prew,
    },{ .name = "ADDR_ERROR_INT_DIS",  .addr = A_ADDR_ERROR_INT_DIS,
        .pre_write = addr_error_int_dis_prew,
    },{ .name = "GLOBAL_GEN_STORAGE0",  .addr = A_GLOBAL_GEN_STORAGE0,
    },{ .name = "GLOBAL_GEN_STORAGE1",  .addr = A_GLOBAL_GEN_STORAGE1,
    },{ .name = "GLOBAL_GEN_STORAGE2",  .addr = A_GLOBAL_GEN_STORAGE2,
    },{ .name = "GLOBAL_GEN_STORAGE3",  .addr = A_GLOBAL_GEN_STORAGE3,
    },{ .name = "GLOBAL_GEN_STORAGE4",  .addr = A_GLOBAL_GEN_STORAGE4,
    },{ .name = "GLOBAL_GEN_STORAGE5",  .addr = A_GLOBAL_GEN_STORAGE5,
    },{ .name = "GLOBAL_GEN_STORAGE6",  .addr = A_GLOBAL_GEN_STORAGE6,
    },{ .name = "GLOBAL_GEN_STORAGE7",  .addr = A_GLOBAL_GEN_STORAGE7,
    },{ .name = "PERS_GLOB_GEN_STORAGE0",  .addr = A_PERS_GLOB_GEN_STORAGE0,
    },{ .name = "PERS_GLOB_GEN_STORAGE1",  .addr = A_PERS_GLOB_GEN_STORAGE1,
    },{ .name = "PERS_GLOB_GEN_STORAGE2",  .addr = A_PERS_GLOB_GEN_STORAGE2,
    },{ .name = "PERS_GLOB_GEN_STORAGE3",  .addr = A_PERS_GLOB_GEN_STORAGE3,
    },{ .name = "PERS_GLOB_GEN_STORAGE4",  .addr = A_PERS_GLOB_GEN_STORAGE4,
    },{ .name = "PERS_GLOB_GEN_STORAGE5",  .addr = A_PERS_GLOB_GEN_STORAGE5,
    },{ .name = "PERS_GLOB_GEN_STORAGE6",  .addr = A_PERS_GLOB_GEN_STORAGE6,
    },{ .name = "PERS_GLOB_GEN_STORAGE7",  .addr = A_PERS_GLOB_GEN_STORAGE7,
    },{ .name = "ASU_INT_STATUS",  .addr = A_ASU_INT_STATUS,
        .rsvd = 0xfffffefe,
        .ro = 0xfffffefe,
        .w1c = 0x101,
        .post_write = asu_int_status_postw,
    },{ .name = "ASU_INT_MASK",  .addr = A_ASU_INT_MASK,
        .rsvd = 0xfffffefe,
        .ro = 0xffffffff,
    },{ .name = "ASU_INT_ENABLE",  .addr = A_ASU_INT_ENABLE,
        .rsvd = 0xfffffefe,
        .ro = 0xfffffefe,
        .pre_write = asu_int_enable_prew,
    },{ .name = "ASU_INT_DISABLE",  .addr = A_ASU_INT_DISABLE,
        .rsvd = 0xfffffefe,
        .ro = 0xfffffefe,
        .pre_write = asu_int_disable_prew,
    },{ .name = "ASU_INT_TRIGGER",  .addr = A_ASU_INT_TRIGGER,
        .rsvd = 0xfffffefe,
        .ro = 0xfffffefe,
        .pre_write = asu_int_trigger_prew,
    },{ .name = "ASU_FATAL_ERROR_STATUS",  .addr = A_ASU_FATAL_ERROR_STATUS,
        .w1c = 0x3f,
        .post_write = asu_fatal_error_status_postw,
    },{ .name = "ASU_FATAL_ERROR_MASK",  .addr = A_ASU_FATAL_ERROR_MASK,
        .reset = 0x3f,
        .ro = 0x3f,
    },{ .name = "ASU_FATAL_ERROR_ENABLE",  .addr = A_ASU_FATAL_ERROR_ENABLE,
        .pre_write = asu_fatal_error_enable_prew,
    },{ .name = "ASU_FATAL_ERROR_DISABLE",  .addr = A_ASU_FATAL_ERROR_DISABLE,
        .pre_write = asu_fatal_error_disable_prew,
    },{ .name = "ASU_FATAL_ERROR_TRIGGER",  .addr = A_ASU_FATAL_ERROR_TRIGGER,
        .pre_write = asu_fatal_error_trigger_prew,
    },{ .name = "ASU_NON_FATAL_ERROR_STATUS",
        .addr = A_ASU_NON_FATAL_ERROR_STATUS,
        .w1c = 0x1ff,
        .post_write = asu_non_fatal_error_status_postw,
    },{ .name = "ASU_NON_FATAL_ERROR_MASK",  .addr = A_ASU_NON_FATAL_ERROR_MASK,
        .reset = 0x1ff,
        .ro = 0x1ff,
    },{ .name = "ASU_NON_FATAL_ERROR_ENABLE",
        .addr = A_ASU_NON_FATAL_ERROR_ENABLE,
        .pre_write = asu_non_fatal_error_enable_prew,
    },{ .name = "ASU_NON_FATAL_ERROR_DISABLE",
        .addr = A_ASU_NON_FATAL_ERROR_DISABLE,
        .pre_write = asu_non_fatal_error_disable_prew,
    },{ .name = "ASU_NON_FATAL_ERROR_TRIGGER",
        .addr = A_ASU_NON_FATAL_ERROR_TRIGGER,
        .pre_write = asu_non_fatal_error_trigger_prew,
    },{ .name = "ASU_DEBUG_CTRL",  .addr = A_ASU_DEBUG_CTRL,
        .reset = 0x1,
        .rsvd = 0xfffffffe,
        .ro = 0xfffffffe,
    },{ .name = "SCAN_CLEAR_LOCK",  .addr = A_SCAN_CLEAR_LOCK,
    },{ .name = "ECO_1",  .addr = A_ECO_1,
    },{ .name = "ECO_2",  .addr = A_ECO_2,
    },{ .name = "GPI_STATUS",  .addr = A_GPI_STATUS,
        .w1c = 0xffffffff,
        .post_write = gpi_status_postw,
    },{ .name = "GPI_MASK",  .addr = A_GPI_MASK,
        .reset = 0xffffffff,
        .ro = 0xffffffff,
    },{ .name = "GPI_EN",  .addr = A_GPI_EN,
        .pre_write = gpi_en_prew,
    },{ .name = "GPI_DIS",  .addr = A_GPI_DIS,
        .pre_write = gpi_dis_prew,
    },{ .name = "GPI_TRIG",  .addr = A_GPI_TRIG,
        .pre_write = gpi_trig_prew,
    }
};

static void asu_global_key_transfer_done(void *obj, int n, int level)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(obj);

    ARRAY_FIELD_DP32(s->regs, ASU_INT_STATUS, KEY_TRANSFER_DONE, 1);
    asu_int_update_irq(s);
}

static void asu_global_reset_enter(Object *obj, ResetType type)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(obj);
    unsigned int i;

    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
        register_reset(&s->regs_info[i]);
    }
}

static void asu_global_reset_hold(Object *obj)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(obj);

    asu_fatal_error_update_irq(s);
    asu_int_update_irq(s);
    asu_non_fatal_error_update_irq(s);
    addr_error_int_update_irq(s);
    gpi_update_irq(s);
}

static const MemoryRegionOps asu_global_ops = {
    .read = register_read_memory,
    .write = register_write_memory,
    .endianness = DEVICE_LITTLE_ENDIAN,
    .valid = {
        .min_access_size = 4,
        .max_access_size = 4,
    },
};

static void asu_global_realize(DeviceState *dev, Error **errp)
{
    /* Delete this if you don't need it */
}

static void asu_global_init(Object *obj)
{
    ASU_GLOBAL *s = XILINX_ASU_GLOBAL(obj);
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    DeviceState *dev = DEVICE(obj);
    RegisterInfoArray *reg_array;

    memory_region_init(&s->iomem, obj, TYPE_XILINX_ASU_GLOBAL,
                       ASU_GLOBAL_R_MAX * 4);
    reg_array =
        register_init_block32(DEVICE(obj), asu_global_regs_info,
                              ARRAY_SIZE(asu_global_regs_info),
                              s->regs_info, s->regs,
                              &asu_global_ops,
                              XILINX_ASU_GLOBAL_ERR_DEBUG,
                              ASU_GLOBAL_R_MAX * 4);
    memory_region_add_subregion(&s->iomem,
                                0x0,
                                &reg_array->mem);
    sysbus_init_mmio(sbd, &s->iomem);
    sysbus_init_irq(sbd, &s->irq_asu_int);
    qdev_init_gpio_out_named(dev, &s->irq_asu_fatal_error, "fatal-error", 1);
    qdev_init_gpio_out_named(dev, &s->irq_asu_non_fatal_error, "non-fatal-error", 1);
    qdev_init_gpio_out_named(dev, &s->irq_addr_error_int, "addr-error", 1);
    qdev_init_gpio_out_named(dev, &s->irq_gpi, "gpi", 1);

    /* Input: driven by ASU-AES */
    qdev_init_gpio_in_named(dev, asu_global_key_transfer_done, "key-xfer-done", 1);
}

static const FDTGenericGPIOSet asu_global_gpios[] = {
    {
        .names = &fdt_generic_gpio_name_set_gpio,
        .gpios = (FDTGenericGPIOConnection []) {
            { .name = "key-xfer-done", .fdt_index = 0, .range = 1 },
            { .name = "fatal-error", .fdt_index = 1, .range = 1 },
            { .name = "non-fatal-error", .fdt_index = 2, .range = 1 },
            { .name = "addr-error", .fdt_index = 3, .range = 1 },
            { },
        },
    },
    { },
};

static const VMStateDescription vmstate_asu_global = {
    .name = TYPE_XILINX_ASU_GLOBAL,
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField[]) {
        VMSTATE_UINT32_ARRAY(regs, ASU_GLOBAL, ASU_GLOBAL_R_MAX),
        VMSTATE_END_OF_LIST(),
    }
};

static void asu_global_class_init(ObjectClass *klass, void *data)
{
    ResettableClass *rc = RESETTABLE_CLASS(klass);
    DeviceClass *dc = DEVICE_CLASS(klass);
    FDTGenericGPIOClass *fggc = FDT_GENERIC_GPIO_CLASS(klass);

    dc->realize = asu_global_realize;
    dc->vmsd = &vmstate_asu_global;
    rc->phases.enter = asu_global_reset_enter;
    rc->phases.hold = asu_global_reset_hold;
    fggc->client_gpios = asu_global_gpios;
}

static const TypeInfo asu_global_info = {
    .name          = TYPE_XILINX_ASU_GLOBAL,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(ASU_GLOBAL),
    .class_init    = asu_global_class_init,
    .instance_init = asu_global_init,
    .interfaces    = (InterfaceInfo []) {
        { TYPE_FDT_GENERIC_GPIO },
        { }
    },
};

static void asu_global_register_types(void)
{
    type_register_static(&asu_global_info);
}

type_init(asu_global_register_types)
