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