1*86d916c6SFrancisco Iglesias /* 2*86d916c6SFrancisco Iglesias * QEMU model of the CFU Configuration Unit. 3*86d916c6SFrancisco Iglesias * 4*86d916c6SFrancisco Iglesias * Copyright (C) 2023, Advanced Micro Devices, Inc. 5*86d916c6SFrancisco Iglesias * 6*86d916c6SFrancisco Iglesias * Written by Edgar E. Iglesias <edgar.iglesias@gmail.com>, 7*86d916c6SFrancisco Iglesias * Sai Pavan Boddu <sai.pavan.boddu@amd.com>, 8*86d916c6SFrancisco Iglesias * Francisco Iglesias <francisco.iglesias@amd.com> 9*86d916c6SFrancisco Iglesias * 10*86d916c6SFrancisco Iglesias * SPDX-License-Identifier: GPL-2.0-or-later 11*86d916c6SFrancisco Iglesias */ 12*86d916c6SFrancisco Iglesias 13*86d916c6SFrancisco Iglesias #include "qemu/osdep.h" 14*86d916c6SFrancisco Iglesias #include "hw/sysbus.h" 15*86d916c6SFrancisco Iglesias #include "hw/register.h" 16*86d916c6SFrancisco Iglesias #include "hw/irq.h" 17*86d916c6SFrancisco Iglesias #include "qemu/bitops.h" 18*86d916c6SFrancisco Iglesias #include "qemu/log.h" 19*86d916c6SFrancisco Iglesias #include "qemu/units.h" 20*86d916c6SFrancisco Iglesias #include "migration/vmstate.h" 21*86d916c6SFrancisco Iglesias #include "hw/qdev-properties.h" 22*86d916c6SFrancisco Iglesias #include "hw/qdev-properties-system.h" 23*86d916c6SFrancisco Iglesias #include "hw/misc/xlnx-versal-cfu.h" 24*86d916c6SFrancisco Iglesias 25*86d916c6SFrancisco Iglesias #ifndef XLNX_VERSAL_CFU_APB_ERR_DEBUG 26*86d916c6SFrancisco Iglesias #define XLNX_VERSAL_CFU_APB_ERR_DEBUG 0 27*86d916c6SFrancisco Iglesias #endif 28*86d916c6SFrancisco Iglesias 29*86d916c6SFrancisco Iglesias #define KEYHOLE_STREAM_4K (4 * KiB) 30*86d916c6SFrancisco Iglesias #define KEYHOLE_STREAM_256K (256 * KiB) 31*86d916c6SFrancisco Iglesias #define CFRAME_BROADCAST_ROW 0x1F 32*86d916c6SFrancisco Iglesias 33*86d916c6SFrancisco Iglesias bool update_wfifo(hwaddr addr, uint64_t value, 34*86d916c6SFrancisco Iglesias uint32_t *wfifo, uint32_t *wfifo_ret) 35*86d916c6SFrancisco Iglesias { 36*86d916c6SFrancisco Iglesias unsigned int idx = extract32(addr, 2, 2); 37*86d916c6SFrancisco Iglesias 38*86d916c6SFrancisco Iglesias wfifo[idx] = value; 39*86d916c6SFrancisco Iglesias 40*86d916c6SFrancisco Iglesias if (idx == 3) { 41*86d916c6SFrancisco Iglesias memcpy(wfifo_ret, wfifo, WFIFO_SZ * sizeof(uint32_t)); 42*86d916c6SFrancisco Iglesias memset(wfifo, 0, WFIFO_SZ * sizeof(uint32_t)); 43*86d916c6SFrancisco Iglesias return true; 44*86d916c6SFrancisco Iglesias } 45*86d916c6SFrancisco Iglesias 46*86d916c6SFrancisco Iglesias return false; 47*86d916c6SFrancisco Iglesias } 48*86d916c6SFrancisco Iglesias 49*86d916c6SFrancisco Iglesias static void cfu_imr_update_irq(XlnxVersalCFUAPB *s) 50*86d916c6SFrancisco Iglesias { 51*86d916c6SFrancisco Iglesias bool pending = s->regs[R_CFU_ISR] & ~s->regs[R_CFU_IMR]; 52*86d916c6SFrancisco Iglesias qemu_set_irq(s->irq_cfu_imr, pending); 53*86d916c6SFrancisco Iglesias } 54*86d916c6SFrancisco Iglesias 55*86d916c6SFrancisco Iglesias static void cfu_isr_postw(RegisterInfo *reg, uint64_t val64) 56*86d916c6SFrancisco Iglesias { 57*86d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(reg->opaque); 58*86d916c6SFrancisco Iglesias cfu_imr_update_irq(s); 59*86d916c6SFrancisco Iglesias } 60*86d916c6SFrancisco Iglesias 61*86d916c6SFrancisco Iglesias static uint64_t cfu_ier_prew(RegisterInfo *reg, uint64_t val64) 62*86d916c6SFrancisco Iglesias { 63*86d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(reg->opaque); 64*86d916c6SFrancisco Iglesias uint32_t val = val64; 65*86d916c6SFrancisco Iglesias 66*86d916c6SFrancisco Iglesias s->regs[R_CFU_IMR] &= ~val; 67*86d916c6SFrancisco Iglesias cfu_imr_update_irq(s); 68*86d916c6SFrancisco Iglesias return 0; 69*86d916c6SFrancisco Iglesias } 70*86d916c6SFrancisco Iglesias 71*86d916c6SFrancisco Iglesias static uint64_t cfu_idr_prew(RegisterInfo *reg, uint64_t val64) 72*86d916c6SFrancisco Iglesias { 73*86d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(reg->opaque); 74*86d916c6SFrancisco Iglesias uint32_t val = val64; 75*86d916c6SFrancisco Iglesias 76*86d916c6SFrancisco Iglesias s->regs[R_CFU_IMR] |= val; 77*86d916c6SFrancisco Iglesias cfu_imr_update_irq(s); 78*86d916c6SFrancisco Iglesias return 0; 79*86d916c6SFrancisco Iglesias } 80*86d916c6SFrancisco Iglesias 81*86d916c6SFrancisco Iglesias static uint64_t cfu_itr_prew(RegisterInfo *reg, uint64_t val64) 82*86d916c6SFrancisco Iglesias { 83*86d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(reg->opaque); 84*86d916c6SFrancisco Iglesias uint32_t val = val64; 85*86d916c6SFrancisco Iglesias 86*86d916c6SFrancisco Iglesias s->regs[R_CFU_ISR] |= val; 87*86d916c6SFrancisco Iglesias cfu_imr_update_irq(s); 88*86d916c6SFrancisco Iglesias return 0; 89*86d916c6SFrancisco Iglesias } 90*86d916c6SFrancisco Iglesias 91*86d916c6SFrancisco Iglesias static void cfu_fgcr_postw(RegisterInfo *reg, uint64_t val64) 92*86d916c6SFrancisco Iglesias { 93*86d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(reg->opaque); 94*86d916c6SFrancisco Iglesias uint32_t val = (uint32_t)val64; 95*86d916c6SFrancisco Iglesias 96*86d916c6SFrancisco Iglesias /* Do a scan. It always looks good. */ 97*86d916c6SFrancisco Iglesias if (FIELD_EX32(val, CFU_FGCR, SC_HBC_TRIGGER)) { 98*86d916c6SFrancisco Iglesias ARRAY_FIELD_DP32(s->regs, CFU_STATUS, SCAN_CLEAR_PASS, 1); 99*86d916c6SFrancisco Iglesias ARRAY_FIELD_DP32(s->regs, CFU_STATUS, SCAN_CLEAR_DONE, 1); 100*86d916c6SFrancisco Iglesias } 101*86d916c6SFrancisco Iglesias } 102*86d916c6SFrancisco Iglesias 103*86d916c6SFrancisco Iglesias static const RegisterAccessInfo cfu_apb_regs_info[] = { 104*86d916c6SFrancisco Iglesias { .name = "CFU_ISR", .addr = A_CFU_ISR, 105*86d916c6SFrancisco Iglesias .rsvd = 0xfffffc00, 106*86d916c6SFrancisco Iglesias .w1c = 0x3ff, 107*86d916c6SFrancisco Iglesias .post_write = cfu_isr_postw, 108*86d916c6SFrancisco Iglesias },{ .name = "CFU_IMR", .addr = A_CFU_IMR, 109*86d916c6SFrancisco Iglesias .reset = 0x3ff, 110*86d916c6SFrancisco Iglesias .rsvd = 0xfffffc00, 111*86d916c6SFrancisco Iglesias .ro = 0x3ff, 112*86d916c6SFrancisco Iglesias },{ .name = "CFU_IER", .addr = A_CFU_IER, 113*86d916c6SFrancisco Iglesias .rsvd = 0xfffffc00, 114*86d916c6SFrancisco Iglesias .pre_write = cfu_ier_prew, 115*86d916c6SFrancisco Iglesias },{ .name = "CFU_IDR", .addr = A_CFU_IDR, 116*86d916c6SFrancisco Iglesias .rsvd = 0xfffffc00, 117*86d916c6SFrancisco Iglesias .pre_write = cfu_idr_prew, 118*86d916c6SFrancisco Iglesias },{ .name = "CFU_ITR", .addr = A_CFU_ITR, 119*86d916c6SFrancisco Iglesias .rsvd = 0xfffffc00, 120*86d916c6SFrancisco Iglesias .pre_write = cfu_itr_prew, 121*86d916c6SFrancisco Iglesias },{ .name = "CFU_PROTECT", .addr = A_CFU_PROTECT, 122*86d916c6SFrancisco Iglesias .reset = 0x1, 123*86d916c6SFrancisco Iglesias },{ .name = "CFU_FGCR", .addr = A_CFU_FGCR, 124*86d916c6SFrancisco Iglesias .rsvd = 0xffff8000, 125*86d916c6SFrancisco Iglesias .post_write = cfu_fgcr_postw, 126*86d916c6SFrancisco Iglesias },{ .name = "CFU_CTL", .addr = A_CFU_CTL, 127*86d916c6SFrancisco Iglesias .rsvd = 0xffff0000, 128*86d916c6SFrancisco Iglesias },{ .name = "CFU_CRAM_RW", .addr = A_CFU_CRAM_RW, 129*86d916c6SFrancisco Iglesias .reset = 0x401f7d9, 130*86d916c6SFrancisco Iglesias .rsvd = 0xf8000000, 131*86d916c6SFrancisco Iglesias },{ .name = "CFU_MASK", .addr = A_CFU_MASK, 132*86d916c6SFrancisco Iglesias },{ .name = "CFU_CRC_EXPECT", .addr = A_CFU_CRC_EXPECT, 133*86d916c6SFrancisco Iglesias },{ .name = "CFU_CFRAME_LEFT_T0", .addr = A_CFU_CFRAME_LEFT_T0, 134*86d916c6SFrancisco Iglesias .rsvd = 0xfff00000, 135*86d916c6SFrancisco Iglesias },{ .name = "CFU_CFRAME_LEFT_T1", .addr = A_CFU_CFRAME_LEFT_T1, 136*86d916c6SFrancisco Iglesias .rsvd = 0xfff00000, 137*86d916c6SFrancisco Iglesias },{ .name = "CFU_CFRAME_LEFT_T2", .addr = A_CFU_CFRAME_LEFT_T2, 138*86d916c6SFrancisco Iglesias .rsvd = 0xfff00000, 139*86d916c6SFrancisco Iglesias },{ .name = "CFU_ROW_RANGE", .addr = A_CFU_ROW_RANGE, 140*86d916c6SFrancisco Iglesias .rsvd = 0xffffffc0, 141*86d916c6SFrancisco Iglesias .ro = 0x3f, 142*86d916c6SFrancisco Iglesias },{ .name = "CFU_STATUS", .addr = A_CFU_STATUS, 143*86d916c6SFrancisco Iglesias .rsvd = 0x80000000, 144*86d916c6SFrancisco Iglesias .ro = 0x7fffffff, 145*86d916c6SFrancisco Iglesias },{ .name = "CFU_INTERNAL_STATUS", .addr = A_CFU_INTERNAL_STATUS, 146*86d916c6SFrancisco Iglesias .rsvd = 0xff800000, 147*86d916c6SFrancisco Iglesias .ro = 0x7fffff, 148*86d916c6SFrancisco Iglesias },{ .name = "CFU_QWORD_CNT", .addr = A_CFU_QWORD_CNT, 149*86d916c6SFrancisco Iglesias .ro = 0xffffffff, 150*86d916c6SFrancisco Iglesias },{ .name = "CFU_CRC_LIVE", .addr = A_CFU_CRC_LIVE, 151*86d916c6SFrancisco Iglesias .ro = 0xffffffff, 152*86d916c6SFrancisco Iglesias },{ .name = "CFU_PENDING_READ_CNT", .addr = A_CFU_PENDING_READ_CNT, 153*86d916c6SFrancisco Iglesias .rsvd = 0xfe000000, 154*86d916c6SFrancisco Iglesias .ro = 0x1ffffff, 155*86d916c6SFrancisco Iglesias },{ .name = "CFU_FDRI_CNT", .addr = A_CFU_FDRI_CNT, 156*86d916c6SFrancisco Iglesias .ro = 0xffffffff, 157*86d916c6SFrancisco Iglesias },{ .name = "CFU_ECO1", .addr = A_CFU_ECO1, 158*86d916c6SFrancisco Iglesias },{ .name = "CFU_ECO2", .addr = A_CFU_ECO2, 159*86d916c6SFrancisco Iglesias } 160*86d916c6SFrancisco Iglesias }; 161*86d916c6SFrancisco Iglesias 162*86d916c6SFrancisco Iglesias static void cfu_apb_reset(DeviceState *dev) 163*86d916c6SFrancisco Iglesias { 164*86d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(dev); 165*86d916c6SFrancisco Iglesias unsigned int i; 166*86d916c6SFrancisco Iglesias 167*86d916c6SFrancisco Iglesias for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { 168*86d916c6SFrancisco Iglesias register_reset(&s->regs_info[i]); 169*86d916c6SFrancisco Iglesias } 170*86d916c6SFrancisco Iglesias memset(s->wfifo, 0, WFIFO_SZ * sizeof(uint32_t)); 171*86d916c6SFrancisco Iglesias 172*86d916c6SFrancisco Iglesias s->regs[R_CFU_STATUS] |= R_CFU_STATUS_HC_COMPLETE_MASK; 173*86d916c6SFrancisco Iglesias cfu_imr_update_irq(s); 174*86d916c6SFrancisco Iglesias } 175*86d916c6SFrancisco Iglesias 176*86d916c6SFrancisco Iglesias static const MemoryRegionOps cfu_apb_ops = { 177*86d916c6SFrancisco Iglesias .read = register_read_memory, 178*86d916c6SFrancisco Iglesias .write = register_write_memory, 179*86d916c6SFrancisco Iglesias .endianness = DEVICE_LITTLE_ENDIAN, 180*86d916c6SFrancisco Iglesias .valid = { 181*86d916c6SFrancisco Iglesias .min_access_size = 4, 182*86d916c6SFrancisco Iglesias .max_access_size = 4, 183*86d916c6SFrancisco Iglesias }, 184*86d916c6SFrancisco Iglesias }; 185*86d916c6SFrancisco Iglesias 186*86d916c6SFrancisco Iglesias static void cfu_transfer_cfi_packet(XlnxVersalCFUAPB *s, uint8_t row_addr, 187*86d916c6SFrancisco Iglesias XlnxCfiPacket *pkt) 188*86d916c6SFrancisco Iglesias { 189*86d916c6SFrancisco Iglesias if (row_addr == CFRAME_BROADCAST_ROW) { 190*86d916c6SFrancisco Iglesias for (int i = 0; i < ARRAY_SIZE(s->cfg.cframe); i++) { 191*86d916c6SFrancisco Iglesias if (s->cfg.cframe[i]) { 192*86d916c6SFrancisco Iglesias xlnx_cfi_transfer_packet(s->cfg.cframe[i], pkt); 193*86d916c6SFrancisco Iglesias } 194*86d916c6SFrancisco Iglesias } 195*86d916c6SFrancisco Iglesias } else { 196*86d916c6SFrancisco Iglesias assert(row_addr < ARRAY_SIZE(s->cfg.cframe)); 197*86d916c6SFrancisco Iglesias 198*86d916c6SFrancisco Iglesias if (s->cfg.cframe[row_addr]) { 199*86d916c6SFrancisco Iglesias xlnx_cfi_transfer_packet(s->cfg.cframe[row_addr], pkt); 200*86d916c6SFrancisco Iglesias } 201*86d916c6SFrancisco Iglesias } 202*86d916c6SFrancisco Iglesias } 203*86d916c6SFrancisco Iglesias 204*86d916c6SFrancisco Iglesias static uint64_t cfu_stream_read(void *opaque, hwaddr addr, unsigned size) 205*86d916c6SFrancisco Iglesias { 206*86d916c6SFrancisco Iglesias qemu_log_mask(LOG_GUEST_ERROR, "%s: Unsupported read from addr=%" 207*86d916c6SFrancisco Iglesias HWADDR_PRIx "\n", __func__, addr); 208*86d916c6SFrancisco Iglesias return 0; 209*86d916c6SFrancisco Iglesias } 210*86d916c6SFrancisco Iglesias 211*86d916c6SFrancisco Iglesias static void cfu_stream_write(void *opaque, hwaddr addr, uint64_t value, 212*86d916c6SFrancisco Iglesias unsigned size) 213*86d916c6SFrancisco Iglesias { 214*86d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(opaque); 215*86d916c6SFrancisco Iglesias uint32_t wfifo[WFIFO_SZ]; 216*86d916c6SFrancisco Iglesias 217*86d916c6SFrancisco Iglesias if (update_wfifo(addr, value, s->wfifo, wfifo)) { 218*86d916c6SFrancisco Iglesias uint8_t packet_type, row_addr, reg_addr; 219*86d916c6SFrancisco Iglesias 220*86d916c6SFrancisco Iglesias packet_type = extract32(wfifo[0], 24, 8); 221*86d916c6SFrancisco Iglesias row_addr = extract32(wfifo[0], 16, 5); 222*86d916c6SFrancisco Iglesias reg_addr = extract32(wfifo[0], 8, 6); 223*86d916c6SFrancisco Iglesias 224*86d916c6SFrancisco Iglesias /* Compressed bitstreams are not supported yet. */ 225*86d916c6SFrancisco Iglesias if (ARRAY_FIELD_EX32(s->regs, CFU_CTL, DECOMPRESS) == 0) { 226*86d916c6SFrancisco Iglesias if (s->regs[R_CFU_FDRI_CNT]) { 227*86d916c6SFrancisco Iglesias XlnxCfiPacket pkt = { 228*86d916c6SFrancisco Iglesias .reg_addr = CFRAME_FDRI, 229*86d916c6SFrancisco Iglesias .data[0] = wfifo[0], 230*86d916c6SFrancisco Iglesias .data[1] = wfifo[1], 231*86d916c6SFrancisco Iglesias .data[2] = wfifo[2], 232*86d916c6SFrancisco Iglesias .data[3] = wfifo[3] 233*86d916c6SFrancisco Iglesias }; 234*86d916c6SFrancisco Iglesias 235*86d916c6SFrancisco Iglesias cfu_transfer_cfi_packet(s, s->fdri_row_addr, &pkt); 236*86d916c6SFrancisco Iglesias 237*86d916c6SFrancisco Iglesias s->regs[R_CFU_FDRI_CNT]--; 238*86d916c6SFrancisco Iglesias 239*86d916c6SFrancisco Iglesias } else if (packet_type == PACKET_TYPE_CFU && 240*86d916c6SFrancisco Iglesias reg_addr == CFRAME_FDRI) { 241*86d916c6SFrancisco Iglesias 242*86d916c6SFrancisco Iglesias /* Load R_CFU_FDRI_CNT, must be multiple of 25 */ 243*86d916c6SFrancisco Iglesias s->regs[R_CFU_FDRI_CNT] = wfifo[1]; 244*86d916c6SFrancisco Iglesias 245*86d916c6SFrancisco Iglesias /* Store target row_addr */ 246*86d916c6SFrancisco Iglesias s->fdri_row_addr = row_addr; 247*86d916c6SFrancisco Iglesias 248*86d916c6SFrancisco Iglesias if (wfifo[1] % 25 != 0) { 249*86d916c6SFrancisco Iglesias qemu_log_mask(LOG_GUEST_ERROR, 250*86d916c6SFrancisco Iglesias "CFU FDRI_CNT is not loaded with " 251*86d916c6SFrancisco Iglesias "a multiple of 25 value\n"); 252*86d916c6SFrancisco Iglesias } 253*86d916c6SFrancisco Iglesias 254*86d916c6SFrancisco Iglesias } else if (packet_type == PACKET_TYPE_CFRAME) { 255*86d916c6SFrancisco Iglesias XlnxCfiPacket pkt = { 256*86d916c6SFrancisco Iglesias .reg_addr = reg_addr, 257*86d916c6SFrancisco Iglesias .data[0] = wfifo[1], 258*86d916c6SFrancisco Iglesias .data[1] = wfifo[2], 259*86d916c6SFrancisco Iglesias .data[2] = wfifo[3], 260*86d916c6SFrancisco Iglesias }; 261*86d916c6SFrancisco Iglesias cfu_transfer_cfi_packet(s, row_addr, &pkt); 262*86d916c6SFrancisco Iglesias } 263*86d916c6SFrancisco Iglesias } 264*86d916c6SFrancisco Iglesias } 265*86d916c6SFrancisco Iglesias } 266*86d916c6SFrancisco Iglesias 267*86d916c6SFrancisco Iglesias static const MemoryRegionOps cfu_stream_ops = { 268*86d916c6SFrancisco Iglesias .read = cfu_stream_read, 269*86d916c6SFrancisco Iglesias .write = cfu_stream_write, 270*86d916c6SFrancisco Iglesias .endianness = DEVICE_LITTLE_ENDIAN, 271*86d916c6SFrancisco Iglesias .valid = { 272*86d916c6SFrancisco Iglesias .min_access_size = 4, 273*86d916c6SFrancisco Iglesias .max_access_size = 8, 274*86d916c6SFrancisco Iglesias }, 275*86d916c6SFrancisco Iglesias }; 276*86d916c6SFrancisco Iglesias 277*86d916c6SFrancisco Iglesias static void cfu_apb_init(Object *obj) 278*86d916c6SFrancisco Iglesias { 279*86d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(obj); 280*86d916c6SFrancisco Iglesias SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 281*86d916c6SFrancisco Iglesias RegisterInfoArray *reg_array; 282*86d916c6SFrancisco Iglesias unsigned int i; 283*86d916c6SFrancisco Iglesias char *name; 284*86d916c6SFrancisco Iglesias 285*86d916c6SFrancisco Iglesias memory_region_init(&s->iomem, obj, TYPE_XLNX_VERSAL_CFU_APB, R_MAX * 4); 286*86d916c6SFrancisco Iglesias reg_array = 287*86d916c6SFrancisco Iglesias register_init_block32(DEVICE(obj), cfu_apb_regs_info, 288*86d916c6SFrancisco Iglesias ARRAY_SIZE(cfu_apb_regs_info), 289*86d916c6SFrancisco Iglesias s->regs_info, s->regs, 290*86d916c6SFrancisco Iglesias &cfu_apb_ops, 291*86d916c6SFrancisco Iglesias XLNX_VERSAL_CFU_APB_ERR_DEBUG, 292*86d916c6SFrancisco Iglesias R_MAX * 4); 293*86d916c6SFrancisco Iglesias memory_region_add_subregion(&s->iomem, 294*86d916c6SFrancisco Iglesias 0x0, 295*86d916c6SFrancisco Iglesias ®_array->mem); 296*86d916c6SFrancisco Iglesias sysbus_init_mmio(sbd, &s->iomem); 297*86d916c6SFrancisco Iglesias for (i = 0; i < NUM_STREAM; i++) { 298*86d916c6SFrancisco Iglesias name = g_strdup_printf(TYPE_XLNX_VERSAL_CFU_APB "-stream%d", i); 299*86d916c6SFrancisco Iglesias memory_region_init_io(&s->iomem_stream[i], obj, &cfu_stream_ops, s, 300*86d916c6SFrancisco Iglesias name, i == 0 ? KEYHOLE_STREAM_4K : 301*86d916c6SFrancisco Iglesias KEYHOLE_STREAM_256K); 302*86d916c6SFrancisco Iglesias sysbus_init_mmio(sbd, &s->iomem_stream[i]); 303*86d916c6SFrancisco Iglesias g_free(name); 304*86d916c6SFrancisco Iglesias } 305*86d916c6SFrancisco Iglesias sysbus_init_irq(sbd, &s->irq_cfu_imr); 306*86d916c6SFrancisco Iglesias } 307*86d916c6SFrancisco Iglesias 308*86d916c6SFrancisco Iglesias static Property cfu_props[] = { 309*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe0", XlnxVersalCFUAPB, cfg.cframe[0], 310*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 311*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe1", XlnxVersalCFUAPB, cfg.cframe[1], 312*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 313*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe2", XlnxVersalCFUAPB, cfg.cframe[2], 314*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 315*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe3", XlnxVersalCFUAPB, cfg.cframe[3], 316*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 317*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe4", XlnxVersalCFUAPB, cfg.cframe[4], 318*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 319*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe5", XlnxVersalCFUAPB, cfg.cframe[5], 320*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 321*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe6", XlnxVersalCFUAPB, cfg.cframe[6], 322*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 323*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe7", XlnxVersalCFUAPB, cfg.cframe[7], 324*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 325*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe8", XlnxVersalCFUAPB, cfg.cframe[8], 326*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 327*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe9", XlnxVersalCFUAPB, cfg.cframe[9], 328*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 329*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe10", XlnxVersalCFUAPB, cfg.cframe[10], 330*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 331*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe11", XlnxVersalCFUAPB, cfg.cframe[11], 332*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 333*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe12", XlnxVersalCFUAPB, cfg.cframe[12], 334*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 335*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe13", XlnxVersalCFUAPB, cfg.cframe[13], 336*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 337*86d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe14", XlnxVersalCFUAPB, cfg.cframe[14], 338*86d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *), 339*86d916c6SFrancisco Iglesias DEFINE_PROP_END_OF_LIST(), 340*86d916c6SFrancisco Iglesias }; 341*86d916c6SFrancisco Iglesias 342*86d916c6SFrancisco Iglesias static const VMStateDescription vmstate_cfu_apb = { 343*86d916c6SFrancisco Iglesias .name = TYPE_XLNX_VERSAL_CFU_APB, 344*86d916c6SFrancisco Iglesias .version_id = 1, 345*86d916c6SFrancisco Iglesias .minimum_version_id = 1, 346*86d916c6SFrancisco Iglesias .fields = (VMStateField[]) { 347*86d916c6SFrancisco Iglesias VMSTATE_UINT32_ARRAY(wfifo, XlnxVersalCFUAPB, 4), 348*86d916c6SFrancisco Iglesias VMSTATE_UINT32_ARRAY(regs, XlnxVersalCFUAPB, R_MAX), 349*86d916c6SFrancisco Iglesias VMSTATE_UINT8(fdri_row_addr, XlnxVersalCFUAPB), 350*86d916c6SFrancisco Iglesias VMSTATE_END_OF_LIST(), 351*86d916c6SFrancisco Iglesias } 352*86d916c6SFrancisco Iglesias }; 353*86d916c6SFrancisco Iglesias 354*86d916c6SFrancisco Iglesias static void cfu_apb_class_init(ObjectClass *klass, void *data) 355*86d916c6SFrancisco Iglesias { 356*86d916c6SFrancisco Iglesias DeviceClass *dc = DEVICE_CLASS(klass); 357*86d916c6SFrancisco Iglesias 358*86d916c6SFrancisco Iglesias dc->reset = cfu_apb_reset; 359*86d916c6SFrancisco Iglesias dc->vmsd = &vmstate_cfu_apb; 360*86d916c6SFrancisco Iglesias device_class_set_props(dc, cfu_props); 361*86d916c6SFrancisco Iglesias } 362*86d916c6SFrancisco Iglesias 363*86d916c6SFrancisco Iglesias static const TypeInfo cfu_apb_info = { 364*86d916c6SFrancisco Iglesias .name = TYPE_XLNX_VERSAL_CFU_APB, 365*86d916c6SFrancisco Iglesias .parent = TYPE_SYS_BUS_DEVICE, 366*86d916c6SFrancisco Iglesias .instance_size = sizeof(XlnxVersalCFUAPB), 367*86d916c6SFrancisco Iglesias .class_init = cfu_apb_class_init, 368*86d916c6SFrancisco Iglesias .instance_init = cfu_apb_init, 369*86d916c6SFrancisco Iglesias .interfaces = (InterfaceInfo[]) { 370*86d916c6SFrancisco Iglesias { TYPE_XLNX_CFI_IF }, 371*86d916c6SFrancisco Iglesias { } 372*86d916c6SFrancisco Iglesias } 373*86d916c6SFrancisco Iglesias }; 374*86d916c6SFrancisco Iglesias 375*86d916c6SFrancisco Iglesias static void cfu_apb_register_types(void) 376*86d916c6SFrancisco Iglesias { 377*86d916c6SFrancisco Iglesias type_register_static(&cfu_apb_info); 378*86d916c6SFrancisco Iglesias } 379*86d916c6SFrancisco Iglesias 380*86d916c6SFrancisco Iglesias type_init(cfu_apb_register_types) 381