Merge commit '4720b83d2c711062cfb55f03591b8f12c897d7cb' of https://github.com/tienfong/uboot_mainline
diff --git a/arch/arm/mach-socfpga/include/mach/misc.h b/arch/arm/mach-socfpga/include/mach/misc.h
index 649d2f6..8460acb 100644
--- a/arch/arm/mach-socfpga/include/mach/misc.h
+++ b/arch/arm/mach-socfpga/include/mach/misc.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (C) 2016-2017 Intel Corporation
+ * Copyright (C) 2016-2021 Intel Corporation
  */
 
 #ifndef _SOCFPGA_MISC_H_
@@ -45,7 +45,12 @@
 #endif
 
 void do_bridge_reset(int enable, unsigned int mask);
+void force_periph_program(unsigned int status);
+bool is_regular_boot_valid(void);
+bool is_periph_program_force(void);
+void set_regular_boot(unsigned int status);
 void socfpga_pl310_clear(void);
 void socfpga_get_managers_addr(void);
+int qspi_flash_software_reset(void);
 
 #endif /* _SOCFPGA_MISC_H_ */
diff --git a/arch/arm/mach-socfpga/include/mach/reset_manager_arria10.h b/arch/arm/mach-socfpga/include/mach/reset_manager_arria10.h
index 19507c2..26faa62 100644
--- a/arch/arm/mach-socfpga/include/mach/reset_manager_arria10.h
+++ b/arch/arm/mach-socfpga/include/mach/reset_manager_arria10.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (C) 2016-2017 Intel Corporation
+ * Copyright (C) 2016-2021 Intel Corporation
  */
 
 #ifndef _RESET_MANAGER_ARRIA10_H_
@@ -22,6 +22,7 @@
 #define RSTMGR_A10_PER1MODRST	0x28
 #define RSTMGR_A10_BRGMODRST	0x2c
 #define RSTMGR_A10_SYSMODRST	0x30
+#define RSTMGR_A10_SYSWARMMASK	0x50
 
 #define RSTMGR_CTRL		RSTMGR_A10_CTRL
 
@@ -115,4 +116,7 @@
 #define ALT_RSTMGR_HDSKEN_FPGAHSEN_SET_MSK	BIT(2)
 #define ALT_RSTMGR_HDSKEN_ETRSTALLEN_SET_MSK	BIT(3)
 
+#define ALT_RSTMGR_FPGAMGRWARMMASK_S2F_SET_MSK	BIT(3)
+#define ALT_RSTMGR_SYSWARMMASK_S2F_SET_MSK	BIT(4)
+
 #endif /* _RESET_MANAGER_ARRIA10_H_ */
diff --git a/arch/arm/mach-socfpga/include/mach/system_manager_arria10.h b/arch/arm/mach-socfpga/include/mach/system_manager_arria10.h
index e4fc6d2..0afe63e 100644
--- a/arch/arm/mach-socfpga/include/mach/system_manager_arria10.h
+++ b/arch/arm/mach-socfpga/include/mach/system_manager_arria10.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (C) 2016-2017 Intel Corporation <www.intel.com>
+ * Copyright (C) 2016-2021 Intel Corporation <www.intel.com>
  */
 
 #ifndef _SYSTEM_MANAGER_ARRIA10_H_
@@ -31,6 +31,11 @@
 #define SYSMGR_A10_NOC_IDLEACK			0xd0
 #define SYSMGR_A10_NOC_IDLESTATUS		0xd4
 #define SYSMGR_A10_FPGA2SOC_CTRL		0xd8
+#define SYSMGR_A10_ROMCODE_CTRL			0x204
+#define SYSMGR_A10_ROMCODE_INITSWSTATE	0x20C
+#define SYSMGR_A10_ROMCODE_QSPIRESETCOMMAND	0x208
+#define SYSMGR_A10_ISW_HANDOFF_BASE		0x230
+#define SYSMGR_A10_ISW_HANDOFF_7		0x1c
 
 #define SYSMGR_SDMMC				SYSMGR_A10_SDMMC
 
diff --git a/arch/arm/mach-socfpga/misc_arria10.c b/arch/arm/mach-socfpga/misc_arria10.c
index bf97805..0ed2adf 100644
--- a/arch/arm/mach-socfpga/misc_arria10.c
+++ b/arch/arm/mach-socfpga/misc_arria10.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (C) 2016-2017 Intel Corporation
+ * Copyright (C) 2016-2021 Intel Corporation
  */
 
 #include <altera.h>
@@ -11,6 +11,7 @@
 #include <miiphy.h>
 #include <netdev.h>
 #include <ns16550.h>
+#include <spi_flash.h>
 #include <watchdog.h>
 #include <asm/arch/misc.h>
 #include <asm/arch/pinmux.h>
@@ -21,6 +22,7 @@
 #include <asm/arch/nic301.h>
 #include <asm/io.h>
 #include <asm/pl310.h>
+#include <linux/sizes.h>
 
 #define PINMUX_UART0_TX_SHARED_IO_OFFSET_Q1_3	0x08
 #define PINMUX_UART0_TX_SHARED_IO_OFFSET_Q2_11	0x58
@@ -29,6 +31,13 @@
 #define PINMUX_UART1_TX_SHARED_IO_OFFSET_Q3_7	0x78
 #define PINMUX_UART1_TX_SHARED_IO_OFFSET_Q4_3	0x98
 
+#define REGULAR_BOOT_MAGIC	0xd15ea5e
+#define PERIPH_RBF_PROG_FORCE	0x50455249
+
+#define QSPI_S25FL_SOFT_RESET_COMMAND	0x00f0ff82
+#define QSPI_N25_SOFT_RESET_COMMAND	0x00000001
+#define QSPI_NO_SOFT_RESET		0x00000000
+
 /*
  * FPGA programming support for SoC FPGA Arria 10
  */
@@ -122,3 +131,118 @@
 	else
 		socfpga_bridges_reset();
 }
+
+/*
+ * This function set/unset flag with number "0x50455249" to
+ * handoff register isw_handoff[7] - 0xffd0624c
+ * This flag is used to force periph RBF program regardless FPGA status
+ * and double periph RBF config are needed on some devices or boards to
+ * stabilize the IO config system.
+ */
+void force_periph_program(unsigned int status)
+{
+	if (status)
+		writel(PERIPH_RBF_PROG_FORCE, socfpga_get_sysmgr_addr() +
+		       SYSMGR_A10_ISW_HANDOFF_BASE + SYSMGR_A10_ISW_HANDOFF_7);
+	else
+		writel(0, socfpga_get_sysmgr_addr() +
+		       SYSMGR_A10_ISW_HANDOFF_BASE + SYSMGR_A10_ISW_HANDOFF_7);
+}
+
+/*
+ * This function is used to check whether
+ * handoff register isw_handoff[7] contains
+ * flag for forcing the periph RBF program "0x50455249".
+ */
+bool is_periph_program_force(void)
+{
+	unsigned int status;
+
+	status = readl(socfpga_get_sysmgr_addr() +
+		       SYSMGR_A10_ISW_HANDOFF_BASE + SYSMGR_A10_ISW_HANDOFF_7);
+
+	if (status == PERIPH_RBF_PROG_FORCE)
+		return true;
+	else
+		return false;
+}
+
+/*
+ * This function set/unset magic number "0xd15ea5e" to
+ * handoff register isw_handoff[7] - 0xffd0624c
+ * This magic number is part of boot progress tracking
+ * and it's required for warm reset workaround on MPFE hang issue.
+ */
+void set_regular_boot(unsigned int status)
+{
+	if (status)
+		writel(REGULAR_BOOT_MAGIC, socfpga_get_sysmgr_addr() +
+		       SYSMGR_A10_ISW_HANDOFF_BASE + SYSMGR_A10_ISW_HANDOFF_7);
+	else
+		writel(0, socfpga_get_sysmgr_addr() +
+		       SYSMGR_A10_ISW_HANDOFF_BASE + SYSMGR_A10_ISW_HANDOFF_7);
+}
+
+/*
+ * This function is used to check whether
+ * handoff register isw_handoff[7] contains
+ * magic number "0xd15ea5e".
+ */
+bool is_regular_boot_valid(void)
+{
+	unsigned int status;
+
+	status = readl(socfpga_get_sysmgr_addr() +
+		       SYSMGR_A10_ISW_HANDOFF_BASE + SYSMGR_A10_ISW_HANDOFF_7);
+
+	if (status == REGULAR_BOOT_MAGIC)
+		return true;
+	else
+		return false;
+}
+
+#if IS_ENABLED(CONFIG_CADENCE_QSPI)
+/* This function is used to trigger software reset
+ * to the QSPI flash. On some boards, the QSPI flash reset may
+ * not be connected to the HPS warm reset.
+ */
+int qspi_flash_software_reset(void)
+{
+	struct udevice *flash;
+	int ret;
+
+	/* Get the flash info */
+	ret = spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS,
+				     CONFIG_SF_DEFAULT_CS,
+				     CONFIG_SF_DEFAULT_SPEED,
+				     CONFIG_SF_DEFAULT_MODE,
+				     &flash);
+
+	if (ret) {
+		debug("Failed to initialize SPI flash at ");
+		debug("%u:%u (error %d)\n", CONFIG_SF_DEFAULT_BUS,
+		      CONFIG_SF_DEFAULT_CS, ret);
+		return -ENODEV;
+	}
+
+	if (!flash)
+		return -EINVAL;
+
+	/*
+	 * QSPI flash software reset command, for the case where
+	 * no HPS reset connected to QSPI flash reset
+	 */
+	if (!memcmp(flash->name, "N25", SZ_1 + SZ_2))
+		writel(QSPI_N25_SOFT_RESET_COMMAND, socfpga_get_sysmgr_addr() +
+		       SYSMGR_A10_ROMCODE_QSPIRESETCOMMAND);
+	else if (!memcmp(flash->name, "S25FL", SZ_1 + SZ_4))
+		writel(QSPI_S25FL_SOFT_RESET_COMMAND,
+		       socfpga_get_sysmgr_addr() +
+		       SYSMGR_A10_ROMCODE_QSPIRESETCOMMAND);
+	else /* No software reset */
+		writel(QSPI_NO_SOFT_RESET, socfpga_get_sysmgr_addr() +
+		       SYSMGR_A10_ROMCODE_QSPIRESETCOMMAND);
+
+	return 0;
+}
+#endif
diff --git a/arch/arm/mach-socfpga/spl_a10.c b/arch/arm/mach-socfpga/spl_a10.c
index ecb656e..d2f454c 100644
--- a/arch/arm/mach-socfpga/spl_a10.c
+++ b/arch/arm/mach-socfpga/spl_a10.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- *  Copyright (C) 2012-2019 Altera Corporation <www.altera.com>
+ *  Copyright (C) 2012-2021 Altera Corporation <www.altera.com>
  */
 
 #include <common.h>
@@ -30,8 +30,13 @@
 #include <asm/arch/fpga_manager.h>
 #include <mmc.h>
 #include <memalign.h>
+#include <linux/delay.h>
 
 #define FPGA_BUFSIZ	16 * 1024
+#define FSBL_IMAGE_IS_VALID	0x49535756
+
+#define FSBL_IMAGE_IS_INVALID	0x0
+#define BOOTROM_CONFIGURES_IO_PINMUX	0x3
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -106,6 +111,8 @@
 
 void spl_board_init(void)
 {
+	int ret;
+
 	ALLOC_CACHE_ALIGN_BUFFER(char, buf, FPGA_BUFSIZ);
 
 	/* enable console uart printing */
@@ -116,8 +123,7 @@
 
 	/* If the full FPGA is already loaded, ie.from EPCQ, config fpga pins */
 	if (is_fpgamgr_user_mode()) {
-		int ret = config_pins(gd->fdt_blob, "shared");
-
+		ret = config_pins(gd->fdt_blob, "shared");
 		if (ret)
 			return;
 
@@ -127,11 +133,110 @@
 	} else if (!is_fpgamgr_early_user_mode()) {
 		/* Program IOSSM(early IO release) or full FPGA */
 		fpgamgr_program(buf, FPGA_BUFSIZ, 0);
+
+		/* Skipping double program for combined RBF */
+		if (!is_fpgamgr_user_mode()) {
+			/*
+			 * Expect FPGA entered early user mode, so
+			 * the flag is set to re-program IOSSM
+			 */
+			force_periph_program(true);
+
+			/* Re-program IOSSM to stabilize IO system */
+			fpgamgr_program(buf, FPGA_BUFSIZ, 0);
+
+			force_periph_program(false);
+		}
 	}
 
 	/* If the IOSSM/full FPGA is already loaded, start DDR */
-	if (is_fpgamgr_early_user_mode() || is_fpgamgr_user_mode())
+	if (is_fpgamgr_early_user_mode() || is_fpgamgr_user_mode()) {
+		if (!is_regular_boot_valid()) {
+			/*
+			 * Ensure all signals in stable state before triggering
+			 * warm reset. This value is recommended from stress
+			 * test.
+			 */
+			mdelay(10);
+
+#if IS_ENABLED(CONFIG_CADENCE_QSPI)
+			/*
+			 * Trigger software reset to QSPI flash.
+			 * On some boards, the QSPI flash reset may not be
+			 * connected to the HPS warm reset.
+			 */
+			qspi_flash_software_reset();
+#endif
+
+			ret = readl(socfpga_get_rstmgr_addr() +
+				    RSTMGR_A10_SYSWARMMASK);
+			/*
+			 * Masking s2f & FPGA manager module reset from warm
+			 * reset
+			 */
+			writel(ret & (~(ALT_RSTMGR_SYSWARMMASK_S2F_SET_MSK |
+			       ALT_RSTMGR_FPGAMGRWARMMASK_S2F_SET_MSK)),
+			       socfpga_get_rstmgr_addr() +
+			       RSTMGR_A10_SYSWARMMASK);
+
+			/*
+			 * BootROM will configure both IO and pin mux after a
+			 * warm reset
+			 */
+			ret = readl(socfpga_get_sysmgr_addr() +
+				    SYSMGR_A10_ROMCODE_CTRL);
+			writel(ret | BOOTROM_CONFIGURES_IO_PINMUX,
+			       socfpga_get_sysmgr_addr() +
+			       SYSMGR_A10_ROMCODE_CTRL);
+
+			/*
+			 * Up to here, image is considered valid and should be
+			 * set as valid before warm reset is triggered
+			 */
+			writel(FSBL_IMAGE_IS_VALID, socfpga_get_sysmgr_addr() +
+			       SYSMGR_A10_ROMCODE_INITSWSTATE);
+
+			/*
+			 * Set this flag to scratch register, so that a proper
+			 * boot progress before / after warm reset can be
+			 * tracked by FSBL
+			 */
+			set_regular_boot(true);
+
+			WATCHDOG_RESET();
+
+			reset_cpu();
+		}
+
+		/*
+		 * Reset this flag to scratch register, so that a proper
+		 * boot progress before / after warm reset can be
+		 * tracked by FSBL
+		 */
+		set_regular_boot(false);
+
+		ret = readl(socfpga_get_rstmgr_addr() +
+			    RSTMGR_A10_SYSWARMMASK);
+
+		/*
+		 * Unmasking s2f & FPGA manager module reset from warm
+		 * reset
+		 */
+		writel(ret | ALT_RSTMGR_SYSWARMMASK_S2F_SET_MSK |
+			ALT_RSTMGR_FPGAMGRWARMMASK_S2F_SET_MSK,
+			socfpga_get_rstmgr_addr() + RSTMGR_A10_SYSWARMMASK);
+
+		/*
+		 * Up to here, MPFE hang workaround is considered done and
+		 * should be reset as invalid until FSBL successfully loading
+		 * SSBL, and prepare jumping to SSBL, then only setting as
+		 * valid
+		 */
+		writel(FSBL_IMAGE_IS_INVALID, socfpga_get_sysmgr_addr() +
+		       SYSMGR_A10_ROMCODE_INITSWSTATE);
+
 		ddr_calibration_sequence();
+	}
 
 	if (!is_fpgamgr_user_mode())
 		fpgamgr_program(buf, FPGA_BUFSIZ, 0);
@@ -169,3 +274,10 @@
 	config_dedicated_pins(gd->fdt_blob);
 	WATCHDOG_RESET();
 }
+
+/* board specific function prior loading SSBL / U-Boot proper */
+void spl_board_prepare_for_boot(void)
+{
+	writel(FSBL_IMAGE_IS_VALID, socfpga_get_sysmgr_addr() +
+	       SYSMGR_A10_ROMCODE_INITSWSTATE);
+}
diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c
index b992e6f..798e3a3 100644
--- a/drivers/fpga/socfpga_arria10.c
+++ b/drivers/fpga/socfpga_arria10.c
@@ -604,7 +604,8 @@
 
 			if (strstr(uname, "fpga-periph") &&
 				(!is_fpgamgr_early_user_mode() ||
-				is_fpgamgr_user_mode())) {
+				is_fpgamgr_user_mode() ||
+				is_periph_program_force())) {
 				fpga_node_name = uname;
 				printf("FPGA: Start to program ");
 				printf("peripheral/full bitstream ...\n");