@@ -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 = "ghrd_10as066n2.periph.rbf.mkimage";
+ altr,bitstream-core = "ghrd_10as066n2.core.rbf.mkimage";
+};
+
&mmc {
u-boot,dm-pre-reloc;
status = "okay";
@@ -1,9 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
- * Copyright (C) 2017 Intel Corporation <www.intel.com>
+ * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
* All rights reserved.
*/
+#include <altera.h>
+#include <image.h>
+
#ifndef _FPGA_MANAGER_ARRIA10_H_
#define _FPGA_MANAGER_ARRIA10_H_
@@ -51,6 +54,10 @@
#define ALT_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SET_MSK BIT(24)
#define ALT_FPGAMGR_IMGCFG_CTL_02_CDRATIO_LSB 16
+#define FPGA_SOCFPGA_A10_RBF_UNENCRYPTED 0xa65c
+#define FPGA_SOCFPGA_A10_RBF_ENCRYPTED 0xa65d
+#define FPGA_SOCFPGA_A10_RBF_PERIPH 0x0001
+#define FPGA_SOCFPGA_A10_RBF_CORE 0x8001
#ifndef __ASSEMBLY__
struct socfpga_fpga_manager {
@@ -88,12 +95,41 @@ struct socfpga_fpga_manager {
u32 imgcfg_fifo_status;
};
+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 fpga_loadfs_info {
+ fpga_fs_info *fpga_fsinfo;
+ u32 remaining;
+ u32 offset;
+ u32 datacrc;
+ struct rbf_info rbfinfo;
+ struct image_header header;
+};
+
/* 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);
-
+int is_fpgamgr_early_user_mode(void);
+const char *get_fpga_filename(const void *fdt, int *len, u32 rbf_type);
+int socfpga_loadfs(fpga_fs_info *fpga_fsinfo, const void *buf, size_t bsize,
+ u32 offset);
#endif /* __ASSEMBLY__ */
#endif /* _FPGA_MANAGER_ARRIA10_H_ */
@@ -21,6 +21,15 @@ config FPGA_SOCFPGA
This provides common functionality for Gen5 and Arria10 devices.
+config FPGA_SOCFPGA_A10_CRC_CHECK
+ bool "Enable CRC cheking on Arria10 FPGA bistream"
+ default y if FPGA_SOCFPGA
+ help
+ Enable the CRC checking on Arria 10 FPGA bitstream
+
+ This provides CRC checking to ensure integrated of Arria 10 FPGA
+ bitstream is programmed into FPGA.
+
config FPGA_CYCLON2
bool "Enable Altera FPGA driver for Cyclone II"
depends on FPGA_ALTERA
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (C) 2017 Intel Corporation <www.intel.com>
+ * Copyright (C) 2017-2018 Intel Corporation <www.intel.com>
*/
#include <asm/io.h>
@@ -10,8 +10,11 @@
#include <asm/arch/sdram.h>
#include <asm/arch/misc.h>
#include <altera.h>
+#include <asm/arch/pinmux.h>
#include <common.h>
+#include <dm/ofnode.h>
#include <errno.h>
+#include <fs_loader.h>
#include <wait_bit.h>
#include <watchdog.h>
@@ -64,7 +67,7 @@ static int wait_for_user_mode(void)
1, FPGA_TIMEOUT_MSEC, false);
}
-static int is_fpgamgr_early_user_mode(void)
+int is_fpgamgr_early_user_mode(void)
{
return (readl(&fpga_manager_base->imgcfg_stat) &
ALT_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE_SET_MSK) != 0;
@@ -447,13 +450,368 @@ int fpgamgr_program_finish(void)
return 0;
}
+const char *get_fpga_filename(const void *fdt, int *len, u32 rbf_type)
+{
+ const char *fpga_filename = NULL;
+ int node_offset;
+
+ fdtdec_find_aliases_for_id(gd->fdt_blob, "fpga_mgr",
+ COMPAT_ALTERA_SOCFPGA_FPGA0,
+ &node_offset, 1);
+
+ ofnode fpgamgr_node = offset_to_ofnode(node_offset);
+
+ if (ofnode_valid(fpgamgr_node)) {
+ if (rbf_type == FPGA_SOCFPGA_A10_RBF_CORE)
+ fpga_filename = ofnode_read_string(fpgamgr_node,
+ "altr,bitstream-core");
+ else if (rbf_type == FPGA_SOCFPGA_A10_RBF_PERIPH)
+ fpga_filename = ofnode_read_string(fpgamgr_node,
+ "altr,bitstream");
+ }
+
+ return fpga_filename;
+}
+
+static void get_rbf_image_info(struct rbf_info *rbf, u16 *buffer)
+{
+ /*
+ * Magic ID starting at:
+ * -> 1st dword[15:0] in periph.rbf
+ * -> 2nd dword[15:0] in core.rbf
+ * Note: dword == 32 bits
+ */
+ u32 word_reading_max = 2;
+ u32 i;
+
+ for (i = 0; i < word_reading_max; i++) {
+ if (*(buffer + i) == FPGA_SOCFPGA_A10_RBF_UNENCRYPTED) {
+ rbf->security = unencrypted;
+ } else if (*(buffer + i) == FPGA_SOCFPGA_A10_RBF_ENCRYPTED) {
+ rbf->security = encrypted;
+ } else if (*(buffer + i + 1) ==
+ FPGA_SOCFPGA_A10_RBF_UNENCRYPTED) {
+ rbf->security = unencrypted;
+ } else if (*(buffer + i + 1) ==
+ FPGA_SOCFPGA_A10_RBF_ENCRYPTED) {
+ rbf->security = encrypted;
+ } else {
+ rbf->security = invalid;
+ continue;
+ }
+
+ /* PERIPH RBF(buffer + i + 1), CORE RBF(buffer + i + 2) */
+ if (*(buffer + i + 1) == FPGA_SOCFPGA_A10_RBF_PERIPH) {
+ rbf->section = periph_section;
+ break;
+ } else if (*(buffer + i + 1) == FPGA_SOCFPGA_A10_RBF_CORE) {
+ rbf->section = core_section;
+ break;
+ } else if (*(buffer + i + 2) == FPGA_SOCFPGA_A10_RBF_PERIPH) {
+ rbf->section = periph_section;
+ break;
+ } else if (*(buffer + i + 2) == FPGA_SOCFPGA_A10_RBF_CORE) {
+ rbf->section = core_section;
+ break;
+ }
+
+ rbf->section = unknown;
+ break;
+
+ WATCHDOG_RESET();
+ }
+}
+
+#ifdef CONFIG_FS_LOADER
+static int first_loading_rbf_to_buffer(struct udevice *dev,
+ struct fpga_loadfs_info *fpga_loadfs,
+ u32 *buffer, u32 *buffer_bsize)
+{
+ u32 *buffer_p_after_header = NULL;
+ u32 buffersz_after_header = 0;
+ u32 totalsz_header_rbf = 0;
+ u32 *buffer_p = (u32 *)*buffer;
+ struct image_header *header = &(fpga_loadfs->header);
+ size_t buffer_size = *buffer_bsize;
+ int ret = 0;
+
+ /* Load mkimage header into buffer */
+ ret = request_firmware_into_buf(dev,
+ fpga_loadfs->fpga_fsinfo->filename,
+ header,
+ sizeof(struct image_header),
+ fpga_loadfs->offset);
+ if (ret < 0) {
+ debug("FPGA: Failed to read RBF mkimage header from flash.\n");
+ return -ENOENT;
+ }
+
+ WATCHDOG_RESET();
+
+ if (!image_check_magic(header)) {
+ debug("FPGA: Bad Magic Number.\n");
+ return -EBADF;
+ }
+
+ if (!image_check_hcrc(header)) {
+ debug("FPGA: Bad Header Checksum.\n");
+ return -EPERM;
+ }
+
+ /* Getting RBF data size from mkimage header */
+ fpga_loadfs->remaining = image_get_data_size(header);
+
+ /* Calculate total size of both RBF with mkimage header */
+ totalsz_header_rbf = fpga_loadfs->remaining +
+ sizeof(struct image_header);
+
+ /*
+ * Determine buffer size vs RBF size, and calculating number of
+ * chunk by chunk transfer is required due to smaller buffer size
+ * compare to RBF
+ */
+ if (totalsz_header_rbf > buffer_size) {
+ /* Calculate size of RBF in the buffer */
+ buffersz_after_header =
+ buffer_size - sizeof(struct image_header);
+ fpga_loadfs->remaining -= buffersz_after_header;
+ } else {
+ /* Loading whole RBF into buffer */
+ buffer_size = totalsz_header_rbf;
+ /* Calculate size of RBF in the buffer */
+ buffersz_after_header =
+ buffer_size - sizeof(struct image_header);
+ fpga_loadfs->remaining = 0;
+ }
+
+ /* Loading mkimage header and RBFinto 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 RBF mkimage header and RBF from ");
+ debug("flash.\n");
+ return -ENOENT;
+ }
+
+ /*
+ * Getting pointer of RBF starting address where it's
+ * right after mkimage header
+ */
+ buffer_p_after_header =
+ (u32 *)((u_char *)buffer_p + sizeof(struct image_header));
+
+ /* Update next reading RBF offset */
+ fpga_loadfs->offset += buffer_size;
+
+ /* Getting info about RBF types */
+ get_rbf_image_info(&fpga_loadfs->rbfinfo, (u16 *)buffer_p_after_header);
+
+ /*
+ * Update the starting addr of RBF to init FPGA & programming RBF
+ * into FPGA
+ */
+ *buffer = (u32)buffer_p_after_header;
+
+ /* Update the size of RBF to be programmed into FPGA */
+ *buffer_bsize = buffersz_after_header;
+
+#ifdef FPGA_SOCFPGA_A10_CRC_CHECK
+ fpga_loadfs->datacrc = crc32(fpga_loadfs->datacrc,
+ (u_char *)buffer_p_after_header,
+ buffersz_after_header);
+#endif
+
+if (fpga_loadfs->remaining == 0) {
+#ifdef FPGA_SOCFPGA_A10_CRC_CHECK
+ if (fpga_loadfs->datacrc != image_get_dcrc(&(fpga_loadfs->header))) {
+ debug("FPGA: Bad Data Checksum.\n");
+ return -EPERM;
+ }
+#endif
+}
+ return 0;
+}
+
+static int subsequent_loading_rbf_to_buffer(struct udevice *dev,
+ struct fpga_loadfs_info *fpga_loadfs,
+ u32 *buffer, u32 *buffer_bsize)
+{
+ int ret = 0;
+ u32 *buffer_p = (u32 *)*buffer;
+
+ /* Read the RBF 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 RBF from flash.\n");
+ return -ENOENT;
+ }
+
+#ifdef FPGA_SOCFPGA_A10_CRC_CHECK
+ fpga_loadfs->datacrc = crc32(fpga_loadfs->datacrc,
+ (unsigned char *)buffer_p,
+ *buffer_bsize);
+#endif
+
+if (fpga_loadfs->remaining == 0) {
+#ifdef FPGA_SOCFPGA_A10_CRC_CHECK
+ if (fpga_loadfs->datacrc != image_get_dcrc(&(fpga_loadfs->header))) {
+ debug("FPGA: Bad Data Checksum.\n");
+ return -EPERM;
+ }
+#endif
+}
+
+ /* Update next reading RBF 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;
+ u32 buffer_ori = (u32) buf;
+ size_t buffer_sizebytes = bsize;
+ size_t buffer_sizebytes_ori = bsize;
+ size_t total_sizeof_mkimage = sizeof(struct image_header);
+ 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("Start to program FPGA ...\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 : FPGA must be in Early Release mode to program ");
+ debug("core.\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 periph rbf failed.\n");
+ return -EPERM;
+ }
+ }
+
+ WATCHDOG_RESET();
+
+ /* Transfer RBF to FPGA Manager */
+ fpgamgr_program_write((void *)buffer, buffer_sizebytes);
+
+ total_sizeof_mkimage += buffer_sizebytes;
+
+ WATCHDOG_RESET();
+
+ while (fpga_loadfs.remaining) {
+ ret = subsequent_loading_rbf_to_buffer(dev,
+ &fpga_loadfs,
+ &buffer_ori,
+ &buffer_sizebytes_ori);
+
+ if (ret)
+ return ret;
+
+ /* Transfer data to FPGA Manager */
+ fpgamgr_program_write((void *)buffer_ori,
+ buffer_sizebytes_ori);
+
+ total_sizeof_mkimage += 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("Config Error: Unsupported FGPA RBF type.\n");
+ return -ENOEXEC;
+ }
+
+ return (int)total_sizeof_mkimage;
+}
+#endif
+
/*
- * FPGA Manager to program the FPGA. This is the interface used by FPGA driver.
- * Return 0 for sucess, non-zero for error.
+ * This function is used to load the core RBF from the OCRAM where the location
+ * of the image is defined in the load property in the FIT image source file
+ * (.its)
*/
int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
{
- int status;
+ unsigned long status;
+ struct rbf_info rbfinfo;
+
+ memset(&rbfinfo, 0, sizeof(rbfinfo));
/* disable all signals from hps peripheral controller to fpga */
writel(0, &system_manager_base->fpgaintf_en_global);
@@ -461,13 +819,31 @@ int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
/* 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 RBF 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 : FPGA must be in Early Release mode to program ");
+ debug("core.\n");
+ return 0;
+ }
/* Write the RBF data 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;
}