Add support for 'fastboot reboot-bootloader'

- Add calls to get and set the MTK_WDT_NONRST2 register, which isn't
cleared on a reset.
- Implement fastboot_set_reboot_flag, using the MTK_WDT_NONRST2 register
to store the flag value at reset time
- Enable MISC_INIT_R and use it to handle the flag, board_init runs before watchdog startup.

Change-Id: I3c18ab3d97b4681775d426d487bf95968ab943d4
diff --git a/board/mediatek/mt8516-coral/mt8516-coral.c b/board/mediatek/mt8516-coral/mt8516-coral.c
index 85b2c4d..4299553 100644
--- a/board/mediatek/mt8516-coral/mt8516-coral.c
+++ b/board/mediatek/mt8516-coral/mt8516-coral.c
@@ -5,6 +5,54 @@
 
 #include <common.h>
 #include <dm.h>
+#include "../../../drivers/watchdog/mtk_wdt.h"
+
+#define WDT_DRIVER_NAME "mtk_wdt"
+#define REBOOT_BOOTLOADER_VALUE (1)
+#define REBOOT_BOOTLOADER_MASK  (1)
+#define REBOOT_BOOTLOADER_SHIFT (2)
+
+int fastboot_set_reboot_flag(void) {
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret = -ENOSYS;
+
+	ret = uclass_get(UCLASS_WDT, &uc);
+	if (ret)
+		return -ENOSYS;
+
+	uclass_foreach_dev(dev, uc) {
+		if (strncmp(dev->driver->name, WDT_DRIVER_NAME, strlen(WDT_DRIVER_NAME)) == 0) {
+			mtk_wdt_set_nonrst2(dev, REBOOT_BOOTLOADER_MASK << REBOOT_BOOTLOADER_SHIFT,
+			                    REBOOT_BOOTLOADER_VALUE << REBOOT_BOOTLOADER_SHIFT);
+			return 0;
+		}
+	}
+
+	return -ENOSYS;
+}
+
+int misc_init_r(void) {
+	int ret;
+	struct udevice *dev;
+	struct uclass *uc;
+	int reg_val;
+
+	ret = uclass_get(UCLASS_WDT, &uc);
+	if (ret)
+		return -ENOSYS;
+
+	uclass_foreach_dev(dev, uc) {
+		if (strncmp(dev->driver->name, WDT_DRIVER_NAME, strlen(WDT_DRIVER_NAME)) == 0) {
+			reg_val = mtk_wdt_get_nonrst2(dev);
+			if (reg_val & (REBOOT_BOOTLOADER_VALUE << REBOOT_BOOTLOADER_SHIFT)) {
+				env_set("force_fastboot", "1");
+				mtk_wdt_set_nonrst2(dev, REBOOT_BOOTLOADER_MASK << REBOOT_BOOTLOADER_SHIFT, 0);
+			}
+		}
+	}
+	return 0;
+}
 
 int board_init(void)
 {
diff --git a/configs/mt8516_coral_defconfig b/configs/mt8516_coral_defconfig
index 26875c2..bf17444 100644
--- a/configs/mt8516_coral_defconfig
+++ b/configs/mt8516_coral_defconfig
@@ -86,3 +86,4 @@
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_SETEXPR=y
 CONFIG_CMD_SOURCE=y
+CONFIG_MISC_INIT_R=y
\ No newline at end of file
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index dafd2b5..64d6df6 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -17,6 +17,7 @@
 #define MTK_WDT_STATUS			0x0c
 #define MTK_WDT_INTERVAL		0x10
 #define MTK_WDT_SWRST			0x14
+#define MTK_WDT_NONRST2			0x24
 #define MTK_WDT_REQ_MODE		0x30
 #define MTK_WDT_DEBUG_CTL		0x40
 
@@ -70,6 +71,17 @@
 	return 0;
 }
 
+int mtk_wdt_get_nonrst2(struct udevice *dev) {
+	struct mtk_wdt_priv *priv = dev_get_priv(dev);
+	return readl(priv->base + MTK_WDT_NONRST2);
+}
+
+void mtk_wdt_set_nonrst2(struct udevice *dev, ulong mask, ulong value) {
+	struct mtk_wdt_priv *priv = dev_get_priv(dev);
+	int reg_val = readl(priv->base + MTK_WDT_NONRST2);
+	writel((reg_val & ~mask) | value, priv->base + MTK_WDT_NONRST2);
+}
+
 static void mtk_wdt_set_timeout(struct udevice *dev, u64 timeout_ms)
 {
 	struct mtk_wdt_priv *priv = dev_get_priv(dev);
diff --git a/drivers/watchdog/mtk_wdt.h b/drivers/watchdog/mtk_wdt.h
new file mode 100644
index 0000000..49de8c6
--- /dev/null
+++ b/drivers/watchdog/mtk_wdt.h
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Watchdog driver for MediaTek SoCs
+ *
+ * Copyright (C) 2020 Google, LLC.
+ */
+#ifndef _MTK_WDT_H
+#define _MTK_WDT_H
+
+void mtk_wdt_set_nonrst2(struct udevice *dev, ulong mask, ulong value);
+int mtk_wdt_get_nonrst2(struct udevice *dev);
+
+#endif  // _MTK_WDT_H