[U-Boot] [PATCH 03/19] arm: socfpga: Add driver for flash to program FPGA

Marek Vasut
2017-08-29T11:55:40Z

On 08/29/2017 12:45 PM, tien.fong.chee at intel.com wrote:
> From: Tien Fong Chee <tien.fong.chee@intel.com>
>
> This driver handles FPGA program operation from flash loading
> RBF to memory and then to program FPGA.
>
> Signed-off-by: Tien Fong Chee <tien.fong.chee@intel.com>
> ---
> .../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 <asm/cache.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)
> @@ -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 <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 <wait_bit.h>
> #include <watchdog.h>
>
> @@ -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