[PATCH v24 06/12] power: reset: Add psci-reboot-mode driver
Shivendra Pratap <[email protected]> Mon, 03 Aug 2026 15:13:37 +0530
| Newsgroups | org.kernel.vger.linux-pm,dev.linux.lists.mfd,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260803-arm-psci-system_reset2-vendor-reboots-v24-6-889281373870@oss.qualcomm.com> |
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. Reviewed-by: Bartosz Golaszewski <[email protected]> Signed-off-by: Shivendra Pratap <[email protected]> --- MAINTAINERS | 1 + drivers/power/reset/Kconfig | 10 +++++ drivers/power/reset/Makefile | 1 + drivers/power/reset/psci-reboot-mode.c | 82 ++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0b6e4f89f319..a3339b98ba86 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21672,6 +21672,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 bce996bbef28..143f3260f04a 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -360,6 +360,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 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 e31cab4ba78e..45d8aaaffaa1 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -41,5 +41,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..2f960fda8229 --- /dev/null +++ b/drivers/power/reset/psci-reboot-mode.c @@ -0,0 +1,82 @@ +// 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/errno.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/psci.h> +#include <linux/reboot-mode.h> +#include <linux/slab.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, + const u32 *magic, u32 count) +{ + (void)reboot; + + 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; + + /* Skip PSCI SYSTEM_RESET2 modes if unsupported */ + count = psci_has_system_reset2_support() ? ARRAY_SIZE(psci_resets) : 1; + + ret = reboot_mode_driver_init(reboot, &pdev->dev, NULL, + psci_reboot_mode_write, 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