qemu/hw/misc/xlnx-versal-cframe-reg.c
<<
>>
Prefs
   1/*
   2 * QEMU model of the CFRAME_REG Configuration Frame Control
   3 *
   4 * Copyright (c) 2022 Xilinx Inc.
   5 *
   6 * Partially autogenerated by xregqemu.py 2022-01-10.
   7 * Written by Francisco Iglesias <francisco.iglesias@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 "hw/registerfields.h"
  32#include "qemu/bitops.h"
  33#include "qemu/log.h"
  34#include "qapi/error.h"
  35#include "hw/qdev-properties.h"
  36#include "migration/vmstate.h"
  37#include "hw/irq.h"
  38#include "hw/misc/xlnx-cfi-if.h"
  39
  40#ifndef XILINX_CFRAME_REG_ERR_DEBUG
  41#define XILINX_CFRAME_REG_ERR_DEBUG 0
  42#endif
  43
  44#define TYPE_XILINX_CFRAME_REG "xlnx.cframe_reg"
  45
  46#define XILINX_CFRAME_REG(obj) \
  47     OBJECT_CHECK(CFRAME_REG, (obj), TYPE_XILINX_CFRAME_REG)
  48
  49#define TYPE_XILINX_CFRAME_BCAST_REG "xlnx.cframe-bcast-reg"
  50
  51#define XILINX_CFRAME_BCAST_REG(obj) \
  52     OBJECT_CHECK(CFRAME_BCAST_REG, (obj), TYPE_XILINX_CFRAME_BCAST_REG)
  53
  54/*
  55 * The registers in this module are 128 bits wide but it is ok to write
  56 * and read them through 4 sequential 32 bit accesses (address[3:2] = 0,
  57 * 1, 2, 3).
  58 */
  59REG32(CRC0, 0x0)
  60    FIELD(CRC, CRC, 0, 32)
  61REG32(CRC1, 0x4)
  62REG32(CRC2, 0x8)
  63REG32(CRC3, 0xc)
  64REG32(FAR0, 0x10)
  65    FIELD(FAR0, SEGMENT, 23, 2)
  66    FIELD(FAR0, BLOCKTYPE, 20, 3)
  67    FIELD(FAR0, FRAME_ADDR, 0, 20)
  68REG32(FAR1, 0x14)
  69REG32(FAR2, 0x18)
  70REG32(FAR3, 0x1c)
  71REG32(FAR_SFR0, 0x20)
  72    FIELD(FAR_SFR0, BLOCKTYPE, 20, 3)
  73    FIELD(FAR_SFR0, FRAME_ADDR, 0, 20)
  74REG32(FAR_SFR1, 0x24)
  75REG32(FAR_SFR2, 0x28)
  76REG32(FAR_SFR3, 0x2c)
  77REG32(FDRI0, 0x40)
  78REG32(FDRI1, 0x44)
  79REG32(FDRI2, 0x48)
  80REG32(FDRI3, 0x4c)
  81REG32(FRCNT0, 0x50)
  82    FIELD(FRCNT0, FRCNT, 0, 32)
  83REG32(FRCNT1, 0x54)
  84REG32(FRCNT2, 0x58)
  85REG32(FRCNT3, 0x5c)
  86REG32(CMD0, 0x60)
  87    FIELD(CMD0, CMD, 0, 5)
  88REG32(CMD1, 0x64)
  89REG32(CMD2, 0x68)
  90REG32(CMD3, 0x6c)
  91REG32(CR_MASK0, 0x70)
  92REG32(CR_MASK1, 0x74)
  93REG32(CR_MASK2, 0x78)
  94REG32(CR_MASK3, 0x7c)
  95REG32(CTL0, 0x80)
  96    FIELD(CTL, PER_FRAME_CRC, 0, 1)
  97REG32(CTL1, 0x84)
  98REG32(CTL2, 0x88)
  99REG32(CTL3, 0x8c)
 100REG32(CFRM_ISR0, 0x150)
 101    FIELD(CFRM_ISR0, READ_BROADCAST_ERROR, 21, 1)
 102    FIELD(CFRM_ISR0, CMD_MISSING_ERROR, 20, 1)
 103    FIELD(CFRM_ISR0, RW_ROWOFF_ERROR, 19, 1)
 104    FIELD(CFRM_ISR0, READ_REG_ADDR_ERROR, 18, 1)
 105    FIELD(CFRM_ISR0, READ_BLK_TYPE_ERROR, 17, 1)
 106    FIELD(CFRM_ISR0, READ_FRAME_ADDR_ERROR, 16, 1)
 107    FIELD(CFRM_ISR0, WRITE_REG_ADDR_ERROR, 15, 1)
 108    FIELD(CFRM_ISR0, WRITE_BLK_TYPE_ERROR, 13, 1)
 109    FIELD(CFRM_ISR0, WRITE_FRAME_ADDR_ERROR, 12, 1)
 110    FIELD(CFRM_ISR0, MFW_OVERRUN_ERROR, 11, 1)
 111    FIELD(CFRM_ISR0, FAR_FIFO_UNDERFLOW, 10, 1)
 112    FIELD(CFRM_ISR0, FAR_FIFO_OVERFLOW, 9, 1)
 113    FIELD(CFRM_ISR0, PER_FRAME_SEQ_ERROR, 8, 1)
 114    FIELD(CFRM_ISR0, CRC_ERROR, 7, 1)
 115    FIELD(CFRM_ISR0, WRITE_OVERRUN_ERROR, 6, 1)
 116    FIELD(CFRM_ISR0, READ_OVERRUN_ERROR, 5, 1)
 117    FIELD(CFRM_ISR0, CMD_INTERRUPT_ERROR, 4, 1)
 118    FIELD(CFRM_ISR0, WRITE_INTERRUPT_ERROR, 3, 1)
 119    FIELD(CFRM_ISR0, READ_INTERRUPT_ERROR, 2, 1)
 120    FIELD(CFRM_ISR0, SEU_CRC_ERROR, 1, 1)
 121    FIELD(CFRM_ISR0, SEU_ECC_ERROR, 0, 1)
 122REG32(CFRM_ISR1, 0x154)
 123REG32(CFRM_ISR2, 0x158)
 124REG32(CFRM_ISR3, 0x15c)
 125REG32(CFRM_IMR0, 0x160)
 126    FIELD(CFRM_IMR0, READ_BROADCAST_ERROR, 21, 1)
 127    FIELD(CFRM_IMR0, CMD_MISSING_ERROR, 20, 1)
 128    FIELD(CFRM_IMR0, RW_ROWOFF_ERROR, 19, 1)
 129    FIELD(CFRM_IMR0, READ_REG_ADDR_ERROR, 18, 1)
 130    FIELD(CFRM_IMR0, READ_BLK_TYPE_ERROR, 17, 1)
 131    FIELD(CFRM_IMR0, READ_FRAME_ADDR_ERROR, 16, 1)
 132    FIELD(CFRM_IMR0, WRITE_REG_ADDR_ERROR, 15, 1)
 133    FIELD(CFRM_IMR0, WRITE_BLK_TYPE_ERROR, 13, 1)
 134    FIELD(CFRM_IMR0, WRITE_FRAME_ADDR_ERROR, 12, 1)
 135    FIELD(CFRM_IMR0, MFW_OVERRUN_ERROR, 11, 1)
 136    FIELD(CFRM_IMR0, FAR_FIFO_UNDERFLOW, 10, 1)
 137    FIELD(CFRM_IMR0, FAR_FIFO_OVERFLOW, 9, 1)
 138    FIELD(CFRM_IMR0, PER_FRAME_SEQ_ERROR, 8, 1)
 139    FIELD(CFRM_IMR0, CRC_ERROR, 7, 1)
 140    FIELD(CFRM_IMR0, WRITE_OVERRUN_ERROR, 6, 1)
 141    FIELD(CFRM_IMR0, READ_OVERRUN_ERROR, 5, 1)
 142    FIELD(CFRM_IMR0, CMD_INTERRUPT_ERROR, 4, 1)
 143    FIELD(CFRM_IMR0, WRITE_INTERRUPT_ERROR, 3, 1)
 144    FIELD(CFRM_IMR0, READ_INTERRUPT_ERROR, 2, 1)
 145    FIELD(CFRM_IMR0, SEU_CRC_ERROR, 1, 1)
 146    FIELD(CFRM_IMR0, SEU_ECC_ERROR, 0, 1)
 147REG32(CFRM_IMR1, 0x164)
 148REG32(CFRM_IMR2, 0x168)
 149REG32(CFRM_IMR3, 0x16c)
 150REG32(CFRM_IER0, 0x170)
 151    FIELD(CFRM_IER0, READ_BROADCAST_ERROR, 21, 1)
 152    FIELD(CFRM_IER0, CMD_MISSING_ERROR, 20, 1)
 153    FIELD(CFRM_IER0, RW_ROWOFF_ERROR, 19, 1)
 154    FIELD(CFRM_IER0, READ_REG_ADDR_ERROR, 18, 1)
 155    FIELD(CFRM_IER0, READ_BLK_TYPE_ERROR, 17, 1)
 156    FIELD(CFRM_IER0, READ_FRAME_ADDR_ERROR, 16, 1)
 157    FIELD(CFRM_IER0, WRITE_REG_ADDR_ERROR, 15, 1)
 158    FIELD(CFRM_IER0, WRITE_BLK_TYPE_ERROR, 13, 1)
 159    FIELD(CFRM_IER0, WRITE_FRAME_ADDR_ERROR, 12, 1)
 160    FIELD(CFRM_IER0, MFW_OVERRUN_ERROR, 11, 1)
 161    FIELD(CFRM_IER0, FAR_FIFO_UNDERFLOW, 10, 1)
 162    FIELD(CFRM_IER0, FAR_FIFO_OVERFLOW, 9, 1)
 163    FIELD(CFRM_IER0, PER_FRAME_SEQ_ERROR, 8, 1)
 164    FIELD(CFRM_IER0, CRC_ERROR, 7, 1)
 165    FIELD(CFRM_IER0, WRITE_OVERRUN_ERROR, 6, 1)
 166    FIELD(CFRM_IER0, READ_OVERRUN_ERROR, 5, 1)
 167    FIELD(CFRM_IER0, CMD_INTERRUPT_ERROR, 4, 1)
 168    FIELD(CFRM_IER0, WRITE_INTERRUPT_ERROR, 3, 1)
 169    FIELD(CFRM_IER0, READ_INTERRUPT_ERROR, 2, 1)
 170    FIELD(CFRM_IER0, SEU_CRC_ERROR, 1, 1)
 171    FIELD(CFRM_IER0, SEU_ECC_ERROR, 0, 1)
 172REG32(CFRM_IER1, 0x174)
 173REG32(CFRM_IER2, 0x178)
 174REG32(CFRM_IER3, 0x17c)
 175REG32(CFRM_IDR0, 0x180)
 176    FIELD(CFRM_IDR0, READ_BROADCAST_ERROR, 21, 1)
 177    FIELD(CFRM_IDR0, CMD_MISSING_ERROR, 20, 1)
 178    FIELD(CFRM_IDR0, RW_ROWOFF_ERROR, 19, 1)
 179    FIELD(CFRM_IDR0, READ_REG_ADDR_ERROR, 18, 1)
 180    FIELD(CFRM_IDR0, READ_BLK_TYPE_ERROR, 17, 1)
 181    FIELD(CFRM_IDR0, READ_FRAME_ADDR_ERROR, 16, 1)
 182    FIELD(CFRM_IDR0, WRITE_REG_ADDR_ERROR, 15, 1)
 183    FIELD(CFRM_IDR0, WRITE_BLK_TYPE_ERROR, 13, 1)
 184    FIELD(CFRM_IDR0, WRITE_FRAME_ADDR_ERROR, 12, 1)
 185    FIELD(CFRM_IDR0, MFW_OVERRUN_ERROR, 11, 1)
 186    FIELD(CFRM_IDR0, FAR_FIFO_UNDERFLOW, 10, 1)
 187    FIELD(CFRM_IDR0, FAR_FIFO_OVERFLOW, 9, 1)
 188    FIELD(CFRM_IDR0, PER_FRAME_SEQ_ERROR, 8, 1)
 189    FIELD(CFRM_IDR0, CRC_ERROR, 7, 1)
 190    FIELD(CFRM_IDR0, WRITE_OVERRUN_ERROR, 6, 1)
 191    FIELD(CFRM_IDR0, READ_OVERRUN_ERROR, 5, 1)
 192    FIELD(CFRM_IDR0, CMD_INTERRUPT_ERROR, 4, 1)
 193    FIELD(CFRM_IDR0, WRITE_INTERRUPT_ERROR, 3, 1)
 194    FIELD(CFRM_IDR0, READ_INTERRUPT_ERROR, 2, 1)
 195    FIELD(CFRM_IDR0, SEU_CRC_ERROR, 1, 1)
 196    FIELD(CFRM_IDR0, SEU_ECC_ERROR, 0, 1)
 197REG32(CFRM_IDR1, 0x184)
 198REG32(CFRM_IDR2, 0x188)
 199REG32(CFRM_IDR3, 0x18c)
 200REG32(CFRM_ITR0, 0x190)
 201    FIELD(CFRM_ITR0, READ_BROADCAST_ERROR, 21, 1)
 202    FIELD(CFRM_ITR0, CMD_MISSING_ERROR, 20, 1)
 203    FIELD(CFRM_ITR0, RW_ROWOFF_ERROR, 19, 1)
 204    FIELD(CFRM_ITR0, READ_REG_ADDR_ERROR, 18, 1)
 205    FIELD(CFRM_ITR0, READ_BLK_TYPE_ERROR, 17, 1)
 206    FIELD(CFRM_ITR0, READ_FRAME_ADDR_ERROR, 16, 1)
 207    FIELD(CFRM_ITR0, WRITE_REG_ADDR_ERROR, 15, 1)
 208    FIELD(CFRM_ITR0, WRITE_BLK_TYPE_ERROR, 13, 1)
 209    FIELD(CFRM_ITR0, WRITE_FRAME_ADDR_ERROR, 12, 1)
 210    FIELD(CFRM_ITR0, MFW_OVERRUN_ERROR, 11, 1)
 211    FIELD(CFRM_ITR0, FAR_FIFO_UNDERFLOW, 10, 1)
 212    FIELD(CFRM_ITR0, FAR_FIFO_OVERFLOW, 9, 1)
 213    FIELD(CFRM_ITR0, PER_FRAME_SEQ_ERROR, 8, 1)
 214    FIELD(CFRM_ITR0, CRC_ERROR, 7, 1)
 215    FIELD(CFRM_ITR0, WRITE_OVERRUN_ERROR, 6, 1)
 216    FIELD(CFRM_ITR0, READ_OVERRUN_ERROR, 5, 1)
 217    FIELD(CFRM_ITR0, CMD_INTERRUPT_ERROR, 4, 1)
 218    FIELD(CFRM_ITR0, WRITE_INTERRUPT_ERROR, 3, 1)
 219    FIELD(CFRM_ITR0, READ_INTERRUPT_ERROR, 2, 1)
 220    FIELD(CFRM_ITR0, SEU_CRC_ERROR, 1, 1)
 221    FIELD(CFRM_ITR0, SEU_ECC_ERROR, 0, 1)
 222REG32(CFRM_ITR1, 0x194)
 223REG32(CFRM_ITR2, 0x198)
 224REG32(CFRM_ITR3, 0x19c)
 225REG32(SEU_SYNDRM00, 0x1a0)
 226REG32(SEU_SYNDRM01, 0x1a4)
 227REG32(SEU_SYNDRM02, 0x1a8)
 228REG32(SEU_SYNDRM03, 0x1ac)
 229REG32(SEU_SYNDRM10, 0x1b0)
 230REG32(SEU_SYNDRM11, 0x1b4)
 231REG32(SEU_SYNDRM12, 0x1b8)
 232REG32(SEU_SYNDRM13, 0x1bc)
 233REG32(SEU_SYNDRM20, 0x1c0)
 234REG32(SEU_SYNDRM21, 0x1c4)
 235REG32(SEU_SYNDRM22, 0x1c8)
 236REG32(SEU_SYNDRM23, 0x1cc)
 237REG32(SEU_SYNDRM30, 0x1d0)
 238REG32(SEU_SYNDRM31, 0x1d4)
 239REG32(SEU_SYNDRM32, 0x1d8)
 240REG32(SEU_SYNDRM33, 0x1dc)
 241REG32(SEU_VIRTUAL_SYNDRM0, 0x1e0)
 242REG32(SEU_VIRTUAL_SYNDRM1, 0x1e4)
 243REG32(SEU_VIRTUAL_SYNDRM2, 0x1e8)
 244REG32(SEU_VIRTUAL_SYNDRM3, 0x1ec)
 245REG32(SEU_CRC0, 0x1f0)
 246REG32(SEU_CRC1, 0x1f4)
 247REG32(SEU_CRC2, 0x1f8)
 248REG32(SEU_CRC3, 0x1fc)
 249REG32(CFRAME_FAR_BOT0, 0x200)
 250REG32(CFRAME_FAR_BOT1, 0x204)
 251REG32(CFRAME_FAR_BOT2, 0x208)
 252REG32(CFRAME_FAR_BOT3, 0x20c)
 253REG32(CFRAME_FAR_TOP0, 0x210)
 254REG32(CFRAME_FAR_TOP1, 0x214)
 255REG32(CFRAME_FAR_TOP2, 0x218)
 256REG32(CFRAME_FAR_TOP3, 0x21c)
 257REG32(LAST_FRAME_BOT0, 0x220)
 258    FIELD(LAST_FRAME_BOT0, BLOCKTYPE1_LAST_FRAME_LSB, 20, 12)
 259    FIELD(LAST_FRAME_BOT0, BLOCKTYPE0_LAST_FRAME, 0, 20)
 260REG32(LAST_FRAME_BOT1, 0x224)
 261    FIELD(LAST_FRAME_BOT1, BLOCKTYPE3_LAST_FRAME_LSB, 28, 4)
 262    FIELD(LAST_FRAME_BOT1, BLOCKTYPE2_LAST_FRAME, 8, 20)
 263    FIELD(LAST_FRAME_BOT1, BLOCKTYPE1_LAST_FRAME_MSB, 0, 8)
 264REG32(LAST_FRAME_BOT2, 0x228)
 265    FIELD(LAST_FRAME_BOT2, BLOCKTYPE3_LAST_FRAME_MSB, 0, 16)
 266REG32(LAST_FRAME_BOT3, 0x22c)
 267REG32(LAST_FRAME_TOP0, 0x230)
 268    FIELD(LAST_FRAME_TOP0, BLOCKTYPE5_LAST_FRAME_LSB, 20, 12)
 269    FIELD(LAST_FRAME_TOP0, BLOCKTYPE4_LAST_FRAME, 0, 20)
 270REG32(LAST_FRAME_TOP1, 0x234)
 271    FIELD(LAST_FRAME_TOP1, BLOCKTYPE6_LAST_FRAME, 8, 20)
 272    FIELD(LAST_FRAME_TOP1, BLOCKTYPE5_LAST_FRAME_MSB, 0, 8)
 273REG32(LAST_FRAME_TOP2, 0x238)
 274REG32(LAST_FRAME_TOP3, 0x23c)
 275
 276#define CFRAME_REG_R_MAX (R_LAST_FRAME_TOP3 + 1)
 277
 278#define KEYHOLE_STREAM_4K 0x1000
 279
 280#define FRAME_NUM_QWORDS 25
 281#define FRAME_NUM_WORDS (FRAME_NUM_QWORDS * 4) /* 25 * 128 bits */
 282
 283#define MAX_BLOCKTYPE 6
 284#define MAX_BLOCKTYPE_FRAMES 0xFFFFF
 285
 286typedef enum {
 287    CFRAME_CMD_WCFG = 1,
 288    CFRAME_CMD_ROWON = 2,
 289    CFRAME_CMD_ROWOFF = 3,
 290    CFRAME_CMD_RCFG = 4,
 291    CFRAME_CMD_DLPARK = 5
 292} cframe_cmd;
 293
 294typedef struct XlnxCFrame {
 295    uint32_t addr;
 296    uint32_t idx;
 297    uint32_t data[FRAME_NUM_WORDS];
 298} XlnxCFrame;
 299
 300typedef struct CFRAME_REG {
 301    SysBusDevice parent_obj;
 302    MemoryRegion iomem;
 303    MemoryRegion iomem_fdri;
 304    qemu_irq irq_cfrm_imr;
 305
 306    /* 128-bit wfifo.  */
 307    uint32_t wfifo[4];
 308
 309    uint32_t regs[CFRAME_REG_R_MAX];
 310    RegisterInfo regs_info[CFRAME_REG_R_MAX];
 311
 312    bool rowon;
 313    bool wcfg;
 314    bool rcfg;
 315
 316    GArray *cframes;
 317    XlnxCFrame new_f;
 318
 319    struct {
 320        XlnxCfiIf *cfu_fdro;
 321        uint32_t blktype_num_frames[7];
 322    } cfg;
 323    bool row_configured;
 324
 325} CFRAME_REG;
 326
 327typedef struct CFRAME_BCAST_REG {
 328    SysBusDevice parent_obj;
 329    MemoryRegion iomem_reg;
 330    MemoryRegion iomem_fdri;
 331
 332    /* 128-bit wfifo. */
 333    uint32_t wfifo[4];
 334
 335    struct {
 336        XlnxCfiIf *cframe[15];
 337    } cfg;
 338
 339} CFRAME_BCAST_REG;
 340
 341static void cfrm_imr_update_irq(CFRAME_REG *s)
 342{
 343    bool pending = s->regs[R_CFRM_ISR0] & ~s->regs[R_CFRM_IMR0];
 344    qemu_set_irq(s->irq_cfrm_imr, pending);
 345}
 346
 347static void cfrm_isr_postw(RegisterInfo *reg, uint64_t val64)
 348{
 349    CFRAME_REG *s = XILINX_CFRAME_REG(reg->opaque);
 350    cfrm_imr_update_irq(s);
 351}
 352
 353static uint64_t cfrm_ier_prew(RegisterInfo *reg, uint64_t val64)
 354{
 355    CFRAME_REG *s = XILINX_CFRAME_REG(reg->opaque);
 356
 357    s->regs[R_CFRM_IMR0] &= ~s->regs[R_CFRM_IER0];
 358    s->regs[R_CFRM_IER0] = 0;
 359    cfrm_imr_update_irq(s);
 360    return 0;
 361}
 362
 363static uint64_t cfrm_idr_prew(RegisterInfo *reg, uint64_t val64)
 364{
 365    CFRAME_REG *s = XILINX_CFRAME_REG(reg->opaque);
 366
 367    s->regs[R_CFRM_IMR0] |= s->regs[R_CFRM_IDR0];
 368    s->regs[R_CFRM_IDR0] = 0;
 369    cfrm_imr_update_irq(s);
 370    return 0;
 371}
 372
 373static uint64_t cfrm_itr_prew(RegisterInfo *reg, uint64_t val64)
 374{
 375    CFRAME_REG *s = XILINX_CFRAME_REG(reg->opaque);
 376
 377    s->regs[R_CFRM_ISR0] |= s->regs[R_CFRM_ITR0];
 378    s->regs[R_CFRM_ITR0] = 0;
 379    cfrm_imr_update_irq(s);
 380    return 0;
 381}
 382
 383static void cframe_incr_far(CFRAME_REG *s)
 384{
 385    uint32_t faddr = ARRAY_FIELD_EX32(s->regs, FAR0, FRAME_ADDR);
 386    uint32_t blktype = ARRAY_FIELD_EX32(s->regs, FAR0, BLOCKTYPE);
 387
 388    assert(blktype <= MAX_BLOCKTYPE);
 389
 390    faddr++;
 391    if (faddr > s->cfg.blktype_num_frames[blktype]) {
 392        /* Restart from 0 and increment block type */
 393        faddr = 0;
 394        blktype++;
 395
 396        assert(blktype <= MAX_BLOCKTYPE);
 397
 398        ARRAY_FIELD_DP32(s->regs, FAR0, BLOCKTYPE, blktype);
 399    }
 400
 401    ARRAY_FIELD_DP32(s->regs, FAR0, FRAME_ADDR, faddr);
 402}
 403
 404static XlnxCFrame *cframes_get_frame(CFRAME_REG *s, uint32_t addr)
 405{
 406    for (int i = 0; i < s->cframes->len; i++) {
 407        XlnxCFrame *f = &g_array_index(s->cframes, XlnxCFrame, i);
 408
 409        if (f->addr == addr) {
 410            return f;
 411        }
 412    }
 413    return NULL;
 414}
 415
 416static void cfrm_fdri_post_write(RegisterInfo *reg, uint64_t val)
 417{
 418    CFRAME_REG *s = XILINX_CFRAME_REG(reg->opaque);
 419
 420    if (s->row_configured && s->rowon && s->wcfg) {
 421        XlnxCFrame *new_f = &s->new_f;
 422
 423        new_f->data[new_f->idx++] = s->regs[R_FDRI0];
 424        new_f->data[new_f->idx++] = s->regs[R_FDRI1];
 425        new_f->data[new_f->idx++] = s->regs[R_FDRI2];
 426        new_f->data[new_f->idx++] = s->regs[R_FDRI3];
 427
 428        assert(new_f->idx <= FRAME_NUM_WORDS);
 429
 430        if (new_f->idx == FRAME_NUM_WORDS) {
 431            XlnxCFrame *cur_f;
 432
 433            /* Include block type and frame address */
 434            new_f->addr = extract32(s->regs[R_FAR0], 0, 23);
 435
 436            cur_f = cframes_get_frame(s, new_f->addr);
 437
 438            if (cur_f) {
 439                /* Overwrite current frame */
 440                cur_f[0] = new_f[0];
 441            } else {
 442                g_array_append_val(s->cframes, new_f[0]);
 443            }
 444
 445            cframe_incr_far(s);
 446
 447            /* Clear out new_f */
 448            memset(new_f, 0, sizeof(*new_f));
 449        }
 450    }
 451}
 452
 453static void cfrm_readout_frames(CFRAME_REG *s, uint32_t start_addr,
 454                                uint32_t end_addr)
 455{
 456    for (uint32_t addr = start_addr; addr < end_addr; addr++) {
 457        XlnxCFrame *f = cframes_get_frame(s, addr);
 458
 459        for (int i = 0; i < FRAME_NUM_WORDS; i += 4) {
 460            XlnxCfiPacket pkt = {};
 461
 462            /* If frame was found transmit the data */
 463            if (f) {
 464                pkt.data[0] = f->data[i];
 465                pkt.data[1] = f->data[i + 1];
 466                pkt.data[2] = f->data[i + 2];
 467                pkt.data[3] = f->data[i + 3];
 468            }
 469
 470            if (s->cfg.cfu_fdro) {
 471                xlnx_cfi_transfer_packet(s->cfg.cfu_fdro, &pkt);
 472            }
 473        }
 474    }
 475}
 476
 477static void cfrm_frcnt_post_write(RegisterInfo *reg, uint64_t val)
 478{
 479    CFRAME_REG *s = XILINX_CFRAME_REG(reg->opaque);
 480
 481    if (s->row_configured && s->rowon && s->rcfg) {
 482        uint32_t start_addr = extract32(s->regs[R_FAR0], 0, 23);
 483        uint32_t end_addr = start_addr + s->regs[R_FRCNT0] / FRAME_NUM_QWORDS;
 484
 485        cfrm_readout_frames(s, start_addr, end_addr);
 486    }
 487}
 488
 489static void cfrm_cmd_post_write(RegisterInfo *reg, uint64_t val)
 490{
 491    CFRAME_REG *s = XILINX_CFRAME_REG(reg->opaque);
 492
 493    if (s->row_configured) {
 494        uint8_t cmd = ARRAY_FIELD_EX32(s->regs, CMD0, CMD);
 495
 496        switch (cmd) {
 497        case CFRAME_CMD_WCFG:
 498            s->wcfg = true;
 499            break;
 500        case CFRAME_CMD_ROWON:
 501            s->rowon = true;
 502            break;
 503        case CFRAME_CMD_ROWOFF:
 504            s->rowon = false;
 505            break;
 506        case CFRAME_CMD_RCFG:
 507            s->rcfg = true;
 508            break;
 509        case CFRAME_CMD_DLPARK:
 510            s->wcfg = false;
 511            s->rcfg = false;
 512            break;
 513        default:
 514            break;
 515        };
 516    }
 517}
 518
 519static uint64_t cfrm_last_frame_bot_post_read(RegisterInfo *reg,
 520                                              uint64_t val64)
 521{
 522    CFRAME_REG *s = XILINX_CFRAME_REG(reg->opaque);
 523    uint64_t val = 0;
 524
 525    switch (reg->access->addr) {
 526    case A_LAST_FRAME_BOT0:
 527        val = FIELD_DP32(val, LAST_FRAME_BOT0, BLOCKTYPE1_LAST_FRAME_LSB,
 528                         s->cfg.blktype_num_frames[1]);
 529        val = FIELD_DP32(val, LAST_FRAME_BOT0, BLOCKTYPE0_LAST_FRAME,
 530                         s->cfg.blktype_num_frames[0]);
 531        break;
 532    case A_LAST_FRAME_BOT1:
 533        val = FIELD_DP32(val, LAST_FRAME_BOT1, BLOCKTYPE3_LAST_FRAME_LSB,
 534                         s->cfg.blktype_num_frames[3]);
 535        val = FIELD_DP32(val, LAST_FRAME_BOT1, BLOCKTYPE2_LAST_FRAME,
 536                         s->cfg.blktype_num_frames[2]);
 537        val = FIELD_DP32(val, LAST_FRAME_BOT1, BLOCKTYPE1_LAST_FRAME_MSB,
 538                         (s->cfg.blktype_num_frames[1] >> 12));
 539        break;
 540    case A_LAST_FRAME_BOT2:
 541        val = FIELD_DP32(val, LAST_FRAME_BOT2, BLOCKTYPE3_LAST_FRAME_MSB,
 542                         (s->cfg.blktype_num_frames[3] >> 4));
 543        break;
 544    case A_LAST_FRAME_BOT3:
 545    default:
 546        break;
 547    }
 548
 549    return val;
 550}
 551
 552static uint64_t cfrm_last_frame_top_post_read(RegisterInfo *reg,
 553                                              uint64_t val64)
 554{
 555    CFRAME_REG *s = XILINX_CFRAME_REG(reg->opaque);
 556    uint64_t val = 0;
 557
 558    switch (reg->access->addr) {
 559    case A_LAST_FRAME_TOP0:
 560        val = FIELD_DP32(val, LAST_FRAME_TOP0, BLOCKTYPE5_LAST_FRAME_LSB,
 561                         s->cfg.blktype_num_frames[5]);
 562        val = FIELD_DP32(val, LAST_FRAME_TOP0, BLOCKTYPE4_LAST_FRAME,
 563                         s->cfg.blktype_num_frames[4]);
 564        break;
 565    case A_LAST_FRAME_TOP1:
 566        val = FIELD_DP32(val, LAST_FRAME_TOP1, BLOCKTYPE6_LAST_FRAME,
 567                         s->cfg.blktype_num_frames[6]);
 568        val = FIELD_DP32(val, LAST_FRAME_TOP1, BLOCKTYPE5_LAST_FRAME_MSB,
 569                         (s->cfg.blktype_num_frames[5] >> 12));
 570        break;
 571    case A_LAST_FRAME_TOP2:
 572    case A_LAST_FRAME_BOT3:
 573    default:
 574        break;
 575    }
 576
 577    return val;
 578}
 579
 580static void cfrm_far_sfr_post_write(RegisterInfo *reg, uint64_t val)
 581{
 582    CFRAME_REG *s = XILINX_CFRAME_REG(reg->opaque);
 583
 584    if (s->row_configured && s->rowon && s->rcfg) {
 585        uint32_t start_addr = extract32(s->regs[R_FAR_SFR0], 0, 23);
 586
 587        /* Readback 1 frame */
 588        cfrm_readout_frames(s, start_addr, start_addr + 1);
 589    }
 590}
 591
 592static const RegisterAccessInfo cframe_reg_regs_info[] = {
 593    {   .name = "CRC0",  .addr = A_CRC0,
 594        .rsvd = 0x00000000,
 595    },{ .name = "CRC1",  .addr = A_CRC0,
 596        .rsvd = 0xffffffff,
 597    },{ .name = "CRC2",  .addr = A_CRC0,
 598        .rsvd = 0xffffffff,
 599    },{ .name = "CRC3",  .addr = A_CRC0,
 600        .rsvd = 0xffffffff,
 601    },{ .name = "FAR0",  .addr = A_FAR0,
 602        .rsvd = 0xfe000000,
 603    },{ .name = "FAR1",  .addr = A_FAR1,
 604        .rsvd = 0xffffffff,
 605    },{ .name = "FAR2",  .addr = A_FAR2,
 606        .rsvd = 0xffffffff,
 607    },{ .name = "FAR3",  .addr = A_FAR3,
 608        .rsvd = 0xffffffff,
 609    },{ .name = "FAR_SFR0",  .addr = A_FAR_SFR0,
 610        .rsvd = 0xff800000,
 611    },{ .name = "FAR_SFR1",  .addr = A_FAR_SFR1,
 612        .rsvd = 0xffffffff,
 613    },{ .name = "FAR_SFR2",  .addr = A_FAR_SFR2,
 614        .rsvd = 0xffffffff,
 615    },{ .name = "FAR_SFR3",  .addr = A_FAR_SFR3,
 616        .rsvd = 0xffffffff,
 617        .post_write = cfrm_far_sfr_post_write,
 618    },{ .name = "FDRI0",  .addr = A_FDRI0,
 619    },{ .name = "FDRI1",  .addr = A_FDRI1,
 620    },{ .name = "FDRI2",  .addr = A_FDRI2,
 621    },{ .name = "FDRI3",  .addr = A_FDRI3,
 622        .post_write = cfrm_fdri_post_write,
 623    },{ .name = "FRCNT0",  .addr = A_FRCNT0,
 624        .rsvd = 0x00000000,
 625    },{ .name = "FRCNT1",  .addr = A_FRCNT1,
 626        .rsvd = 0xffffffff,
 627    },{ .name = "FRCNT2",  .addr = A_FRCNT2,
 628        .rsvd = 0xffffffff,
 629    },{ .name = "FRCNT3",  .addr = A_FRCNT3,
 630        .rsvd = 0xffffffff,
 631        .post_write = cfrm_frcnt_post_write
 632    },{ .name = "CMD0",  .addr = A_CMD0,
 633        .rsvd = 0xffffffe0,
 634    },{ .name = "CMD1",  .addr = A_CMD1,
 635        .rsvd = 0xffffffff,
 636    },{ .name = "CMD2",  .addr = A_CMD2,
 637        .rsvd = 0xffffffff,
 638    },{ .name = "CMD3",  .addr = A_CMD3,
 639        .rsvd = 0xffffffff,
 640        .post_write = cfrm_cmd_post_write
 641    },{ .name = "CR_MASK0",  .addr = A_CR_MASK0,
 642        .rsvd = 0x00000000,
 643    },{ .name = "CR_MASK1",  .addr = A_CR_MASK1,
 644        .rsvd = 0x00000000,
 645    },{ .name = "CR_MASK2",  .addr = A_CR_MASK2,
 646        .rsvd = 0x00000000,
 647    },{ .name = "CR_MASK3",  .addr = A_CR_MASK3,
 648        .rsvd = 0xffffffff,
 649    },{ .name = "CTL0",  .addr = A_CTL0,
 650        .rsvd = 0xfffffff8,
 651    },{ .name = "CTL1",  .addr = A_CTL1,
 652        .rsvd = 0xffffffff,
 653    },{ .name = "CTL2",  .addr = A_CTL2,
 654        .rsvd = 0xffffffff,
 655    },{ .name = "CTL3",  .addr = A_CTL3,
 656        .rsvd = 0xffffffff,
 657    },{ .name = "CFRM_ISR0",  .addr = A_CFRM_ISR0,
 658        .rsvd = 0xffc04000,
 659        .w1c = 0x3bfff,
 660    },{ .name = "CFRM_ISR1",  .addr = A_CFRM_ISR1,
 661        .rsvd = 0xffffffff,
 662    },{ .name = "CFRM_ISR2",  .addr = A_CFRM_ISR2,
 663        .rsvd = 0xffffffff,
 664    },{ .name = "CFRM_ISR3",  .addr = A_CFRM_ISR3,
 665        .rsvd = 0xffffffff,
 666        .post_write = cfrm_isr_postw,
 667    },{ .name = "CFRM_IMR0",  .addr = A_CFRM_IMR0,
 668        .rsvd = 0xffc04000,
 669        .ro = 0xfffff,
 670        .reset = 0x3bfff,
 671    },{ .name = "CFRM_IMR1",  .addr = A_CFRM_IMR1,
 672        .rsvd = 0xffffffff,
 673    },{ .name = "CFRM_IMR2",  .addr = A_CFRM_IMR2,
 674        .rsvd = 0xffffffff,
 675    },{ .name = "CFRM_IMR3",  .addr = A_CFRM_IMR3,
 676        .rsvd = 0xffffffff,
 677    },{ .name = "CFRM_IER0",  .addr = A_CFRM_IER0,
 678        .rsvd = 0xffc04000,
 679    },{ .name = "CFRM_IER1",  .addr = A_CFRM_IER1,
 680        .rsvd = 0xffffffff,
 681    },{ .name = "CFRM_IER2",  .addr = A_CFRM_IER2,
 682        .rsvd = 0xffffffff,
 683    },{ .name = "CFRM_IER3",  .addr = A_CFRM_IER3,
 684        .rsvd = 0xffffffff,
 685        .pre_write = cfrm_ier_prew,
 686    },{ .name = "CFRM_IDR0",  .addr = A_CFRM_IDR0,
 687        .rsvd = 0xffc04000,
 688    },{ .name = "CFRM_IDR1",  .addr = A_CFRM_IDR1,
 689        .rsvd = 0xffffffff,
 690    },{ .name = "CFRM_IDR2",  .addr = A_CFRM_IDR2,
 691        .rsvd = 0xffffffff,
 692    },{ .name = "CFRM_IDR3",  .addr = A_CFRM_IDR3,
 693        .rsvd = 0xffffffff,
 694        .pre_write = cfrm_idr_prew,
 695    },{ .name = "CFRM_ITR0",  .addr = A_CFRM_ITR0,
 696        .rsvd = 0xffc04000,
 697    },{ .name = "CFRM_ITR1",  .addr = A_CFRM_ITR1,
 698        .rsvd = 0xffffffff,
 699    },{ .name = "CFRM_ITR2",  .addr = A_CFRM_ITR2,
 700        .rsvd = 0xffffffff,
 701    },{ .name = "CFRM_ITR3",  .addr = A_CFRM_ITR3,
 702        .rsvd = 0xffffffff,
 703        .pre_write = cfrm_itr_prew,
 704    },{ .name = "SEU_SYNDRM00",  .addr = A_SEU_SYNDRM00,
 705    },{ .name = "SEU_SYNDRM01",  .addr = A_SEU_SYNDRM01,
 706    },{ .name = "SEU_SYNDRM02",  .addr = A_SEU_SYNDRM02,
 707    },{ .name = "SEU_SYNDRM03",  .addr = A_SEU_SYNDRM03,
 708    },{ .name = "SEU_SYNDRM10",  .addr = A_SEU_SYNDRM10,
 709    },{ .name = "SEU_SYNDRM11",  .addr = A_SEU_SYNDRM11,
 710    },{ .name = "SEU_SYNDRM12",  .addr = A_SEU_SYNDRM12,
 711    },{ .name = "SEU_SYNDRM13",  .addr = A_SEU_SYNDRM13,
 712    },{ .name = "SEU_SYNDRM20",  .addr = A_SEU_SYNDRM20,
 713    },{ .name = "SEU_SYNDRM21",  .addr = A_SEU_SYNDRM21,
 714    },{ .name = "SEU_SYNDRM22",  .addr = A_SEU_SYNDRM22,
 715    },{ .name = "SEU_SYNDRM23",  .addr = A_SEU_SYNDRM23,
 716    },{ .name = "SEU_SYNDRM30",  .addr = A_SEU_SYNDRM30,
 717    },{ .name = "SEU_SYNDRM31",  .addr = A_SEU_SYNDRM31,
 718    },{ .name = "SEU_SYNDRM32",  .addr = A_SEU_SYNDRM32,
 719    },{ .name = "SEU_SYNDRM33",  .addr = A_SEU_SYNDRM33,
 720    },{ .name = "SEU_VIRTUAL_SYNDRM0",  .addr = A_SEU_VIRTUAL_SYNDRM0,
 721    },{ .name = "SEU_VIRTUAL_SYNDRM1",  .addr = A_SEU_VIRTUAL_SYNDRM1,
 722    },{ .name = "SEU_VIRTUAL_SYNDRM2",  .addr = A_SEU_VIRTUAL_SYNDRM2,
 723    },{ .name = "SEU_VIRTUAL_SYNDRM3",  .addr = A_SEU_VIRTUAL_SYNDRM3,
 724    },{ .name = "SEU_CRC0",  .addr = A_SEU_CRC0,
 725    },{ .name = "SEU_CRC1",  .addr = A_SEU_CRC1,
 726    },{ .name = "SEU_CRC2",  .addr = A_SEU_CRC2,
 727    },{ .name = "SEU_CRC3",  .addr = A_SEU_CRC3,
 728    },{ .name = "CFRAME_FAR_BOT0",  .addr = A_CFRAME_FAR_BOT0,
 729    },{ .name = "CFRAME_FAR_BOT1",  .addr = A_CFRAME_FAR_BOT1,
 730    },{ .name = "CFRAME_FAR_BOT2",  .addr = A_CFRAME_FAR_BOT2,
 731    },{ .name = "CFRAME_FAR_BOT3",  .addr = A_CFRAME_FAR_BOT3,
 732    },{ .name = "CFRAME_FAR_TOP0",  .addr = A_CFRAME_FAR_TOP0,
 733    },{ .name = "CFRAME_FAR_TOP1",  .addr = A_CFRAME_FAR_TOP1,
 734    },{ .name = "CFRAME_FAR_TOP2",  .addr = A_CFRAME_FAR_TOP2,
 735    },{ .name = "CFRAME_FAR_TOP3",  .addr = A_CFRAME_FAR_TOP3,
 736    },{ .name = "LAST_FRAME_BOT0",  .addr = A_LAST_FRAME_BOT0,
 737        .ro = 0xffffffff,
 738        .post_read = cfrm_last_frame_bot_post_read,
 739    },{ .name = "LAST_FRAME_BOT1",  .addr = A_LAST_FRAME_BOT1,
 740        .ro = 0xffffffff,
 741        .post_read = cfrm_last_frame_bot_post_read,
 742    },{ .name = "LAST_FRAME_BOT2",  .addr = A_LAST_FRAME_BOT2,
 743        .ro = 0xffffffff,
 744        .post_read = cfrm_last_frame_bot_post_read,
 745    },{ .name = "LAST_FRAME_BOT3",  .addr = A_LAST_FRAME_BOT3,
 746        .ro = 0xffffffff,
 747        .post_read = cfrm_last_frame_bot_post_read,
 748    },{ .name = "LAST_FRAME_TOP0",  .addr = A_LAST_FRAME_TOP0,
 749        .ro = 0xffffffff,
 750        .post_read = cfrm_last_frame_top_post_read,
 751    },{ .name = "LAST_FRAME_TOP1",  .addr = A_LAST_FRAME_TOP1,
 752        .ro = 0xffffffff,
 753        .post_read = cfrm_last_frame_top_post_read,
 754    },{ .name = "LAST_FRAME_TOP2",  .addr = A_LAST_FRAME_TOP2,
 755        .ro = 0xffffffff,
 756        .post_read = cfrm_last_frame_top_post_read,
 757    },{ .name = "LAST_FRAME_TOP3",  .addr = A_LAST_FRAME_TOP3,
 758        .ro = 0xffffffff,
 759        .post_read = cfrm_last_frame_top_post_read,
 760    }
 761};
 762
 763static void cframe_reg_cfi_transfer_packet(XlnxCfiIf *cfi_if,
 764                                           XlnxCfiPacket *pkt)
 765{
 766    CFRAME_REG *s = XILINX_CFRAME_REG(cfi_if);
 767    uint64_t we = MAKE_64BIT_MASK(0, 4 * 8);
 768
 769    if (!s->row_configured) {
 770        return;
 771    }
 772
 773    switch (pkt->reg_addr) {
 774    case CFRAME_FAR:
 775        s->regs[R_FAR0] = pkt->data[0];
 776        break;
 777    case CFRAME_SFR:
 778        s->regs[R_FAR_SFR0] = pkt->data[0];
 779        register_write(&s->regs_info[R_FAR_SFR3], 0,
 780                       we, object_get_typename(OBJECT(s)),
 781                       XILINX_CFRAME_REG_ERR_DEBUG);
 782        break;
 783    case CFRAME_FDRI:
 784    {
 785        s->regs[R_FDRI0] = pkt->data[0];
 786        s->regs[R_FDRI1] = pkt->data[1];
 787        s->regs[R_FDRI2] = pkt->data[2];
 788        register_write(&s->regs_info[R_FDRI3], pkt->data[3],
 789                       we, object_get_typename(OBJECT(s)),
 790                       XILINX_CFRAME_REG_ERR_DEBUG);
 791        break;
 792    }
 793    case CFRAME_CMD:
 794        ARRAY_FIELD_DP32(s->regs, CMD0, CMD, pkt->data[0]);
 795
 796        register_write(&s->regs_info[R_CMD3], 0,
 797                       we, object_get_typename(OBJECT(s)),
 798                       XILINX_CFRAME_REG_ERR_DEBUG);
 799        break;
 800    default:
 801        break;
 802    }
 803}
 804
 805static uint64_t cframe_reg_fdri_read(void *opaque, hwaddr addr, unsigned size)
 806{
 807    qemu_log_mask(LOG_GUEST_ERROR, "%s: Unsupported read from addr=%"
 808                  HWADDR_PRIx "\n", __func__, addr);
 809    return 0;
 810}
 811
 812static void cframe_reg_fdri_write(void *opaque, hwaddr addr, uint64_t value,
 813                      unsigned size)
 814{
 815    CFRAME_REG *s = XILINX_CFRAME_REG(opaque);
 816    unsigned int idx;
 817
 818    /* 4 32bit words. */
 819    idx = (addr >> 2) & 3;
 820
 821    s->wfifo[idx] = value;
 822
 823    /* Writing to the top word triggers the forwarding to the FDRI. */
 824    if (idx == 3) {
 825        uint64_t we = MAKE_64BIT_MASK(0, 4 * 8);
 826
 827        s->regs[R_FDRI0] = s->wfifo[0];
 828        s->regs[R_FDRI1] = s->wfifo[1];
 829        s->regs[R_FDRI2] = s->wfifo[2];
 830        register_write(&s->regs_info[R_FDRI3], s->wfifo[3],
 831                       we, object_get_typename(OBJECT(s)),
 832                       XILINX_CFRAME_REG_ERR_DEBUG);
 833
 834        memset(s->wfifo, 0, 4 * sizeof(uint32_t));
 835    }
 836}
 837
 838static void cframe_reg_reset_enter(Object *obj, ResetType type)
 839{
 840    CFRAME_REG *s = XILINX_CFRAME_REG(obj);
 841    unsigned int i;
 842
 843    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
 844        register_reset(&s->regs_info[i]);
 845    }
 846}
 847
 848static void cframe_reg_reset_hold(Object *obj)
 849{
 850    CFRAME_REG *s = XILINX_CFRAME_REG(obj);
 851
 852    cfrm_imr_update_irq(s);
 853}
 854
 855static const MemoryRegionOps cframe_reg_ops = {
 856    .read = register_read_memory,
 857    .write = register_write_memory,
 858    .endianness = DEVICE_LITTLE_ENDIAN,
 859    .valid = {
 860        .min_access_size = 4,
 861        .max_access_size = 4,
 862    },
 863};
 864
 865static const MemoryRegionOps cframe_reg_fdri_ops = {
 866    .read = cframe_reg_fdri_read,
 867    .write = cframe_reg_fdri_write,
 868    .endianness = DEVICE_LITTLE_ENDIAN,
 869    .valid = {
 870        .min_access_size = 4,
 871        .max_access_size = 4,
 872    },
 873};
 874
 875static uint64_t cframes_bcast_reg_read(void *opaque, hwaddr addr, unsigned size)
 876{
 877    qemu_log_mask(LOG_GUEST_ERROR, "%s: Unsupported read from addr=%"
 878                  HWADDR_PRIx "\n", __func__, addr);
 879    return 0;
 880}
 881
 882static void cframes_bcast_reg_write(void *opaque, hwaddr addr, uint64_t value,
 883                      unsigned size)
 884{
 885    CFRAME_BCAST_REG *s = XILINX_CFRAME_BCAST_REG(opaque);
 886    unsigned int idx;
 887
 888    /* 4 32bit words. */
 889    idx = (addr >> 2) & 3;
 890
 891    s->wfifo[idx] = value;
 892
 893    /* Writing to the top word triggers the transmit onto CFI. */
 894    if (idx == 3) {
 895        uint32_t reg_addr = extract32(addr, 4, 6);
 896        XlnxCfiPacket pkt = {
 897            .reg_addr = reg_addr,
 898            .data[0] = s->wfifo[0],
 899            .data[1] = s->wfifo[1],
 900            .data[2] = s->wfifo[2],
 901            .data[3] = s->wfifo[3]
 902        };
 903
 904        for (int i = 0; i < ARRAY_SIZE(s->cfg.cframe); i++) {
 905            if (s->cfg.cframe[i]) {
 906                xlnx_cfi_transfer_packet(s->cfg.cframe[i], &pkt);
 907            }
 908        }
 909
 910        memset(s->wfifo, 0, 4 * sizeof(uint32_t));
 911    }
 912}
 913
 914static uint64_t cframes_bcast_fdri_read(void *opaque, hwaddr addr,
 915                                        unsigned size)
 916{
 917    qemu_log_mask(LOG_GUEST_ERROR, "%s: Unsupported read from addr=%"
 918                  HWADDR_PRIx "\n", __func__, addr);
 919    return 0;
 920}
 921
 922static void cframes_bcast_fdri_write(void *opaque, hwaddr addr, uint64_t value,
 923                      unsigned size)
 924{
 925    CFRAME_BCAST_REG *s = XILINX_CFRAME_BCAST_REG(opaque);
 926    unsigned int idx;
 927
 928    /* 4 32bit words. */
 929    idx = (addr >> 2) & 3;
 930
 931    s->wfifo[idx] = value;
 932
 933    /* Writing to the top word triggers the transmit onto CFI. */
 934    if (idx == 3) {
 935        XlnxCfiPacket pkt = {
 936            .reg_addr = CFRAME_FDRI,
 937            .data[0] = s->wfifo[0],
 938            .data[1] = s->wfifo[1],
 939            .data[2] = s->wfifo[2],
 940            .data[3] = s->wfifo[3]
 941        };
 942
 943        for (int i = 0; i < ARRAY_SIZE(s->cfg.cframe); i++) {
 944            if (s->cfg.cframe[i]) {
 945                xlnx_cfi_transfer_packet(s->cfg.cframe[i], &pkt);
 946            }
 947        }
 948
 949        memset(s->wfifo, 0, 4 * sizeof(uint32_t));
 950    }
 951}
 952
 953static const MemoryRegionOps cframes_bcast_reg_reg_ops = {
 954    .read = cframes_bcast_reg_read,
 955    .write = cframes_bcast_reg_write,
 956    .endianness = DEVICE_LITTLE_ENDIAN,
 957    .valid = {
 958        .min_access_size = 4,
 959        .max_access_size = 4,
 960    },
 961};
 962
 963static const MemoryRegionOps cframes_bcast_reg_fdri_ops = {
 964    .read = cframes_bcast_fdri_read,
 965    .write = cframes_bcast_fdri_write,
 966    .endianness = DEVICE_LITTLE_ENDIAN,
 967    .valid = {
 968        .min_access_size = 4,
 969        .max_access_size = 4,
 970    },
 971};
 972
 973static void cframe_reg_realize(DeviceState *dev, Error **errp)
 974{
 975    CFRAME_REG *s = XILINX_CFRAME_REG(dev);
 976
 977    for (int i = 0; i < ARRAY_SIZE(s->cfg.blktype_num_frames); i++) {
 978        if (s->cfg.blktype_num_frames[i] > MAX_BLOCKTYPE_FRAMES) {
 979            error_setg(errp,
 980                       "blktype-frames%d > 0xFFFFF (max frame per block)",
 981                       i);
 982            return;
 983        }
 984        if (s->cfg.blktype_num_frames[i]) {
 985            s->row_configured = true;
 986        }
 987    }
 988}
 989
 990static void cframe_reg_init(Object *obj)
 991{
 992    CFRAME_REG *s = XILINX_CFRAME_REG(obj);
 993    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 994    RegisterInfoArray *reg_array;
 995
 996    memory_region_init(&s->iomem, obj, TYPE_XILINX_CFRAME_REG,
 997                       CFRAME_REG_R_MAX * 4);
 998    reg_array =
 999        register_init_block32(DEVICE(obj), cframe_reg_regs_info,
1000                              ARRAY_SIZE(cframe_reg_regs_info),
1001                              s->regs_info, s->regs,
1002                              &cframe_reg_ops,
1003                              XILINX_CFRAME_REG_ERR_DEBUG,
1004                              CFRAME_REG_R_MAX * 4);
1005    memory_region_add_subregion(&s->iomem,
1006                                0x0,
1007                                &reg_array->mem);
1008    sysbus_init_mmio(sbd, &s->iomem);
1009    memory_region_init_io(&s->iomem_fdri, obj, &cframe_reg_fdri_ops, s,
1010                          TYPE_XILINX_CFRAME_REG "-fdri", KEYHOLE_STREAM_4K);
1011    sysbus_init_mmio(sbd, &s->iomem_fdri);
1012    sysbus_init_irq(sbd, &s->irq_cfrm_imr);
1013
1014    s->cframes = g_array_new(FALSE, FALSE, sizeof(XlnxCFrame));
1015}
1016
1017static const VMStateDescription vmstate_cframe_reg = {
1018    .name = TYPE_XILINX_CFRAME_REG,
1019    .version_id = 1,
1020    .minimum_version_id = 1,
1021    .fields = (VMStateField[]) {
1022        VMSTATE_UINT32_ARRAY(regs, CFRAME_REG, CFRAME_REG_R_MAX),
1023        VMSTATE_END_OF_LIST(),
1024    }
1025};
1026
1027static Property cframe_regs_props[] = {
1028    /* Kept for backwards compatibility */
1029    DEFINE_PROP_LINK("cfu", CFRAME_REG, cfg.cfu_fdro,
1030                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1031    DEFINE_PROP_LINK("cfu-fdro", CFRAME_REG, cfg.cfu_fdro,
1032                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1033    DEFINE_PROP_UINT32("blktype0-frames", CFRAME_REG,
1034                       cfg.blktype_num_frames[0], 0),
1035    DEFINE_PROP_UINT32("blktype1-frames", CFRAME_REG,
1036                       cfg.blktype_num_frames[1], 0),
1037    DEFINE_PROP_UINT32("blktype2-frames", CFRAME_REG,
1038                       cfg.blktype_num_frames[2], 0),
1039    DEFINE_PROP_UINT32("blktype3-frames", CFRAME_REG,
1040                       cfg.blktype_num_frames[3], 0),
1041    DEFINE_PROP_UINT32("blktype4-frames", CFRAME_REG,
1042                       cfg.blktype_num_frames[4], 0),
1043    DEFINE_PROP_UINT32("blktype5-frames", CFRAME_REG,
1044                       cfg.blktype_num_frames[5], 0),
1045    DEFINE_PROP_UINT32("blktype6-frames", CFRAME_REG,
1046                       cfg.blktype_num_frames[6], 0),
1047    DEFINE_PROP_END_OF_LIST(),
1048};
1049
1050static void cframe_bcast_reg_init(Object *obj)
1051{
1052    CFRAME_BCAST_REG *s = XILINX_CFRAME_BCAST_REG(obj);
1053    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1054
1055    memory_region_init_io(&s->iomem_reg, obj, &cframes_bcast_reg_reg_ops, s,
1056                          TYPE_XILINX_CFRAME_BCAST_REG, KEYHOLE_STREAM_4K);
1057    memory_region_init_io(&s->iomem_fdri, obj, &cframes_bcast_reg_fdri_ops, s,
1058                          TYPE_XILINX_CFRAME_BCAST_REG "-fdri",
1059                          KEYHOLE_STREAM_4K);
1060    sysbus_init_mmio(sbd, &s->iomem_reg);
1061    sysbus_init_mmio(sbd, &s->iomem_fdri);
1062}
1063
1064static Property cframe_bcast_regs_props[] = {
1065    DEFINE_PROP_LINK("cframe0", CFRAME_BCAST_REG, cfg.cframe[0],
1066                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1067    DEFINE_PROP_LINK("cframe1", CFRAME_BCAST_REG, cfg.cframe[1],
1068                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1069    DEFINE_PROP_LINK("cframe2", CFRAME_BCAST_REG, cfg.cframe[2],
1070                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1071    DEFINE_PROP_LINK("cframe3", CFRAME_BCAST_REG, cfg.cframe[3],
1072                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1073    DEFINE_PROP_LINK("cframe4", CFRAME_BCAST_REG, cfg.cframe[4],
1074                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1075    DEFINE_PROP_LINK("cframe5", CFRAME_BCAST_REG, cfg.cframe[5],
1076                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1077    DEFINE_PROP_LINK("cframe6", CFRAME_BCAST_REG, cfg.cframe[6],
1078                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1079    DEFINE_PROP_LINK("cframe7", CFRAME_BCAST_REG, cfg.cframe[7],
1080                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1081    DEFINE_PROP_LINK("cframe8", CFRAME_BCAST_REG, cfg.cframe[8],
1082                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1083    DEFINE_PROP_LINK("cframe9", CFRAME_BCAST_REG, cfg.cframe[9],
1084                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1085    DEFINE_PROP_LINK("cframe10", CFRAME_BCAST_REG, cfg.cframe[10],
1086                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1087    DEFINE_PROP_LINK("cframe11", CFRAME_BCAST_REG, cfg.cframe[11],
1088                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1089    DEFINE_PROP_LINK("cframe12", CFRAME_BCAST_REG, cfg.cframe[12],
1090                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1091    DEFINE_PROP_LINK("cframe13", CFRAME_BCAST_REG, cfg.cframe[13],
1092                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1093    DEFINE_PROP_LINK("cframe14", CFRAME_BCAST_REG, cfg.cframe[14],
1094                     TYPE_XLNX_CFI_IF, XlnxCfiIf *),
1095    DEFINE_PROP_END_OF_LIST(),
1096};
1097
1098static void cframe_reg_class_init(ObjectClass *klass, void *data)
1099{
1100    ResettableClass *rc = RESETTABLE_CLASS(klass);
1101    DeviceClass *dc = DEVICE_CLASS(klass);
1102    XlnxCfiIfClass *xcic = XLNX_CFI_IF_CLASS(klass);
1103
1104    dc->vmsd = &vmstate_cframe_reg;
1105    dc->realize = cframe_reg_realize;
1106    rc->phases.enter = cframe_reg_reset_enter;
1107    rc->phases.hold = cframe_reg_reset_hold;
1108    device_class_set_props(dc, cframe_regs_props);
1109    xcic->cfi_transfer_packet = cframe_reg_cfi_transfer_packet;
1110}
1111
1112static void cframe_bcast_reg_class_init(ObjectClass *klass, void *data)
1113{
1114    DeviceClass *dc = DEVICE_CLASS(klass);
1115
1116    device_class_set_props(dc, cframe_bcast_regs_props);
1117}
1118
1119static const TypeInfo cframe_reg_info = {
1120    .name          = TYPE_XILINX_CFRAME_REG,
1121    .parent        = TYPE_SYS_BUS_DEVICE,
1122    .instance_size = sizeof(CFRAME_REG),
1123    .class_init    = cframe_reg_class_init,
1124    .instance_init = cframe_reg_init,
1125    .interfaces = (InterfaceInfo[]) {
1126        { TYPE_XLNX_CFI_IF },
1127        { }
1128    }
1129};
1130
1131static const TypeInfo cframe_bcast_reg_info = {
1132    .name          = TYPE_XILINX_CFRAME_BCAST_REG,
1133    .parent        = TYPE_SYS_BUS_DEVICE,
1134    .instance_size = sizeof(CFRAME_BCAST_REG),
1135    .class_init    = cframe_bcast_reg_class_init,
1136    .instance_init = cframe_bcast_reg_init,
1137};
1138
1139static void cframe_reg_register_types(void)
1140{
1141    type_register_static(&cframe_reg_info);
1142    type_register_static(&cframe_bcast_reg_info);
1143}
1144
1145type_init(cframe_reg_register_types)
1146