firmware/raspberrypi: Notify firmware of a reboot
authorPhil Elwell <phil@raspberrypi.org>
Sat, 12 May 2018 20:35:43 +0000 (21:35 +0100)
committerDom Cobley <popcornmix@gmail.com>
Mon, 19 Feb 2024 11:32:48 +0000 (11:32 +0000)
Register for reboot notifications, sending RPI_FIRMWARE_NOTIFY_REBOOT
over the mailbox interface on reception.

Signed-off-by: Phil Elwell <phil@raspberrypi.org>
drivers/firmware/raspberrypi.c

index d631ed2..ed6882d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/reboot.h>
 #include <linux/slab.h>
 #include <soc/bcm2835/raspberrypi-firmware.h>
 
@@ -180,6 +181,26 @@ int rpi_firmware_property(struct rpi_firmware *fw,
 }
 EXPORT_SYMBOL_GPL(rpi_firmware_property);
 
+static int rpi_firmware_notify_reboot(struct notifier_block *nb,
+                                     unsigned long action,
+                                     void *data)
+{
+       struct rpi_firmware *fw;
+       struct platform_device *pdev = g_pdev;
+
+       if (!pdev)
+               return 0;
+
+       fw = platform_get_drvdata(pdev);
+       if (!fw)
+               return 0;
+
+       (void)rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_REBOOT,
+                                   0, 0);
+
+       return 0;
+}
+
 static void
 rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
 {
@@ -412,15 +433,32 @@ static struct platform_driver rpi_firmware_driver = {
        .remove         = rpi_firmware_remove,
 };
 
+static struct notifier_block rpi_firmware_reboot_notifier = {
+       .notifier_call = rpi_firmware_notify_reboot,
+};
+
 static int __init rpi_firmware_init(void)
 {
-       return platform_driver_register(&rpi_firmware_driver);
+       int ret = register_reboot_notifier(&rpi_firmware_reboot_notifier);
+       if (ret)
+               goto out1;
+       ret = platform_driver_register(&rpi_firmware_driver);
+       if (ret)
+               goto out2;
+
+       return 0;
+
+out2:
+       unregister_reboot_notifier(&rpi_firmware_reboot_notifier);
+out1:
+       return ret;
 }
 subsys_initcall(rpi_firmware_init);
 
 static void __init rpi_firmware_exit(void)
 {
        platform_driver_unregister(&rpi_firmware_driver);
+       unregister_reboot_notifier(&rpi_firmware_reboot_notifier);
 }
 module_exit(rpi_firmware_exit);