[PATCH 3/8] reboot-mode: add PSCI reboot-mode driver

Balaji Selvanathan via U-Boot <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <20260811-b4-reset-edl-rebootmode-v1-3-2e15adc156a3@oss.qualcomm.com>
Add a PSCI backend for the reboot-mode framework that triggers a
SYSTEM_RESET2 vendor-specific reset described by a "mode-*" property under
a "reboot-mode" subnode of the PSCI device tree node (for example
"mode-edl = <0x80000000 0x00000001>" to enter Qualcomm EDL/download mode).

All device tree parsing and name matching already live in the reboot-mode
uclass; this driver only turns a decoded set of magic cells into a
firmware call.

U-Boot's psci_system_reset2() client takes only a 32-bit cookie and ORs in
PSCI_RESET2_TYPE_VENDOR itself, so the trigger folds the low cells into a
cookie and rejects a 3-cell mode whose cookie_hi is non-zero rather than
silently truncating it.

psci_bind() binds the driver to the "reboot-mode" subnode when
CONFIG_REBOOT_MODE_PSCI is enabled, using device_bind_driver_to_node().

Signed-off-by: Balaji Selvanathan <[email protected]>
---
 drivers/firmware/psci.c                | 16 ++++++++++
 drivers/reboot-mode/Kconfig            | 11 +++++++
 drivers/reboot-mode/Makefile           |  1 +
 drivers/reboot-mode/reboot-mode-psci.c | 58 ++++++++++++++++++++++++++++++++++
 4 files changed, 86 insertions(+)

diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 2e3223e1c32..781a848e350 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -188,6 +188,22 @@ static int psci_bind(struct udevice *dev)
 			pr_debug("PSCI System Reset was not bound.\n");
 	}
 
+	/*
+	 * Bind the PSCI reboot-mode driver to the "reboot-mode" subnode so it
+	 * can trigger SYSTEM_RESET2 vendor resets described by "mode-*"
+	 * properties there (for example EDL/download mode).
+	 */
+	if (CONFIG_IS_ENABLED(REBOOT_MODE_PSCI)) {
+		ofnode rm_node = ofnode_find_subnode(dev_ofnode(dev),
+						     "reboot-mode");
+
+		if (ofnode_valid(rm_node) &&
+		    device_bind_driver_to_node(dev, "reboot-mode-psci",
+					       "reboot-mode-psci", rm_node,
+					       NULL))
+			pr_warn("PSCI reboot-mode was not bound.\n");
+	}
+
 	/* From PSCI v1.0 onward we can discover services through ARM_SMCCC_FEATURE */
 	if (IS_ENABLED(CONFIG_ARM_SMCCC_FEATURES) && device_is_compatible(dev, "arm,psci-1.0"))
 		dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
diff --git a/drivers/reboot-mode/Kconfig b/drivers/reboot-mode/Kconfig
index 3fdb4218a8b..109a196a3c9 100644
--- a/drivers/reboot-mode/Kconfig
+++ b/drivers/reboot-mode/Kconfig
@@ -39,4 +39,15 @@ config REBOOT_MODE_NVMEM
 	  Use any kind of non-volatile memory (EEPROM, RTC, etc) to control the
 	  reboot mode.
 
+config REBOOT_MODE_PSCI
+	bool "Use PSCI SYSTEM_RESET2 vendor resets as reboot modes"
+	depends on DM_REBOOT_MODE && ARM_SMCCC
+	help
+	  Trigger PSCI SYSTEM_RESET2 vendor-specific resets (for example
+	  rebooting a Qualcomm SoC into EDL/download mode) via the reboot-mode
+	  framework. Each reset is described by a "mode-*" property under the
+	  "reboot-mode" subnode of the psci device tree node, so the magic
+	  values are not hard-coded in the driver. The modes can then be
+	  triggered from the "reset" command by name.
+
 endmenu
diff --git a/drivers/reboot-mode/Makefile b/drivers/reboot-mode/Makefile
index 48c8ab7fe71..56c7078258b 100644
--- a/drivers/reboot-mode/Makefile
+++ b/drivers/reboot-mode/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode-uclass.o
 obj-$(CONFIG_DM_REBOOT_MODE_GPIO) += reboot-mode-gpio.o
 obj-$(CONFIG_DM_REBOOT_MODE_RTC) += reboot-mode-rtc.o
 obj-$(CONFIG_REBOOT_MODE_NVMEM) += reboot-mode-nvmem.o
+obj-$(CONFIG_REBOOT_MODE_PSCI) += reboot-mode-psci.o
diff --git a/drivers/reboot-mode/reboot-mode-psci.c b/drivers/reboot-mode/reboot-mode-psci.c
new file mode 100644
index 00000000000..88133c68ab4
--- /dev/null
+++ b/drivers/reboot-mode/reboot-mode-psci.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ */
+
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <reboot-mode/reboot-mode.h>
+#include <asm/psci.h>
+#include <asm/system.h>
+#include <linux/errno.h>
+
+static int psci_reboot_mode_trigger(struct udevice *dev, const u32 *magic,
+				    int count)
+{
+	u32 reset_type = magic[0];
+	u64 cookie = 0;
+	int i;
+
+	if (count < 1 || count > REBOOT_MODE_MAX_MAGIC)
+		return -EINVAL;
+
+	/*
+	 * U-Boot's psci_system_reset2() takes only a 32-bit cookie, whereas
+	 * the binding allows a 64-bit cookie in the 3-cell form (magic[1] is
+	 * cookie_hi, magic[2] is cookie_lo). Reject a non-zero high half
+	 * rather than silently truncating it.
+	 */
+	if (count == REBOOT_MODE_MAX_MAGIC && magic[1]) {
+		dev_err(dev, "64-bit reset cookie is not supported\n");
+		return -EINVAL;
+	}
+
+	for (i = 1; i < count; i++)
+		cookie = (cookie << 32) | magic[i];
+
+	if (psci_features(ARM_PSCI_1_1_FN64_SYSTEM_RESET2) !=
+	    ARM_PSCI_RET_SUCCESS) {
+		dev_err(dev, "SYSTEM_RESET2 is not supported by firmware\n");
+		return -EPROTONOSUPPORT;
+	}
+
+	/* Does not return on success. */
+	psci_system_reset2(reset_type, (u32)cookie);
+
+	return -EINPROGRESS;
+}
+
+static const struct reboot_mode_ops psci_reboot_mode_ops = {
+	.trigger = psci_reboot_mode_trigger,
+};
+
+U_BOOT_DRIVER(psci_reboot_mode) = {
+	.name = "reboot-mode-psci",
+	.id = UCLASS_REBOOT_MODE,
+	.ops = &psci_reboot_mode_ops,
+};

-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.