/*
 * QEMU model of the CMT_DPLL 
 *
 * Copyright (c) 2019 Xilinx Inc.
 *
 * Autogenerated by xregqemu.py 2019-02-06.
 *
 * 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/qdev-properties.h"

#ifndef XILINX_CMT_DPLL_ERR_DEBUG
#define XILINX_CMT_DPLL_ERR_DEBUG 0
#endif

#define TYPE_XILINX_CMT_DPLL "xlnx.versal-cmt-dpll"

#define XILINX_CMT_DPLL(obj) \
     OBJECT_CHECK(CMT_DPLL, (obj), TYPE_XILINX_CMT_DPLL)

REG32(REG_PCSR_MASK, 0x0)
    FIELD(REG_PCSR_MASK, TEST_SAFE, 20, 1)
    FIELD(REG_PCSR_MASK, SLVERREN, 19, 1)
    FIELD(REG_PCSR_MASK, MEM_CLEAR_TRIGGER, 18, 1)
    FIELD(REG_PCSR_MASK, SYS_RST_MASK, 15, 3)
    FIELD(REG_PCSR_MASK, PWRDN, 14, 1)
    FIELD(REG_PCSR_MASK, DISNPICLK, 13, 1)
    FIELD(REG_PCSR_MASK, APBEN, 12, 1)
    FIELD(REG_PCSR_MASK, SCAN_CLEAR_TRIGGER, 11, 1)
    FIELD(REG_PCSR_MASK, STARTCAL, 10, 1)
    FIELD(REG_PCSR_MASK, FABRICEN, 9, 1)
    FIELD(REG_PCSR_MASK, TRISTATE, 8, 1)
    FIELD(REG_PCSR_MASK, HOLDSTATE, 7, 1)
    FIELD(REG_PCSR_MASK, INITSTATE, 6, 1)
    FIELD(REG_PCSR_MASK, ODISABLE, 2, 4)
    FIELD(REG_PCSR_MASK, GATEREG, 1, 1)
    FIELD(REG_PCSR_MASK, PCOMPLETE, 0, 1)
REG32(REG_PCSR_CONTROL, 0x4)
    FIELD(REG_PCSR_CONTROL, TEST_SAFE, 20, 1)
    FIELD(REG_PCSR_CONTROL, SLVERREN, 19, 1)
    FIELD(REG_PCSR_CONTROL, MEM_CLEAR_TRIGGER, 18, 1)
    FIELD(REG_PCSR_CONTROL, SYS_RST_MASK, 15, 3)
    FIELD(REG_PCSR_CONTROL, PWRDN, 14, 1)
    FIELD(REG_PCSR_CONTROL, DISNPICLK, 13, 1)
    FIELD(REG_PCSR_CONTROL, APBEN, 12, 1)
    FIELD(REG_PCSR_CONTROL, SCAN_CLEAR_TRIGGER, 11, 1)
    FIELD(REG_PCSR_CONTROL, STARTCAL, 10, 1)
    FIELD(REG_PCSR_CONTROL, FABRICEN, 9, 1)
    FIELD(REG_PCSR_CONTROL, TRISTATE, 8, 1)
    FIELD(REG_PCSR_CONTROL, HOLDSTATE, 7, 1)
    FIELD(REG_PCSR_CONTROL, INITSTATE, 6, 1)
    FIELD(REG_PCSR_CONTROL, ODISABLE, 2, 4)
    FIELD(REG_PCSR_CONTROL, GATEREG, 1, 1)
    FIELD(REG_PCSR_CONTROL, PCOMPLETE, 0, 1)
REG32(REG_PCSR_STATUS, 0x8)
    FIELD(REG_PCSR_STATUS, HARD_FAIL_OR, 11, 3)
    FIELD(REG_PCSR_STATUS, HARD_FAIL_AND, 8, 3)
    FIELD(REG_PCSR_STATUS, MEM_CLEAR_PASS, 7, 1)
    FIELD(REG_PCSR_STATUS, MEM_CLEAR_DONE, 6, 1)
    FIELD(REG_PCSR_STATUS, CALERROR, 5, 1)
    FIELD(REG_PCSR_STATUS, CALDONE, 4, 1)
    FIELD(REG_PCSR_STATUS, INCAL, 3, 1)
    FIELD(REG_PCSR_STATUS, SCAN_CLEAR_PASS, 2, 1)
    FIELD(REG_PCSR_STATUS, SCAN_CLEAR_DONE, 1, 1)
    FIELD(REG_PCSR_STATUS, PCSRLOCK, 0, 1)
REG32(REG_PCSR_LOCK, 0xc)
    FIELD(REG_PCSR_LOCK, STATE, 0, 1)
REG32(REG_ITR, 0x10)
    FIELD(REG_ITR, LOCK_B, 0, 1)
REG32(REG_ISR, 0x14)
    FIELD(REG_ISR, LOCK_B, 0, 1)
REG32(REG_IMR0, 0x18)
    FIELD(REG_IMR0, LOCK_B, 0, 1)
REG32(REG_IER0, 0x1c)
    FIELD(REG_IER0, LOCK_B, 0, 1)
REG32(REG_IDR0, 0x20)
    FIELD(REG_IDR0, LOCK_B, 0, 1)
REG32(REG_IOR, 0x24)
    FIELD(REG_IOR, OFFSET, 0, 5)
REG32(REG_0, 0x30)
    FIELD(REG_0, ALLOW_RESIDULE, 11, 1)
    FIELD(REG_0, AVDD_COMP_SET, 8, 3)
    FIELD(REG_0, AVDD_VBG_PD, 5, 3)
    FIELD(REG_0, AVDD_VBG_SEL, 0, 5)
REG32(REG_1, 0x34)
    FIELD(REG_1, CLKBURST_REPEAT, 12, 1)
    FIELD(REG_1, CLKBURST_ENABLE, 11, 1)
    FIELD(REG_1, CLKBURST_CNT, 3, 8)
    FIELD(REG_1, BYPASS, 2, 1)
    FIELD(REG_1, BITSHFT, 0, 2)
REG32(REG_2, 0x38)
    FIELD(REG_2, CLKFBOUT_MULT, 6, 9)
    FIELD(REG_2, CLKFBOUT_FRACT, 0, 6)
REG32(REG_3, 0x3c)
    FIELD(REG_3, CLKOUT0_USED, 11, 1)
    FIELD(REG_3, CLKOUT0_MX, 9, 2)
    FIELD(REG_3, CLKOUT0_DIVIDE, 0, 9)
REG32(REG_4, 0x40)
    FIELD(REG_4, CLKOUT0_DT, 0, 8)
REG32(REG_5, 0x44)
    FIELD(REG_5, CLKOUT1_USED, 11, 1)
    FIELD(REG_5, CLKOUT1_MX, 9, 2)
    FIELD(REG_5, CLKOUT1_DIVIDE, 0, 9)
REG32(REG_6, 0x48)
    FIELD(REG_6, CLKOUT1_DT, 0, 8)
REG32(REG_7, 0x4c)
    FIELD(REG_7, CLKOUT2_USED, 11, 1)
    FIELD(REG_7, CLKOUT2_MX, 9, 2)
    FIELD(REG_7, CLKOUT2_DIVIDE, 0, 9)
REG32(REG_8, 0x50)
    FIELD(REG_8, CLKOUT2_DT, 0, 8)
REG32(REG_9, 0x54)
    FIELD(REG_9, CLKOUT3_USED, 11, 1)
    FIELD(REG_9, CLKOUT3_MX, 9, 2)
    FIELD(REG_9, CLKOUT3_DIVIDE, 0, 9)
REG32(REG_10, 0x58)
    FIELD(REG_10, CLKOUT3_DT, 0, 8)
REG32(REG_11, 0x5c)
    FIELD(REG_11, CNT_EDGE_SEL, 0, 9)
REG32(REG_12, 0x60)
    FIELD(REG_12, DIRECT_PATH_CNTRL, 9, 1)
    FIELD(REG_12, DESKEW_EN, 8, 1)
    FIELD(REG_12, DESKEW_DLY_PATH, 7, 1)
    FIELD(REG_12, DESKEW_DLY_EN, 6, 1)
    FIELD(REG_12, DESKEW_DLY, 0, 6)
REG32(REG_13, 0x64)
    FIELD(REG_13, EN_RKSHORT, 11, 1)
    FIELD(REG_13, EN_CURR_SINK, 10, 1)
    FIELD(REG_13, DPLL_EN, 9, 1)
    FIELD(REG_13, DIVCLK_DIVIDE, 0, 9)
REG32(REG_14, 0x68)
    FIELD(REG_14, FORCE_SENSE_SHORT, 15, 1)
    FIELD(REG_14, ENWIN_TDC, 14, 1)
    FIELD(REG_14, EN_VCO_DIV6, 13, 1)
    FIELD(REG_14, EN_VCO_DIV1, 12, 1)
    FIELD(REG_14, EN_TESTIN, 11, 1)
    FIELD(REG_14, EN_SYNC_CK_TEST, 10, 1)
    FIELD(REG_14, EN_SWITCH, 9, 1)
    FIELD(REG_14, EN_NBTI_TURNOFFREGULATOR, 8, 1)
    FIELD(REG_14, EN_MOD, 7, 1)
    FIELD(REG_14, EN_MCLK_GATED, 6, 1)
    FIELD(REG_14, EN_LOCKED_DESKEW, 5, 1)
    FIELD(REG_14, EN_JUMP_PRESET, 4, 1)
    FIELD(REG_14, EN_EDGESEL_DLY, 3, 1)
    FIELD(REG_14, EN_DIVOUT, 2, 1)
    FIELD(REG_14, EN_DESKEW_TRACK, 1, 1)
    FIELD(REG_14, EN_CALIBRATION, 0, 1)
REG32(REG_15, 0x6c)
    FIELD(REG_15, HYST_TYPE1, 4, 4)
    FIELD(REG_15, HYST, 0, 4)
REG32(REG_16, 0x70)
    FIELD(REG_16, INTERP1_SKEW, 10, 5)
    FIELD(REG_16, INTERP1_SEL, 8, 2)
    FIELD(REG_16, INTERP0_SKEW, 2, 5)
    FIELD(REG_16, INTERP0_SEL, 0, 2)
REG32(REG_17, 0x74)
    FIELD(REG_17, INTERP3_SKEW, 10, 5)
    FIELD(REG_17, INTERP3_SEL, 8, 2)
    FIELD(REG_17, INTERP2_SKEW, 2, 5)
    FIELD(REG_17, INTERP2_SEL, 0, 2)
REG32(REG_18, 0x78)
    FIELD(REG_18, IS_RST_INVERTED, 4, 1)
    FIELD(REG_18, IS_PWRDWN_INVERTED, 3, 1)
    FIELD(REG_18, IS_PSINCDEC_INVERTED, 2, 1)
    FIELD(REG_18, IS_PSEN_INVERTED, 1, 1)
    FIELD(REG_18, IS_CLKIN_INVERTED, 0, 1)
REG32(REG_19, 0x7c)
    FIELD(REG_19, JUMP3, 10, 5)
    FIELD(REG_19, JUMP2, 5, 5)
    FIELD(REG_19, JUMP1, 0, 5)
REG32(REG_20, 0x80)
    FIELD(REG_20, JUMP6, 10, 5)
    FIELD(REG_20, JUMP5, 5, 5)
    FIELD(REG_20, JUMP4, 0, 5)
REG32(REG_21, 0x84)
    FIELD(REG_21, JUMP9, 10, 5)
    FIELD(REG_21, JUMP8, 5, 5)
    FIELD(REG_21, JUMP7, 0, 5)
REG32(REG_22, 0x88)
    FIELD(REG_22, JUMP12, 10, 5)
    FIELD(REG_22, JUMP11, 5, 5)
    FIELD(REG_22, JUMP10, 0, 5)
REG32(REG_23, 0x8c)
    FIELD(REG_23, JUMP15, 10, 5)
    FIELD(REG_23, JUMP14, 5, 5)
    FIELD(REG_23, JUMP13, 0, 5)
REG32(REG_24, 0x90)
    FIELD(REG_24, KIP, 8, 4)
    FIELD(REG_24, KPP, 5, 3)
REG32(REG_25, 0x94)
    FIELD(REG_25, LOCK_TH, 0, 12)
REG32(REG_26, 0x98)
    FIELD(REG_26, LOCK_TH_TYPE1, 0, 12)
REG32(REG_27, 0x9c)
    FIELD(REG_27, LOCK_TMR, 0, 12)
REG32(REG_28, 0xa0)
    FIELD(REG_28, LOCK_TMR_TYPE1, 0, 12)
REG32(REG_29, 0xa4)
    FIELD(REG_29, RETIME_SEL, 3, 2)
    FIELD(REG_29, REGLPF_RES_SHORT, 2, 1)
    FIELD(REG_29, NBTI_MUX, 0, 2)
REG32(REG_30, 0xa8)
    FIELD(REG_30, SEL_LOCKED_IN, 14, 1)
    FIELD(REG_30, SEL_REG_DELAY, 12, 2)
    FIELD(REG_30, SPARE_DIGITAL, 2, 10)
    FIELD(REG_30, SENSE_TEST_EN, 1, 1)
    FIELD(REG_30, SEL_FREQ_LOCK, 0, 1)
REG32(REG_31, 0xac)
    FIELD(REG_31, SUP_SEL_VCCINT, 4, 1)
    FIELD(REG_31, SUP_SEL_VCCAUX, 3, 1)
    FIELD(REG_31, SUP_SEL_VBGHALF, 2, 1)
    FIELD(REG_31, SUP_SEL_VBG, 1, 1)
    FIELD(REG_31, SUP_SEL_AVDD, 0, 1)
REG32(REG_32, 0xb0)
    FIELD(REG_32, TESTOUT1_MUX_SEL, 6, 6)
    FIELD(REG_32, TESTOUT0_MUX_SEL, 0, 6)
REG32(REG_33, 0xb4)
    FIELD(REG_33, TESTOUT3_MUX_SEL, 6, 6)
    FIELD(REG_33, TESTOUT2_MUX_SEL, 0, 6)
REG32(REG_34, 0xb8)
    FIELD(REG_34, SKEW_SEL, 9, 6)
    FIELD(REG_34, USE_REG_VALID, 8, 1)
    FIELD(REG_34, VLF_VALID_SEL, 5, 3)
    FIELD(REG_34, VLF_SWITCH_SEL, 2, 3)
    FIELD(REG_34, TMUX_MUX_SEL, 0, 2)

#define CMT_DPLL_R_MAX (R_REG_34 + 1)

typedef struct CMT_DPLL {
    SysBusDevice parent_obj;
    MemoryRegion iomem;

    uint32_t regs[CMT_DPLL_R_MAX];
    RegisterInfo regs_info[CMT_DPLL_R_MAX];
} CMT_DPLL;

#define LOCK_VAL 0xF9E8D7C6

static void cmt_dpll_lock_postw(RegisterInfo *reg, uint64_t val64)
{
    CMT_DPLL *s = XILINX_CMT_DPLL(reg->opaque);
    bool locked = val64 != LOCK_VAL;

    ARRAY_FIELD_DP32(s->regs, REG_PCSR_STATUS, PCSRLOCK, locked);
    ARRAY_FIELD_DP32(s->regs, REG_PCSR_LOCK, STATE, locked);
}

static const RegisterAccessInfo cmt_dpll_regs_info[] = {
    {   .name = "REG_PCSR_MASK",  .addr = A_REG_PCSR_MASK,
        .rsvd = 0xffe00000,
    },{ .name = "REG_PCSR_CONTROL",  .addr = A_REG_PCSR_CONTROL,
        .reset = 0x1fe,
        .rsvd = 0xffe00000,
    },{ .name = "REG_PCSR_STATUS",  .addr = A_REG_PCSR_STATUS,
        .reset = R_REG_PCSR_STATUS_PCSRLOCK_MASK \
                 | R_REG_PCSR_STATUS_MEM_CLEAR_PASS_MASK \
                 | R_REG_PCSR_STATUS_MEM_CLEAR_DONE_MASK \
                 | R_REG_PCSR_STATUS_CALDONE_MASK \
                 | R_REG_PCSR_STATUS_SCAN_CLEAR_PASS_MASK \
                 | R_REG_PCSR_STATUS_SCAN_CLEAR_DONE_MASK,
        .rsvd = 0xffffc000,
        .ro = 0x3fff,
    },{ .name = "REG_PCSR_LOCK",  .addr = A_REG_PCSR_LOCK,
        .reset = 0x1,
        .post_write = cmt_dpll_lock_postw
    },{ .name = "REG_ITR",  .addr = A_REG_ITR,
        .rsvd = 0xfffffffe,
    },{ .name = "REG_ISR",  .addr = A_REG_ISR,
        .rsvd = 0xfffffffe,
        .w1c = 0x1,
    },{ .name = "REG_IMR0",  .addr = A_REG_IMR0,
        .reset = 0x1,
        .rsvd = 0xfffffffe,
        .ro = 0x1,
    },{ .name = "REG_IER0",  .addr = A_REG_IER0,
        .rsvd = 0xfffffffe,
    },{ .name = "REG_IDR0",  .addr = A_REG_IDR0,
        .rsvd = 0xfffffffe,
    },{ .name = "REG_IOR",  .addr = A_REG_IOR,
        .reset = 0xb,
        .rsvd = 0xffffffe0,
    },{ .name = "REG_0",  .addr = A_REG_0,
        .reset = 0xbc8,
        .rsvd = 0xfffff000,
    },{ .name = "REG_1",  .addr = A_REG_1,
        .reset = 0xa,
        .rsvd = 0xffffe000,
    },{ .name = "REG_2",  .addr = A_REG_2,
        .reset = 0xa80,
        .rsvd = 0xffff8000,
    },{ .name = "REG_3",  .addr = A_REG_3,
        .reset = 0x202,
        .rsvd = 0xfffff000,
    },{ .name = "REG_4",  .addr = A_REG_4,
        .rsvd = 0xffffff00,
    },{ .name = "REG_5",  .addr = A_REG_5,
        .reset = 0x202,
        .rsvd = 0xfffff000,
    },{ .name = "REG_6",  .addr = A_REG_6,
        .rsvd = 0xffffff00,
    },{ .name = "REG_7",  .addr = A_REG_7,
        .reset = 0x202,
        .rsvd = 0xfffff000,
    },{ .name = "REG_8",  .addr = A_REG_8,
        .rsvd = 0xffffff00,
    },{ .name = "REG_9",  .addr = A_REG_9,
        .reset = 0x202,
        .rsvd = 0xfffff000,
    },{ .name = "REG_10",  .addr = A_REG_10,
        .rsvd = 0xffffff00,
    },{ .name = "REG_11",  .addr = A_REG_11,
        .reset = 0x80,
        .rsvd = 0xfffffe00,
    },{ .name = "REG_12",  .addr = A_REG_12,
        .rsvd = 0xfffffc00,
    },{ .name = "REG_13",  .addr = A_REG_13,
        .reset = 0x1,
        .rsvd = 0xfffff000,
    },{ .name = "REG_14",  .addr = A_REG_14,
        .reset = 0xb1c,
        .rsvd = 0xffff0000,
    },{ .name = "REG_15",  .addr = A_REG_15,
        .reset = 0x48,
        .rsvd = 0xffffff00,
    },{ .name = "REG_16",  .addr = A_REG_16,
        .rsvd = 0xffff8080,
        .ro = 0x80,
    },{ .name = "REG_17",  .addr = A_REG_17,
        .rsvd = 0xffff8080,
        .ro = 0x80,
    },{ .name = "REG_18",  .addr = A_REG_18,
        .rsvd = 0xffffffe0,
    },{ .name = "REG_19",  .addr = A_REG_19,
        .reset = 0x1482,
        .rsvd = 0xffff8000,
    },{ .name = "REG_20",  .addr = A_REG_20,
        .reset = 0x1487,
        .rsvd = 0xffff8000,
    },{ .name = "REG_21",  .addr = A_REG_21,
        .reset = 0x24e6,
        .rsvd = 0xffff8000,
    },{ .name = "REG_22",  .addr = A_REG_22,
        .reset = 0x14a7,
        .rsvd = 0xffff8000,
    },{ .name = "REG_23",  .addr = A_REG_23,
        .reset = 0x1ca4,
        .rsvd = 0xffff8000,
    },{ .name = "REG_24",  .addr = A_REG_24,
        .reset = 0x240,
        .rsvd = 0xfffff01f,
        .ro = 0x1f,
    },{ .name = "REG_25",  .addr = A_REG_25,
        .reset = 0x40,
        .rsvd = 0xfffff000,
    },{ .name = "REG_26",  .addr = A_REG_26,
        .reset = 0x20,
        .rsvd = 0xfffff000,
    },{ .name = "REG_27",  .addr = A_REG_27,
        .reset = 0x20,
        .rsvd = 0xfffff000,
    },{ .name = "REG_28",  .addr = A_REG_28,
        .reset = 0x20,
        .rsvd = 0xfffff000,
    },{ .name = "REG_29",  .addr = A_REG_29,
        .reset = 0x11,
        .rsvd = 0xffffffe0,
    },{ .name = "REG_30",  .addr = A_REG_30,
        .reset = 0x4000,
        .rsvd = 0xffff8000,
    },{ .name = "REG_31",  .addr = A_REG_31,
        .rsvd = 0xffffffe0,
    },{ .name = "REG_32",  .addr = A_REG_32,
        .rsvd = 0xfffff000,
    },{ .name = "REG_33",  .addr = A_REG_33,
        .rsvd = 0xfffff000,
    },{ .name = "REG_34",  .addr = A_REG_34,
        .reset = 0x16c,
        .rsvd = 0xffff8000,
    }
};

static void cmt_dpll_reset(DeviceState *dev)
{
    CMT_DPLL *s = XILINX_CMT_DPLL(dev);
    unsigned int i;

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

static MemTxResult reg_write(void *opaque, hwaddr addr,
                             uint64_t data, unsigned size, MemTxAttrs attrs)
{
    RegisterInfoArray *reg_array = opaque;
    CMT_DPLL *s = XILINX_CMT_DPLL(reg_array->r[0]->opaque);

    /* Is the register set Locked?  */
    if (ARRAY_FIELD_EX32(s->regs, REG_PCSR_LOCK, STATE)
        && addr != A_REG_PCSR_LOCK) {
        return MEMTX_ERROR;
    }

    register_write_memory(opaque, addr, data, size);
    return MEMTX_OK;
}

