2 * QEMU model of the Configuration Frame Control module
4 * Copyright (C) 2023, Advanced Micro Devices, Inc.
6 * Written by Francisco Iglesias <francisco.iglesias@amd.com>
8 * SPDX-License-Identifier: GPL-2.0-or-later
11 #include "qemu/osdep.h"
12 #include "hw/sysbus.h"
13 #include "hw/register.h"
14 #include "hw/registerfields.h"
15 #include "qemu/bitops.h"
17 #include "qemu/units.h"
18 #include "qapi/error.h"
19 #include "hw/qdev-properties.h"
20 #include "migration/vmstate.h"
22 #include "hw/misc/xlnx-versal-cframe-reg.h"
24 #ifndef XLNX_VERSAL_CFRAME_REG_ERR_DEBUG
25 #define XLNX_VERSAL_CFRAME_REG_ERR_DEBUG 0
28 #define KEYHOLE_STREAM_4K (4 * KiB)
29 #define N_WORDS_128BIT 4
31 #define MAX_BLOCKTYPE 6
32 #define MAX_BLOCKTYPE_FRAMES 0xFFFFF
37 CFRAME_CMD_ROWOFF
= 3,
39 CFRAME_CMD_DLPARK
= 5,
42 static gint
int_cmp(gconstpointer a
, gconstpointer b
, gpointer user_data
)
44 guint ua
= GPOINTER_TO_UINT(a
);
45 guint ub
= GPOINTER_TO_UINT(b
);
46 return (ua
> ub
) - (ua
< ub
);
49 static void cfrm_imr_update_irq(XlnxVersalCFrameReg
*s
)
51 bool pending
= s
->regs
[R_CFRM_ISR0
] & ~s
->regs
[R_CFRM_IMR0
];
52 qemu_set_irq(s
->irq_cfrm_imr
, pending
);
55 static void cfrm_isr_postw(RegisterInfo
*reg
, uint64_t val64
)
57 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(reg
->opaque
);
58 cfrm_imr_update_irq(s
);
61 static uint64_t cfrm_ier_prew(RegisterInfo
*reg
, uint64_t val64
)
63 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(reg
->opaque
);
65 s
->regs
[R_CFRM_IMR0
] &= ~s
->regs
[R_CFRM_IER0
];
66 s
->regs
[R_CFRM_IER0
] = 0;
67 cfrm_imr_update_irq(s
);
71 static uint64_t cfrm_idr_prew(RegisterInfo
*reg
, uint64_t val64
)
73 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(reg
->opaque
);
75 s
->regs
[R_CFRM_IMR0
] |= s
->regs
[R_CFRM_IDR0
];
76 s
->regs
[R_CFRM_IDR0
] = 0;
77 cfrm_imr_update_irq(s
);
81 static uint64_t cfrm_itr_prew(RegisterInfo
*reg
, uint64_t val64
)
83 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(reg
->opaque
);
85 s
->regs
[R_CFRM_ISR0
] |= s
->regs
[R_CFRM_ITR0
];
86 s
->regs
[R_CFRM_ITR0
] = 0;
87 cfrm_imr_update_irq(s
);
91 static void cframe_incr_far(XlnxVersalCFrameReg
*s
)
93 uint32_t faddr
= ARRAY_FIELD_EX32(s
->regs
, FAR0
, FRAME_ADDR
);
94 uint32_t blktype
= ARRAY_FIELD_EX32(s
->regs
, FAR0
, BLOCKTYPE
);
96 assert(blktype
<= MAX_BLOCKTYPE
);
99 if (faddr
> s
->cfg
.blktype_num_frames
[blktype
]) {
100 /* Restart from 0 and increment block type */
104 assert(blktype
<= MAX_BLOCKTYPE
);
106 ARRAY_FIELD_DP32(s
->regs
, FAR0
, BLOCKTYPE
, blktype
);
109 ARRAY_FIELD_DP32(s
->regs
, FAR0
, FRAME_ADDR
, faddr
);
112 static void cfrm_fdri_post_write(RegisterInfo
*reg
, uint64_t val
)
114 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(reg
->opaque
);
116 if (s
->row_configured
&& s
->rowon
&& s
->wcfg
) {
118 if (fifo32_num_free(&s
->new_f_data
) >= N_WORDS_128BIT
) {
119 fifo32_push(&s
->new_f_data
, s
->regs
[R_FDRI0
]);
120 fifo32_push(&s
->new_f_data
, s
->regs
[R_FDRI1
]);
121 fifo32_push(&s
->new_f_data
, s
->regs
[R_FDRI2
]);
122 fifo32_push(&s
->new_f_data
, s
->regs
[R_FDRI3
]);
125 if (fifo32_is_full(&s
->new_f_data
)) {
126 uint32_t addr
= extract32(s
->regs
[R_FAR0
], 0, 23);
127 XlnxCFrame
*f
= g_new(XlnxCFrame
, 1);
129 for (int i
= 0; i
< FRAME_NUM_WORDS
; i
++) {
130 f
->data
[i
] = fifo32_pop(&s
->new_f_data
);
133 g_tree_replace(s
->cframes
, GUINT_TO_POINTER(addr
), f
);
137 fifo32_reset(&s
->new_f_data
);
142 static void cfrm_readout_frames(XlnxVersalCFrameReg
*s
, uint32_t start_addr
,
146 * NB: when our minimum glib version is at least 2.68 we can improve the
147 * performance of the cframe traversal by using g_tree_lookup_node and
148 * g_tree_node_next (instead of calling g_tree_lookup for finding each
151 for (uint32_t addr
= start_addr
; addr
< end_addr
; addr
++) {
152 XlnxCFrame
*f
= g_tree_lookup(s
->cframes
, GUINT_TO_POINTER(addr
));
154 /* Transmit the data if a frame was found */
156 for (int i
= 0; i
< FRAME_NUM_WORDS
; i
+= 4) {
157 XlnxCfiPacket pkt
= {};
159 pkt
.data
[0] = f
->data
[i
];
160 pkt
.data
[1] = f
->data
[i
+ 1];
161 pkt
.data
[2] = f
->data
[i
+ 2];
162 pkt
.data
[3] = f
->data
[i
+ 3];
164 if (s
->cfg
.cfu_fdro
) {
165 xlnx_cfi_transfer_packet(s
->cfg
.cfu_fdro
, &pkt
);
172 static void cfrm_frcnt_post_write(RegisterInfo
*reg
, uint64_t val
)
174 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(reg
->opaque
);
176 if (s
->row_configured
&& s
->rowon
&& s
->rcfg
) {
177 uint32_t start_addr
= extract32(s
->regs
[R_FAR0
], 0, 23);
178 uint32_t end_addr
= start_addr
+ s
->regs
[R_FRCNT0
] / FRAME_NUM_QWORDS
;
180 cfrm_readout_frames(s
, start_addr
, end_addr
);
184 static void cfrm_cmd_post_write(RegisterInfo
*reg
, uint64_t val
)
186 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(reg
->opaque
);
188 if (s
->row_configured
) {
189 uint8_t cmd
= ARRAY_FIELD_EX32(s
->regs
, CMD0
, CMD
);
192 case CFRAME_CMD_WCFG
:
195 case CFRAME_CMD_ROWON
:
198 case CFRAME_CMD_ROWOFF
:
201 case CFRAME_CMD_RCFG
:
204 case CFRAME_CMD_DLPARK
:
214 static uint64_t cfrm_last_frame_bot_post_read(RegisterInfo
*reg
,
217 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(reg
->opaque
);
220 switch (reg
->access
->addr
) {
221 case A_LAST_FRAME_BOT0
:
222 val
= FIELD_DP32(val
, LAST_FRAME_BOT0
, BLOCKTYPE1_LAST_FRAME_LSB
,
223 s
->cfg
.blktype_num_frames
[1]);
224 val
= FIELD_DP32(val
, LAST_FRAME_BOT0
, BLOCKTYPE0_LAST_FRAME
,
225 s
->cfg
.blktype_num_frames
[0]);
227 case A_LAST_FRAME_BOT1
:
228 val
= FIELD_DP32(val
, LAST_FRAME_BOT1
, BLOCKTYPE3_LAST_FRAME_LSB
,
229 s
->cfg
.blktype_num_frames
[3]);
230 val
= FIELD_DP32(val
, LAST_FRAME_BOT1
, BLOCKTYPE2_LAST_FRAME
,
231 s
->cfg
.blktype_num_frames
[2]);
232 val
= FIELD_DP32(val
, LAST_FRAME_BOT1
, BLOCKTYPE1_LAST_FRAME_MSB
,
233 (s
->cfg
.blktype_num_frames
[1] >> 12));
235 case A_LAST_FRAME_BOT2
:
236 val
= FIELD_DP32(val
, LAST_FRAME_BOT2
, BLOCKTYPE3_LAST_FRAME_MSB
,
237 (s
->cfg
.blktype_num_frames
[3] >> 4));
239 case A_LAST_FRAME_BOT3
:
247 static uint64_t cfrm_last_frame_top_post_read(RegisterInfo
*reg
,
250 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(reg
->opaque
);
253 switch (reg
->access
->addr
) {
254 case A_LAST_FRAME_TOP0
:
255 val
= FIELD_DP32(val
, LAST_FRAME_TOP0
, BLOCKTYPE5_LAST_FRAME_LSB
,
256 s
->cfg
.blktype_num_frames
[5]);
257 val
= FIELD_DP32(val
, LAST_FRAME_TOP0
, BLOCKTYPE4_LAST_FRAME
,
258 s
->cfg
.blktype_num_frames
[4]);
260 case A_LAST_FRAME_TOP1
:
261 val
= FIELD_DP32(val
, LAST_FRAME_TOP1
, BLOCKTYPE6_LAST_FRAME
,
262 s
->cfg
.blktype_num_frames
[6]);
263 val
= FIELD_DP32(val
, LAST_FRAME_TOP1
, BLOCKTYPE5_LAST_FRAME_MSB
,
264 (s
->cfg
.blktype_num_frames
[5] >> 12));
266 case A_LAST_FRAME_TOP2
:
267 case A_LAST_FRAME_BOT3
:
275 static void cfrm_far_sfr_post_write(RegisterInfo
*reg
, uint64_t val
)
277 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(reg
->opaque
);
279 if (s
->row_configured
&& s
->rowon
&& s
->rcfg
) {
280 uint32_t start_addr
= extract32(s
->regs
[R_FAR_SFR0
], 0, 23);
282 /* Readback 1 frame */
283 cfrm_readout_frames(s
, start_addr
, start_addr
+ 1);
287 static const RegisterAccessInfo cframe_reg_regs_info
[] = {
288 { .name
= "CRC0", .addr
= A_CRC0
,
290 },{ .name
= "CRC1", .addr
= A_CRC0
,
292 },{ .name
= "CRC2", .addr
= A_CRC0
,
294 },{ .name
= "CRC3", .addr
= A_CRC0
,
296 },{ .name
= "FAR0", .addr
= A_FAR0
,
298 },{ .name
= "FAR1", .addr
= A_FAR1
,
300 },{ .name
= "FAR2", .addr
= A_FAR2
,
302 },{ .name
= "FAR3", .addr
= A_FAR3
,
304 },{ .name
= "FAR_SFR0", .addr
= A_FAR_SFR0
,
306 },{ .name
= "FAR_SFR1", .addr
= A_FAR_SFR1
,
308 },{ .name
= "FAR_SFR2", .addr
= A_FAR_SFR2
,
310 },{ .name
= "FAR_SFR3", .addr
= A_FAR_SFR3
,
312 .post_write
= cfrm_far_sfr_post_write
,
313 },{ .name
= "FDRI0", .addr
= A_FDRI0
,
314 },{ .name
= "FDRI1", .addr
= A_FDRI1
,
315 },{ .name
= "FDRI2", .addr
= A_FDRI2
,
316 },{ .name
= "FDRI3", .addr
= A_FDRI3
,
317 .post_write
= cfrm_fdri_post_write
,
318 },{ .name
= "FRCNT0", .addr
= A_FRCNT0
,
320 },{ .name
= "FRCNT1", .addr
= A_FRCNT1
,
322 },{ .name
= "FRCNT2", .addr
= A_FRCNT2
,
324 },{ .name
= "FRCNT3", .addr
= A_FRCNT3
,
326 .post_write
= cfrm_frcnt_post_write
327 },{ .name
= "CMD0", .addr
= A_CMD0
,
329 },{ .name
= "CMD1", .addr
= A_CMD1
,
331 },{ .name
= "CMD2", .addr
= A_CMD2
,
333 },{ .name
= "CMD3", .addr
= A_CMD3
,
335 .post_write
= cfrm_cmd_post_write
336 },{ .name
= "CR_MASK0", .addr
= A_CR_MASK0
,
338 },{ .name
= "CR_MASK1", .addr
= A_CR_MASK1
,
340 },{ .name
= "CR_MASK2", .addr
= A_CR_MASK2
,
342 },{ .name
= "CR_MASK3", .addr
= A_CR_MASK3
,
344 },{ .name
= "CTL0", .addr
= A_CTL0
,
346 },{ .name
= "CTL1", .addr
= A_CTL1
,
348 },{ .name
= "CTL2", .addr
= A_CTL2
,
350 },{ .name
= "CTL3", .addr
= A_CTL3
,
352 },{ .name
= "CFRM_ISR0", .addr
= A_CFRM_ISR0
,
355 },{ .name
= "CFRM_ISR1", .addr
= A_CFRM_ISR1
,
357 },{ .name
= "CFRM_ISR2", .addr
= A_CFRM_ISR2
,
359 },{ .name
= "CFRM_ISR3", .addr
= A_CFRM_ISR3
,
361 .post_write
= cfrm_isr_postw
,
362 },{ .name
= "CFRM_IMR0", .addr
= A_CFRM_IMR0
,
366 },{ .name
= "CFRM_IMR1", .addr
= A_CFRM_IMR1
,
368 },{ .name
= "CFRM_IMR2", .addr
= A_CFRM_IMR2
,
370 },{ .name
= "CFRM_IMR3", .addr
= A_CFRM_IMR3
,
372 },{ .name
= "CFRM_IER0", .addr
= A_CFRM_IER0
,
374 },{ .name
= "CFRM_IER1", .addr
= A_CFRM_IER1
,
376 },{ .name
= "CFRM_IER2", .addr
= A_CFRM_IER2
,
378 },{ .name
= "CFRM_IER3", .addr
= A_CFRM_IER3
,
380 .pre_write
= cfrm_ier_prew
,
381 },{ .name
= "CFRM_IDR0", .addr
= A_CFRM_IDR0
,
383 },{ .name
= "CFRM_IDR1", .addr
= A_CFRM_IDR1
,
385 },{ .name
= "CFRM_IDR2", .addr
= A_CFRM_IDR2
,
387 },{ .name
= "CFRM_IDR3", .addr
= A_CFRM_IDR3
,
389 .pre_write
= cfrm_idr_prew
,
390 },{ .name
= "CFRM_ITR0", .addr
= A_CFRM_ITR0
,
392 },{ .name
= "CFRM_ITR1", .addr
= A_CFRM_ITR1
,
394 },{ .name
= "CFRM_ITR2", .addr
= A_CFRM_ITR2
,
396 },{ .name
= "CFRM_ITR3", .addr
= A_CFRM_ITR3
,
398 .pre_write
= cfrm_itr_prew
,
399 },{ .name
= "SEU_SYNDRM00", .addr
= A_SEU_SYNDRM00
,
400 },{ .name
= "SEU_SYNDRM01", .addr
= A_SEU_SYNDRM01
,
401 },{ .name
= "SEU_SYNDRM02", .addr
= A_SEU_SYNDRM02
,
402 },{ .name
= "SEU_SYNDRM03", .addr
= A_SEU_SYNDRM03
,
403 },{ .name
= "SEU_SYNDRM10", .addr
= A_SEU_SYNDRM10
,
404 },{ .name
= "SEU_SYNDRM11", .addr
= A_SEU_SYNDRM11
,
405 },{ .name
= "SEU_SYNDRM12", .addr
= A_SEU_SYNDRM12
,
406 },{ .name
= "SEU_SYNDRM13", .addr
= A_SEU_SYNDRM13
,
407 },{ .name
= "SEU_SYNDRM20", .addr
= A_SEU_SYNDRM20
,
408 },{ .name
= "SEU_SYNDRM21", .addr
= A_SEU_SYNDRM21
,
409 },{ .name
= "SEU_SYNDRM22", .addr
= A_SEU_SYNDRM22
,
410 },{ .name
= "SEU_SYNDRM23", .addr
= A_SEU_SYNDRM23
,
411 },{ .name
= "SEU_SYNDRM30", .addr
= A_SEU_SYNDRM30
,
412 },{ .name
= "SEU_SYNDRM31", .addr
= A_SEU_SYNDRM31
,
413 },{ .name
= "SEU_SYNDRM32", .addr
= A_SEU_SYNDRM32
,
414 },{ .name
= "SEU_SYNDRM33", .addr
= A_SEU_SYNDRM33
,
415 },{ .name
= "SEU_VIRTUAL_SYNDRM0", .addr
= A_SEU_VIRTUAL_SYNDRM0
,
416 },{ .name
= "SEU_VIRTUAL_SYNDRM1", .addr
= A_SEU_VIRTUAL_SYNDRM1
,
417 },{ .name
= "SEU_VIRTUAL_SYNDRM2", .addr
= A_SEU_VIRTUAL_SYNDRM2
,
418 },{ .name
= "SEU_VIRTUAL_SYNDRM3", .addr
= A_SEU_VIRTUAL_SYNDRM3
,
419 },{ .name
= "SEU_CRC0", .addr
= A_SEU_CRC0
,
420 },{ .name
= "SEU_CRC1", .addr
= A_SEU_CRC1
,
421 },{ .name
= "SEU_CRC2", .addr
= A_SEU_CRC2
,
422 },{ .name
= "SEU_CRC3", .addr
= A_SEU_CRC3
,
423 },{ .name
= "CFRAME_FAR_BOT0", .addr
= A_CFRAME_FAR_BOT0
,
424 },{ .name
= "CFRAME_FAR_BOT1", .addr
= A_CFRAME_FAR_BOT1
,
425 },{ .name
= "CFRAME_FAR_BOT2", .addr
= A_CFRAME_FAR_BOT2
,
426 },{ .name
= "CFRAME_FAR_BOT3", .addr
= A_CFRAME_FAR_BOT3
,
427 },{ .name
= "CFRAME_FAR_TOP0", .addr
= A_CFRAME_FAR_TOP0
,
428 },{ .name
= "CFRAME_FAR_TOP1", .addr
= A_CFRAME_FAR_TOP1
,
429 },{ .name
= "CFRAME_FAR_TOP2", .addr
= A_CFRAME_FAR_TOP2
,
430 },{ .name
= "CFRAME_FAR_TOP3", .addr
= A_CFRAME_FAR_TOP3
,
431 },{ .name
= "LAST_FRAME_BOT0", .addr
= A_LAST_FRAME_BOT0
,
433 .post_read
= cfrm_last_frame_bot_post_read
,
434 },{ .name
= "LAST_FRAME_BOT1", .addr
= A_LAST_FRAME_BOT1
,
436 .post_read
= cfrm_last_frame_bot_post_read
,
437 },{ .name
= "LAST_FRAME_BOT2", .addr
= A_LAST_FRAME_BOT2
,
439 .post_read
= cfrm_last_frame_bot_post_read
,
440 },{ .name
= "LAST_FRAME_BOT3", .addr
= A_LAST_FRAME_BOT3
,
442 .post_read
= cfrm_last_frame_bot_post_read
,
443 },{ .name
= "LAST_FRAME_TOP0", .addr
= A_LAST_FRAME_TOP0
,
445 .post_read
= cfrm_last_frame_top_post_read
,
446 },{ .name
= "LAST_FRAME_TOP1", .addr
= A_LAST_FRAME_TOP1
,
448 .post_read
= cfrm_last_frame_top_post_read
,
449 },{ .name
= "LAST_FRAME_TOP2", .addr
= A_LAST_FRAME_TOP2
,
451 .post_read
= cfrm_last_frame_top_post_read
,
452 },{ .name
= "LAST_FRAME_TOP3", .addr
= A_LAST_FRAME_TOP3
,
454 .post_read
= cfrm_last_frame_top_post_read
,
458 static void cframe_reg_cfi_transfer_packet(XlnxCfiIf
*cfi_if
,
461 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(cfi_if
);
462 uint64_t we
= MAKE_64BIT_MASK(0, 4 * 8);
464 if (!s
->row_configured
) {
468 switch (pkt
->reg_addr
) {
470 s
->regs
[R_FAR0
] = pkt
->data
[0];
473 s
->regs
[R_FAR_SFR0
] = pkt
->data
[0];
474 register_write(&s
->regs_info
[R_FAR_SFR3
], 0,
475 we
, object_get_typename(OBJECT(s
)),
476 XLNX_VERSAL_CFRAME_REG_ERR_DEBUG
);
479 s
->regs
[R_FDRI0
] = pkt
->data
[0];
480 s
->regs
[R_FDRI1
] = pkt
->data
[1];
481 s
->regs
[R_FDRI2
] = pkt
->data
[2];
482 register_write(&s
->regs_info
[R_FDRI3
], pkt
->data
[3],
483 we
, object_get_typename(OBJECT(s
)),
484 XLNX_VERSAL_CFRAME_REG_ERR_DEBUG
);
487 ARRAY_FIELD_DP32(s
->regs
, CMD0
, CMD
, pkt
->data
[0]);
489 register_write(&s
->regs_info
[R_CMD3
], 0,
490 we
, object_get_typename(OBJECT(s
)),
491 XLNX_VERSAL_CFRAME_REG_ERR_DEBUG
);
498 static uint64_t cframe_reg_fdri_read(void *opaque
, hwaddr addr
, unsigned size
)
500 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Unsupported read from addr=%"
501 HWADDR_PRIx
"\n", __func__
, addr
);
505 static void cframe_reg_fdri_write(void *opaque
, hwaddr addr
, uint64_t value
,
508 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(opaque
);
509 uint32_t wfifo
[WFIFO_SZ
];
511 if (update_wfifo(addr
, value
, s
->wfifo
, wfifo
)) {
512 uint64_t we
= MAKE_64BIT_MASK(0, 4 * 8);
514 s
->regs
[R_FDRI0
] = wfifo
[0];
515 s
->regs
[R_FDRI1
] = wfifo
[1];
516 s
->regs
[R_FDRI2
] = wfifo
[2];
517 register_write(&s
->regs_info
[R_FDRI3
], wfifo
[3],
518 we
, object_get_typename(OBJECT(s
)),
519 XLNX_VERSAL_CFRAME_REG_ERR_DEBUG
);
523 static void cframe_reg_reset_enter(Object
*obj
, ResetType type
)
525 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(obj
);
528 for (i
= 0; i
< ARRAY_SIZE(s
->regs_info
); ++i
) {
529 register_reset(&s
->regs_info
[i
]);
531 memset(s
->wfifo
, 0, WFIFO_SZ
* sizeof(uint32_t));
532 fifo32_reset(&s
->new_f_data
);
534 if (g_tree_nnodes(s
->cframes
)) {
536 * Take a reference so when g_tree_destroy() unrefs it we keep the
537 * GTree and only destroy its contents. NB: when our minimum
538 * glib version is at least 2.70 we could use g_tree_remove_all().
540 g_tree_ref(s
->cframes
);
541 g_tree_destroy(s
->cframes
);
545 static void cframe_reg_reset_hold(Object
*obj
)
547 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(obj
);
549 cfrm_imr_update_irq(s
);
552 static const MemoryRegionOps cframe_reg_ops
= {
553 .read
= register_read_memory
,
554 .write
= register_write_memory
,
555 .endianness
= DEVICE_LITTLE_ENDIAN
,
557 .min_access_size
= 4,
558 .max_access_size
= 4,
562 static const MemoryRegionOps cframe_reg_fdri_ops
= {
563 .read
= cframe_reg_fdri_read
,
564 .write
= cframe_reg_fdri_write
,
565 .endianness
= DEVICE_LITTLE_ENDIAN
,
567 .min_access_size
= 4,
568 .max_access_size
= 4,
572 static uint64_t cframes_bcast_reg_read(void *opaque
, hwaddr addr
, unsigned size
)
574 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Unsupported read from addr=%"
575 HWADDR_PRIx
"\n", __func__
, addr
);
579 static void cframes_bcast_write(XlnxVersalCFrameBcastReg
*s
, uint8_t reg_addr
,
582 XlnxCfiPacket pkt
= {
583 .reg_addr
= reg_addr
,
590 for (int i
= 0; i
< ARRAY_SIZE(s
->cfg
.cframe
); i
++) {
591 if (s
->cfg
.cframe
[i
]) {
592 xlnx_cfi_transfer_packet(s
->cfg
.cframe
[i
], &pkt
);
597 static void cframes_bcast_reg_write(void *opaque
, hwaddr addr
, uint64_t value
,
600 XlnxVersalCFrameBcastReg
*s
= XLNX_VERSAL_CFRAME_BCAST_REG(opaque
);
601 uint32_t wfifo
[WFIFO_SZ
];
603 if (update_wfifo(addr
, value
, s
->wfifo
, wfifo
)) {
604 uint8_t reg_addr
= extract32(addr
, 4, 6);
606 cframes_bcast_write(s
, reg_addr
, wfifo
);
610 static uint64_t cframes_bcast_fdri_read(void *opaque
, hwaddr addr
,
613 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Unsupported read from addr=%"
614 HWADDR_PRIx
"\n", __func__
, addr
);
618 static void cframes_bcast_fdri_write(void *opaque
, hwaddr addr
, uint64_t value
,
621 XlnxVersalCFrameBcastReg
*s
= XLNX_VERSAL_CFRAME_BCAST_REG(opaque
);
622 uint32_t wfifo
[WFIFO_SZ
];
624 if (update_wfifo(addr
, value
, s
->wfifo
, wfifo
)) {
625 cframes_bcast_write(s
, CFRAME_FDRI
, wfifo
);
629 static const MemoryRegionOps cframes_bcast_reg_reg_ops
= {
630 .read
= cframes_bcast_reg_read
,
631 .write
= cframes_bcast_reg_write
,
632 .endianness
= DEVICE_LITTLE_ENDIAN
,
634 .min_access_size
= 4,
635 .max_access_size
= 4,
639 static const MemoryRegionOps cframes_bcast_reg_fdri_ops
= {
640 .read
= cframes_bcast_fdri_read
,
641 .write
= cframes_bcast_fdri_write
,
642 .endianness
= DEVICE_LITTLE_ENDIAN
,
644 .min_access_size
= 4,
645 .max_access_size
= 4,
649 static void cframe_reg_realize(DeviceState
*dev
, Error
**errp
)
651 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(dev
);
653 for (int i
= 0; i
< ARRAY_SIZE(s
->cfg
.blktype_num_frames
); i
++) {
654 if (s
->cfg
.blktype_num_frames
[i
] > MAX_BLOCKTYPE_FRAMES
) {
656 "blktype-frames%d > 0xFFFFF (max frame per block)",
660 if (s
->cfg
.blktype_num_frames
[i
]) {
661 s
->row_configured
= true;
666 static void cframe_reg_init(Object
*obj
)
668 XlnxVersalCFrameReg
*s
= XLNX_VERSAL_CFRAME_REG(obj
);
669 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
670 RegisterInfoArray
*reg_array
;
672 memory_region_init(&s
->iomem
, obj
, TYPE_XLNX_VERSAL_CFRAME_REG
,
673 CFRAME_REG_R_MAX
* 4);
675 register_init_block32(DEVICE(obj
), cframe_reg_regs_info
,
676 ARRAY_SIZE(cframe_reg_regs_info
),
677 s
->regs_info
, s
->regs
,
679 XLNX_VERSAL_CFRAME_REG_ERR_DEBUG
,
680 CFRAME_REG_R_MAX
* 4);
681 memory_region_add_subregion(&s
->iomem
,
684 sysbus_init_mmio(sbd
, &s
->iomem
);
685 memory_region_init_io(&s
->iomem_fdri
, obj
, &cframe_reg_fdri_ops
, s
,
686 TYPE_XLNX_VERSAL_CFRAME_REG
"-fdri",
688 sysbus_init_mmio(sbd
, &s
->iomem_fdri
);
689 sysbus_init_irq(sbd
, &s
->irq_cfrm_imr
);
691 s
->cframes
= g_tree_new_full((GCompareDataFunc
)int_cmp
, NULL
,
692 NULL
, (GDestroyNotify
)g_free
);
693 fifo32_create(&s
->new_f_data
, FRAME_NUM_WORDS
);
696 static const VMStateDescription vmstate_cframe
= {
699 .minimum_version_id
= 1,
700 .fields
= (VMStateField
[]) {
701 VMSTATE_UINT32_ARRAY(data
, XlnxCFrame
, FRAME_NUM_WORDS
),
702 VMSTATE_END_OF_LIST()
706 static const VMStateDescription vmstate_cframe_reg
= {
707 .name
= TYPE_XLNX_VERSAL_CFRAME_REG
,
709 .minimum_version_id
= 1,
710 .fields
= (VMStateField
[]) {
711 VMSTATE_UINT32_ARRAY(wfifo
, XlnxVersalCFrameReg
, 4),
712 VMSTATE_UINT32_ARRAY(regs
, XlnxVersalCFrameReg
, CFRAME_REG_R_MAX
),
713 VMSTATE_BOOL(rowon
, XlnxVersalCFrameReg
),
714 VMSTATE_BOOL(wcfg
, XlnxVersalCFrameReg
),
715 VMSTATE_BOOL(rcfg
, XlnxVersalCFrameReg
),
716 VMSTATE_GTREE_DIRECT_KEY_V(cframes
, XlnxVersalCFrameReg
, 1,
717 &vmstate_cframe
, XlnxCFrame
),
718 VMSTATE_FIFO32(new_f_data
, XlnxVersalCFrameReg
),
719 VMSTATE_END_OF_LIST(),
723 static Property cframe_regs_props
[] = {
724 DEFINE_PROP_LINK("cfu-fdro", XlnxVersalCFrameReg
, cfg
.cfu_fdro
,
725 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
726 DEFINE_PROP_UINT32("blktype0-frames", XlnxVersalCFrameReg
,
727 cfg
.blktype_num_frames
[0], 0),
728 DEFINE_PROP_UINT32("blktype1-frames", XlnxVersalCFrameReg
,
729 cfg
.blktype_num_frames
[1], 0),
730 DEFINE_PROP_UINT32("blktype2-frames", XlnxVersalCFrameReg
,
731 cfg
.blktype_num_frames
[2], 0),
732 DEFINE_PROP_UINT32("blktype3-frames", XlnxVersalCFrameReg
,
733 cfg
.blktype_num_frames
[3], 0),
734 DEFINE_PROP_UINT32("blktype4-frames", XlnxVersalCFrameReg
,
735 cfg
.blktype_num_frames
[4], 0),
736 DEFINE_PROP_UINT32("blktype5-frames", XlnxVersalCFrameReg
,
737 cfg
.blktype_num_frames
[5], 0),
738 DEFINE_PROP_UINT32("blktype6-frames", XlnxVersalCFrameReg
,
739 cfg
.blktype_num_frames
[6], 0),
740 DEFINE_PROP_END_OF_LIST(),
743 static void cframe_bcast_reg_init(Object
*obj
)
745 XlnxVersalCFrameBcastReg
*s
= XLNX_VERSAL_CFRAME_BCAST_REG(obj
);
746 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
748 memory_region_init_io(&s
->iomem_reg
, obj
, &cframes_bcast_reg_reg_ops
, s
,
749 TYPE_XLNX_VERSAL_CFRAME_BCAST_REG
, KEYHOLE_STREAM_4K
);
750 memory_region_init_io(&s
->iomem_fdri
, obj
, &cframes_bcast_reg_fdri_ops
, s
,
751 TYPE_XLNX_VERSAL_CFRAME_BCAST_REG
"-fdri",
753 sysbus_init_mmio(sbd
, &s
->iomem_reg
);
754 sysbus_init_mmio(sbd
, &s
->iomem_fdri
);
757 static void cframe_bcast_reg_reset_enter(Object
*obj
, ResetType type
)
759 XlnxVersalCFrameBcastReg
*s
= XLNX_VERSAL_CFRAME_BCAST_REG(obj
);
761 memset(s
->wfifo
, 0, WFIFO_SZ
* sizeof(uint32_t));
764 static const VMStateDescription vmstate_cframe_bcast_reg
= {
765 .name
= TYPE_XLNX_VERSAL_CFRAME_BCAST_REG
,
767 .minimum_version_id
= 1,
768 .fields
= (VMStateField
[]) {
769 VMSTATE_UINT32_ARRAY(wfifo
, XlnxVersalCFrameBcastReg
, 4),
770 VMSTATE_END_OF_LIST(),
774 static Property cframe_bcast_regs_props
[] = {
775 DEFINE_PROP_LINK("cframe0", XlnxVersalCFrameBcastReg
, cfg
.cframe
[0],
776 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
777 DEFINE_PROP_LINK("cframe1", XlnxVersalCFrameBcastReg
, cfg
.cframe
[1],
778 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
779 DEFINE_PROP_LINK("cframe2", XlnxVersalCFrameBcastReg
, cfg
.cframe
[2],
780 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
781 DEFINE_PROP_LINK("cframe3", XlnxVersalCFrameBcastReg
, cfg
.cframe
[3],
782 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
783 DEFINE_PROP_LINK("cframe4", XlnxVersalCFrameBcastReg
, cfg
.cframe
[4],
784 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
785 DEFINE_PROP_LINK("cframe5", XlnxVersalCFrameBcastReg
, cfg
.cframe
[5],
786 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
787 DEFINE_PROP_LINK("cframe6", XlnxVersalCFrameBcastReg
, cfg
.cframe
[6],
788 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
789 DEFINE_PROP_LINK("cframe7", XlnxVersalCFrameBcastReg
, cfg
.cframe
[7],
790 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
791 DEFINE_PROP_LINK("cframe8", XlnxVersalCFrameBcastReg
, cfg
.cframe
[8],
792 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
793 DEFINE_PROP_LINK("cframe9", XlnxVersalCFrameBcastReg
, cfg
.cframe
[9],
794 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
795 DEFINE_PROP_LINK("cframe10", XlnxVersalCFrameBcastReg
, cfg
.cframe
[10],
796 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
797 DEFINE_PROP_LINK("cframe11", XlnxVersalCFrameBcastReg
, cfg
.cframe
[11],
798 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
799 DEFINE_PROP_LINK("cframe12", XlnxVersalCFrameBcastReg
, cfg
.cframe
[12],
800 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
801 DEFINE_PROP_LINK("cframe13", XlnxVersalCFrameBcastReg
, cfg
.cframe
[13],
802 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
803 DEFINE_PROP_LINK("cframe14", XlnxVersalCFrameBcastReg
, cfg
.cframe
[14],
804 TYPE_XLNX_CFI_IF
, XlnxCfiIf
*),
805 DEFINE_PROP_END_OF_LIST(),
808 static void cframe_reg_class_init(ObjectClass
*klass
, void *data
)
810 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
811 DeviceClass
*dc
= DEVICE_CLASS(klass
);
812 XlnxCfiIfClass
*xcic
= XLNX_CFI_IF_CLASS(klass
);
814 dc
->vmsd
= &vmstate_cframe_reg
;
815 dc
->realize
= cframe_reg_realize
;
816 rc
->phases
.enter
= cframe_reg_reset_enter
;
817 rc
->phases
.hold
= cframe_reg_reset_hold
;
818 device_class_set_props(dc
, cframe_regs_props
);
819 xcic
->cfi_transfer_packet
= cframe_reg_cfi_transfer_packet
;
822 static void cframe_bcast_reg_class_init(ObjectClass
*klass
, void *data
)
824 DeviceClass
*dc
= DEVICE_CLASS(klass
);
825 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
827 dc
->vmsd
= &vmstate_cframe_bcast_reg
;
828 device_class_set_props(dc
, cframe_bcast_regs_props
);
829 rc
->phases
.enter
= cframe_bcast_reg_reset_enter
;
832 static const TypeInfo cframe_reg_info
= {
833 .name
= TYPE_XLNX_VERSAL_CFRAME_REG
,
834 .parent
= TYPE_SYS_BUS_DEVICE
,
835 .instance_size
= sizeof(XlnxVersalCFrameReg
),
836 .class_init
= cframe_reg_class_init
,
837 .instance_init
= cframe_reg_init
,
838 .interfaces
= (InterfaceInfo
[]) {
839 { TYPE_XLNX_CFI_IF
},
844 static const TypeInfo cframe_bcast_reg_info
= {
845 .name
= TYPE_XLNX_VERSAL_CFRAME_BCAST_REG
,
846 .parent
= TYPE_SYS_BUS_DEVICE
,
847 .instance_size
= sizeof(XlnxVersalCFrameBcastReg
),
848 .class_init
= cframe_bcast_reg_class_init
,
849 .instance_init
= cframe_bcast_reg_init
,
852 static void cframe_reg_register_types(void)
854 type_register_static(&cframe_reg_info
);
855 type_register_static(&cframe_bcast_reg_info
);
858 type_init(cframe_reg_register_types
)