[PATCH v23 07/13] power: reset: Add psci-reboot-mode driver
From: Shivendra Pratap
Date: Tue Jul 14 2026 - 13:19:50 EST
PSCI supports different types of resets like SYSTEM_RESET, SYSTEM_RESET2
ARCH WARM reset and SYSTEM_RESET2 vendor-specific resets. Currently
there is no common driver that handles all supported psci resets at one
place. Additionally, there is no common mechanism to issue the supported
psci resets from userspace.
Add a psci-reboot-mode driver, and define two types of PSCI resets,
predefined-resets and vendor-specific resets. Predefined-resets are
defined by psci driver and vendor-specific resets are defined by SoC
vendors, under the psci:reboot-mode node of SoC device tree.
Register the driver with the reboot-mode framework to interface these
resets to userspace. When userspace initiates a supported command, pass
the reset arguments to the PSCI driver to enable command-based reset.
This change allows userspace to issue supported PSCI reset commands
using the standard reboot system calls while enabling SoC vendors to
define their specific resets for PSCI.
Signed-off-by: Shivendra Pratap <shivendra.pratap@xxxxxxxxxxxxxxxx>
---
MAINTAINERS | 1 +
drivers/power/reset/Kconfig | 10 +++++
drivers/power/reset/Makefile | 1 +
drivers/power/reset/psci-reboot-mode.c | 78 ++++++++++++++++++++++++++++++++++
4 files changed, 90 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index e1ed6abef62a..4910abafa170 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21576,6 +21576,7 @@ S: Maintained
F: Documentation/devicetree/bindings/arm/psci.yaml
F: drivers/firmware/psci/
F: drivers/mfd/psci-mfd.c
+F: drivers/power/reset/psci-reboot-mode.c
F: include/linux/psci.h
F: include/uapi/linux/psci.h
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 124afb99febe..93e4029d9506 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -348,6 +348,16 @@ config NVMEM_REBOOT_MODE
then the bootloader can read it and take different
action according to the mode.
+config PSCI_REBOOT_MODE
+ bool "PSCI reboot mode driver"
+ depends on OF && (ARM_PSCI_FW || COMPILE_TEST)
+ select REBOOT_MODE
+ help
+ Say y here will enable PSCI reboot mode driver. This gets
+ the PSCI reboot mode arguments and passes them to psci
+ driver. psci driver uses these arguments for issuing
+ device reset into different boot states.
+
config POWER_MLXBF
tristate "Mellanox BlueField power handling driver"
depends on (GPIO_MLXBF2 || GPIO_MLXBF3) && ACPI
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index d7ae97241a83..02948622fe3d 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -40,5 +40,6 @@ obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o
obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o
+obj-$(CONFIG_PSCI_REBOOT_MODE) += psci-reboot-mode.o
obj-$(CONFIG_POWER_MLXBF) += pwr-mlxbf.o
obj-$(CONFIG_POWER_RESET_QEMU_VIRT_CTRL) += qemu-virt-ctrl.o
diff --git a/drivers/power/reset/psci-reboot-mode.c b/drivers/power/reset/psci-reboot-mode.c
new file mode 100644
index 000000000000..955ed68f1402
--- /dev/null
+++ b/drivers/power/reset/psci-reboot-mode.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/array_size.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/psci.h>
+#include <linux/reboot-mode.h>
+#include <linux/types.h>
+
+static const struct reboot_mode_entry psci_resets[] = {
+ {
+ .name = "psci-system-reset",
+ .magic = { 0, PSCI_SYSTEM_RESET_COLD_RESET },
+ .count = 2,
+ },
+ {
+ .name = "psci-system-reset2-arch-warm-reset",
+ .magic = { 0, PSCI_SYSTEM_RESET2_ARCH_WARM_RESET },
+ .count = 2,
+ },
+};
+
+static u64 psci_reboot_mode_get_cookie(const u32 *magic, int count)
+{
+ u64 cookie = 0;
+ int i;
+
+ /* Build cookie from arg2/arg3 cells in order: cookie_hi then cookie_lo. */
+ for (i = 1; i < count; i++)
+ cookie = (cookie << 32) | magic[i];
+
+ return cookie;
+}
+
+static int psci_reboot_mode_write(struct reboot_mode_driver *reboot,
+ u32 *magic, int count)
+{
+ if (count < 1 || count > 3)
+ return -EINVAL;
+
+ return psci_set_reset_cmd(magic[0], psci_reboot_mode_get_cookie(magic, count));
+}
+
+static int psci_reboot_mode_probe(struct platform_device *pdev)
+{
+ struct reboot_mode_driver *reboot;
+ size_t count;
+ int ret;
+
+ reboot = devm_kzalloc(&pdev->dev, sizeof(*reboot), GFP_KERNEL);
+ if (!reboot)
+ return -ENOMEM;
+
+ reboot_mode_driver_init(reboot, &pdev->dev, psci_reboot_mode_write);
+
+ /* Skip PSCI SYSTEM_RESET2 modes if unsupported */
+ count = psci_has_system_reset2_support() ? ARRAY_SIZE(psci_resets) : 1;
+ ret = reboot_mode_add_predefined_modes(reboot, psci_resets, count);
+ if (ret)
+ return ret;
+
+ return devm_reboot_mode_register(&pdev->dev, reboot);
+}
+
+static struct platform_driver psci_reboot_mode_driver = {
+ .probe = psci_reboot_mode_probe,
+ .driver = {
+ .name = "psci-reboot-mode",
+ },
+};
+module_platform_driver(psci_reboot_mode_driver);
+
+MODULE_DESCRIPTION("PSCI reboot mode driver");
+MODULE_LICENSE("GPL");
--
2.34.1