Hello,
I am currently trying to enable FPGA peripheral interrupt requests for DMA-330 controller inside Cyclone V HPS accessing On-Chip RAM through the h2f AXI Master bus but with no luck.
As a base for the project I use Test_DMA_PL330_LKM - the code for building DMA programs and starting transactions works fine even from Linux userpace together with u-dma-buf kernel driver for allocating DMAble buffers.
For example, this function works fine for data transfers with data lengths equal to multiplies of 128B:
ALT_STATUS_CODE pl330_read(void *dma_transfer_src_h, void *dma_transfer_dst_h, size_t len)
{
ALT_DMA_CHANNEL_STATE_t channel_state;
ALT_DMA_CHANNEL_FAULT_t fault;
int error_count = 0;
// If the size is zero, and no event is requested, just return success.//
if ((len == 0))
{
return ALT_E_SUCCESS;
}
// For simplicity, we want len as a multiple of 128 B
if ((len % 128) != 0) {
printf("Error: Transfer size must be a multiple of 128 B!\r\n");
return ALT_E_ERROR;
}
ALT_DMA_PROGRAM_t* program = (ALT_DMA_PROGRAM_t *)DMA_PROG_RD_V;
if (alt_dma_program_init(program) != ALT_E_SUCCESS)
return prog_err("Error at alt_dma_program_init - clearing program..\r\n");
// Set source DMA transfer address
if (alt_dma_program_DMAMOV(program, ALT_DMA_PROGRAM_REG_SAR, (uintptr_t)dma_transfer_src_h) != ALT_E_SUCCESS)
return prog_err("Error at alt_dma_program_DMAMOV to SAR - clearing program..\r\n");
// Set destination DMA transfer address
if (alt_dma_program_DMAMOV(program, ALT_DMA_PROGRAM_REG_DAR, (uintptr_t)dma_transfer_dst_h) != ALT_E_SUCCESS)
return prog_err("Error at alt_dma_program_DMAMOV to DAR - clearing program..\r\n");
// Setup Config register for burst length of 16 transactions, each transaction is 64-bit (8B) => 128 B in total (largest possible config)
uint32_t CCR_CFG = ALT_DMA_CCR_OPT_SB16 | ALT_DMA_CCR_OPT_SS64 | ALT_DMA_CCR_OPT_SA_DEFAULT | ALT_DMA_CCR_OPT_SP_DEFAULT | ALT_DMA_CCR_OPT_SC(7) | ALT_DMA_CCR_OPT_DB16 | ALT_DMA_CCR_OPT_DS64 | ALT_DMA_CCR_OPT_DA_DEFAULT | ALT_DMA_CCR_OPT_DP_DEFAULT | ALT_DMA_CCR_OPT_DC(7) | ALT_DMA_CCR_OPT_ES_DEFAULT;
if (alt_dma_program_DMAMOV(program, ALT_DMA_PROGRAM_REG_CCR, CCR_CFG) != ALT_E_SUCCESS)
return prog_err("Error at alt_dma_program_DMAMOV to CCR - clearing program..\r\n");
// Add loop for bursts
uint32_t loopcount = len / 128;
if (loopcount > 1) {
if (alt_dma_program_DMALP(program, loopcount) != ALT_E_SUCCESS)
return prog_err("Error at alt_dma_program_DMALP - clearing program..\r\n");
}
// Add Load instruction
if (alt_dma_program_DMALD(program, ALT_DMA_PROGRAM_INST_MOD_NONE) != ALT_E_SUCCESS)
return prog_err("Error at alt_dma_program_DMALD - clearing program..\r\n");
// Add Store instruction
if (alt_dma_program_DMAST(program, ALT_DMA_PROGRAM_INST_MOD_NONE) != ALT_E_SUCCESS)
return prog_err("Error at alt_dma_program_DMAST - clearing program..\r\n");
// Add Loop End instruction
if (loopcount > 1) {
if (alt_dma_program_DMALPEND(program, ALT_DMA_PROGRAM_INST_MOD_NONE) != ALT_E_SUCCESS)
return prog_err("Error at alt_dma_program_DMALPEND - clearing program..\r\n");
}
// Now that everything is done, end the program.
if (alt_dma_program_DMAEND(program) != ALT_E_SUCCESS)
return prog_err("Error at alt_dma_program_DMAEND - clearing program..\r\n");
// Execute the program on the given channel.
if (alt_dma_channel_exec(Dma_Channel, (ALT_DMA_PROGRAM_t *)DMA_PROG_RD_H) != ALT_E_SUCCESS)
return prog_err("Error at alt_dma_channel_exec - clearing program..\r\n");
return ALT_E_SUCCESS;
}
But I am not sure how to add the DMAFLUSHP
, DMAWFP
and the other instructions to make it work with the peripheral requests from the FPGA. When I tried to add DMAFLUSHP
and DMAWFP
with ALT_DMA_PERIPH_FPGA_0
before the loop, changed ALT_DMA_PROGRAM_INST_MOD_NONE
to ALT_DMA_PROGRAM_INST_MOD_BURST
and modified the last store instruction in the loop to DMASTP
with ALT_DMA_PERIPH_FPGA_0
, the DMA channel state is stuck at ALT_DMA_CHANNEL_STATE_WFP
when I toggle the f2h_dma_req0_burst signal inside the FPGA.
In other words, when the DMA program looks like this, it remains stuck waiting for the peripheral signal:
DMAMOV SAR, <source physical 32b addr>
DMAMOV DAR, <destination physical 32b addr>
DMAMOV CCR, <config 16 trans., 64b each, RO cache, defaults>
DMAFLUSHP P0
DMAWFP P0, burst
DMALP <num_loops_of_128B_trans - 1>
DMALDB
DMASTB
DMALPENDB
DMALDB
DMASTPB P0
DMAEND
(In my understanding the P0 peripheral is the ALT_DMA_PERIPH_FPGA_0, ie. f2h_dma_req0 signal in the fabric.)
I am also clearing all 8 bits in the RSTMGR-PER2MODRST register during boot to enable FPGA request interfaces.
Is there any other register I should modify to make it work? How should the DMA program look like for memory-to-memory operation with FPGA requests?
Thanks for any help.