Skip to content

Commit

Permalink
fpga: zynq: Use helper functions for zynq dma
Browse files Browse the repository at this point in the history
Use zynq_dma_xfer_init, zynq_align_dma_buffer,
zynq_dma_transfer helper function performing dma
transfers so that the code can be reused easily for
different cases of dma transfer.

Signed-off-by: Siva Durga Prasad Paladugu <[email protected]>
Signed-off-by: Michal Simek <[email protected]>
  • Loading branch information
Siva Durga Prasad Paladugu authored and Michal Simek committed Mar 17, 2014
1 parent 3c8f5c7 commit 08dd9be
Showing 1 changed file with 115 additions and 87 deletions.
202 changes: 115 additions & 87 deletions drivers/fpga/zynqpl.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,71 +153,52 @@ static void *check_data(u8 *buf, size_t bsize, u32 *swap)
return 0;
}


int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize)
static int zynq_dma_transfer(u32 srcbuf, u32 srclen, u32 dstbuf, u32 dstlen)
{
unsigned long ts; /* Timestamp */
u32 partialbit = 0;
u32 i, control, isr_status, status, swap, diff;
u32 *buf_start;

/* Detect if we are going working with partial or full bitstream */
if (bsize != desc->size) {
printf("%s: Working with partial bitstream\n", __func__);
partialbit = 1;
}
unsigned long ts;
u32 isr_status;

buf_start = check_data((u8 *)buf, bsize, &swap);
if (!buf_start)
return FPGA_FAIL;

/* Check if data is postpone from start */
diff = (u32)buf_start - (u32)buf;
if (diff) {
printf("%s: Bitstream is not validated yet (diff %x)\n",
__func__, diff);
return FPGA_FAIL;
}
/* Set up the transfer */
writel((u32)srcbuf, &devcfg_base->dma_src_addr);
writel(dstbuf, &devcfg_base->dma_dst_addr);
writel(srclen, &devcfg_base->dma_src_len);
writel(dstlen, &devcfg_base->dma_dst_len);

if ((u32)buf < SZ_1M) {
printf("%s: Bitstream has to be placed up to 1MB (%x)\n",
__func__, (u32)buf);
return FPGA_FAIL;
}
isr_status = readl(&devcfg_base->int_sts);

if ((u32)buf != ALIGN((u32)buf, ARCH_DMA_MINALIGN)) {
u32 *new_buf = (u32 *)ALIGN((u32)buf, ARCH_DMA_MINALIGN);
/* Polling the PCAP_INIT status for Set */
ts = get_timer(0);
while (!(isr_status & DEVCFG_ISR_DMA_DONE)) {
if (isr_status & DEVCFG_ISR_ERROR_FLAGS_MASK) {
debug("%s: Error: isr = 0x%08X\n", __func__,
isr_status);
debug("%s: Write count = 0x%08X\n", __func__,
readl(&devcfg_base->write_count));
debug("%s: Read count = 0x%08X\n", __func__,
readl(&devcfg_base->read_count));

/*
* This might be dangerous but permits to flash if
* ARCH_DMA_MINALIGN is greater than header size
*/
if (new_buf > buf_start) {
debug("%s: Aligned buffer is after buffer start\n",
__func__);
new_buf -= ARCH_DMA_MINALIGN;
return FPGA_FAIL;
}
if (get_timer(ts) > CONFIG_SYS_FPGA_PROG_TIME) {
printf("%s: Timeout wait for DMA to complete\n",
__func__);
return FPGA_FAIL;
}
isr_status = readl(&devcfg_base->int_sts);
}

printf("%s: Align buffer at %x to %x(swap %d)\n", __func__,
(u32)buf_start, (u32)new_buf, swap);

for (i = 0; i < (bsize/4); i++)
new_buf[i] = load_word(&buf_start[i], swap);

swap = SWAP_DONE;
buf = new_buf;
} else if (swap != SWAP_DONE) {
/* For bitstream which are aligned */
u32 *new_buf = (u32 *)buf;
debug("%s: DMA transfer is done\n", __func__);

printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__,
swap);
/* Clear out the DMA status */
writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts);

for (i = 0; i < (bsize/4); i++)
new_buf[i] = load_word(&buf_start[i], swap);
return FPGA_SUCCESS;
}

