tools: mkimage: Add support to generate FlexSPI Header for i.MX8m

Add struct with Flex SPI Configuration Block and enable generating
fspi header using mkimage.

Refer i.MX 8M Mini Application Processor Reference Manual for
detailed information about parameters for FlexSPI Configuration block.

Signed-off-by: Mamta Shukla <mamta.shukla@leica-geosystems.com>
Signed-off-by: Thomas Haemmerle <thomas.haemmerle@leica-geosystems.com>
Tested-by: Adam Ford <aford173@gmail.com>
Reviewed-by: Fabio Estevam <festevam@denx.de>
Reviewed-by: Andrey Zhizhikin <andrey.zhizhikin@leica-geosystems.com>
diff --git a/tools/Kconfig b/tools/Kconfig
index 117c921..539708f 100644
--- a/tools/Kconfig
+++ b/tools/Kconfig
@@ -98,4 +98,63 @@
 	  optionally sign that file. If you want to enable UEFI capsule
 	  update feature on your target, you certainly need this.
 
+menuconfig FSPI_CONF_HEADER
+	bool "FlexSPI Header Configuration"
+	help
+	  FSPI Header Configuration
+
+config FSPI_CONF_FILE
+	string "FlexSPI Header File"
+	depends on FSPI_CONF_HEADER
+	help
+	  FlexSPI Header File name
+
+config READ_CLK_SOURCE
+	hex "Sampling Clock Source"
+	default 0x00
+	depends on FSPI_CONF_HEADER
+	help
+	  Sample Clock source for Flash, default is internal loopback clock
+
+config DEVICE_TYPE
+	hex "Flash Type"
+	default 0x01
+	depends on FSPI_CONF_HEADER
+	help
+	  Flash type: Serial NOR (0X01) and Serial NAND (0x02)
+
+config FLASH_PAD_TYPE
+	hex "Flash Pad Type"
+	default 0x01
+	depends on FSPI_CONF_HEADER
+	help
+	  Flash Pad type :
+	  Single Pad 0x01
+	  Dual Pads  0x02
+	  Quad Pad   0x04
+	  Octal Pad  0x08
+
+config SERIAL_CLK_FREQUENCY
+	hex "Serial Clock Frequency"
+	default 0x02
+	depends on FSPI_CONF_HEADER
+	help
+	  Chip specific frequency: other value 30MHz
+	  1-30MHz  2-50MHz 3-60MHz 4-75MHz 5-80MHz 6-100MHz 7-133MHz 8-166MHz
+
+config LUT_CUSTOM_SEQUENCE
+	hex "Enable Custom Look Up Table(LUT) Sequence"
+	default 0x00
+	depends on FSPI_CONF_HEADER
+	help
+	  0 - Use predefined LUT Sequence
+	  1 - Use LUT Sequence provided
+
+config LUT_SEQUENCE
+	string "Look Up Table Sequence"
+	default "0x0b, 0x04, 0x18, 0x08, 0x08, 0x30, 0x04, 0x24"
+	depends on FSPI_CONF_HEADER
+	help
+	  Look Up Table Sequence
+
 endmenu
diff --git a/tools/imx8mimage.c b/tools/imx8mimage.c
index 52baf4c..a4699de 100644
--- a/tools/imx8mimage.c
+++ b/tools/imx8mimage.c
@@ -120,7 +120,6 @@
 			rom_version = ROM_V1;
 		}
 		break;
-
 	}
 }
 
@@ -412,9 +411,75 @@
 		imx_header[index].boot_data.plugin);
 }
 
