diff options
Diffstat (limited to 'arch/arm/mach-socfpga/arria10-xload.c')
-rw-r--r-- | arch/arm/mach-socfpga/arria10-xload.c | 63 |
1 files changed, 45 insertions, 18 deletions
diff --git a/arch/arm/mach-socfpga/arria10-xload.c b/arch/arm/mach-socfpga/arria10-xload.c index e52fd1ed87..db3cc209ee 100644 --- a/arch/arm/mach-socfpga/arria10-xload.c +++ b/arch/arm/mach-socfpga/arria10-xload.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <asm/sections.h> #include <debug_ll.h> @@ -6,12 +8,12 @@ #include <filetype.h> #include <io.h> #include <asm/unaligned.h> -#include <mach/arria10-pinmux.h> -#include <mach/arria10-regs.h> -#include <mach/arria10-system-manager.h> -#include <mach/arria10-fpga.h> -#include <mach/arria10-xload.h> -#include <mach/generic.h> +#include <mach/socfpga/arria10-pinmux.h> +#include <mach/socfpga/arria10-regs.h> +#include <mach/socfpga/arria10-system-manager.h> +#include <mach/socfpga/arria10-fpga.h> +#include <mach/socfpga/arria10-xload.h> +#include <mach/socfpga/generic.h> #include <linux/sizes.h> int a10_update_bits(unsigned int reg, unsigned int mask, @@ -351,17 +353,9 @@ int arria10_prepare_mmc(int barebox_part, int rbf_part) return 0; } -int arria10_load_fpga(int offset, int bitstream_size) +static inline int __arria10_load_fpga(void *buf, uint32_t count, uint32_t size) { - void *buf = (void *)0xffe00000 + SZ_256K - 256 - SZ_16K; int ret; - uint32_t count; - uint32_t size = bitstream_size / SECTOR_SIZE; - - if (offset) - offset = offset / SECTOR_SIZE; - - count = offset; arria10_read_blocks(buf, count + bitstream.first_sec, SZ_16K); @@ -369,23 +363,56 @@ int arria10_load_fpga(int offset, int bitstream_size) ret = a10_fpga_init(buf); if (ret) - hang(); + return -EAGAIN; while (count <= size) { ret = a10_fpga_write(buf, SZ_16K); if (ret == -ENOSPC) - break; + return -EAGAIN; + count += SZ_16K / SECTOR_SIZE; ret = arria10_read_blocks(buf, count, SZ_16K); + // Reading failed, consider this a failed attempt to configure the FPGA and retry + if (ret) + return -EAGAIN; } ret = a10_fpga_write_complete(); if (ret) - hang(); + return -EAGAIN; return 0; } +int arria10_load_fpga(int offset, int bitstream_size) +{ + int ret; + void *buf = (void *)0xffe00000 + SZ_256K - 256 - SZ_16K; + uint32_t count; + uint32_t size = bitstream_size / SECTOR_SIZE; + uint32_t retryCount; + + if (offset) + offset = offset / SECTOR_SIZE; + + /* Up to 4 retries have been seen on the Enclustra Mercury AA1+ board, as + * FPGA configuration is mandatory to be able to continue the boot, take + * some margin and try up to 10 times + */ + for (retryCount = 0; retryCount < 10; ++retryCount) { + count = offset; + + ret = __arria10_load_fpga(buf, count, size); + if (!ret) + return 0; + else if (ret == -EAGAIN) + continue; + } + + hang(); + return -EIO; +} + void arria10_start_image(int offset) { void *buf = (void *)0x0; |