X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Ffpga%2Fzynqpl.c;h=ef6d1caca4103e4c199839a3a8f08fda46e063f1;hb=a0735a34f8ab2d7060b6f8c16d3cccf78b137283;hp=14363c9a5b883b93f8316d74479434c432e21cdd;hpb=b98d934128bcd98106e764d2f492ac79c38ae53d;p=oweals%2Fu-boot.git diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c index 14363c9a5b..ef6d1caca4 100644 --- a/drivers/fpga/zynqpl.c +++ b/drivers/fpga/zynqpl.c @@ -4,12 +4,13 @@ * (C) Copyright 2012 * Joe Hershberger * - * SPDX-License-Identifier: GPL-2.0+ + * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include +#include #include #include @@ -35,7 +36,7 @@ #define CONFIG_SYS_FPGA_PROG_TIME (CONFIG_SYS_HZ * 4) /* 4 s */ #endif -int zynq_info(Xilinx_desc *desc) +static int zynq_info(xilinx_desc *desc) { return FPGA_SUCCESS; } @@ -146,60 +147,57 @@ static void *check_data(u8 *buf, size_t bsize, u32 *swap) } /* Loop can be huge - support CTRL + C */ if (ctrlc()) - return 0; + return NULL; } - return 0; + return NULL; } - -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_start & 0x3) { - u32 *new_buf = (u32 *)((u32)buf & ~0x3); + 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); + /* 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)); - for (i = 0; i < (bsize/4); i++) - new_buf[i] = load_word(&buf_start[i], swap); + 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); + } - 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); @@ -281,40 +279,94 @@ int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize) writel(DEVCFG_STATUS_DMA_DONE_CNT_MASK, &devcfg_base->status); } - debug("%s: Source = 0x%08X\n", __func__, (u32)buf); - debug("%s: Size = %zu\n", __func__, bsize); - - /* 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); + return FPGA_SUCCESS; +} - isr_status = readl(&devcfg_base->int_sts); +static u32 *zynq_align_dma_buffer(u32 *buf, u32 len, u32 swap) +{ + u32 *new_buf; + u32 i; - /* 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)); + if ((u32)buf != ALIGN((u32)buf, ARCH_DMA_MINALIGN)) { + new_buf = (u32 *)ALIGN((u32)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; + /* + * 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; } - isr_status = readl(&devcfg_base->int_sts); + 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); } - debug("%s: DMA transfer is done\n", __func__); + return buf; +} + +static 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)); + + if (zynq_dma_transfer((u32)buf | 1, bsize >> 2, 0xffffffff, 0)) + return FPGA_FAIL; + + isr_status = readl(&devcfg_base->int_sts); /* Check FPGA configuration completion */ ts = get_timer(0); while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) { @@ -328,16 +380,19 @@ 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(); return FPGA_SUCCESS; } -int zynq_dump(Xilinx_desc *desc, const void *buf, size_t bsize) +static int zynq_dump(xilinx_desc *desc, const void *buf, size_t bsize) { return FPGA_FAIL; } + +struct xilinx_fpga_op zynq_op = { + .load = zynq_load, + .dump = zynq_dump, + .info = zynq_info, +};