From: Tien Fong Chee <tien.fong.c...@intel.com> Add FPGA drivers to support FPGA loadfs to program FPGA. The drivers are designed based on generic firmware loader framework, specific firmware loader handling is defined in fpga_manager_arria10.c. These drivers can handle FPGA program operation from loading RBF image in flash to memory and then to program FPGA.
Signed-off-by: Tien Fong Chee <tien.fong.c...@intel.com> --- .../include/mach/fpga_manager_arria10.h | 22 + drivers/fpga/socfpga_arria10.c | 402 ++++++++++++++++++++ include/altera.h | 4 + 3 files changed, 428 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h b/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h index a112453..743d6b7 100644 --- a/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h +++ b/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h @@ -7,6 +7,9 @@ #ifndef _FPGA_MANAGER_ARRIA10_H_ #define _FPGA_MANAGER_ARRIA10_H_ +#include <asm/cache.h> +#include <fs_loader.h> + #define ALT_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR_SET_MSK BIT(0) #define ALT_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE_SET_MSK BIT(1) #define ALT_FPGAMGR_IMGCFG_STAT_F2S_USERMODE_SET_MSK BIT(2) @@ -88,6 +91,25 @@ struct socfpga_fpga_manager { u32 imgcfg_fifo_status; }; +#if defined(CONFIG_CMD_FPGA_LOADFS) +enum rbf_type {unknown, periph_section, core_section}; +enum rbf_security {invalid, unencrypted, encrypted}; + +struct rbf_info { + enum rbf_type section; + enum rbf_security security; +}; + +struct fpga_info { + char *filename; + int fstype; + u32 remaining; + u32 offset; + struct rbf_info rbfinfo; + struct image_header header; +}; +#endif + /* Functions */ int fpgamgr_program_init(u32 * rbf_data, size_t rbf_size); int fpgamgr_program_finish(void); diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c index c0252fb..2f9006f 100644 --- a/drivers/fpga/socfpga_arria10.c +++ b/drivers/fpga/socfpga_arria10.c @@ -12,6 +12,13 @@ #include <altera.h> #include <common.h> #include <errno.h> +#include <fat.h> +#include <fs.h> +#include <fdtdec.h> +#include <malloc.h> +#include <part.h> +#include <spl.h> +#include <dm.h> #include <wait_bit.h> #include <watchdog.h> @@ -21,6 +28,12 @@ #define COMPRESSION_OFFSET 229 #define FPGA_TIMEOUT_MSEC 1000 /* timeout in ms */ #define FPGA_TIMEOUT_CNT 0x1000000 +#define RBF_UNENCRYPTED 0xa65c +#define RBF_ENCRYPTED 0xa65d +#define ARRIA10RBF_PERIPH 0x0001 +#define ARRIA10RBF_CORE 0x8001 +#define PERIPH_RBF 0 +#define CORE_RBF 1 static const struct socfpga_fpga_manager *fpga_manager_base = (void *)SOCFPGA_FPGAMGRREGS_ADDRESS; @@ -30,6 +43,8 @@ static const struct socfpga_system_manager *system_manager_base = static void fpgamgr_set_cd_ratio(unsigned long ratio); +struct firmware *fw = NULL; + static uint32_t fpgamgr_get_msel(void) { u32 reg; @@ -471,3 +486,390 @@ int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) return fpgamgr_program_finish(); } + +#if defined(CONFIG_CMD_FPGA_LOADFS) +const char *get_fpga_filename(const void *fdt, int *len, u32 core) +{ + const char *fpga_filename = NULL; + const char *cell; + int nodeoffset; + + nodeoffset = fdtdec_next_compatible(fdt, 0, + COMPAT_ALTERA_SOCFPGA_FPGA0); + if (nodeoffset >= 0) { + if (core) { + cell = fdt_getprop(fdt, + nodeoffset, + "altr,bitstream_core", + len); + } + else { + cell = fdt_getprop(fdt, nodeoffset, + "altr,bitstream_periph", len); + } + + if (cell) + fpga_filename = cell; + } + + return fpga_filename; +} + +void get_rbf_image_info(struct rbf_info *rbf, u16 *buffer) +{ + /* + * Magic ID starting at: + * -> 1st dword in periph.rbf + * -> 2nd dword in core.rbf + */ + u32 word_reading_max = 2; + u32 i; + + for (i = 0; i < word_reading_max; i++) { + if (*(buffer + i) == RBF_UNENCRYPTED) { /* PERIPH RBF */ + rbf->security = unencrypted; + } + else if (*(buffer + i) == RBF_ENCRYPTED) { + rbf->security = encrypted; + } + else if (*(buffer + i + 1) == RBF_UNENCRYPTED) { /* CORE RBF */ + rbf->security = unencrypted; + } + else if (*(buffer + i + 1) == RBF_ENCRYPTED) { + rbf->security = encrypted; + } + else { + rbf->security = invalid; + continue; + } + + /* PERIPH RBF(buffer + i + 1), CORE RBF(buffer + i + 2) */ + if (*(buffer + i + 1) == ARRIA10RBF_PERIPH) { + rbf->section = periph_section; + break; + } else if (*(buffer + i + 1) == ARRIA10RBF_CORE) { + rbf->section = core_section; + break; + } else if (*(buffer + i + 2) == ARRIA10RBF_PERIPH) { + rbf->section = periph_section; + break; + } else if (*(buffer + i + 2) == ARRIA10RBF_CORE) { + rbf->section = core_section; + break; + } else { + rbf->section = unknown; + break; + } + } + + return; +} + +int fs_flash_preinit(struct device_platdata *plat, + struct fpga_info *fpgainfo, + u32 *buffer, u32 *buffer_sizebytes) +{ + u32 *bufferptr_after_header = NULL; + u32 buffersize_after_header = 0; + u32 rbf_header_data_size = 0; + int ret = 0; + + fpgainfo->offset = 0; + + /* To avoid from keeping re-read the contents */ + struct image_header *header = &(fpgainfo->header); + size_t buffer_size = *buffer_sizebytes; + u32 *buffer_ptr = (u32 *)*buffer; + + /* Load mkimage header into buffer */ + ret = request_firmware_into_buf(plat, + fpgainfo->filename, + buffer_ptr, + sizeof(struct image_header), + fpgainfo->offset, + &fw); + if (ret < 0) { + puts("Failed to read mkimage header from flash.\n"); + return -ENOENT; + } + + WATCHDOG_RESET(); + + memcpy(header, (u_char *)buffer_ptr, sizeof(*header)); + + if (!image_check_magic(header)) { + puts("FPGA: Bad Magic Number.\n"); + return -EBADF; + } + + if (!image_check_hcrc(header)) { + puts("FPGA: Bad Header Checksum.\n"); + return -EPERM; + } + + /* Getting rbf data size */ + fpgainfo->remaining = + image_get_data_size(header); + + /* Calculate total size of both rbf data with mkimage header */ + rbf_header_data_size = fpgainfo->remaining + + sizeof(struct image_header); + + /* Loading to buffer chunk by chunk, normally for OCRAM buffer */ + if (rbf_header_data_size > buffer_size) { + /* Calculate size of rbf data in the buffer */ + buffersize_after_header = + buffer_size - sizeof(struct image_header); + fpgainfo->remaining -= buffersize_after_header; + } else { + /* Loading whole rbf image into buffer, normally for DDR buffer */ + buffer_size = rbf_header_data_size; + /* Calculate size of rbf data in the buffer */ + buffersize_after_header = + buffer_size - sizeof(struct image_header); + fpgainfo->remaining = 0; + } + + /* Loading mkimage header and rbf data into buffer */ + ret = request_firmware_into_buf(plat, + fpgainfo->filename, + buffer_ptr, + buffer_size, + fpgainfo->offset, + &fw); + if (ret < 0) { + puts(" Failed to read mkimage header and rbf data "); + puts("from flash.\n"); + return -ENOENT; + } + + /* + * Getting pointer of rbf data starting address where is it + * right after mkimage header + */ + bufferptr_after_header = + (u32 *)((u_char *)buffer_ptr + sizeof(struct image_header)); + + /* Update next reading rbf data flash offset */ + fpgainfo->offset += buffer_size; + + /* + * Update the starting addr of rbf data to init FPGA & programming + * into FPGA + */ + *buffer = (u32)bufferptr_after_header; + + get_rbf_image_info(&fpgainfo->rbfinfo, (u16 *)bufferptr_after_header); + + /* Update the size of rbf data to be programmed into FPGA */ + *buffer_sizebytes = buffersize_after_header; + +#ifdef CONFIG_CHECK_FPGA_DATA_CRC + fpgainfo->datacrc = + crc32(fpgainfo->datacrc, + (u_char *)bufferptr_after_header, + buffersize_after_header); +#endif + +if (fpgainfo->remaining == 0) { +#ifdef CONFIG_CHECK_FPGA_DATA_CRC + if (fpgainfo->datacrc != + image_get_dcrc(&(fpgainfo->header))) { + puts("FPGA: Bad Data Checksum.\n"); + return -EPERM; + } +#endif +} + return 0; +} + +int fs_flash_read(struct device_platdata *plat, + struct fpga_info *fpgainfo, u32 *buffer, + u32 *buffer_sizebytes) +{ + int ret = 0; + /* To avoid from keeping re-read the contents */ + size_t buffer_size = *buffer_sizebytes; + u32 *buffer_ptr = (u32 *)*buffer; + u32 flash_addr = fpgainfo->offset; + + /* Buffer allocated in OCRAM */ + /* Read the data by small chunk by chunk. */ + if (fpgainfo->remaining > buffer_size) { + fpgainfo->remaining -= buffer_size; + } + else { + /* + * Buffer allocated in DDR, larger than rbf data most + * of the time + */ + buffer_size = fpgainfo->remaining; + fpgainfo->remaining = 0; + } + + ret = request_firmware_into_buf(plat, + fpgainfo->filename, + buffer_ptr, + buffer_size, + fpgainfo->offset, + &fw); + if (ret < 0) { + puts(" Failed to read rbf data from flash.\n"); + return -ENOENT; + } + +#ifdef CONFIG_CHECK_FPGA_DATA_CRC + fpgainfo->datacrc = + crc32(fpgainfo->datacrc, + (unsigned char *)buffer_ptr, buffer_size); +#endif + +if (fpgainfo->remaining == 0) { +#ifdef CONFIG_CHECK_FPGA_DATA_CRC + if (fpgainfo->datacrc != + image_get_dcrc(&(fpgainfo->header))) { + puts("FPGA: Bad Data Checksum.\n"); + return -EPERM; + } +#endif +} + /* Update next reading rbf data flash offset */ + flash_addr += buffer_size; + + fpgainfo->offset = flash_addr; + + /* Update the size of rbf data to be programmed into FPGA */ + *buffer_sizebytes = buffer_size; + + return 0; +} + +int socfpga_loadfs(Altera_desc *desc, const void *buf, size_t bsize, + fpga_fs_info *fpga_fsinfo) +{ + struct fpga_info fpgainfo; + u32 status = 0; + int ret = 0; + int len = 0; + u32 buffer = 0; + u32 buffer_ori = 0; + size_t buffer_sizebytes = 0; + size_t buffer_sizebytes_ori = 0; + buffer_sizebytes = buffer_sizebytes_ori = bsize; + buffer = buffer_ori = (u32) buf; + struct udevice *dev; + struct device_platdata *plat; + char *filename = NULL; + + ret = uclass_get_device(UCLASS_FS_FIRMWARE_LOADER, 0, &dev); + if (ret) + return ret; + + plat = dev->platdata; +/* + if (strcmp("default", fpga_fsinfo->interface)) + env_set("storage_interface", fpga_fsinfo->interface); + + if (strcmp("default", fpga_fsinfo->dev_part)) + env_set("fw_dev_part", fpga_fsinfo->dev_part); +*/ + if (!strcmp("default", fpga_fsinfo->filename)) { + filename = env_get("CORE_RBF"); + if (filename) + fpga_fsinfo->filename = filename; + else { + fpga_fsinfo->filename = + (char *)get_fpga_filename(gd->fdt_blob, + &len, + CORE_RBF); + } + } + + memset(&fpgainfo, 0, sizeof(fpgainfo)); + + fpgainfo.filename = fpga_fsinfo->filename; + fpgainfo.fstype = fpga_fsinfo->fstype; + + WATCHDOG_RESET(); + + /* + * Note: Both buffer and buffer_sizebytes values can be altered by + * function below. + */ + ret = fs_flash_preinit(plat, &fpgainfo, &buffer, &buffer_sizebytes); + if (ret) { + release_firmware(fw); + fw = NULL; + return ret; + } + + if (fpgainfo.rbfinfo.section == periph_section) { + /* Initialize the FPGA Manager */ + status = fpgamgr_program_init((u32 *)buffer, buffer_sizebytes); + if (status) { + puts("FPGA: Init with periph rbf failed.\n"); + release_firmware(fw); + fw = NULL; + return -EPERM; + } + } + + WATCHDOG_RESET(); + + /* Transfer data to FPGA Manager */ + fpgamgr_program_write((void *)buffer, + buffer_sizebytes); + + WATCHDOG_RESET(); + + while (fpgainfo.remaining) { + ret = fs_flash_read(plat, &fpgainfo, &buffer_ori, + &buffer_sizebytes_ori); + + if (ret) { + release_firmware(fw); + fw = NULL; + return ret; + } + + /* transfer data to FPGA Manager */ + fpgamgr_program_write((void *)buffer_ori, + buffer_sizebytes_ori); + + WATCHDOG_RESET(); + } + + if (fpgainfo.rbfinfo.section == periph_section) { + if (fpgamgr_wait_early_user_mode() != -ETIMEDOUT) { + puts("FPGA: Early Release Succeeded.\n"); + } + else { + puts("FPGA: Failed to see Early Release.\n"); + release_firmware(fw); + fw = NULL; + return -EIO; + } + } else if (fpgainfo.rbfinfo.section == core_section) { + /* Ensure the FPGA entering config done */ + status = fpgamgr_program_finish(); + if (status) { + release_firmware(fw); + fw = NULL; + return status; + } + else { + puts("FPGA: Enter user mode.\n"); + } + + } else { + puts("Config Error: Unsupported FGPA raw binary type.\n"); + release_firmware(fw); + fw = NULL; + return -ENOEXEC; + } + + release_firmware(fw); + fw = NULL; + return 0; +} +#endif diff --git a/include/altera.h b/include/altera.h index ead5d3d..cf0c021 100644 --- a/include/altera.h +++ b/include/altera.h @@ -83,6 +83,10 @@ typedef struct { extern int altera_load(Altera_desc *desc, const void *image, size_t size); extern int altera_dump(Altera_desc *desc, const void *buf, size_t bsize); extern int altera_info(Altera_desc *desc); +#if defined(CONFIG_CMD_FPGA_LOADFS) +int altera_loadfs(Altera_desc *desc, const void *buf, size_t bsize, + fpga_fs_info *fpga_fsinfo); +#endif /* Board specific implementation specific function types *********************************************************************/ -- 1.7.7.4 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot