[U-Boot,v3,08/20] arm: socfpga: Add drivers for programing FPGA from flash

Message ID 1507882137-27841-9-git-send-email-tien.fong.chee@intel.com
State Superseded
Delegated to: Marek Vasut
Headers show
Series
  • Add FPGA, SDRAM, SPL loadfs U-boot & booting to console
Related show

Commit Message

Chee, Tien Fong Oct. 13, 2017, 8:08 a.m.
From: Tien Fong Chee <tien.fong.chee@intel.com>

These drivers handle FPGA program operation from flash loading
RBF to memory and then to program FPGA.

Signed-off-by: Tien Fong Chee <tien.fong.chee@intel.com>
---
 .../include/mach/fpga_manager_arria10.h            |  28 ++
 drivers/fpga/socfpga_arria10.c                     | 435 ++++++++++++++++++++-
 include/altera.h                                   |   6 +
 3 files changed, 467 insertions(+), 2 deletions(-)

Comments

Dinh Nguyen Oct. 16, 2017, 3:33 p.m. | #1
On 10/13/2017 03:08 AM, tien.fong.chee@intel.com wrote:
> From: Tien Fong Chee <tien.fong.chee@intel.com>
> 
> These drivers handle FPGA program operation from flash loading
> RBF to memory and then to program FPGA.
> 
> Signed-off-by: Tien Fong Chee <tien.fong.chee@intel.com>
> ---
>  .../include/mach/fpga_manager_arria10.h            |  28 ++
>  drivers/fpga/socfpga_arria10.c                     | 435 ++++++++++++++++++++-
>  include/altera.h                                   |   6 +
>  3 files changed, 467 insertions(+), 2 deletions(-)

Yikes, 467 changes in 1 patch and 2 line commit message? Anyway you can
split up the patch to smaller parts? And please update the commit
message to be a bit more descriptive?

Thanks,
Dinh
Chee, Tien Fong Oct. 24, 2017, 5:52 a.m. | #2
On Isn, 2017-10-16 at 10:33 -0500, Dinh Nguyen wrote:
> 

> On 10/13/2017 03:08 AM, tien.fong.chee@intel.com wrote:

> > 

> > From: Tien Fong Chee <tien.fong.chee@intel.com>

> > 

> > These drivers handle FPGA program operation from flash loading

> > RBF to memory and then to program FPGA.

> > 

> > Signed-off-by: Tien Fong Chee <tien.fong.chee@intel.com>

> > ---

> >  .../include/mach/fpga_manager_arria10.h            |  28 ++

> >  drivers/fpga/socfpga_arria10.c                     | 435

> > ++++++++++++++++++++-

> >  include/altera.h                                   |   6 +

> >  3 files changed, 467 insertions(+), 2 deletions(-)

> Yikes, 467 changes in 1 patch and 2 line commit message? Anyway you

> can

> split up the patch to smaller parts? And please update the commit

> message to be a bit more descriptive?

> 

I can improve the commit messages. This patch serves for one purpose,
adding all necessary functions required by fpga loadfs, so that fpga
lodfs can support implementation as described above.

> Thanks,

> Dinh

Patch

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 <asm/cache.h>
+
 #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 <altera.h>
 #include <common.h>
 #include <errno.h>
+#include <fat.h>
+#include <fs.h>
+#include <fdtdec.h>
+#include <load_fs.h>
+#include <malloc.h>
+#include <part.h>
+#include <spl.h>
 #include <wait_bit.h>
 #include <watchdog.h>
 
@@ -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