186d916c6SFrancisco Iglesias /*
286d916c6SFrancisco Iglesias * QEMU model of the CFU Configuration Unit.
386d916c6SFrancisco Iglesias *
486d916c6SFrancisco Iglesias * Copyright (C) 2023, Advanced Micro Devices, Inc.
586d916c6SFrancisco Iglesias *
686d916c6SFrancisco Iglesias * Written by Edgar E. Iglesias <edgar.iglesias@gmail.com>,
786d916c6SFrancisco Iglesias * Sai Pavan Boddu <sai.pavan.boddu@amd.com>,
886d916c6SFrancisco Iglesias * Francisco Iglesias <francisco.iglesias@amd.com>
986d916c6SFrancisco Iglesias *
1086d916c6SFrancisco Iglesias * SPDX-License-Identifier: GPL-2.0-or-later
1186d916c6SFrancisco Iglesias */
1286d916c6SFrancisco Iglesias
1386d916c6SFrancisco Iglesias #include "qemu/osdep.h"
1486d916c6SFrancisco Iglesias #include "hw/sysbus.h"
1586d916c6SFrancisco Iglesias #include "hw/register.h"
1686d916c6SFrancisco Iglesias #include "hw/irq.h"
1786d916c6SFrancisco Iglesias #include "qemu/bitops.h"
1886d916c6SFrancisco Iglesias #include "qemu/log.h"
1986d916c6SFrancisco Iglesias #include "qemu/units.h"
2086d916c6SFrancisco Iglesias #include "migration/vmstate.h"
2186d916c6SFrancisco Iglesias #include "hw/qdev-properties.h"
2286d916c6SFrancisco Iglesias #include "hw/qdev-properties-system.h"
2386d916c6SFrancisco Iglesias #include "hw/misc/xlnx-versal-cfu.h"
2486d916c6SFrancisco Iglesias
2586d916c6SFrancisco Iglesias #ifndef XLNX_VERSAL_CFU_APB_ERR_DEBUG
2686d916c6SFrancisco Iglesias #define XLNX_VERSAL_CFU_APB_ERR_DEBUG 0
2786d916c6SFrancisco Iglesias #endif
2886d916c6SFrancisco Iglesias
2986d916c6SFrancisco Iglesias #define KEYHOLE_STREAM_4K (4 * KiB)
3086d916c6SFrancisco Iglesias #define KEYHOLE_STREAM_256K (256 * KiB)
3186d916c6SFrancisco Iglesias #define CFRAME_BROADCAST_ROW 0x1F
3286d916c6SFrancisco Iglesias
update_wfifo(hwaddr addr,uint64_t value,uint32_t * wfifo,uint32_t * wfifo_ret)3386d916c6SFrancisco Iglesias bool update_wfifo(hwaddr addr, uint64_t value,
3486d916c6SFrancisco Iglesias uint32_t *wfifo, uint32_t *wfifo_ret)
3586d916c6SFrancisco Iglesias {
3686d916c6SFrancisco Iglesias unsigned int idx = extract32(addr, 2, 2);
3786d916c6SFrancisco Iglesias
3886d916c6SFrancisco Iglesias wfifo[idx] = value;
3986d916c6SFrancisco Iglesias
4086d916c6SFrancisco Iglesias if (idx == 3) {
4186d916c6SFrancisco Iglesias memcpy(wfifo_ret, wfifo, WFIFO_SZ * sizeof(uint32_t));
4286d916c6SFrancisco Iglesias memset(wfifo, 0, WFIFO_SZ * sizeof(uint32_t));
4386d916c6SFrancisco Iglesias return true;
4486d916c6SFrancisco Iglesias }
4586d916c6SFrancisco Iglesias
4686d916c6SFrancisco Iglesias return false;
4786d916c6SFrancisco Iglesias }
4886d916c6SFrancisco Iglesias
cfu_imr_update_irq(XlnxVersalCFUAPB * s)4986d916c6SFrancisco Iglesias static void cfu_imr_update_irq(XlnxVersalCFUAPB *s)
5086d916c6SFrancisco Iglesias {
5186d916c6SFrancisco Iglesias bool pending = s->regs[R_CFU_ISR] & ~s->regs[R_CFU_IMR];
5286d916c6SFrancisco Iglesias qemu_set_irq(s->irq_cfu_imr, pending);
5386d916c6SFrancisco Iglesias }
5486d916c6SFrancisco Iglesias
cfu_isr_postw(RegisterInfo * reg,uint64_t val64)5586d916c6SFrancisco Iglesias static void cfu_isr_postw(RegisterInfo *reg, uint64_t val64)
5686d916c6SFrancisco Iglesias {
5786d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(reg->opaque);
5886d916c6SFrancisco Iglesias cfu_imr_update_irq(s);
5986d916c6SFrancisco Iglesias }
6086d916c6SFrancisco Iglesias
cfu_ier_prew(RegisterInfo * reg,uint64_t val64)6186d916c6SFrancisco Iglesias static uint64_t cfu_ier_prew(RegisterInfo *reg, uint64_t val64)
6286d916c6SFrancisco Iglesias {
6386d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(reg->opaque);
6486d916c6SFrancisco Iglesias uint32_t val = val64;
6586d916c6SFrancisco Iglesias
6686d916c6SFrancisco Iglesias s->regs[R_CFU_IMR] &= ~val;
6786d916c6SFrancisco Iglesias cfu_imr_update_irq(s);
6886d916c6SFrancisco Iglesias return 0;
6986d916c6SFrancisco Iglesias }
7086d916c6SFrancisco Iglesias
cfu_idr_prew(RegisterInfo * reg,uint64_t val64)7186d916c6SFrancisco Iglesias static uint64_t cfu_idr_prew(RegisterInfo *reg, uint64_t val64)
7286d916c6SFrancisco Iglesias {
7386d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(reg->opaque);
7486d916c6SFrancisco Iglesias uint32_t val = val64;
7586d916c6SFrancisco Iglesias
7686d916c6SFrancisco Iglesias s->regs[R_CFU_IMR] |= val;
7786d916c6SFrancisco Iglesias cfu_imr_update_irq(s);
7886d916c6SFrancisco Iglesias return 0;
7986d916c6SFrancisco Iglesias }
8086d916c6SFrancisco Iglesias
cfu_itr_prew(RegisterInfo * reg,uint64_t val64)8186d916c6SFrancisco Iglesias static uint64_t cfu_itr_prew(RegisterInfo *reg, uint64_t val64)
8286d916c6SFrancisco Iglesias {
8386d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(reg->opaque);
8486d916c6SFrancisco Iglesias uint32_t val = val64;
8586d916c6SFrancisco Iglesias
8686d916c6SFrancisco Iglesias s->regs[R_CFU_ISR] |= val;
8786d916c6SFrancisco Iglesias cfu_imr_update_irq(s);
8886d916c6SFrancisco Iglesias return 0;
8986d916c6SFrancisco Iglesias }
9086d916c6SFrancisco Iglesias
cfu_fgcr_postw(RegisterInfo * reg,uint64_t val64)9186d916c6SFrancisco Iglesias static void cfu_fgcr_postw(RegisterInfo *reg, uint64_t val64)
9286d916c6SFrancisco Iglesias {
9386d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(reg->opaque);
9486d916c6SFrancisco Iglesias uint32_t val = (uint32_t)val64;
9586d916c6SFrancisco Iglesias
9686d916c6SFrancisco Iglesias /* Do a scan. It always looks good. */
9786d916c6SFrancisco Iglesias if (FIELD_EX32(val, CFU_FGCR, SC_HBC_TRIGGER)) {
9886d916c6SFrancisco Iglesias ARRAY_FIELD_DP32(s->regs, CFU_STATUS, SCAN_CLEAR_PASS, 1);
9986d916c6SFrancisco Iglesias ARRAY_FIELD_DP32(s->regs, CFU_STATUS, SCAN_CLEAR_DONE, 1);
10086d916c6SFrancisco Iglesias }
10186d916c6SFrancisco Iglesias }
10286d916c6SFrancisco Iglesias
10386d916c6SFrancisco Iglesias static const RegisterAccessInfo cfu_apb_regs_info[] = {
10486d916c6SFrancisco Iglesias { .name = "CFU_ISR", .addr = A_CFU_ISR,
10586d916c6SFrancisco Iglesias .rsvd = 0xfffffc00,
10686d916c6SFrancisco Iglesias .w1c = 0x3ff,
10786d916c6SFrancisco Iglesias .post_write = cfu_isr_postw,
10886d916c6SFrancisco Iglesias },{ .name = "CFU_IMR", .addr = A_CFU_IMR,
10986d916c6SFrancisco Iglesias .reset = 0x3ff,
11086d916c6SFrancisco Iglesias .rsvd = 0xfffffc00,
11186d916c6SFrancisco Iglesias .ro = 0x3ff,
11286d916c6SFrancisco Iglesias },{ .name = "CFU_IER", .addr = A_CFU_IER,
11386d916c6SFrancisco Iglesias .rsvd = 0xfffffc00,
11486d916c6SFrancisco Iglesias .pre_write = cfu_ier_prew,
11586d916c6SFrancisco Iglesias },{ .name = "CFU_IDR", .addr = A_CFU_IDR,
11686d916c6SFrancisco Iglesias .rsvd = 0xfffffc00,
11786d916c6SFrancisco Iglesias .pre_write = cfu_idr_prew,
11886d916c6SFrancisco Iglesias },{ .name = "CFU_ITR", .addr = A_CFU_ITR,
11986d916c6SFrancisco Iglesias .rsvd = 0xfffffc00,
12086d916c6SFrancisco Iglesias .pre_write = cfu_itr_prew,
12186d916c6SFrancisco Iglesias },{ .name = "CFU_PROTECT", .addr = A_CFU_PROTECT,
12286d916c6SFrancisco Iglesias .reset = 0x1,
12386d916c6SFrancisco Iglesias },{ .name = "CFU_FGCR", .addr = A_CFU_FGCR,
12486d916c6SFrancisco Iglesias .rsvd = 0xffff8000,
12586d916c6SFrancisco Iglesias .post_write = cfu_fgcr_postw,
12686d916c6SFrancisco Iglesias },{ .name = "CFU_CTL", .addr = A_CFU_CTL,
12786d916c6SFrancisco Iglesias .rsvd = 0xffff0000,
12886d916c6SFrancisco Iglesias },{ .name = "CFU_CRAM_RW", .addr = A_CFU_CRAM_RW,
12986d916c6SFrancisco Iglesias .reset = 0x401f7d9,
13086d916c6SFrancisco Iglesias .rsvd = 0xf8000000,
13186d916c6SFrancisco Iglesias },{ .name = "CFU_MASK", .addr = A_CFU_MASK,
13286d916c6SFrancisco Iglesias },{ .name = "CFU_CRC_EXPECT", .addr = A_CFU_CRC_EXPECT,
13386d916c6SFrancisco Iglesias },{ .name = "CFU_CFRAME_LEFT_T0", .addr = A_CFU_CFRAME_LEFT_T0,
13486d916c6SFrancisco Iglesias .rsvd = 0xfff00000,
13586d916c6SFrancisco Iglesias },{ .name = "CFU_CFRAME_LEFT_T1", .addr = A_CFU_CFRAME_LEFT_T1,
13686d916c6SFrancisco Iglesias .rsvd = 0xfff00000,
13786d916c6SFrancisco Iglesias },{ .name = "CFU_CFRAME_LEFT_T2", .addr = A_CFU_CFRAME_LEFT_T2,
13886d916c6SFrancisco Iglesias .rsvd = 0xfff00000,
13986d916c6SFrancisco Iglesias },{ .name = "CFU_ROW_RANGE", .addr = A_CFU_ROW_RANGE,
14086d916c6SFrancisco Iglesias .rsvd = 0xffffffc0,
14186d916c6SFrancisco Iglesias .ro = 0x3f,
14286d916c6SFrancisco Iglesias },{ .name = "CFU_STATUS", .addr = A_CFU_STATUS,
14386d916c6SFrancisco Iglesias .rsvd = 0x80000000,
14486d916c6SFrancisco Iglesias .ro = 0x7fffffff,
14586d916c6SFrancisco Iglesias },{ .name = "CFU_INTERNAL_STATUS", .addr = A_CFU_INTERNAL_STATUS,
14686d916c6SFrancisco Iglesias .rsvd = 0xff800000,
14786d916c6SFrancisco Iglesias .ro = 0x7fffff,
14886d916c6SFrancisco Iglesias },{ .name = "CFU_QWORD_CNT", .addr = A_CFU_QWORD_CNT,
14986d916c6SFrancisco Iglesias .ro = 0xffffffff,
15086d916c6SFrancisco Iglesias },{ .name = "CFU_CRC_LIVE", .addr = A_CFU_CRC_LIVE,
15186d916c6SFrancisco Iglesias .ro = 0xffffffff,
15286d916c6SFrancisco Iglesias },{ .name = "CFU_PENDING_READ_CNT", .addr = A_CFU_PENDING_READ_CNT,
15386d916c6SFrancisco Iglesias .rsvd = 0xfe000000,
15486d916c6SFrancisco Iglesias .ro = 0x1ffffff,
15586d916c6SFrancisco Iglesias },{ .name = "CFU_FDRI_CNT", .addr = A_CFU_FDRI_CNT,
15686d916c6SFrancisco Iglesias .ro = 0xffffffff,
15786d916c6SFrancisco Iglesias },{ .name = "CFU_ECO1", .addr = A_CFU_ECO1,
15886d916c6SFrancisco Iglesias },{ .name = "CFU_ECO2", .addr = A_CFU_ECO2,
15986d916c6SFrancisco Iglesias }
16086d916c6SFrancisco Iglesias };
16186d916c6SFrancisco Iglesias
cfu_apb_reset(DeviceState * dev)16286d916c6SFrancisco Iglesias static void cfu_apb_reset(DeviceState *dev)
16386d916c6SFrancisco Iglesias {
16486d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(dev);
16586d916c6SFrancisco Iglesias unsigned int i;
16686d916c6SFrancisco Iglesias
16786d916c6SFrancisco Iglesias for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
16886d916c6SFrancisco Iglesias register_reset(&s->regs_info[i]);
16986d916c6SFrancisco Iglesias }
17086d916c6SFrancisco Iglesias memset(s->wfifo, 0, WFIFO_SZ * sizeof(uint32_t));
17186d916c6SFrancisco Iglesias
17286d916c6SFrancisco Iglesias s->regs[R_CFU_STATUS] |= R_CFU_STATUS_HC_COMPLETE_MASK;
17386d916c6SFrancisco Iglesias cfu_imr_update_irq(s);
17486d916c6SFrancisco Iglesias }
17586d916c6SFrancisco Iglesias
17686d916c6SFrancisco Iglesias static const MemoryRegionOps cfu_apb_ops = {
17786d916c6SFrancisco Iglesias .read = register_read_memory,
17886d916c6SFrancisco Iglesias .write = register_write_memory,
17986d916c6SFrancisco Iglesias .endianness = DEVICE_LITTLE_ENDIAN,
18086d916c6SFrancisco Iglesias .valid = {
18186d916c6SFrancisco Iglesias .min_access_size = 4,
18286d916c6SFrancisco Iglesias .max_access_size = 4,
18386d916c6SFrancisco Iglesias },
18486d916c6SFrancisco Iglesias };
18586d916c6SFrancisco Iglesias
cfu_transfer_cfi_packet(XlnxVersalCFUAPB * s,uint8_t row_addr,XlnxCfiPacket * pkt)18686d916c6SFrancisco Iglesias static void cfu_transfer_cfi_packet(XlnxVersalCFUAPB *s, uint8_t row_addr,
18786d916c6SFrancisco Iglesias XlnxCfiPacket *pkt)
18886d916c6SFrancisco Iglesias {
18986d916c6SFrancisco Iglesias if (row_addr == CFRAME_BROADCAST_ROW) {
19086d916c6SFrancisco Iglesias for (int i = 0; i < ARRAY_SIZE(s->cfg.cframe); i++) {
19186d916c6SFrancisco Iglesias if (s->cfg.cframe[i]) {
19286d916c6SFrancisco Iglesias xlnx_cfi_transfer_packet(s->cfg.cframe[i], pkt);
19386d916c6SFrancisco Iglesias }
19486d916c6SFrancisco Iglesias }
19586d916c6SFrancisco Iglesias } else {
19686d916c6SFrancisco Iglesias assert(row_addr < ARRAY_SIZE(s->cfg.cframe));
19786d916c6SFrancisco Iglesias
19886d916c6SFrancisco Iglesias if (s->cfg.cframe[row_addr]) {
19986d916c6SFrancisco Iglesias xlnx_cfi_transfer_packet(s->cfg.cframe[row_addr], pkt);
20086d916c6SFrancisco Iglesias }
20186d916c6SFrancisco Iglesias }
20286d916c6SFrancisco Iglesias }
20386d916c6SFrancisco Iglesias
cfu_stream_read(void * opaque,hwaddr addr,unsigned size)20486d916c6SFrancisco Iglesias static uint64_t cfu_stream_read(void *opaque, hwaddr addr, unsigned size)
20586d916c6SFrancisco Iglesias {
20686d916c6SFrancisco Iglesias qemu_log_mask(LOG_GUEST_ERROR, "%s: Unsupported read from addr=%"
20786d916c6SFrancisco Iglesias HWADDR_PRIx "\n", __func__, addr);
20886d916c6SFrancisco Iglesias return 0;
20986d916c6SFrancisco Iglesias }
21086d916c6SFrancisco Iglesias
cfu_stream_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)21186d916c6SFrancisco Iglesias static void cfu_stream_write(void *opaque, hwaddr addr, uint64_t value,
21286d916c6SFrancisco Iglesias unsigned size)
21386d916c6SFrancisco Iglesias {
21486d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(opaque);
21586d916c6SFrancisco Iglesias uint32_t wfifo[WFIFO_SZ];
21686d916c6SFrancisco Iglesias
21786d916c6SFrancisco Iglesias if (update_wfifo(addr, value, s->wfifo, wfifo)) {
21886d916c6SFrancisco Iglesias uint8_t packet_type, row_addr, reg_addr;
21986d916c6SFrancisco Iglesias
22086d916c6SFrancisco Iglesias packet_type = extract32(wfifo[0], 24, 8);
22186d916c6SFrancisco Iglesias row_addr = extract32(wfifo[0], 16, 5);
22286d916c6SFrancisco Iglesias reg_addr = extract32(wfifo[0], 8, 6);
22386d916c6SFrancisco Iglesias
22486d916c6SFrancisco Iglesias /* Compressed bitstreams are not supported yet. */
22586d916c6SFrancisco Iglesias if (ARRAY_FIELD_EX32(s->regs, CFU_CTL, DECOMPRESS) == 0) {
22686d916c6SFrancisco Iglesias if (s->regs[R_CFU_FDRI_CNT]) {
22786d916c6SFrancisco Iglesias XlnxCfiPacket pkt = {
22886d916c6SFrancisco Iglesias .reg_addr = CFRAME_FDRI,
22986d916c6SFrancisco Iglesias .data[0] = wfifo[0],
23086d916c6SFrancisco Iglesias .data[1] = wfifo[1],
23186d916c6SFrancisco Iglesias .data[2] = wfifo[2],
23286d916c6SFrancisco Iglesias .data[3] = wfifo[3]
23386d916c6SFrancisco Iglesias };
23486d916c6SFrancisco Iglesias
23586d916c6SFrancisco Iglesias cfu_transfer_cfi_packet(s, s->fdri_row_addr, &pkt);
23686d916c6SFrancisco Iglesias
23786d916c6SFrancisco Iglesias s->regs[R_CFU_FDRI_CNT]--;
23886d916c6SFrancisco Iglesias
23986d916c6SFrancisco Iglesias } else if (packet_type == PACKET_TYPE_CFU &&
24086d916c6SFrancisco Iglesias reg_addr == CFRAME_FDRI) {
24186d916c6SFrancisco Iglesias
24286d916c6SFrancisco Iglesias /* Load R_CFU_FDRI_CNT, must be multiple of 25 */
24386d916c6SFrancisco Iglesias s->regs[R_CFU_FDRI_CNT] = wfifo[1];
24486d916c6SFrancisco Iglesias
24586d916c6SFrancisco Iglesias /* Store target row_addr */
24686d916c6SFrancisco Iglesias s->fdri_row_addr = row_addr;
24786d916c6SFrancisco Iglesias
24886d916c6SFrancisco Iglesias if (wfifo[1] % 25 != 0) {
24986d916c6SFrancisco Iglesias qemu_log_mask(LOG_GUEST_ERROR,
25086d916c6SFrancisco Iglesias "CFU FDRI_CNT is not loaded with "
25186d916c6SFrancisco Iglesias "a multiple of 25 value\n");
25286d916c6SFrancisco Iglesias }
25386d916c6SFrancisco Iglesias
25486d916c6SFrancisco Iglesias } else if (packet_type == PACKET_TYPE_CFRAME) {
25586d916c6SFrancisco Iglesias XlnxCfiPacket pkt = {
25686d916c6SFrancisco Iglesias .reg_addr = reg_addr,
25786d916c6SFrancisco Iglesias .data[0] = wfifo[1],
25886d916c6SFrancisco Iglesias .data[1] = wfifo[2],
25986d916c6SFrancisco Iglesias .data[2] = wfifo[3],
26086d916c6SFrancisco Iglesias };
26186d916c6SFrancisco Iglesias cfu_transfer_cfi_packet(s, row_addr, &pkt);
26286d916c6SFrancisco Iglesias }
26386d916c6SFrancisco Iglesias }
26486d916c6SFrancisco Iglesias }
26586d916c6SFrancisco Iglesias }
26686d916c6SFrancisco Iglesias
cfu_sfr_read(void * opaque,hwaddr addr,unsigned size)267975dd496SFrancisco Iglesias static uint64_t cfu_sfr_read(void *opaque, hwaddr addr, unsigned size)
268975dd496SFrancisco Iglesias {
269975dd496SFrancisco Iglesias qemu_log_mask(LOG_GUEST_ERROR, "%s: Unsupported read from addr=%"
270975dd496SFrancisco Iglesias HWADDR_PRIx "\n", __func__, addr);
271975dd496SFrancisco Iglesias return 0;
272975dd496SFrancisco Iglesias }
273975dd496SFrancisco Iglesias
cfu_sfr_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)274975dd496SFrancisco Iglesias static void cfu_sfr_write(void *opaque, hwaddr addr, uint64_t value,
275975dd496SFrancisco Iglesias unsigned size)
276975dd496SFrancisco Iglesias {
277975dd496SFrancisco Iglesias XlnxVersalCFUSFR *s = XLNX_VERSAL_CFU_SFR(opaque);
278975dd496SFrancisco Iglesias uint32_t wfifo[WFIFO_SZ];
279975dd496SFrancisco Iglesias
280975dd496SFrancisco Iglesias if (update_wfifo(addr, value, s->wfifo, wfifo)) {
281975dd496SFrancisco Iglesias uint8_t row_addr = extract32(wfifo[0], 23, 5);
282975dd496SFrancisco Iglesias uint32_t frame_addr = extract32(wfifo[0], 0, 23);
283975dd496SFrancisco Iglesias XlnxCfiPacket pkt = { .reg_addr = CFRAME_SFR,
284975dd496SFrancisco Iglesias .data[0] = frame_addr };
285975dd496SFrancisco Iglesias
286975dd496SFrancisco Iglesias if (s->cfg.cfu) {
287975dd496SFrancisco Iglesias cfu_transfer_cfi_packet(s->cfg.cfu, row_addr, &pkt);
288975dd496SFrancisco Iglesias }
289975dd496SFrancisco Iglesias }
290975dd496SFrancisco Iglesias }
291975dd496SFrancisco Iglesias
cfu_fdro_read(void * opaque,hwaddr addr,unsigned size)292ebfdc494SFrancisco Iglesias static uint64_t cfu_fdro_read(void *opaque, hwaddr addr, unsigned size)
293ebfdc494SFrancisco Iglesias {
294ebfdc494SFrancisco Iglesias XlnxVersalCFUFDRO *s = XLNX_VERSAL_CFU_FDRO(opaque);
295ebfdc494SFrancisco Iglesias uint64_t ret = 0;
296ebfdc494SFrancisco Iglesias
297ebfdc494SFrancisco Iglesias if (!fifo32_is_empty(&s->fdro_data)) {
298ebfdc494SFrancisco Iglesias ret = fifo32_pop(&s->fdro_data);
299ebfdc494SFrancisco Iglesias }
300ebfdc494SFrancisco Iglesias
301ebfdc494SFrancisco Iglesias return ret;
302ebfdc494SFrancisco Iglesias }
303ebfdc494SFrancisco Iglesias
cfu_fdro_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)304ebfdc494SFrancisco Iglesias static void cfu_fdro_write(void *opaque, hwaddr addr, uint64_t value,
305ebfdc494SFrancisco Iglesias unsigned size)
306ebfdc494SFrancisco Iglesias {
307ebfdc494SFrancisco Iglesias qemu_log_mask(LOG_GUEST_ERROR, "%s: Unsupported write from addr=%"
308ebfdc494SFrancisco Iglesias HWADDR_PRIx "\n", __func__, addr);
309ebfdc494SFrancisco Iglesias }
310ebfdc494SFrancisco Iglesias
31186d916c6SFrancisco Iglesias static const MemoryRegionOps cfu_stream_ops = {
31286d916c6SFrancisco Iglesias .read = cfu_stream_read,
31386d916c6SFrancisco Iglesias .write = cfu_stream_write,
31486d916c6SFrancisco Iglesias .endianness = DEVICE_LITTLE_ENDIAN,
31586d916c6SFrancisco Iglesias .valid = {
31686d916c6SFrancisco Iglesias .min_access_size = 4,
31786d916c6SFrancisco Iglesias .max_access_size = 8,
31886d916c6SFrancisco Iglesias },
31986d916c6SFrancisco Iglesias };
32086d916c6SFrancisco Iglesias
321975dd496SFrancisco Iglesias static const MemoryRegionOps cfu_sfr_ops = {
322975dd496SFrancisco Iglesias .read = cfu_sfr_read,
323975dd496SFrancisco Iglesias .write = cfu_sfr_write,
324975dd496SFrancisco Iglesias .endianness = DEVICE_LITTLE_ENDIAN,
325975dd496SFrancisco Iglesias .valid = {
326975dd496SFrancisco Iglesias .min_access_size = 4,
327975dd496SFrancisco Iglesias .max_access_size = 4,
328975dd496SFrancisco Iglesias },
329975dd496SFrancisco Iglesias };
330975dd496SFrancisco Iglesias
331ebfdc494SFrancisco Iglesias static const MemoryRegionOps cfu_fdro_ops = {
332ebfdc494SFrancisco Iglesias .read = cfu_fdro_read,
333ebfdc494SFrancisco Iglesias .write = cfu_fdro_write,
334ebfdc494SFrancisco Iglesias .endianness = DEVICE_LITTLE_ENDIAN,
335ebfdc494SFrancisco Iglesias .valid = {
336ebfdc494SFrancisco Iglesias .min_access_size = 4,
337ebfdc494SFrancisco Iglesias .max_access_size = 4,
338ebfdc494SFrancisco Iglesias },
339ebfdc494SFrancisco Iglesias };
340ebfdc494SFrancisco Iglesias
cfu_apb_init(Object * obj)34186d916c6SFrancisco Iglesias static void cfu_apb_init(Object *obj)
34286d916c6SFrancisco Iglesias {
34386d916c6SFrancisco Iglesias XlnxVersalCFUAPB *s = XLNX_VERSAL_CFU_APB(obj);
34486d916c6SFrancisco Iglesias SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
34586d916c6SFrancisco Iglesias RegisterInfoArray *reg_array;
34686d916c6SFrancisco Iglesias unsigned int i;
34786d916c6SFrancisco Iglesias char *name;
34886d916c6SFrancisco Iglesias
34986d916c6SFrancisco Iglesias memory_region_init(&s->iomem, obj, TYPE_XLNX_VERSAL_CFU_APB, R_MAX * 4);
35086d916c6SFrancisco Iglesias reg_array =
35186d916c6SFrancisco Iglesias register_init_block32(DEVICE(obj), cfu_apb_regs_info,
35286d916c6SFrancisco Iglesias ARRAY_SIZE(cfu_apb_regs_info),
35386d916c6SFrancisco Iglesias s->regs_info, s->regs,
35486d916c6SFrancisco Iglesias &cfu_apb_ops,
35586d916c6SFrancisco Iglesias XLNX_VERSAL_CFU_APB_ERR_DEBUG,
35686d916c6SFrancisco Iglesias R_MAX * 4);
35786d916c6SFrancisco Iglesias memory_region_add_subregion(&s->iomem,
35886d916c6SFrancisco Iglesias 0x0,
35986d916c6SFrancisco Iglesias ®_array->mem);
36086d916c6SFrancisco Iglesias sysbus_init_mmio(sbd, &s->iomem);
36186d916c6SFrancisco Iglesias for (i = 0; i < NUM_STREAM; i++) {
36286d916c6SFrancisco Iglesias name = g_strdup_printf(TYPE_XLNX_VERSAL_CFU_APB "-stream%d", i);
36386d916c6SFrancisco Iglesias memory_region_init_io(&s->iomem_stream[i], obj, &cfu_stream_ops, s,
36486d916c6SFrancisco Iglesias name, i == 0 ? KEYHOLE_STREAM_4K :
36586d916c6SFrancisco Iglesias KEYHOLE_STREAM_256K);
36686d916c6SFrancisco Iglesias sysbus_init_mmio(sbd, &s->iomem_stream[i]);
36786d916c6SFrancisco Iglesias g_free(name);
36886d916c6SFrancisco Iglesias }
36986d916c6SFrancisco Iglesias sysbus_init_irq(sbd, &s->irq_cfu_imr);
37086d916c6SFrancisco Iglesias }
37186d916c6SFrancisco Iglesias
cfu_sfr_init(Object * obj)372975dd496SFrancisco Iglesias static void cfu_sfr_init(Object *obj)
373975dd496SFrancisco Iglesias {
374975dd496SFrancisco Iglesias XlnxVersalCFUSFR *s = XLNX_VERSAL_CFU_SFR(obj);
375975dd496SFrancisco Iglesias SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
376975dd496SFrancisco Iglesias
377975dd496SFrancisco Iglesias memory_region_init_io(&s->iomem_sfr, obj, &cfu_sfr_ops, s,
378975dd496SFrancisco Iglesias TYPE_XLNX_VERSAL_CFU_SFR, KEYHOLE_STREAM_4K);
379975dd496SFrancisco Iglesias sysbus_init_mmio(sbd, &s->iomem_sfr);
380975dd496SFrancisco Iglesias }
381975dd496SFrancisco Iglesias
cfu_sfr_reset_enter(Object * obj,ResetType type)382975dd496SFrancisco Iglesias static void cfu_sfr_reset_enter(Object *obj, ResetType type)
383975dd496SFrancisco Iglesias {
384975dd496SFrancisco Iglesias XlnxVersalCFUSFR *s = XLNX_VERSAL_CFU_SFR(obj);
385975dd496SFrancisco Iglesias
386975dd496SFrancisco Iglesias memset(s->wfifo, 0, WFIFO_SZ * sizeof(uint32_t));
387975dd496SFrancisco Iglesias }
388975dd496SFrancisco Iglesias
cfu_fdro_init(Object * obj)389ebfdc494SFrancisco Iglesias static void cfu_fdro_init(Object *obj)
390ebfdc494SFrancisco Iglesias {
391ebfdc494SFrancisco Iglesias XlnxVersalCFUFDRO *s = XLNX_VERSAL_CFU_FDRO(obj);
392ebfdc494SFrancisco Iglesias SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
393ebfdc494SFrancisco Iglesias
394ebfdc494SFrancisco Iglesias memory_region_init_io(&s->iomem_fdro, obj, &cfu_fdro_ops, s,
395ebfdc494SFrancisco Iglesias TYPE_XLNX_VERSAL_CFU_FDRO, KEYHOLE_STREAM_4K);
396ebfdc494SFrancisco Iglesias sysbus_init_mmio(sbd, &s->iomem_fdro);
397ebfdc494SFrancisco Iglesias fifo32_create(&s->fdro_data, 8 * KiB / sizeof(uint32_t));
398ebfdc494SFrancisco Iglesias }
399ebfdc494SFrancisco Iglesias
cfu_fdro_finalize(Object * obj)400d30d590bSPeter Maydell static void cfu_fdro_finalize(Object *obj)
401d30d590bSPeter Maydell {
402d30d590bSPeter Maydell XlnxVersalCFUFDRO *s = XLNX_VERSAL_CFU_FDRO(obj);
403d30d590bSPeter Maydell
404d30d590bSPeter Maydell fifo32_destroy(&s->fdro_data);
405d30d590bSPeter Maydell }
406d30d590bSPeter Maydell
cfu_fdro_reset_enter(Object * obj,ResetType type)407ebfdc494SFrancisco Iglesias static void cfu_fdro_reset_enter(Object *obj, ResetType type)
408ebfdc494SFrancisco Iglesias {
409ebfdc494SFrancisco Iglesias XlnxVersalCFUFDRO *s = XLNX_VERSAL_CFU_FDRO(obj);
410ebfdc494SFrancisco Iglesias
411ebfdc494SFrancisco Iglesias fifo32_reset(&s->fdro_data);
412ebfdc494SFrancisco Iglesias }
413ebfdc494SFrancisco Iglesias
cfu_fdro_cfi_transfer_packet(XlnxCfiIf * cfi_if,XlnxCfiPacket * pkt)414ebfdc494SFrancisco Iglesias static void cfu_fdro_cfi_transfer_packet(XlnxCfiIf *cfi_if, XlnxCfiPacket *pkt)
415ebfdc494SFrancisco Iglesias {
416ebfdc494SFrancisco Iglesias XlnxVersalCFUFDRO *s = XLNX_VERSAL_CFU_FDRO(cfi_if);
417ebfdc494SFrancisco Iglesias
418ebfdc494SFrancisco Iglesias if (fifo32_num_free(&s->fdro_data) >= ARRAY_SIZE(pkt->data)) {
419ebfdc494SFrancisco Iglesias for (int i = 0; i < ARRAY_SIZE(pkt->data); i++) {
420ebfdc494SFrancisco Iglesias fifo32_push(&s->fdro_data, pkt->data[i]);
421ebfdc494SFrancisco Iglesias }
422ebfdc494SFrancisco Iglesias } else {
423ebfdc494SFrancisco Iglesias /* It is a programming error to fill the fifo. */
424ebfdc494SFrancisco Iglesias qemu_log_mask(LOG_GUEST_ERROR,
425ebfdc494SFrancisco Iglesias "CFU_FDRO: CFI data dropped due to full read fifo\n");
426ebfdc494SFrancisco Iglesias }
427ebfdc494SFrancisco Iglesias }
428ebfdc494SFrancisco Iglesias
42986d916c6SFrancisco Iglesias static Property cfu_props[] = {
43086d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe0", XlnxVersalCFUAPB, cfg.cframe[0],
43186d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
43286d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe1", XlnxVersalCFUAPB, cfg.cframe[1],
43386d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
43486d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe2", XlnxVersalCFUAPB, cfg.cframe[2],
43586d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
43686d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe3", XlnxVersalCFUAPB, cfg.cframe[3],
43786d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
43886d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe4", XlnxVersalCFUAPB, cfg.cframe[4],
43986d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
44086d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe5", XlnxVersalCFUAPB, cfg.cframe[5],
44186d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
44286d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe6", XlnxVersalCFUAPB, cfg.cframe[6],
44386d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
44486d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe7", XlnxVersalCFUAPB, cfg.cframe[7],
44586d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
44686d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe8", XlnxVersalCFUAPB, cfg.cframe[8],
44786d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
44886d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe9", XlnxVersalCFUAPB, cfg.cframe[9],
44986d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
45086d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe10", XlnxVersalCFUAPB, cfg.cframe[10],
45186d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
45286d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe11", XlnxVersalCFUAPB, cfg.cframe[11],
45386d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
45486d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe12", XlnxVersalCFUAPB, cfg.cframe[12],
45586d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
45686d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe13", XlnxVersalCFUAPB, cfg.cframe[13],
45786d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
45886d916c6SFrancisco Iglesias DEFINE_PROP_LINK("cframe14", XlnxVersalCFUAPB, cfg.cframe[14],
45986d916c6SFrancisco Iglesias TYPE_XLNX_CFI_IF, XlnxCfiIf *),
46086d916c6SFrancisco Iglesias DEFINE_PROP_END_OF_LIST(),
46186d916c6SFrancisco Iglesias };
46286d916c6SFrancisco Iglesias
463975dd496SFrancisco Iglesias static Property cfu_sfr_props[] = {
464975dd496SFrancisco Iglesias DEFINE_PROP_LINK("cfu", XlnxVersalCFUSFR, cfg.cfu,
465975dd496SFrancisco Iglesias TYPE_XLNX_VERSAL_CFU_APB, XlnxVersalCFUAPB *),
466975dd496SFrancisco Iglesias DEFINE_PROP_END_OF_LIST(),
467975dd496SFrancisco Iglesias };
468975dd496SFrancisco Iglesias
46986d916c6SFrancisco Iglesias static const VMStateDescription vmstate_cfu_apb = {
47086d916c6SFrancisco Iglesias .name = TYPE_XLNX_VERSAL_CFU_APB,
47186d916c6SFrancisco Iglesias .version_id = 1,
47286d916c6SFrancisco Iglesias .minimum_version_id = 1,
473e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
47486d916c6SFrancisco Iglesias VMSTATE_UINT32_ARRAY(wfifo, XlnxVersalCFUAPB, 4),
47586d916c6SFrancisco Iglesias VMSTATE_UINT32_ARRAY(regs, XlnxVersalCFUAPB, R_MAX),
47686d916c6SFrancisco Iglesias VMSTATE_UINT8(fdri_row_addr, XlnxVersalCFUAPB),
47786d916c6SFrancisco Iglesias VMSTATE_END_OF_LIST(),
47886d916c6SFrancisco Iglesias }
47986d916c6SFrancisco Iglesias };
48086d916c6SFrancisco Iglesias
481ebfdc494SFrancisco Iglesias static const VMStateDescription vmstate_cfu_fdro = {
482ebfdc494SFrancisco Iglesias .name = TYPE_XLNX_VERSAL_CFU_FDRO,
483ebfdc494SFrancisco Iglesias .version_id = 1,
484ebfdc494SFrancisco Iglesias .minimum_version_id = 1,
485e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
486ebfdc494SFrancisco Iglesias VMSTATE_FIFO32(fdro_data, XlnxVersalCFUFDRO),
487ebfdc494SFrancisco Iglesias VMSTATE_END_OF_LIST(),
488ebfdc494SFrancisco Iglesias }
489ebfdc494SFrancisco Iglesias };
490ebfdc494SFrancisco Iglesias
491975dd496SFrancisco Iglesias static const VMStateDescription vmstate_cfu_sfr = {
492975dd496SFrancisco Iglesias .name = TYPE_XLNX_VERSAL_CFU_SFR,
493975dd496SFrancisco Iglesias .version_id = 1,
494975dd496SFrancisco Iglesias .minimum_version_id = 1,
495e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
496975dd496SFrancisco Iglesias VMSTATE_UINT32_ARRAY(wfifo, XlnxVersalCFUSFR, 4),
497975dd496SFrancisco Iglesias VMSTATE_END_OF_LIST(),
498975dd496SFrancisco Iglesias }
499975dd496SFrancisco Iglesias };
500975dd496SFrancisco Iglesias
cfu_apb_class_init(ObjectClass * klass,void * data)50186d916c6SFrancisco Iglesias static void cfu_apb_class_init(ObjectClass *klass, void *data)
50286d916c6SFrancisco Iglesias {
50386d916c6SFrancisco Iglesias DeviceClass *dc = DEVICE_CLASS(klass);
50486d916c6SFrancisco Iglesias
505*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, cfu_apb_reset);
50686d916c6SFrancisco Iglesias dc->vmsd = &vmstate_cfu_apb;
50786d916c6SFrancisco Iglesias device_class_set_props(dc, cfu_props);
50886d916c6SFrancisco Iglesias }
50986d916c6SFrancisco Iglesias
cfu_fdro_class_init(ObjectClass * klass,void * data)510ebfdc494SFrancisco Iglesias static void cfu_fdro_class_init(ObjectClass *klass, void *data)
511ebfdc494SFrancisco Iglesias {
512ebfdc494SFrancisco Iglesias DeviceClass *dc = DEVICE_CLASS(klass);
513ebfdc494SFrancisco Iglesias ResettableClass *rc = RESETTABLE_CLASS(klass);
514ebfdc494SFrancisco Iglesias XlnxCfiIfClass *xcic = XLNX_CFI_IF_CLASS(klass);
515ebfdc494SFrancisco Iglesias
516ebfdc494SFrancisco Iglesias dc->vmsd = &vmstate_cfu_fdro;
517ebfdc494SFrancisco Iglesias xcic->cfi_transfer_packet = cfu_fdro_cfi_transfer_packet;
518ebfdc494SFrancisco Iglesias rc->phases.enter = cfu_fdro_reset_enter;
519ebfdc494SFrancisco Iglesias }
520ebfdc494SFrancisco Iglesias
cfu_sfr_class_init(ObjectClass * klass,void * data)521975dd496SFrancisco Iglesias static void cfu_sfr_class_init(ObjectClass *klass, void *data)
522975dd496SFrancisco Iglesias {
523975dd496SFrancisco Iglesias DeviceClass *dc = DEVICE_CLASS(klass);
524975dd496SFrancisco Iglesias ResettableClass *rc = RESETTABLE_CLASS(klass);
525975dd496SFrancisco Iglesias
526975dd496SFrancisco Iglesias device_class_set_props(dc, cfu_sfr_props);
527975dd496SFrancisco Iglesias dc->vmsd = &vmstate_cfu_sfr;
528975dd496SFrancisco Iglesias rc->phases.enter = cfu_sfr_reset_enter;
529975dd496SFrancisco Iglesias }
530975dd496SFrancisco Iglesias
53186d916c6SFrancisco Iglesias static const TypeInfo cfu_apb_info = {
53286d916c6SFrancisco Iglesias .name = TYPE_XLNX_VERSAL_CFU_APB,
53386d916c6SFrancisco Iglesias .parent = TYPE_SYS_BUS_DEVICE,
53486d916c6SFrancisco Iglesias .instance_size = sizeof(XlnxVersalCFUAPB),
53586d916c6SFrancisco Iglesias .class_init = cfu_apb_class_init,
53686d916c6SFrancisco Iglesias .instance_init = cfu_apb_init,
53786d916c6SFrancisco Iglesias .interfaces = (InterfaceInfo[]) {
53886d916c6SFrancisco Iglesias { TYPE_XLNX_CFI_IF },
53986d916c6SFrancisco Iglesias { }
54086d916c6SFrancisco Iglesias }
54186d916c6SFrancisco Iglesias };
54286d916c6SFrancisco Iglesias
543ebfdc494SFrancisco Iglesias static const TypeInfo cfu_fdro_info = {
544ebfdc494SFrancisco Iglesias .name = TYPE_XLNX_VERSAL_CFU_FDRO,
545ebfdc494SFrancisco Iglesias .parent = TYPE_SYS_BUS_DEVICE,
546ebfdc494SFrancisco Iglesias .instance_size = sizeof(XlnxVersalCFUFDRO),
547ebfdc494SFrancisco Iglesias .class_init = cfu_fdro_class_init,
548ebfdc494SFrancisco Iglesias .instance_init = cfu_fdro_init,
549d30d590bSPeter Maydell .instance_finalize = cfu_fdro_finalize,
550ebfdc494SFrancisco Iglesias .interfaces = (InterfaceInfo[]) {
551ebfdc494SFrancisco Iglesias { TYPE_XLNX_CFI_IF },
552ebfdc494SFrancisco Iglesias { }
553ebfdc494SFrancisco Iglesias }
554ebfdc494SFrancisco Iglesias };
555ebfdc494SFrancisco Iglesias
556975dd496SFrancisco Iglesias static const TypeInfo cfu_sfr_info = {
557975dd496SFrancisco Iglesias .name = TYPE_XLNX_VERSAL_CFU_SFR,
558975dd496SFrancisco Iglesias .parent = TYPE_SYS_BUS_DEVICE,
559975dd496SFrancisco Iglesias .instance_size = sizeof(XlnxVersalCFUSFR),
560975dd496SFrancisco Iglesias .class_init = cfu_sfr_class_init,
561975dd496SFrancisco Iglesias .instance_init = cfu_sfr_init,
562975dd496SFrancisco Iglesias };
563975dd496SFrancisco Iglesias
cfu_apb_register_types(void)56486d916c6SFrancisco Iglesias static void cfu_apb_register_types(void)
56586d916c6SFrancisco Iglesias {
56686d916c6SFrancisco Iglesias type_register_static(&cfu_apb_info);
567ebfdc494SFrancisco Iglesias type_register_static(&cfu_fdro_info);
568975dd496SFrancisco Iglesias type_register_static(&cfu_sfr_info);
56986d916c6SFrancisco Iglesias }
57086d916c6SFrancisco Iglesias
57186d916c6SFrancisco Iglesias type_init(cfu_apb_register_types)
572