return FPGA_SUCCESS;
}
+#define DUMMY_WORD 0xffffffff
+
/* Xilinx binary format header */
static const u32 bin_format[] = {
- 0xffffffff, /* Dummy words */
- 0xffffffff,
- 0xffffffff,
- 0xffffffff,
- 0xffffffff,
- 0xffffffff,
- 0xffffffff,
- 0xffffffff,
+ DUMMY_WORD, /* Dummy words */
+ DUMMY_WORD,
+ DUMMY_WORD,
+ DUMMY_WORD,
+ DUMMY_WORD,
+ DUMMY_WORD,
+ DUMMY_WORD,
+ DUMMY_WORD,
0x000000bb, /* Sync word */
0x11220044, /* Sync word */
- 0xffffffff,
- 0xffffffff,
+ DUMMY_WORD,
+ DUMMY_WORD,
0xaa995566, /* Sync word */
};
-int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize)
+#define SWAP_NO 1
+#define SWAP_DONE 2
+
+/*
+ * Load the whole word from unaligned buffer
+ * Keep in your mind that it is byte loading on little-endian system
+ */
+static u32 load_word(const void *buf, u32 swap)
{
- unsigned long ts; /* Timestamp */
- u32 control;
- u32 isr_status;
- u32 status;
- const u32 *test = buf;
- int i;
-
- if ((u32)buf & 0x3) {
- printf("Error: Buffer is not aligned %x\n", (u32)buf);
- return FPGA_FAIL;
+ u32 word = 0;
+ u8 *bitc = (u8 *)buf;
+ int p;
+
+ if (swap == SWAP_NO) {
+ for (p = 0; p < 4; p++) {
+ word <<= 8;
+ word |= bitc[p];
+ }
+ } else {
+ for (p = 3; p >= 0; p--) {
+ word <<= 8;
+ word |= bitc[p];
+ }
}
- /* Check bitstream size */
- if (bsize != desc->size) {
- printf("Error: File size is wrong - should be %x.\n",
- desc->size);
- return FPGA_FAIL;
- }
+ return word;
+}
+
+static u32 check_header(const void *buf)
+{
+ u32 i, pattern;
+ int swap = SWAP_NO;
+ u32 *test = (u32 *)buf;
+
+ debug("%s: Let's check bitstream header\n", __func__);
/* Checking that passing bin is not a bitstream */
for (i = 0; i < ARRAY_SIZE(bin_format); i++) {
- if (test[i] != bin_format[i]) {
- puts("Error: File not in binary format.\n");
- return FPGA_FAIL;
+ pattern = load_word(&test[i], swap);
+
+ /*
+ * Bitstreams in binary format are swapped
+ * compare to regular bistream.
+ * Do not swap dummy word but if swap is done assume
+ * that parsing buffer is binary format
+ */
+ if ((__swab32(pattern) != DUMMY_WORD) &&
+ (__swab32(pattern) == bin_format[i])) {
+ pattern = __swab32(pattern);
+ swap = SWAP_DONE;
+ debug("%s: data swapped - let's swap\n", __func__);
}
- }
- zynq_slcr_devcfg_disable();
+ debug("%s: %d/%x: pattern %x/%x bin_format\n", __func__, i,
+ (u32)&test[i], pattern, bin_format[i]);
+ if (pattern != bin_format[i]) {
+ debug("%s: Bitstream is not recognized\n", __func__);
+ return 0;
+ }
+ }
+ debug("%s: Found bitstream header at %x %s swapinng\n", __func__,
+ (u32)buf, swap == SWAP_NO ? "without" : "with");
- /* Setting PCFG_PROG_B signal to high */
- control = readl(&devcfg_base->ctrl);
- writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
- /* Setting PCFG_PROG_B signal to low */
- writel(control & ~DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+ return swap;
+}
- /* Polling the PCAP_INIT status for Reset */
- ts = get_timer(0);
- while (readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT) {
- if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
- puts("Error: Timeout waiting for INIT to clear.\n");
- return FPGA_FAIL;
+static void *check_data(u8 *buf, size_t bsize, u32 *swap)
+{
+ u32 word, p = 0; /* possition */
+
+ /* Because buf doesn't need to be aligned let's read it by chars */
+ for (p = 0; p < bsize; p++) {
+ word = load_word(&buf[p], SWAP_NO);
+ debug("%s: word %x %x/%x\n", __func__, word, p, (u32)&buf[p]);
+
+ /* Find the first bitstream dummy word */
+ if (word == DUMMY_WORD) {
+ debug("%s: Found dummy word at position %x/%x\n",
+ __func__, p, (u32)&buf[p]);
+ *swap = check_header(&buf[p]);
+ if (*swap) {
+ /* FIXME add full bitstream checking here */
+ return &buf[p];
+ }
}
+ /* Loop can be huge - support CTRL + C */
+ if (ctrlc())
+ return 0;
+ }
+ return 0;
+}
+
+
+int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize)
+{
+ 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;
}
- /* Setting PCFG_PROG_B signal to high */
- writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+ buf_start = check_data((u8 *)buf, bsize, &swap);
+ if (!buf_start)
+ return FPGA_FAIL;
- /* Polling the PCAP_INIT status for Set */
- ts = get_timer(0);
- while (!(readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT)) {
- if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
- puts("Error: Timeout waiting for INIT to set.\n");
- 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_start & 0x3) {
+ u32 *new_buf = (u32 *)((u32)buf & ~0x3);
+
+ 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;
+
+ printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__,
+ swap);
+
+ for (i = 0; i < (bsize/4); i++)
+ new_buf[i] = load_word(&buf_start[i], swap);
+
+ swap = SWAP_DONE;
+ }
+
+ if (!partialbit) {
+ zynq_slcr_devcfg_disable();
+
+ /* Setting PCFG_PROG_B signal to high */
+ control = readl(&devcfg_base->ctrl);
+ writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+ /* Setting PCFG_PROG_B signal to low */
+ writel(control & ~DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+
+ /* Polling the PCAP_INIT status for Reset */
+ ts = get_timer(0);
+ while (readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT) {
+ if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
+ printf("%s: Timeout wait for INIT to clear\n",
+ __func__);
+ return FPGA_FAIL;
+ }
+ }
+
+ /* Setting PCFG_PROG_B signal to high */
+ writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl);
+
+ /* Polling the PCAP_INIT status for Set */
+ ts = get_timer(0);
+ while (!(readl(&devcfg_base->status) &
+ DEVCFG_STATUS_PCFG_INIT)) {
+ if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) {
+ printf("%s: Timeout wait for INIT to set\n",
+ __func__);
+ return FPGA_FAIL;
+ }
}
}
/* Clear out the DMA status */
writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts);
- zynq_slcr_devcfg_enable();
+ if (!partialbit)
+ zynq_slcr_devcfg_enable();
return FPGA_SUCCESS;
}