From git@z Thu Jan  1 00:00:00 1970
Subject: [PATCH RFC] rockchip: Reset to bootrom download mode on hang
From: Jonas Karlman <jonas@kwiboo.se>
Date: Fri, 02 Feb 2024 00:12:18 +0000
Message-Id: <20240202001221.531207-1-jonas@kwiboo.se>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit

Add support to reset to bootrom download mode on hang in U-Boot SPL and
proper. ROCKCHIP_HANG_TO_BROM can be used to enable this feature.

Example when SPL cannot load FIT:

  U-Boot SPL 2024.04-rc1 (Feb 01 2024 - 23:01:12 +0000)
  Trying to boot from MMC1
  mmc_load_image_raw_sector: mmc block read error
  Trying to boot from MMC2
  Card did not respond to voltage select! : -110
  spl: mmc init failed with error: -95
  Trying to boot from MMC1
  mmc_load_image_raw_sector: mmc block read error
  SPL: failed to boot from all boot devices
  ### ERROR ### Please RESET the board ###
  entering download mode ...
  resetting ...

Procedure to start bootrom download mode:
- U-Boot SPL or proper write 0xEF08A53C to BOOT_MODE_REG and then reset
- Bootrom loads and run boot code (TPL) from e.g. SPI > eMMC > SD-card
- TPL check for 0xEF08A53C in BOOT_MODE_REG very early, i.e. Rockchip
  TPL blobs check for this value directly at start
- TPL return to bootrom with a return value != 0
- Bootrom enter download mode

This also fixes an issue where the BOOT_MODE_REG is reset to 0 when
board is reset on RK35xx after TF-A has been loaded. To fix this the
SOC_CON1 reg value is reset prior to issuing a global reset.

The RK356x TF-A blobs will clear SOC_CON1 as part of a PSCI reset,
however the RK3588 TF-A blobs does not seem to clear SOC_CON1.

Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
---
- Is reset to bootrom download mode on hang a feature of intereset to
  anyone else?
- How can we best handle the issue with BOOT_MODE_REG being reset?
- Should we instead enable SYSRESET_PSCI and relay on TF-A to properly
  reset without loosing value in BOOT_MODE_REG? Currently works on
  RK356x bl31 blobs but not on the RK3588 bl31 blobs.
---
 arch/arm/mach-rockchip/Kconfig     |  9 +++++++
 arch/arm/mach-rockchip/Makefile    |  9 ++++---
 arch/arm/mach-rockchip/boot_mode.c | 38 ++++++++++++++++++++++++++----
 configs/generic-rk3568_defconfig   |  1 +
 configs/generic-rk3588_defconfig   |  1 +
 5 files changed, 48 insertions(+), 10 deletions(-)

--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -696,6 +696,15 @@ config TPL_ROCKCHIP_EARLYRETURN_TO_BROM
 	  This enables support code in the BOOT0 hook for the TPL stage
 	  to allow multiple entries.
 
+config ROCKCHIP_HANG_TO_BROM
+	bool "Reset to bootrom download mode on hang"
+	select SHOW_BOOT_PROGRESS
+
+config SPL_ROCKCHIP_HANG_TO_BROM
+	bool "Reset to bootrom download mode on hang in SPL"
+	default y if ROCKCHIP_HANG_TO_BROM
+	select SPL_SHOW_BOOT_PROGRESS
+
 config SPL_MMC
 	default y if !SPL_ROCKCHIP_BACK_TO_BROM
 
--- a/arch/arm/mach-rockchip/Makefile
+++ b/arch/arm/mach-rockchip/Makefile
@@ -16,16 +16,15 @@ obj-tpl-$(CONFIG_ROCKCHIP_PX30) += px30-
 obj-spl-$(CONFIG_ROCKCHIP_RK3036) += rk3036-board-spl.o spl_common.o
 
 ifeq ($(CONFIG_XPL_BUILD)$(CONFIG_TPL_BUILD),)
+obj-$(CONFIG_ROCKCHIP_COMMON_BOARD) += board.o
+endif
 
