[PATCH v21 07/13] power: reset: Add psci-reboot-mode driver

Shivendra Pratap
2026-04-27T17:36:26Z

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@oss.qualcomm.com>
---
MAINTAINERS | 1 +
drivers/power/reset/Kconfig | 10 +++
drivers/power/reset/Makefile | 1 +
drivers/power/reset/psci-reboot-mode.c | 109 +++++++++++++++++++++++++++++++++
4 files changed, 121 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 333b01fa00b8fbd15e6f31a6b9af47600411624e..8cebc2c7e161c8a226802a4102756b4ed6034395 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21240,6 +21240,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 124afb99febe92450b6ae322aeed3b63fa2070df..d9d1f768b8691abc3b32f2675519f2ddbaf19b84 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
+ 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 d7ae97241a838fe1b536b2f911868e7590d12e3b..02948622fe3d00e165f941108ab92ecb66b0f0e8 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 0000000000000000000000000000000000000000..29f53d2f50da8e34e714adef9507d340bc4130e2
--- /dev/null
+++ b/drivers/power/reset/psci-reboot-mode.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/psci.h>
+#include <linux/reboot.h>
+#include <linux/reboot-mode.h>
+#include <linux/types.h>
+
+/* Predefined modes use reset_type = 0 and cookie in magic[63:32]. */
+#define PSCI_PREDEF_MAGIC(cookie) ((cookie) * BIT_ULL(32))
+
+struct psci_predefined_reset {
+ const char *mode;
+ u64 magic;
+};
+
+static const struct psci_predefined_reset psci_resets[] = {
+ {
+ .mode = "psci-system-reset",
+ .magic = PSCI_PREDEF_MAGIC(PSCI_RESET_TYPE_SYSTEM_RESET),
+ },
+ {
+ .mode = "psci-system-reset2-arch-warm-reset",
+ .magic = PSCI_PREDEF_MAGIC(PSCI_RESET_TYPE_SYSTEM_RESET2_ARCH_WARM),
+ },
+};
+
+static int psci_reboot_mode_add_predefined_mode(struct device *dev,
+ struct reboot_mode_driver *reboot,
+ const struct psci_predefined_reset *predef)
+{
+ struct mode_info *info;
+
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&info->list);
+ info->mode = predef->mode;
+ info->magic = predef->magic;
+ list_add_tail(&info->list, &reboot->predefined_modes);
+
+ return 0;
+}
+
+static int psci_reboot_mode_set_predefined_modes(struct device *dev,
+ struct reboot_mode_driver *reboot)
+{
+ int ret;
+
+ INIT_LIST_HEAD(&reboot->predefined_modes);
+
+ /* Always register psci-system-reset. */
+ ret = psci_reboot_mode_add_predefined_mode(dev, reboot, &psci_resets[0]);
+ if (ret)
+ return ret;
+
+ /* Register arch warm reset only if SYSTEM_RESET2 is supported. */
+ if (!psci_has_system_reset2_support())
+ return 0;
+
+ return psci_reboot_mode_add_predefined_mode(dev, reboot, &psci_resets[1]);
+}
+
+/*
+ * Pass the encoded magic to psci_set_reset_cmd.
+ * magic is encoded as reset_type (low 32 bits) and cookie (high 32 bits).
+ */
+static int psci_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
+{
+ psci_set_reset_cmd(magic);
+ return 0;
+}
+
+static int psci_reboot_mode_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct reboot_mode_driver *reboot;
+ int ret;
+
+ reboot = devm_kzalloc(dev, sizeof(*reboot), GFP_KERNEL);
+ if (!reboot)
+ return -ENOMEM;
+
+ ret = psci_reboot_mode_set_predefined_modes(dev, reboot);
+ if (ret)
+ return ret;
+
+ reboot->write = psci_reboot_mode_write;
+ reboot->dev = dev;
+
+ return devm_reboot_mode_register(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_LICENSE("GPL");

--
2.34.1