]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
arm: socfpga: arria10: Reset MPFE NoC after program periph / combined RBF
authorTien Fong Chee <tien.fong.chee@intel.com>
Sun, 7 Nov 2021 15:08:55 +0000 (23:08 +0800)
committerTien Fong Chee <tien.fong.chee@intel.com>
Fri, 17 Dec 2021 04:58:01 +0000 (12:58 +0800)
This patch triggers warm reset to recover the MPFE NoC from corruption
due to high frequency transient clock output from HPS EMIF IOPLL at
VCO startup after peripheral RBF is programmed.

Signed-off-by: Tien Fong Chee <tien.fong.chee@intel.com>
Signed-off-by: Sin Hui Kho <sin.hui.kho@intel.com>
Reviewed-by: Tien Fong Chee <tien.fong.chee@intel.com>
arch/arm/mach-socfpga/include/mach/misc.h
arch/arm/mach-socfpga/include/mach/reset_manager_arria10.h
arch/arm/mach-socfpga/include/mach/system_manager_arria10.h
arch/arm/mach-socfpga/misc_arria10.c
arch/arm/mach-socfpga/spl_a10.c

index 649d2f6ce245f5d5574fea612b7e86d149f26347..74e8e2590fbf427f8f7f4341de0c25c12670eb1d 100644 (file)
@@ -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,10 @@ int is_fpga_config_ready(void);
 #endif
 
 void do_bridge_reset(int enable, unsigned int mask);
+bool is_regular_boot_valid(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_ */
index 19507c292dd059e243b8f5313d25d50d61b1224c..26faa628a05dbf8a0b4643c61da3cad4c760127f 100644 (file)
@@ -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 @@ int socfpga_bridges_reset(void);
 #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 @@ int socfpga_bridges_reset(void);
 #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_ */
index 75e1fcd80f12937543ea0df108feea618b16bfc4..0afe63e647ec88a1ba0aadb58debfbf0297dcd86 100644 (file)
 #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
 
index bf978053ca6443da898558cbf020e0a91120e514..634e63ed42bcf9335ae402f3a5f693720abf436e 100644 (file)
@@ -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
 #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 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 +130,83 @@ void do_bridge_reset(int enable, unsigned int mask)
        else
                socfpga_bridges_reset();
 }
+
+/*
+ * 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
index f6c4b5708d85915579ad711dbc5cff57d7bb8b2a..6450f7505831f5b548faaf4031e7c09dbb1ce009 100644 (file)
 #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;
 
 #define BOOTROM_SHARED_MEM_SIZE                0x800   /* 2KB */
@@ -107,6 +111,8 @@ u32 spl_mmc_boot_mode(const u32 boot_device)
 
 void spl_board_init(void)
 {
+       int ret;
+
        ALLOC_CACHE_ALIGN_BUFFER(char, buf, FPGA_BUFSIZ);
 
        /* enable console uart printing */
@@ -117,8 +123,7 @@ void spl_board_init(void)
 
        /* 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;
 
@@ -131,8 +136,93 @@ void spl_board_init(void)
        }
 
        /* 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);