+#ifdef CONFIG_FSPI_CONF_HEADER
+static int generate_fspi_header (int ifd)
+{
+	int ret, i = 0;
+	char *val;
+	char lut_str[] = CONFIG_LUT_SEQUENCE;
+
+	fspi_conf fspi_conf_data = {
+	.tag = {0x46, 0x43, 0x46, 0x42},
+	.version = {0x00, 0x00, 0x01, 0x56},
+	.reserved_1 = {0x00, 0x00, 0x00, 0x00},
+	.read_sample = CONFIG_READ_CLK_SOURCE,
+	.datahold =  0x03,
+	.datasetup = 0x03,
+	.coladdrwidth = 0x00,
+	.devcfgenable = 0x00,
+	.reserved_2 = {0x00, 0x00, 0x00},
+	.devmodeseq =  {0x00, 0x00, 0x00, 0x00},
+	.devmodearg =  {0x00, 0x00, 0x00, 0x00},
+	.cmd_enable =  0x00,
+	.reserved_3 = {0x00},
+	.cmd_seq = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+							0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	.cmd_arg = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+							0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	.controllermisc = {0x00, 0x00, 0x00, 0x00},
+	.dev_type = CONFIG_DEVICE_TYPE,
+	.sflash_pad = CONFIG_FLASH_PAD_TYPE,
+	.serial_clk = CONFIG_SERIAL_CLK_FREQUENCY,
+	.lut_custom = CONFIG_LUT_CUSTOM_SEQUENCE,
+	.reserved_4 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	.sflashA1  =  {0x00, 0x00, 0x00, 0x10},
+	.sflashA2 = {0x00, 0x00, 0x00, 0x00},
+	.sflashB1 = {0x00, 0x00, 0x00, 0x00},
+	.sflashB2 =  {0x00, 0x00, 0x00, 0x00},
+	.cspadover = {0x00, 0x00, 0x00, 0x00},
+	.sclkpadover = {0x00, 0x00, 0x00, 0x00},
+	.datapadover = {0x00, 0x00, 0x00, 0x00},
+	.dqspadover = {0x00, 0x00, 0x00, 0x00},
+	.timeout =  {0x00, 0x00, 0x00, 0x00},
+	.commandInt = {0x00, 0x00, 0x00, 0x00},
+	.datavalid  = {0x00, 0x00, 0x00, 0x00},
+	.busyoffset = {0x00, 0x00},
+	.busybitpolarity = {0x00, 0x00},
+	};
+
+	for (val = strtok(lut_str, ","); val; val = strtok(NULL, ",")) {
+		fspi_conf_data.lut[i++] = strtoul(val, NULL, 16);
+	}
+
+	ret = lseek(ifd, 0, SEEK_CUR);
+	if (write(ifd, &fspi_conf_data, sizeof(fspi_conf_data)) == -1)
+		exit(EXIT_FAILURE);
+
+	ret = lseek(ifd, sizeof(fspi_conf_data), SEEK_CUR);
+
+	return ret;
+}
+#endif
+
 void build_image(int ofd)
 {
 	int file_off, header_hdmi_off = 0, header_image_off;
+
+#ifdef CONFIG_FSPI_CONF_HEADER
+	int fspi_off, fspi_fd;
+	char *fspi;
+#endif
+
 	int hdmi_fd, ap_fd, sld_fd;
 	uint32_t sld_load_addr = 0;
 	uint32_t csf_off, sld_csf_off = 0;
@@ -455,6 +520,20 @@
 
 	header_image_off = file_off + ivt_offset;
 
+#ifdef CONFIG_FSPI_CONF_HEADER
+	fspi = CONFIG_FSPI_CONF_FILE;
+	fspi_fd = open(fspi, O_RDWR | O_CREAT, S_IRWXU);
+	if (fspi_fd < 0) {
+		fprintf(stderr, "Can't open %s: %s\n",
+			fspi, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	fspi_off = generate_fspi_header(fspi_fd);
+	file_off = header_image_off + fspi_off;
+	close(fspi_fd);
+
+#endif
 	ap_fd = open(ap_img, O_RDONLY | O_BINARY);
 	if (ap_fd < 0) {
 		fprintf(stderr, "%s: Can't open: %s\n",