The C-SKY architecture does not support ACPI and no other standardized
mechanism for system poweroff.
On QEMU a virtual device "csky_exit" is available which can be used for
poweroff.
Add a driver for this virtual device.

There are more features provided by the device but these are not
required at this time and therefore not supported yet.

Signed-off-by: Thomas Weißschuh <[email protected]>

---
The OF compatible will never show up in a DTS file, it is synthesized by
QEMU. Therefore I think it doesn't need explicit documentation.
---
 drivers/virt/Kconfig     | 11 ++++++++++
 drivers/virt/Makefile    |  1 +
 drivers/virt/csky_exit.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+)

diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig
index 
d8c848cf09a6afad65b28be20f5fd7e90a0c5307..652546c52d2e00138a782b949672d47c5f5d2189
 100644
--- a/drivers/virt/Kconfig
+++ b/drivers/virt/Kconfig
@@ -41,6 +41,17 @@ config FSL_HV_MANAGER
           4) A kernel interface for receiving callbacks when a managed
             partition shuts down.
 
+config CSKY_EXIT
+       tristate "C-SKY QEMU shutdown driver"
+       depends on OF
+       depends on CSKY || COMPILE_TEST
+       help
+         This driver supports system shutdown via the virtual csky_exit device
+         provided by QEMU.
+
+         To compile this driver as a module, choose M here: the module will
+         be called csky_exit.
+
 source "drivers/virt/vboxguest/Kconfig"
 
 source "drivers/virt/nitro_enclaves/Kconfig"
diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile
index 
f29901bd782058d3552cdec2c2128ad47ce6fe27..5c62db9fbfa501a31c87c4902f835db91633daeb
 100644
--- a/drivers/virt/Makefile
+++ b/drivers/virt/Makefile
@@ -3,6 +3,7 @@
 # Makefile for drivers that support virtualization
 #
 
+obj-$(CONFIG_CSKY_EXIT)                += csky_exit.o
 obj-$(CONFIG_FSL_HV_MANAGER)   += fsl_hypervisor.o
 obj-$(CONFIG_VMGENID)          += vmgenid.o
 obj-y                          += vboxguest/
diff --git a/drivers/virt/csky_exit.c b/drivers/virt/csky_exit.c
new file mode 100644
index 
0000000000000000000000000000000000000000..6f42eb74071ab9ac1b7e9ef03b32f9ba0ef2cf26
--- /dev/null
+++ b/drivers/virt/csky_exit.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * C-SKY QEMU shutdown driver
+ *
+ *  Copyright (C) 2024 Thomas Weißschuh <[email protected]>
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/types.h>
+
+#define CSKY_EXIT_COMMAND_EXIT 0
+
+static void csky_exit_command(void __iomem *base, u32 command, u64 value)
+{
+       writew(value, base + command);
+}
+
+static int csky_exit_poweroff(struct sys_off_data *data)
+{
+       csky_exit_command(data->cb_data, CSKY_EXIT_COMMAND_EXIT, 0);
+       return 0;
+}
+
+static int csky_exit_probe(struct platform_device *pdev)
+{
+       void __iomem *base;
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       return devm_register_sys_off_handler(&pdev->dev, SYS_OFF_MODE_POWER_OFF,
+                                            SYS_OFF_PRIO_PLATFORM + 1,
+                                            csky_exit_poweroff, base);
+}
+
+static const struct of_device_id csky_exit_match[] = {
+       { .compatible = "csky,qemu-exit" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, csky_exit_match);
+
+static struct platform_driver csky_exit_driver = {
+       .driver.name = "csky_exit",
+       .driver.of_match_table = csky_exit_match,
+       .probe = csky_exit_probe,
+};
+module_platform_driver(csky_exit_driver);
+
+MODULE_AUTHOR("Thomas Weißschuh <[email protected]>");
+MODULE_DESCRIPTION("C-SKY QEMU shutdown driver");
+MODULE_LICENSE("GPL");

-- 
2.46.2


Reply via email to