static const MemoryRegionOps cmt_dpll_ops = {
    .read = register_read_memory,
    .write_with_attrs = reg_write,
    .endianness = DEVICE_LITTLE_ENDIAN,
    .valid = {
        .min_access_size = 4,
        .max_access_size = 4,
    },
};

static void cmt_dpll_init(Object *obj)
{
    CMT_DPLL *s = XILINX_CMT_DPLL(obj);
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    RegisterInfoArray *reg_array;

    memory_region_init(&s->iomem, obj, TYPE_XILINX_CMT_DPLL,
                       CMT_DPLL_R_MAX * 4);
    reg_array =
        register_init_block32(DEVICE(obj), cmt_dpll_regs_info,
                              ARRAY_SIZE(cmt_dpll_regs_info),
                              s->regs_info, s->regs,
                              &cmt_dpll_ops,
                              XILINX_CMT_DPLL_ERR_DEBUG,
                              CMT_DPLL_R_MAX * 4);
    memory_region_add_subregion(&s->iomem,
                                0x0,
                                &reg_array->mem);
    sysbus_init_mmio(sbd, &s->iomem);
}

static const VMStateDescription vmstate_cmt_dpll = {
    .name = TYPE_XILINX_CMT_DPLL,
    .version_id = 1,
    .minimum_version_id = 1,
    .fields = (VMStateField[]) {
        VMSTATE_UINT32_ARRAY(regs, CMT_DPLL, CMT_DPLL_R_MAX),
        VMSTATE_END_OF_LIST(),
    }
};

static void cmt_dpll_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);

    dc->reset = cmt_dpll_reset;
    dc->vmsd = &vmstate_cmt_dpll;
}

static const TypeInfo cmt_dpll_info = {
    .name          = TYPE_XILINX_CMT_DPLL,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(CMT_DPLL),
    .class_init    = cmt_dpll_class_init,
    .instance_init = cmt_dpll_init,
};

static void cmt_dpll_register_types(void)
{
    type_register_static(&cmt_dpll_info);
}

type_init(cmt_dpll_register_types)