swap = SWAP_DONE;
}
static int zynq_dma_xfer_init(u32 partialbit)
{
u32 status, control, isr_status;
unsigned long ts;

/* Clear loopback bit */
clrbits_le32(&devcfg_base->mctrl, DEVCFG_MCTRL_PCAP_LPBK);
Expand Down Expand Up @@ -299,44 +280,94 @@ int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize)
writel(DEVCFG_STATUS_DMA_DONE_CNT_MASK, &devcfg_base->status);
}

return FPGA_SUCCESS;
}

static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap)
{
u32 *new_buf;
u32 i;

if ((u32)buf != ALIGN((u32)buf, ARCH_DMA_MINALIGN)) {
new_buf = (u32 *)ALIGN((u32)buf, ARCH_DMA_MINALIGN);

/*
* This might be dangerous but permits to flash if
* ARCH_DMA_MINALIGN is greater than header size
*/
if (new_buf > buf) {
debug("%s: Aligned buffer is after buffer start\n",
__func__);
new_buf -= ARCH_DMA_MINALIGN;
}
printf("%s: Align buffer at %x to %x(swap %d)\n", __func__,
(u32)buf, (u32)new_buf, swap);

for (i = 0; i < (len/4); i++)
new_buf[i] = load_word(&buf[i], swap);

buf = new_buf;
} else if (swap != SWAP_DONE) {
/* For bitstream which are aligned */
u32 *new_buf = (u32 *)buf;

printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__,
swap);

for (i = 0; i < (len/4); i++)
new_buf[i] = load_word(&buf[i], swap);
}

return buf;
}

int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize)
{
unsigned long ts; /* Timestamp */
u32 partialbit = 0;
u32 isr_status, swap, diff;
u32 *buf_start;

/* Detect if we are going working with partial or full bitstream */
if (bsize != desc->size) {
printf("%s: Working with partial bitstream\n", __func__);
partialbit = 1;
}

buf_start = check_data((u8 *)buf, bsize, &swap);
if (!buf_start)
return FPGA_FAIL;

/* Check if data is postpone from start */
diff = (u32)buf_start - (u32)buf;
if (diff) {
printf("%s: Bitstream is not validated yet (diff %x)\n",
__func__, diff);
return FPGA_FAIL;
}

if ((u32)buf < SZ_1M) {
printf("%s: Bitstream has to be placed up to 1MB (%x)\n",
__func__, (u32)buf);
return FPGA_FAIL;
}

if (zynq_dma_xfer_init(partialbit))
return FPGA_FAIL;

buf = zynq_align_dma_buffer((u32 *)buf, bsize, swap);

debug("%s: Source = 0x%08X\n", __func__, (u32)buf);
debug("%s: Size = %zu\n", __func__, bsize);

/* flush(clean & invalidate) d-cache range buf */
flush_dcache_range((u32)buf, (u32)buf +
roundup(bsize, ARCH_DMA_MINALIGN));

/* Set up the transfer */
writel((u32)buf | 1, &devcfg_base->dma_src_addr);
writel(0xFFFFFFFF, &devcfg_base->dma_dst_addr);
writel(bsize >> 2, &devcfg_base->dma_src_len);
writel(0, &devcfg_base->dma_dst_len);
if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0))
return FPGA_FAIL;

isr_status = readl(&devcfg_base->int_sts);

/* Polling the PCAP_INIT status for Set */
ts = get_timer(0);
while (!(isr_status & DEVCFG_ISR_DMA_DONE)) {
if (isr_status & DEVCFG_ISR_ERROR_FLAGS_MASK) {
debug("%s: Error: isr = 0x%08X\n", __func__,
isr_status);
debug("%s: Write count = 0x%08X\n", __func__,
readl(&devcfg_base->write_count));
debug("%s: Read count = 0x%08X\n", __func__,
readl(&devcfg_base->read_count));

return FPGA_FAIL;
}
if (get_timer(ts) > CONFIG_SYS_FPGA_PROG_TIME) {
printf("%s: Timeout wait for DMA to complete\n",
__func__);
return FPGA_FAIL;
}
isr_status = readl(&devcfg_base->int_sts);
}

debug("%s: DMA transfer is done\n", __func__);

/* Check FPGA configuration completion */
ts = get_timer(0);
while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) {
Expand All @@ -350,9 +381,6 @@ int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize)

debug("%s: FPGA config done\n", __func__);

/* Clear out the DMA status */
writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts);

if (!partialbit)
zynq_slcr_devcfg_enable();

Expand Down

0 comments on commit 08dd9be

Please sign in to comment.