From patchwork Tue Dec 5 07:57:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chee, Tien Fong" X-Patchwork-Id: 844634 X-Patchwork-Delegate: marek.vasut@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3yrZ693nBYz9sPt for ; Tue, 5 Dec 2017 19:04:49 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id B1D1AC21E1D; Tue, 5 Dec 2017 08:00:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id E6D99C21E8A; Tue, 5 Dec 2017 07:59:07 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 0C30EC21E90; Tue, 5 Dec 2017 07:58:48 +0000 (UTC) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by lists.denx.de (Postfix) with ESMTPS id 0C4A9C21E77 for ; Tue, 5 Dec 2017 07:58:42 +0000 (UTC) Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 04 Dec 2017 23:58:42 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.45,363,1508828400"; d="scan'208";a="184140316" Received: from tfchee-mobl.gar.corp.intel.com (HELO tienfong.fm.intel.com, ) ([10.226.242.147]) by fmsmga006.fm.intel.com with ESMTP; 04 Dec 2017 23:58:40 -0800 From: tien.fong.chee@intel.com To: u-boot@lists.denx.de Date: Tue, 5 Dec 2017 15:57:59 +0800 Message-Id: <1512460690-3454-10-git-send-email-tien.fong.chee@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1512460690-3454-1-git-send-email-tien.fong.chee@intel.com> References: <1512460690-3454-1-git-send-email-tien.fong.chee@intel.com> Cc: Marek Vasut , Tien Fong Chee , Ching Liang See , Tien Fong , Westergteen Dalon Subject: [U-Boot] [PATCH v5 09/20] arm: socfpga: Add FPGA drivers for Arria 10 FPGA loadfs X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Tien Fong Chee Add FPGA drivers to support FPGA loadfs to program FPGA. The drivers are designed based on generic firmware loader framework, specific firmware loader handling is defined in fpga_manager_arria10.c. These drivers can handle FPGA program operation from loading RBF image in flash to memory and then to program FPGA. Signed-off-by: Tien Fong Chee --- .../include/mach/fpga_manager_arria10.h | 32 ++ drivers/fpga/socfpga_arria10.c | 371 +++++++++++++++++++++ include/altera.h | 6 + 3 files changed, 409 insertions(+) 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..afcf7d8 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,9 @@ #ifndef _FPGA_MANAGER_ARRIA10_H_ #define _FPGA_MANAGER_ARRIA10_H_ +#include +#include + #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 +92,40 @@ 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 { + struct device_location dev; + char *filename; + int fstype; + u32 remaining; + u32 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); +int fs_flash_preinit(struct flash_info *flashinfo, u32 *buffer, + u32 *buffer_sizebytes); +int fs_flash_read(struct flash_info *flashinfo, u32 *buffer, + u32 *buffer_sizebytes); +#endif +void set_flash_devpart(char *name, char *devpart); #endif /* __ASSEMBLY__ */ diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c index e076bda..6fd1d36 100644 --- a/drivers/fpga/socfpga_arria10.c +++ b/drivers/fpga/socfpga_arria10.c @@ -13,6 +13,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -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; @@ -478,3 +488,364 @@ int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) return fpgamgr_program_finish(); } + +#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 = fdtdec_next_compatible(fdt, 0, + COMPAT_ALTERA_SOCFPGA_FPGA0); + + if (nodeoffset >= 0) { + if (core) + cell = fdt_getprop(fdt, + nodeoffset, + "altr,bitstream_core", + len); + else + cell = fdt_getprop(fdt, nodeoffset, + "altr,bitstream_periph", len); + + 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 = fdtdec_next_compatible(fdt, 0, + COMPAT_ALTERA_SOCFPGA_FPGA0); + + cell = fdt_getprop(fdt, nodeoffset, "altr,bitstream_devpart", len); + + 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 + */ + u32 word_reading_max = 2; + u32 i; + + for (i = 0; i < word_reading_max; i++) { + if (*(buffer + i) == RBF_UNENCRYPTED) /* PERIPH RBF */ + rbf->security = unencrypted; + else if (*(buffer + i) == RBF_ENCRYPTED) + rbf->security = encrypted; + else if (*(buffer + i + 1) == RBF_UNENCRYPTED) /* CORE RBF */ + rbf->security = unencrypted; + else if (*(buffer + i + 1) == RBF_ENCRYPTED) + rbf->security = encrypted; + else { + rbf->security = invalid; + continue; + } + + /* PERIPH RBF(buffer + i + 1), CORE RBF(buffer + i + 2) */ + if (*(buffer + i + 1) == ARRIA10RBF_PERIPH) { + rbf->section = periph_section; + break; + } else if (*(buffer + i + 1) == ARRIA10RBF_CORE) { + rbf->section = core_section; + break; + } else if (*(buffer + i + 2) == ARRIA10RBF_PERIPH) { + rbf->section = periph_section; + break; + } else if (*(buffer + i + 2) == ARRIA10RBF_CORE) { + rbf->section = core_section; + break; + } else { + rbf->section = unknown; + break; + } + } + + return; +} + +int fs_flash_preinit(struct flash_info *flashinfo, + u32 *buffer, u32 *buffer_sizebytes) +{ + u32 *bufferptr_after_header = NULL; + u32 buffersize_after_header = 0; + u32 rbf_header_data_size = 0; + struct firmware *fw = NULL; + int ret = 0; + + flashinfo->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; + + /* Load mkimage header into buffer */ + ret = request_firmware_into_buf(&fw, flashinfo->filename, + &(flashinfo->dev), buffer_ptr, + sizeof(struct image_header), + flashinfo->offset); + + if (ret < 0) { + error(" 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)) { + error("FPGA: Bad Magic Number.\n"); + return -EBADF; + } + + if (!image_check_hcrc(header)) { + error("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 = request_firmware_into_buf(&fw, flashinfo->filename, + &(flashinfo->dev), buffer_ptr, + buffer_size, + flashinfo->offset); + + /*ret = flash_read(default_flash_locations, flashinfo, + buffer_size, buffer_ptr);*/ + + if (ret < 0) { + error(" Failed to read mkimage header and rbf data "); + error("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->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 (flashinfo->remaining == 0) { +#ifdef CONFIG_CHECK_FPGA_DATA_CRC + if (flashinfo->datacrc != + image_get_dcrc(&(flashinfo->header))) { + error("FPGA: Bad Data Checksum.\n"); + return -EPERM; + } +#endif +} + return 0; +} + +int fs_flash_read(struct flash_info *flashinfo, u32 *buffer, + u32 *buffer_sizebytes) +{ + int ret = 0; + struct firmware *fw = NULL; + /* To avoid from keeping re-read the contents */ + size_t buffer_size = *buffer_sizebytes; + u32 *buffer_ptr = (u32 *)*buffer; + u32 flash_addr = flashinfo->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 = request_firmware_into_buf(&fw, flashinfo->filename, + &(flashinfo->dev), buffer_ptr, + buffer_size, + flashinfo->offset); + + /*ret = flash_read(default_flash_locations, flashinfo, + buffer_size, buffer_ptr);*/ + + if (ret < 0) { + error(" 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 (flashinfo->remaining == 0) { +#ifdef CONFIG_CHECK_FPGA_DATA_CRC + if (flashinfo->datacrc != + image_get_dcrc(&(flashinfo->header))) { + error("FPGA: Bad Data Checksum.\n"); + return -EPERM; + } +#endif +} + /* Update next reading rbf data flash offset */ + flash_addr += buffer_size; + + flashinfo->offset = flash_addr; + + /* Update the size of rbf data to be programmed into FPGA */ + *buffer_sizebytes = buffer_size; + + return 0; +} + +int socfpga_loadfs(Altera_desc *desc, const void *buf, size_t bsize, + fpga_fs_info *fpga_fsinfo) +{ + struct flash_info flashinfo; + u32 status = 0; + int ret = 0; + u32 buffer = 0; + u32 buffer_ori = 0; + size_t buffer_sizebytes = 0; + size_t buffer_sizebytes_ori = 0; + buffer_sizebytes = buffer_sizebytes_ori = bsize; + buffer = buffer_ori = (u32) buf; + + memset(&flashinfo, 0, sizeof(flashinfo)); + + flashinfo.filename = fpga_fsinfo->filename; + flashinfo.dev.name = fpga_fsinfo->interface; + flashinfo.dev.devpart = fpga_fsinfo->dev_part; + flashinfo.fstype = fpga_fsinfo->fstype; + + WATCHDOG_RESET(); + + if (!flashinfo.dev.name) { + error("FPGA: Invalid storage device."); + return -EPERM; + } + + /* + * 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 (flashinfo.rbfinfo.section == periph_section) { + /* Initialize the FPGA Manager */ + status = fpgamgr_program_init((u32 *)buffer, buffer_sizebytes); + if (status) { + error("FPGA: Init with periph rbf failed with error."); + error("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 (flashinfo.rbfinfo.section == periph_section) { + if (fpgamgr_wait_early_user_mode() != -ETIMEDOUT) + puts("FPGA: Early Release Succeeded.\n"); + else { + puts("FPGA: Failed to see Early Release.\n"); + return -EIO; + } + } else if (flashinfo.rbfinfo.section == core_section) { + /* Ensure the FPGA entering config done */ + status = fpgamgr_program_finish(); + if (status) + return status; + else + puts("FPGA: Enter user mode.\n"); + + } else { + puts("Config Error: Unsupported FGPA raw binary type.\n"); + return -ENOEXEC; + } + + return 0; +} +#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