On Thu, 2019-01-31 at 22:51 +0800, tien.fong.c...@intel.com wrote:
> From: Tien Fong Chee <tien.fong.c...@intel.com>
> 
> Add FPGA driver to support program FPGA with FPGA bitstream loading from
> filesystem. The driver are designed based on generic firmware loader
> framework. The driver can handle FPGA program operation from loading FPGA
> bitstream in flash to memory and then to program FPGA.
> 
> Signed-off-by: Tien Fong Chee <tien.fong.c...@intel.com>
> 
> ---
> 
> changes for v7
> - Restructure the FPGA driver to support both peripheral bitstream and core
>   bitstream bundled into FIT image.
> - Support loadable property for core bitstream. User can set loadable
>   in DDR for better performance. This loading would be done in one large
>   chunk instead of chunk by chunk loading with small memory buffer.
> ---
>  arch/arm/dts/socfpga_arria10_socdk_sdmmc.dts       |  18 +
>  .../include/mach/fpga_manager_arria10.h            |  39 +-
>  drivers/fpga/socfpga_arria10.c                     | 417
> ++++++++++++++++++++-
>  3 files changed, 457 insertions(+), 17 deletions(-)
> 
> diff --git a/arch/arm/dts/socfpga_arria10_socdk_sdmmc.dts
> b/arch/arm/dts/socfpga_arria10_socdk_sdmmc.dts
> index 998d811..dc55618 100644
> --- a/arch/arm/dts/socfpga_arria10_socdk_sdmmc.dts
> +++ b/arch/arm/dts/socfpga_arria10_socdk_sdmmc.dts
> @@ -18,6 +18,24 @@
>  /dts-v1/;
>  #include "socfpga_arria10_socdk.dtsi"
>  
> +/ {
> +     chosen {
> +             firmware-loader = &fs_loader0;
> +     };
> +
> +     fs_loader0: fs-loader@0 {
> +             u-boot,dm-pre-reloc;
> +             compatible = "u-boot,fs-loader";
> +             phandlepart = <&mmc 1>;
> +     };
> +};
> +
> +&fpga_mgr {
> +     u-boot,dm-pre-reloc;
> +     altr,bitstream = "fit_spl_fpga.itb";
> +     altr,bitstream-core = "fit_spl_fpga.itb";
> +};
> +
>  &mmc {
>       u-boot,dm-pre-reloc;
>       status = "okay";
> 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 09d13f6..683c84c 100644
> --- a/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h
> +++ b/arch/arm/mach-socfpga/include/mach/fpga_manager_arria10.h
> @@ -1,9 +1,13 @@
>  /* SPDX-License-Identifier: GPL-2.0 */
>  /*
> - * Copyright (C) 2017 Intel Corporation <www.intel.com>
> + * Copyright (C) 2017-2019 Intel Corporation <www.intel.com>
>   * All rights reserved.
>   */
>  
> 
[...]   }
> +
> +     if (!is_fpgamgr_early_user_mode() || is_fpgamgr_user_mode()) {
> +             fpga_node_name = "fpga-1";
> +             printf("FPGA: Start to program peripheral bitstream ...\n");
> +     } else if (!is_fpgamgr_user_mode()) {
> +             fpga_node_name = "fpga-2";
> +             printf("FPGA: Start to program core bitstream ...\n");
> +     }

Why are you relying on the node name to define the core / periph RBF? Would
it not be better to define this in a property?  how would one have multiple
core and periph rbfs in a single fit image?

--dalon