+ifeq ($(CONFIG_TPL_BUILD),)
 # Always include boot_mode.o, as we bypass it (i.e. turn it off)
 # inside of boot_mode.c when CONFIG_ROCKCHIP_BOOT_MODE_REG is 0.  This way,
 # we can have the preprocessor correctly recognise both 0x0 and 0
 # meaning "turn it off".
 obj-y += boot_mode.o
-obj-$(CONFIG_ROCKCHIP_COMMON_BOARD) += board.o
-endif
-
-ifeq ($(CONFIG_TPL_BUILD),)
 obj-$(CONFIG_DISPLAY_CPUINFO) += cpu-info.o
 endif
 
--- a/arch/arm/mach-rockchip/boot_mode.c
+++ b/arch/arm/mach-rockchip/boot_mode.c
@@ -4,6 +4,7 @@
  */
 
 #include <adc.h>
+#include <bootstage.h>
 #include <command.h>
 #include <env.h>
 #include <log.h>
@@ -22,11 +23,31 @@ int setup_boot_mode(void)
 
 #else
 
-void set_back_to_bootrom_dnl_flag(void)
+static void set_back_to_bootrom_dnl_flag(void)
 {
+	/*
+	 * These SOC_CON1 regs needs to be cleared before a reset or the
+	 * BOOT_MODE_REG do not retain its value and it is not possible
+	 * to reset to bootrom download mode once TF-A has been started.
+	 *
+	 * TF-A blobs for RK3568 already clear SOC_CON1 for PSCI reset.
+	 * However, the TF-A blobs for RK3588 does not clear SOC_CON1.
+	 */
+	if (IS_ENABLED(CONFIG_ROCKCHIP_RK3568))
+		writel(0x40000, 0xFDC20104);
+	if (IS_ENABLED(CONFIG_ROCKCHIP_RK3588))
+		writel(0xFFFF0000, 0xFD58A004);
+
 	writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG);
 }
 
+static void rockchip_reset_to_dnl_mode(void)
+{
+	puts("entering download mode ...\n");
+	set_back_to_bootrom_dnl_flag();
+	do_reset(NULL, 0, 0, NULL);
+}
+
 /*
  * detect download key status by adc, most rockchip
  * based boards use adc sample the download key status,
@@ -74,12 +95,19 @@ __weak int rockchip_dnl_key_pressed(void
 #endif
 }
 
-void rockchip_dnl_mode_check(void)
+#if CONFIG_IS_ENABLED(ROCKCHIP_HANG_TO_BROM)
+void show_boot_progress(int val)
+{
+	if (val == -BOOTSTAGE_ID_NEED_RESET)
+		rockchip_reset_to_dnl_mode();
+}
+#endif
+
+static void rockchip_dnl_mode_check(void)
 {
 	if (rockchip_dnl_key_pressed()) {
-		printf("download key pressed, entering download mode...");
-		set_back_to_bootrom_dnl_flag();
-		do_reset(NULL, 0, 0, NULL);
+		puts("download key pressed, ");
+		rockchip_reset_to_dnl_mode();
 	}
 }
 
--- a/configs/generic-rk3568_defconfig
+++ b/configs/generic-rk3568_defconfig
@@ -5,6 +5,7 @@ CONFIG_ARCH_ROCKCHIP=y
 CONFIG_SF_DEFAULT_SPEED=24000000
 CONFIG_DEFAULT_DEVICE_TREE="rk3568-generic"
 CONFIG_ROCKCHIP_RK3568=y
+CONFIG_ROCKCHIP_HANG_TO_BROM=y
 CONFIG_ROCKCHIP_SPI_IMAGE=y
 CONFIG_SPL_SERIAL=y
 CONFIG_SYS_LOAD_ADDR=0xc00800
--- a/configs/generic-rk3588_defconfig
+++ b/configs/generic-rk3588_defconfig
@@ -4,6 +4,7 @@ CONFIG_COUNTER_FREQUENCY=24000000
 CONFIG_ARCH_ROCKCHIP=y
 CONFIG_DEFAULT_DEVICE_TREE="rk3588-generic"
 CONFIG_ROCKCHIP_RK3588=y
+CONFIG_ROCKCHIP_HANG_TO_BROM=y
 CONFIG_SPL_SERIAL=y
 CONFIG_TARGET_EVB_RK3588=y
 CONFIG_SYS_LOAD_ADDR=0xc00800
