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

Dalon L Westergreen dalon.westergreen at linux.intel.com
Fri Feb 1 20:12:39 UTC 2019


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



More information about the U-Boot mailing list