> +
> +     node_offset = fit_image_get_node(buffer_p, fpga_node_name);
> +     if (node_offset < 0) {
> +             debug("FPGA: Could not find node '%s' in FIT\n",
> +                  fpga_node_name);
> +             return -ENOENT;
> +     }
> +
> +     const char *uname = fit_get_name(buffer_p, node_offset, NULL);
> +
> +     if (uname)
> +             debug("FPGA: %s\n", uname);
> +
> +     ret = fit_image_get_data_position(buffer_p, node_offset, &rbf_offset);
> +     if (ret < 0) {
> +             debug("FPGA: Could not find data position (err=%d)\n", ret);
> +             return -ENOENT;
> +     }
> +
> +     ret = fit_image_get_data_size(buffer_p, node_offset, &rbf_size);
> +     if (ret < 0) {
> +             debug("FPGA: Could not find data size (err=%d)\n", ret);
> +             return -ENOENT;
> +     }
> +
> +     ret = fit_image_get_load(buffer_p, node_offset, (ulong *)loadable);
> +     if (ret < 0) {
> +             debug("FPGA: Could not find loadable (err=%d)\n", ret);
> +             debug("FPGA: Using default buffer and size\n");
> +     } else {
> +             buffer_p = (u32 *)*loadable;
> +             buffer_size = rbf_size;
> +             debug("FPGA: Found loadable address = 0x%x\n", *loadable);
> +     }
> +
> +     debug("FPGA: External data: offset = 0x%x, size = 0x%x\n",
> +           rbf_offset, rbf_size);
> +
> +     fpga_loadfs->remaining = rbf_size;
> +
> +     /*
> +      * Determine buffer size vs bitstream size, and calculating number of
> +      * chunk by chunk transfer is required due to smaller buffer size
> +      * compare to bitstream
> +      */
> +     if (rbf_size <= buffer_size) {
> +             /* Loading whole bitstream into buffer */
> +             buffer_size = rbf_size;
> +             fpga_loadfs->remaining = 0;
> +     } else {
> +             fpga_loadfs->remaining -= buffer_size;
> +     }
> +
> +     fpga_loadfs->offset = rbf_offset;
> +     /* Loading bitstream into buffer */
> +     ret = request_firmware_into_buf(dev,
> +                                     fpga_loadfs->fpga_fsinfo->filename,
> +                                     buffer_p,
> +                                     buffer_size,
> +                                     fpga_loadfs->offset);
> +     if (ret < 0) {
> +             debug("FPGA: Failed to read bitstream from flash.\n");
> +             return -ENOENT;
> +     }
> +
> +     /* Update next reading bitstream offset */
> +     fpga_loadfs->offset += buffer_size;
> +
> +     /* Getting info about bitstream types */
> +     get_rbf_image_info(&fpga_loadfs->rbfinfo, (u16 *)buffer_p);
> +
> +     /* Update the final addr for bitstream */
> +     *buffer = (u32)buffer_p;
> +
> +     /* Update the size of bitstream to be programmed into FPGA */
> +     *buffer_bsize = buffer_size;
> +
> +     return 0;
> +}
> +
> +static int subsequent_loading_rbf_to_buffer(struct udevice *dev,
> +                                     struct fpga_loadfs_info *fpga_loadfs,
> +                                     u32 *buffer, size_t *buffer_bsize)
> +{
> +     int ret = 0;
> +     u32 *buffer_p = (u32 *)*buffer;
> +
> +     /* Read the bitstream chunk by chunk. */
> +     if (fpga_loadfs->remaining > *buffer_bsize) {
> +             fpga_loadfs->remaining -= *buffer_bsize;
> +     } else {
> +             *buffer_bsize = fpga_loadfs->remaining;
> +             fpga_loadfs->remaining = 0;
> +     }
> +
> +     ret = request_firmware_into_buf(dev,
> +                                     fpga_loadfs->fpga_fsinfo->filename,
> +                                     buffer_p,
> +                                     *buffer_bsize,
> +                                     fpga_loadfs->offset);
> +     if (ret < 0) {
> +             debug("FPGA: Failed to read bitstream from flash.\n");
> +             return -ENOENT;
> +     }
> +
> +     /* Update next reading bitstream offset */
> +     fpga_loadfs->offset += *buffer_bsize;
> +
> +     return 0;
> +}
> +
> +int socfpga_loadfs(fpga_fs_info *fpga_fsinfo, const void *buf, size_t bsize,
> +                     u32 offset)
> +{
> +     struct fpga_loadfs_info fpga_loadfs;
> +     int status = 0;
> +     int ret = 0;
> +     u32 buffer = (u32)buf;
> +     size_t buffer_sizebytes = bsize;
> +     size_t buffer_sizebytes_ori = bsize;
> +     size_t total_sizeof_image = 0;
> +     struct udevice *dev;
> +
> +     ret = uclass_get_device(UCLASS_FS_FIRMWARE_LOADER, 0, &dev);
> +     if (ret)
> +             return ret;
> +
> +     memset(&fpga_loadfs, 0, sizeof(fpga_loadfs));
> +
> +     WATCHDOG_RESET();
> +
> +     fpga_loadfs.fpga_fsinfo = fpga_fsinfo;
> +     fpga_loadfs.offset = offset;
> +
> +     printf("FPGA: Start to program ...\n");
> +
> +     /*
> +      * Note: Both buffer and buffer_sizebytes values can be altered by
> +      * function below.
> +      */
> +     ret = first_loading_rbf_to_buffer(dev, &fpga_loadfs, &buffer,
> +                                        &buffer_sizebytes);
> +     if (ret)
> +             return ret;
> +
> +     if (fpga_loadfs.rbfinfo.section == core_section &&
> +             !(is_fpgamgr_early_user_mode() && !is_fpgamgr_user_mode())) {
> +             debug("FPGA : Must be in Early Release mode to program ");
> +             debug("core bitstream.\n");
> +             return 0;
> +     }
> +
> +     /* Disable all signals from HPS peripheral controller to FPGA */
> +     writel(0, &system_manager_base->fpgaintf_en_global);
> +
> +     /* Disable all axi bridges (hps2fpga, lwhps2fpga & fpga2hps) */
> +     socfpga_bridges_reset();
> +
> +     if (fpga_loadfs.rbfinfo.section == periph_section) {
> +             /* Initialize the FPGA Manager */
> +             status = fpgamgr_program_init((u32 *)buffer, buffer_sizebytes);
> +             if (status) {
> +                     debug("FPGA: Init with peripheral bitstream failed.\n");
> +                     return -EPERM;
> +             }
> +     }
> +
> +     WATCHDOG_RESET();
> +
> +     /* Transfer bitstream to FPGA Manager */
> +     fpgamgr_program_write((void *)buffer, buffer_sizebytes);
> +
> +     total_sizeof_image += buffer_sizebytes;
> +
> +     WATCHDOG_RESET();
> +
> +     while (fpga_loadfs.remaining) {
> +             ret = subsequent_loading_rbf_to_buffer(dev,
> +                                                     &fpga_loadfs,
> +                                                     &buffer,
> +                                                     &buffer_sizebytes_ori);
> +
> +             if (ret)
> +                     return ret;
> +
> +             /* Transfer data to FPGA Manager */
> +             fpgamgr_program_write((void *)buffer,
> +                                     buffer_sizebytes_ori);
> +
> +             total_sizeof_image += buffer_sizebytes_ori;
> +
> +             WATCHDOG_RESET();
> +     }
> +
> +     if (fpga_loadfs.rbfinfo.section == periph_section) {
> +             if (fpgamgr_wait_early_user_mode() != -ETIMEDOUT) {
> +                     config_pins(gd->fdt_blob, "shared");
> +                     puts("FPGA: Early Release Succeeded.\n");
> +             } else {
> +                     debug("FPGA: Failed to see Early Release.\n");
> +                     return -EIO;
> +             }
> +
> +             /* For monolithic bitstream */
> +             if (is_fpgamgr_user_mode()) {
> +                     /* Ensure the FPGA entering config done */
> +                     status = fpgamgr_program_finish();
> +                     if (status)
> +                             return status;
> +
> +                     config_pins(gd->fdt_blob, "fpga");
> +                     puts("FPGA: Enter user mode.\n");
> +             }
> +     } else if (fpga_loadfs.rbfinfo.section == core_section) {
> +             /* Ensure the FPGA entering config done */
> +             status = fpgamgr_program_finish();
> +             if (status)
> +                     return status;
> +
> +             config_pins(gd->fdt_blob, "fpga");
> +             puts("FPGA: Enter user mode.\n");
> +     } else {
> +             debug("FPGA: Config Error: Unsupported bitstream type.\n");
> +             return -ENOEXEC;
> +     }
> +
> +     return (int)total_sizeof_image;
> +}
> +#endif
> +
> +/* This function is used to load the core bitstream from the OCRAM. */
>  int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
>  {
> -     int status;
> +     unsigned long status;
> +     struct rbf_info rbfinfo;
>  
> -     /* disable all signals from hps peripheral controller to fpga */
> +     memset(&rbfinfo, 0, sizeof(rbfinfo));
> +
> +     /* Disable all signals from hps peripheral controller to fpga */
>       writel(0, &system_manager_base->fpgaintf_en_global);
>  
> -     /* disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */
> +     /* Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */
>       socfpga_bridges_reset();
>  
> -     /* Initialize the FPGA Manager */
> -     status = fpgamgr_program_init((u32 *)rbf_data, rbf_size);
> -     if (status)
> -             return status;
> +     /* Getting info about bitstream types */
> +     get_rbf_image_info(&rbfinfo, (u16 *)rbf_data);
> +
> +     if (rbfinfo.section == periph_section) {
> +             /* Initialize the FPGA Manager */
> +             status = fpgamgr_program_init((u32 *)rbf_data, rbf_size);
> +             if (status)
> +                     return status;
> +     }
> +
> +     if (rbfinfo.section == core_section &&
> +             !(is_fpgamgr_early_user_mode() && !is_fpgamgr_user_mode())) {
> +             debug("FPGA : Must be in early release mode to program ");
> +             debug("core bitstream.\n");
> +             return 0;
> +     }
>  
> -     /* Write the RBF data to FPGA Manager */
> +     /* Write the bitstream to FPGA Manager */
>       fpgamgr_program_write(rbf_data, rbf_size);
>  
> -     return fpgamgr_program_finish();
> +     status = fpgamgr_program_finish();
> +     if (status) {
> +             config_pins(gd->fdt_blob, "fpga");
> +             puts("FPGA: Enter user mode.\n");
> +     }
> +
> +     return status;
>  }

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to