From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Piotr Szczepanik <piter75@gmail.com>
Date: Sun, 4 Oct 2020 18:19:02 +0200
Subject: Enabled advanced recovery button support for rockchip

---
 arch/arm/mach-rockchip/Kconfig     |  25 ++
 arch/arm/mach-rockchip/boot_mode.c | 148 ++++++++++
 2 files changed, 173 insertions(+)

diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig
index 308dc09b03..5140495849 100644
--- a/arch/arm/mach-rockchip/Kconfig
+++ b/arch/arm/mach-rockchip/Kconfig
@@ -393,6 +393,31 @@ config ROCKCHIP_SPI_IMAGE
 config LNX_KRNL_IMG_TEXT_OFFSET_BASE
 	default SYS_TEXT_BASE
 
+config ROCKCHIP_ADVANCED_RECOVERY
+	bool "Advanced recovery button for Rockchip boards"
+	default n
+
+config ROCKCHIP_ADVANCED_RECOVERY_LED
+	string "Advanced recovery button for Rockchip boards - toggled led label"
+	depends on ROCKCHIP_ADVANCED_RECOVERY
+
+config ROCKCHIP_ADVANCED_RECOVERY_UMS
+	bool "Advanced recovery for Rockchip boards - UMS support"
+	depends on ROCKCHIP_ADVANCED_RECOVERY
+	depends on CMD_USB_MASS_STORAGE
+	default y if ROCKCHIP_ADVANCED_RECOVERY
+
+config ROCKCHIP_ADVANCED_RECOVERY_ROCKUSB
+	bool "Advanced recovery for Rockchip boards - ROCKUSB support"
+	depends on ROCKCHIP_ADVANCED_RECOVERY
+	depends on CMD_ROCKUSB
+	default y if ROCKCHIP_ADVANCED_RECOVERY
+
+config ROCKCHIP_ADVANCED_RECOVERY_MASKROM
+	bool "Advanced recovery for Rockchip boards - MASKROM support"
+	depends on ROCKCHIP_ADVANCED_RECOVERY
+	default y if ROCKCHIP_ADVANCED_RECOVERY
+
 source "arch/arm/mach-rockchip/px30/Kconfig"
 source "arch/arm/mach-rockchip/rk3036/Kconfig"
 source "arch/arm/mach-rockchip/rk3128/Kconfig"
diff --git a/arch/arm/mach-rockchip/boot_mode.c b/arch/arm/mach-rockchip/boot_mode.c
index 1a1a887fc2..a8d6c1f2b5 100644
--- a/arch/arm/mach-rockchip/boot_mode.c
+++ b/arch/arm/mach-rockchip/boot_mode.c
@@ -7,7 +7,10 @@
 #include <adc.h>
 #include <command.h>
 #include <env.h>
+#include <led.h>
 #include <log.h>
+#include <mmc.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 #include <asm/arch-rockchip/boot_mode.h>
 #include <dm/device.h>
@@ -70,13 +73,158 @@ __weak int rockchip_dnl_key_pressed(void)
 		return false;
 }
 
+#if defined(CONFIG_ROCKCHIP_ADVANCED_RECOVERY)
+#define RECOVERY_LED_BY_LABEL(dev) led_get_by_label(CONFIG_ROCKCHIP_ADVANCED_RECOVERY_LED, dev)
+void rockchip_blink_recovery_led(int times)
+{
+	struct udevice *dev;
+	RECOVERY_LED_BY_LABEL(&dev);
+	for (int i = 0; i < times; ++i) {
+		led_set_state(dev, LEDST_ON);
+		mdelay(100);
+		led_set_state(dev, LEDST_OFF);
+		mdelay(100);
+	}
+}
+
+int rockchip_dnl_mode(int num_modes)
+{
+	int mode = 0;
+	const char *mode_names[5] = {
+		"none",
+		"ums",
+		"rockusb",
+		"fastboot",
+		"maskrom"
+	};
+
+	const int modes_enabled[5] = {
+		1,
+#if defined(CONFIG_ROCKCHIP_ADVANCED_RECOVERY_UMS)
+		1,
+#else
+		0,
+#endif
+#if defined(CONFIG_ROCKCHIP_ADVANCED_RECOVERY_ROCKUSB)
+		1,
+#else
+		0,
+#endif
+#if defined(CONFIG_ROCKCHIP_ADVANCED_RECOVERY_FASTBOOT)
+		1,
+#else
+		0,
+#endif
+#if defined(CONFIG_ROCKCHIP_ADVANCED_RECOVERY_MASKROM)
+		1,
+#else
+		0,
+#endif
+	};
+
+	while(mode < num_modes) {
+		++mode;
+
+		if (modes_enabled[mode]) {
+			printf("rockchip_dnl_mode = %s mode\n", mode_names[mode]);
+			rockchip_blink_recovery_led(mode);
+
+			// return early
+	 		if (mode == num_modes) {
+	 			goto end;
+	 		}
+
+			// wait 2 seconds
+			for (int i = 0; i < 100; ++i) {
+				if (!rockchip_dnl_key_pressed()) {
+					goto end;
+				}
+				mdelay(20);
+			}
+		}
+	}
+
+end:
+	return mode;
+}
+
+__weak void rockchip_prepare_download_mode(void)
+{
+}
+
+int rockchip_has_mmc_device(int devnum)
+{
+	struct mmc *mmc;
+	mmc = find_mmc_device(devnum);
+	if (!mmc || mmc_init(mmc))
+		return 0;
+	else
+		return 1;
+}
+#endif
+
 void rockchip_dnl_mode_check(void)
 {
+#if defined(CONFIG_ROCKCHIP_ADVANCED_RECOVERY)
+	int mmc_device = 0;
+	int ret = 0;
+	char cmd[32];
+
+	if (!rockchip_dnl_key_pressed()) {
+		return 0;
+	}
+
+	if (rockchip_has_mmc_device(0)) {
+		mmc_device = 0;
+	} else if (rockchip_has_mmc_device(1)) {
+		mmc_device = 1;
+	} else {
+		printf("no mmc device suitable for download mode!\n");
+		return 0;
+	}
+
+	printf("using mmc%d device for download mode\n", mmc_device);
+
+	switch(rockchip_dnl_mode(4)) {
+	case 0:
+		return;
+
+	case 1:
+		printf("entering ums mode...\n");
+		rockchip_prepare_download_mode();
+		sprintf(cmd, "ums 0 mmc %d", mmc_device);
+		cli_simple_run_command(cmd, 0);
+		break;
+
+	case 2:
+		printf("entering rockusb mode...\n");
+		rockchip_prepare_download_mode();
+		sprintf(cmd, "rockusb 0 mmc %d", mmc_device);
+		cli_simple_run_command(cmd, 0);
+		break;
+
+	case 3:
+		printf("entering fastboot mode...\n");
+		rockchip_prepare_download_mode();
+		sprintf(cmd, "mmc dev %d; fastboot usb 0", mmc_device);
+		cli_simple_run_command(cmd, 0);
+		break;
+
+	case 4:
+		printf("entering maskrom mode...\n");
+		rockchip_prepare_download_mode();
+		break;
+	}
+
+	set_back_to_bootrom_dnl_flag();
+	do_reset(NULL, 0, 0, NULL);
+#else
 	if (rockchip_dnl_key_pressed()) {
 		printf("download key pressed, entering download mode...");
 		set_back_to_bootrom_dnl_flag();
 		do_reset(NULL, 0, 0, NULL);
 	}
+#endif
 }
 
 int setup_boot_mode(void)
-- 
Armbian

