[U-Boot] [PATCH v7 3/7] ARM: socfpga: Add FPGA drivers for Arria 10 FPGA bitstream loading

Dalon L Westergreen
2019-02-01T20:12:39Z

On Thu, 2019-01-31 at 22:51 +0800, tien.fong.chee at intel.com wrote:
> From: Tien Fong Chee <tien.fong.chee@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.chee@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 at 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;
> }