From patchwork Fri Oct 13 08:08:45 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: 825257 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 3yD0pg3QpMz9sPm for ; Fri, 13 Oct 2017 19:13:31 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 1F7CEC21FD7; Fri, 13 Oct 2017 08:12:27 +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=none 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 BD240C21FA2; Fri, 13 Oct 2017 08:10:11 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id C3D14C21FEE; Fri, 13 Oct 2017 08:09:53 +0000 (UTC) Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by lists.denx.de (Postfix) with ESMTPS id 43B7EC21FA1 for ; Fri, 13 Oct 2017 08:09:44 +0000 (UTC) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga103.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 13 Oct 2017 01:09:42 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.43,369,1503385200"; d="scan'208";a="146036826" Received: from tfchee-mobl.gar.corp.intel.com (HELO tienfong.fm.intel.com, ) ([10.226.242.149]) by orsmga002.jf.intel.com with ESMTP; 13 Oct 2017 01:09:28 -0700 From: tien.fong.chee@intel.com To: u-boot@lists.denx.de Date: Fri, 13 Oct 2017 16:08:45 +0800 Message-Id: <1507882137-27841-9-git-send-email-tien.fong.chee@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1507882137-27841-1-git-send-email-tien.fong.chee@intel.com> References: <1507882137-27841-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 v3 08/20] arm: socfpga: Add drivers for programing FPGA from flash 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 These drivers handle FPGA program operation from flash loading RBF to memory and then to program FPGA. Signed-off-by: Tien Fong Chee --- .../include/mach/fpga_manager_arria10.h | 28 ++ drivers/fpga/socfpga_arria10.c | 435 ++++++++++++++++++++- include/altera.h | 6 + 3 files changed, 467 insertions(+), 2 deletions(-) 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..1fc5b92 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,8 @@ #ifndef _FPGA_MANAGER_ARRIA10_H_ #define _FPGA_MANAGER_ARRIA10_H_ +#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 +91,37 @@ 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 { + char *interface; + char *dev_part; + char *filename; + int fstype; + u32 remaining; + u32 flash_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); +#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..bfc8700 100644 --- a/drivers/fpga/socfpga_arria10.c +++ b/drivers/fpga/socfpga_arria10.c @@ -13,6 +13,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -22,6 +29,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; @@ -33,6 +44,32 @@ static const struct socfpga_system_manager *system_manager_base = static void fpgamgr_set_cd_ratio(unsigned long ratio); +static struct flash_location default_flash_locations[] = { + { + .name = "mmc", + .storage = FLASH_STORAGE_MMC, + .flags = FLASH_STORAGE_FS, + .devpart = "0:1", + }, +}; + +void set_flash_devpart(char *name, char *devpart) +{ + int i; + u32 size; + + size = ARRAY_SIZE(default_flash_locations); + + for (i = 0; i < size; i++) { + if (!strcmp(default_flash_locations[i].name, name)) + default_flash_locations[i].devpart = devpart; + return; + } + + printf("No flash is found\n"); + return; +} + static uint32_t fpgamgr_get_msel(void) { u32 reg; @@ -181,7 +218,8 @@ static int fpgamgr_set_cdratio_cdwidth(unsigned int cfg_width, u32 *rbf_data, debug("header word %d = %08x\n", 69, rbf_data[69]); debug("header word %d = %08x\n", 229, rbf_data[229]); - debug("read from rbf header: encrypt=%d compress=%d\n", encrypt, compress); + debug("read from rbf header: encrypt=%d compress=%d\n", encrypt, + compress); /* * from the register map description of cdratio in imgcfg_ctrl_02: @@ -362,7 +400,8 @@ static int fpgamgr_program_poll_cd(void) if (reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN_SET_MSK) return 0; - if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK) == 0) { + if ((reg & ALT_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN_SET_MSK) == + 0) { printf("nstatus == 0 while waiting for condone\n"); return -EPERM; } @@ -470,6 +509,7 @@ int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) /* Initialize the FPGA Manager */ status = fpgamgr_program_init((u32 *)rbf_data, rbf_size); + if (status) return status; @@ -478,3 +518,394 @@ 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 flash_read(struct flash_location *location, + void *file_info, + size_t size_read, + u32 *buffer_ptr) +{ + size_t ret = EEXIST; + loff_t actread = 0; + struct flash_info *flashinfo = (struct flash_info *)file_info; + + if (flash_select_fs_dev(location)) + return FPGA_FAIL; + + ret = fs_read(flashinfo->filename, + (u32) buffer_ptr, flashinfo->flash_offset, + size_read, &actread); + + if (ret || actread != size_read) { + printf("Failed to read %s from flash %d ", + flashinfo->filename, + ret); + printf("!= %d.\n", size_read); + return -EPERM; + } else + ret = actread; + + return ret; +} + +static 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; + int ret = 0; + + flashinfo->flash_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 = flash_read(default_flash_locations, flashinfo, + sizeof(struct image_header), buffer_ptr); + + if (ret < 0) { + printf(" 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)) { + printf("FPGA: Bad Magic Number.\n"); + return -EBADF; + } + + if (!image_check_hcrc(header)) { + printf("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 = flash_read(default_flash_locations, flashinfo, + buffer_size, buffer_ptr); + + if (ret < 0) { + printf(" Failed to read mkimage header and rbf data "); + printf("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->flash_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))) { + printf("FPGA: Bad Data Checksum.\n"); + return -EPERM; + } +#endif +} + return 0; +} + +static int fs_flash_read(struct flash_info *flashinfo, u32 *buffer, + u32 *buffer_sizebytes) +{ + int ret = 0; + /* To avoid from keeping re-read the contents */ + size_t buffer_size = *buffer_sizebytes; + u32 *buffer_ptr = (u32 *)*buffer; + u32 flash_addr = flashinfo->flash_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 = flash_read(default_flash_locations, flashinfo, + buffer_size, buffer_ptr); + + if (ret < 0) { + printf(" 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))) { + printf("FPGA: Bad Data Checksum.\n"); + return -EPERM; + } +#endif +} + /* Update next reading rbf data flash offset */ + flash_addr += buffer_size; + + flashinfo->flash_offset = flash_addr; + + /* Update the size of rbf data to be programmed into FPGA */ + *buffer_sizebytes = buffer_size; + + return 0; +} + +char *get_file(void *file_info) +{ + fpga_fs_info *fpga_fsinfo; + + fpga_fsinfo = (fpga_fs_info *)file_info; + + return fpga_fsinfo->filename; +} + +int fs_loading(void *file_info, const void *load_addr, size_t bsize) +{ + struct flash_info flashinfo; + fpga_fs_info *fpga_fsinfo; + 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) load_addr; + + memset(&flashinfo, 0, sizeof(flashinfo)); + + fpga_fsinfo = (fpga_fs_info *)file_info; + flashinfo.interface = fpga_fsinfo->interface; + flashinfo.dev_part = fpga_fsinfo->dev_part; + flashinfo.filename = fpga_fsinfo->filename; + flashinfo.fstype = fpga_fsinfo->fstype; + + WATCHDOG_RESET(); + /* + * 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) { + printf("FPGA: Init with periph rbf failed with error."); + printf("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) + printf("FPGA: Early Release Succeeded.\n"); + else { + printf("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 + printf("FPGA: Enter user mode.\n"); + + } else { + printf("Config Error: Unsupported FGPA raw binary type.\n"); + return -ENOEXEC; + } + + return 0; +} + +int socfpga_loadfs(Altera_desc *desc, const void *buf, size_t bsize, + fpga_fs_info *fpga_fsinfo) +{ + WATCHDOG_RESET(); + + if (fpga_fsinfo->dev_part && fpga_fsinfo->interface) + set_flash_devpart(fpga_fsinfo->interface, + fpga_fsinfo->dev_part); + + return load_fs(default_flash_locations, fpga_fsinfo, buf, bsize); +} +#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