From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marek Vasut Date: Tue, 29 Aug 2017 13:55:40 +0200 Subject: [U-Boot] [PATCH 03/19] arm: socfpga: Add driver for flash to program FPGA In-Reply-To: <1504003561-6290-4-git-send-email-tien.fong.chee@intel.com> References: <1504003561-6290-1-git-send-email-tien.fong.chee@intel.com> <1504003561-6290-4-git-send-email-tien.fong.chee@intel.com> Message-ID: <04c8e56d-860b-98c9-2893-2692c64197ee@denx.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On 08/29/2017 12:45 PM, tien.fong.chee at intel.com wrote: > From: Tien Fong Chee > > This driver handles FPGA program operation from flash loading > RBF to memory and then to program FPGA. > > Signed-off-by: Tien Fong Chee > --- > .../include/mach/fpga_manager_arria10.h | 27 ++ > drivers/fpga/socfpga_arria10.c | 386 +++++++++++++++++++- > include/altera.h | 6 + > include/configs/socfpga_common.h | 4 + > 4 files changed, 422 insertions(+), 1 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 9cbf696..93a9122 100644 > --- a/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h > +++ b/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h > @@ -8,6 +8,8 @@ > #ifndef _FPGA_MANAGER_ARRIA10_H_ > #define _FPGA_MANAGER_ARRIA10_H_ > > +#include > + > #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) > @@ -89,11 +91,36 @@ 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 flash_info { > + char *interface; > + char *dev_part; > + char *filename; > + int fstype; > + u32 remaining; > + u32 flash_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); > int is_fpgamgr_user_mode(void); > int fpgamgr_wait_early_user_mode(void); > +#if defined(CONFIG_CMD_FPGA_LOADFS) > +const char *get_cff_filename(const void *fdt, int *len, u32 core); > +const char *get_cff_devpart(const void *fdt, int *len); > +#endif > > #endif /* __ASSEMBLY__ */ > > diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c > index 5c1a68a..90c55e5 100644 > --- a/drivers/fpga/socfpga_arria10.c > +++ b/drivers/fpga/socfpga_arria10.c > @@ -13,6 +13,12 @@ > #include > #include > #include > +#include > +#include > +#include > +#include > +#include > +#include > #include > #include > > @@ -22,6 +28,10 @@ > #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 > > DECLARE_GLOBAL_DATA_PTR; > > @@ -118,7 +128,7 @@ static int wait_for_nconfig_pin_and_nstatus_pin(void) > return wait_for_bit(__func__, > &fpga_manager_base->imgcfg_stat, > mask, > - false, FPGA_TIMEOUT_MSEC, false); > + true, FPGA_TIMEOUT_MSEC, false); > } > > static int wait_for_f2s_nstatus_pin(unsigned long value) > @@ -453,6 +463,281 @@ int fpgamgr_program_finish(void) > return 0; > } > > +#if defined(CONFIG_CMD_FPGA_LOADFS) > +const char *get_cff_filename(const void *fdt, int *len, u32 core) > +{ > + const char *cff_filename = NULL; > + const char *cell; > + int nodeoffset; > + nodeoffset = fdt_subnode_offset(fdt, 0, "chosen"); > + > + if (nodeoffset >= 0) { > + if (core) > + cell = fdt_getprop(fdt, > + nodeoffset, > + "cffcore-file", > + len); > + else > + cell = fdt_getprop(fdt, nodeoffset, "cff-file", len); This should be a property of the FPGA , not the system . You can have multiple FPGAs and then this would become a problem. > + > + if (cell) > + cff_filename = cell; > + } > + > + return cff_filename; > +} > + > +const char *get_cff_devpart(const void *fdt, int *len) > +{ > + const char *cff_devpart = NULL; > + const char *cell; > + int nodeoffset; > + nodeoffset = fdt_subnode_offset(fdt, 0, "chosen"); > + > + cell = fdt_getprop(fdt, nodeoffset, "cff_devpart", len); Indent ? What is this new undocumented DT node about ? > + if (cell) > + cff_devpart = cell; > + > + return cff_devpart; > +} > + > +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 > + */ Checkpatch should complain about incorrect multiline comment style here ... > + u32 word_reading_max = 2; > + u32 i; > + > + for(i = 0; i < word_reading_max; i++) > + { > + if(RBF_UNENCRYPTED == *(buffer + i)) /* PERIPH RBF */ > + rbf->security = unencrypted; > + else if (RBF_ENCRYPTED == *(buffer + i)) > + rbf->security = encrypted; > + else if (RBF_UNENCRYPTED == *(buffer + i + 1)) /* CORE RBF */ > + rbf->security = unencrypted; > + else if (RBF_ENCRYPTED == *(buffer + i + 1)) > + rbf->security = encrypted; > + else { > + rbf->security = invalid; > + continue; > + } > + > + /* PERIPH RBF */ > + if (ARRIA10RBF_PERIPH == *(buffer + i + 1)) { > + rbf->section = periph_section; > + break; > + } > + else if (ARRIA10RBF_CORE == *(buffer + i + 1)) { > + rbf->section = core_section; > + break; > + } /* CORE RBF */ > + else if (ARRIA10RBF_PERIPH == *(buffer + i + 2)) { > + rbf->section = periph_section; > + break; > + } > + else if (ARRIA10RBF_CORE == *(buffer + i + 2)) { > + rbf->section = core_section; > + break; > + } > + else { } else { ... coding style ... > + rbf->section = unknown; > + break; > + } > + } > + > + return; > +} > + > +static int flash_read(struct flash_info *flashinfo, > + u32 size_read, > + u32 *buffer_ptr) > +{ > + size_t ret = EEXIST; > + loff_t actread = 0; > + > +#ifdef CONFIG_FS_FAT > + ret = fat_read_file(flashinfo->filename, > + buffer_ptr, flashinfo->flash_offset, > + size_read, &actread); > +#endif How can a generic FPGA driver depend on random FS functionality ? This is broken ... > + if (ret || actread != size_read) { > + printf("Failed to read %s from flash %d ", > + flashinfo->filename, > + ret); > + printf("!= %d.\n", size_read); > + return -EPERM; > + } else > + ret = actread; > + > + return ret; > +} > + > +static int fs_flash_preinit(struct flash_info *flashinfo, > + u32 *buffer, u32 *buffer_sizebytes) Is this an FPGA driver or MTD driver ? > +{ > + u32 *bufferptr_after_header = NULL; > + u32 buffersize_after_header = 0; > + u32 rbf_header_data_size = 0; > + int ret = 0; > + > + flashinfo->flash_offset = 0; > + > + /* To avoid from keeping re-read the contents */ > + struct image_header *header = &(flashinfo->header); > + size_t buffer_size = *buffer_sizebytes; > + u32 *buffer_ptr = (u32 *)*buffer; > + > + Two newlines ... fix > + /* Load mkimage header into buffer */ > + ret = flash_read(flashinfo, > + sizeof(struct image_header), buffer_ptr); > + > + if (0 >= ret) { > + printf(" 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)) { > + printf("FPGA: Bad Magic Number.\n"); > + return -EBADF; > + } > + > + if (!image_check_hcrc(header)) { > + printf("FPGA: Bad Header Checksum.\n"); > + return -EPERM; > + } > + > + /* Getting rbf data size */ > + flashinfo->remaining = > + image_get_data_size(header); > + > + /* Calculate total size of both rbf data with mkimage header */ > + rbf_header_data_size = flashinfo->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); > + flashinfo->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); > + flashinfo->remaining = 0; > + } > + > + /* Loading mkimage header and rbf data into buffer */ > + ret = flash_read(flashinfo, buffer_size, buffer_ptr); > + > + if (0 >= ret) { > + printf(" Failed to read mkimage header and rbf data "); > + printf("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 */ > + flashinfo->flash_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(&flashinfo->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 > + flashinfo->datacrc = > + crc32(flashinfo->datacrc, > + (u_char *)bufferptr_after_header, > + buffersize_after_header); > +#endif > + > +if (0 == flashinfo->remaining) { > +#ifdef CONFIG_CHECK_FPGA_DATA_CRC > + if (flashinfo->datacrc != > + image_get_dcrc(&(flashinfo->header))) { > + printf("FPGA: Bad Data Checksum.\n"); > + return -EPERM; > + } > +#endif > +} > + return 0; > +} > + > +static int fs_flash_read(struct flash_info *flashinfo, 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 = flashinfo->flash_offset; > + > + /* Buffer allocated in OCRAM */ > + /* Read the data by small chunk by chunk. */ > + if (flashinfo->remaining > buffer_size) > + flashinfo->remaining -= buffer_size; > + else { > + /* Buffer allocated in DDR, larger than rbf data most > + of the time */ > + buffer_size = flashinfo->remaining; > + flashinfo->remaining = 0; > + } > + > + ret = flash_read(flashinfo, buffer_size, buffer_ptr); > + > + if (0 >= ret) { > + printf(" Failed to read rbf data from flash.\n"); > + return -ENOENT; > + } > + > +#ifdef CONFIG_CHECK_FPGA_DATA_CRC > + flashinfo->datacrc = > + crc32(flashinfo->datacrc, > + (unsigned char *)buffer_ptr, buffer_size); > +#endif > + > +if (0 == flashinfo->remaining) { > +#ifdef CONFIG_CHECK_FPGA_DATA_CRC > + if (flashinfo->datacrc != > + image_get_dcrc(&(flashinfo->header))) { > + printf("FPGA: Bad Data Checksum.\n"); > + return -EPERM; > + } > +#endif > +} > + /* Update next reading rbf data flash offset */ > + flash_addr += buffer_size; > + > + flashinfo->flash_offset = flash_addr; > + > + /* Update the size of rbf data to be programmed into FPGA */ > + *buffer_sizebytes = buffer_size; > + > + return 0; > +} > + > /* > * FPGA Manager to program the FPGA. This is the interface used by FPGA driver. > * Return 0 for sucess, non-zero for error. > @@ -469,6 +754,7 @@ int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) > > /* Initialize the FPGA Manager */ > status = fpgamgr_program_init((u32 *)rbf_data, rbf_size); > + > if (status) > return status; > > @@ -477,3 +763,101 @@ int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) > > return fpgamgr_program_finish(); > } > + > +int socfpga_loadfs(Altera_desc *desc, const void *buf, size_t bsize, > + fpga_fs_info *fpga_fsinfo) > +{ > + u32 buffer = 0; > + u32 buffer_ori = 0; > + size_t buffer_sizebytes = 0; > + size_t buffer_sizebytes_ori = 0; > + struct flash_info flashinfo; > + u32 status = 0; > + int ret = 0; > + > + memset(&flashinfo, 0, sizeof(flashinfo)); > + > + if (fpga_fsinfo->filename == NULL) { > + printf("no peripheral RBF filename specified.\n"); > + return -EINVAL; > + } > + > + WATCHDOG_RESET(); > + > + buffer_sizebytes = buffer_sizebytes_ori = bsize; > + buffer = buffer_ori = (u32) buf; > + flashinfo.interface = fpga_fsinfo->interface; > + flashinfo.dev_part = fpga_fsinfo->dev_part; > + flashinfo.filename = fpga_fsinfo->filename; > + flashinfo.fstype = fpga_fsinfo->fstype; > + > +#ifndef CONFIG_SPL_BUILD > + if (fs_set_blk_dev(flashinfo.interface, flashinfo.dev_part, > + flashinfo.fstype)) > + return FPGA_FAIL; > +#endif > + > + /* Note: Both buffer and buffer_sizebytes values can be altered by > + function below. */ > + ret = fs_flash_preinit(&flashinfo, &buffer, &buffer_sizebytes); > + > + if (ret) > + return ret; > + > + if (periph_section == flashinfo.rbfinfo.section) { > + /* Initialize the FPGA Manager */ > + status = fpgamgr_program_init((u32 *)buffer, buffer_sizebytes); > + if (status) { > + printf("FPGA: Init with periph rbf failed with error. "); > + printf("code %d\n", status); > + return -EPERM; > + } > + } > + > + WATCHDOG_RESET(); > + > + /* Transfer data to FPGA Manager */ > + fpgamgr_program_write((void *)buffer, > + buffer_sizebytes); > + > + WATCHDOG_RESET(); > + > + while (flashinfo.remaining) { > + ret = fs_flash_read(&flashinfo, &buffer_ori, > + &buffer_sizebytes_ori); > + > + if (ret) > + return ret; > + > + /* transfer data to FPGA Manager */ > + fpgamgr_program_write((void *)buffer_ori, > + buffer_sizebytes_ori); > + > + WATCHDOG_RESET(); > + } > + > + if (periph_section == flashinfo.rbfinfo.section) { > + if (-ETIMEDOUT != fpgamgr_wait_early_user_mode()) > + printf("FPGA: Early Release Succeeded.\n"); > + else { > + printf("FPGA: Failed to see Early Release.\n"); > + return -EIO; > + } > + } else if (core_section == flashinfo.rbfinfo.section) { > + /* Ensure the FPGA entering config done */ > + status = fpgamgr_program_finish(); > + if (status) > + return status; > + else > + printf("FPGA: Enter user mode.\n"); > + > + } else { > + printf("Config Error: Unsupported FGPA raw binary type.\n"); > + return -ENOEXEC; > + } > + > + WATCHDOG_RESET(); > + return 1; > + > +} > +#endif > diff --git a/include/altera.h b/include/altera.h > index 48d3eb7..0597e8a 100644 > --- a/include/altera.h > +++ b/include/altera.h > @@ -84,6 +84,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 > *********************************************************************/ > @@ -111,6 +115,8 @@ typedef struct { > > #ifdef CONFIG_FPGA_SOCFPGA > int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size); > +int socfpga_loadfs(Altera_desc *desc, const void *buf, size_t bsize, > + fpga_fs_info *fpga_fsinfo); > #endif > > #ifdef CONFIG_FPGA_STRATIX_V > diff --git a/include/configs/socfpga_common.h b/include/configs/socfpga_common.h > index 9be9e79..c15d244 100644 > --- a/include/configs/socfpga_common.h > +++ b/include/configs/socfpga_common.h > @@ -27,7 +27,11 @@ > */ > #define CONFIG_NR_DRAM_BANKS 1 > #define PHYS_SDRAM_1 0x0 > +#if defined(CONFIG_TARGET_SOCFPGA_GEN5) > #define CONFIG_SYS_MALLOC_LEN (64 * 1024 * 1024) > +#elif defined(CONFIG_TARGET_SOCFPGA_ARRIA10) > +#define CONFIG_SYS_MALLOC_LEN (128 * 1024 * 1024) > +#endif 128 MiB malloc area is nonsense, even those 64 MiB are iffy. Why would you ever need that in a bootloader ? > #define CONFIG_SYS_MEMTEST_START PHYS_SDRAM_1 > #define CONFIG_SYS_MEMTEST_END PHYS_SDRAM_1_SIZE > #if defined(CONFIG_TARGET_SOCFPGA_GEN5) > -- Best regards, Marek Vasut