diff mbox series

[RFC,4/4] power: reset: Implement a PSCI SYSTEM_RESET2 reboot-mode driver

Message ID 20230724223057.1208122-5-quic_eberman@quicinc.com
State New
Headers show
Series Implement a PSCI SYSTEM_RESET2 reboot-mode driver | expand

Commit Message

Elliot Berman July 24, 2023, 10:30 p.m. UTC
PSCI implements a restart notifier for architectural defined resets.
The SYSTEM_RESET2 allows vendor firmware to define additional reset
types which could be mapped to the reboot reason.

Implement a driver to wire the reboot-mode framework to make vendor
SYSTEM_RESET2 calls on reboot.

Signed-off-by: Elliot Berman <quic_eberman@quicinc.com>
---
 MAINTAINERS                             |  1 +
 drivers/firmware/psci/psci.c            |  9 +++++
 drivers/power/reset/Kconfig             |  9 +++++
 drivers/power/reset/Makefile            |  1 +
 drivers/power/reset/psci-vendor-reset.c | 49 +++++++++++++++++++++++++
 include/linux/psci.h                    |  2 +
 6 files changed, 71 insertions(+)
 create mode 100644 drivers/power/reset/psci-vendor-reset.c
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 2da4c5f1917b..214b14c1da63 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16984,6 +16984,7 @@  L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	Documentation/devicetree/bindings/power/reset/arm,psci-vendor-reset.yaml
 F:	drivers/firmware/psci/
+F:	drivers/power/reset/psci-vendor-reset.c
 F:	include/linux/psci.h
 F:	include/uapi/linux/psci.h
 
diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index d9629ff87861..6db73f9d2304 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -328,6 +328,15 @@  static struct notifier_block psci_sys_reset_nb = {
 	.priority = 129,
 };
 
+void psci_vendor_sys_reset2(u32 reset_type, u32 cookie)
+{
+	if (psci_system_reset2_supported)
+		invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2),
+			reset_type | BIT_ULL(31),
+			cookie, 0);
+}
+EXPORT_SYMBOL_GPL(psci_vendor_sys_reset2);
+
 static void psci_sys_poweroff(void)
 {
 	invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index fff07b2bd77b..1474b9d51089 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -311,4 +311,13 @@  config POWER_MLXBF
 	help
 	  This driver supports reset or low power mode handling for Mellanox BlueField.
 
+config POWER_RESET_PSCI_VENDOR_RESET
+	tristate "PSCI Vendor SYSTEM_RESET2 driver"
+	depends on ARM64 || ARM || COMPILE_TEST
+	select ARM_PSCI_FW
+	select REBOOT_MODE
+	help
+	  Say y/m here to enable driver to use Vendor SYSTEM_RESET2 types on
+	  chips which have firmware implementing custom SYSTEM_RESET2 types.
+
 endif
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index d763e6735ee3..d09243966b74 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -37,3 +37,4 @@  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_POWER_MLXBF) += pwr-mlxbf.o
+obj-$(CONFIG_POWER_RESET_PSCI_VENDOR_RESET) += psci-vendor-reset.o
diff --git a/drivers/power/reset/psci-vendor-reset.c b/drivers/power/reset/psci-vendor-reset.c
new file mode 100644
index 000000000000..95d027225185
--- /dev/null
+++ b/drivers/power/reset/psci-vendor-reset.c
@@ -0,0 +1,49 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/**
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/reboot-mode.h>
+#include <linux/psci.h>
+
+static int psci_vendor_system_reset2(struct reboot_mode_driver *reboot, unsigned int magic)
+{
+	psci_vendor_sys_reset2(magic, 0);
+
+	return NOTIFY_DONE;
+}
+
+static int psci_vendor_reset_probe(struct platform_device *pdev)
+{
+	struct reboot_mode_driver *reboot;
+
+	reboot = devm_kzalloc(&pdev->dev, sizeof(*reboot), GFP_KERNEL);
+	if (!reboot)
+		return -ENOMEM;
+
+	reboot->write = psci_vendor_system_reset2;
+
+	return devm_reboot_mode_register(&pdev->dev, reboot);
+}
+
+static const struct of_device_id psci_vendor_reset_id_table[] = {
+	{ .compatible = "arm,psci-vendor-reset" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, psci_vendor_reset_id_table);
+
+static struct platform_driver psci_vendor_reset_driver = {
+	.probe = psci_vendor_reset_probe,
+	.driver = {
+		.name = "psci-vendor-reset",
+		.of_match_table = of_match_ptr(psci_vendor_reset_id_table),
+	},
+};
+module_platform_driver(psci_vendor_reset_driver);
+
+MODULE_DESCRIPTION("PSCI Vendor SYSTEM_RESET2 Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/psci.h b/include/linux/psci.h
index 4ca0060a3fc4..0c652c12e0a8 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -21,6 +21,8 @@  bool psci_power_state_is_valid(u32 state);
 int psci_set_osi_mode(bool enable);
 bool psci_has_osi_support(void);
 
+void psci_vendor_sys_reset2(u32 reset_type, u32 cookie);
+
 struct psci_operations {
 	u32 (*get_version)(void);
 	int (*cpu_suspend)(u32 state, unsigned long entry_point);