1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * QEMU Virt Machine System Controller Driver 4 * 5 * Copyright (C) 2026 Kuan-Wei Chiu <visitorckw@gmail.com> 6 */ 7 8 #include <linux/io.h> 9 #include <linux/module.h> 10 #include <linux/mod_devicetable.h> 11 #include <linux/platform_device.h> 12 #include <linux/reboot.h> 13 14 /* Registers */ 15 #define VIRT_CTRL_REG_FEATURES 0x00 16 #define VIRT_CTRL_REG_CMD 0x04 17 18 /* Commands */ 19 #define CMD_NOOP 0 20 #define CMD_RESET 1 21 #define CMD_HALT 2 22 #define CMD_PANIC 3 23 24 struct qemu_virt_ctrl { 25 void __iomem *base; 26 struct notifier_block reboot_nb; 27 }; 28 29 static inline void virt_ctrl_write32(u32 val, void __iomem *addr) 30 { 31 if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 32 iowrite32be(val, addr); 33 else 34 iowrite32(val, addr); 35 } 36 37 static int qemu_virt_ctrl_power_off(struct sys_off_data *data) 38 { 39 struct qemu_virt_ctrl *ctrl = data->cb_data; 40 41 virt_ctrl_write32(CMD_HALT, ctrl->base + VIRT_CTRL_REG_CMD); 42 43 return NOTIFY_DONE; 44 } 45 46 static int qemu_virt_ctrl_restart(struct sys_off_data *data) 47 { 48 struct qemu_virt_ctrl *ctrl = data->cb_data; 49 50 virt_ctrl_write32(CMD_RESET, ctrl->base + VIRT_CTRL_REG_CMD); 51 52 return NOTIFY_DONE; 53 } 54 55 static int qemu_virt_ctrl_reboot_notify(struct notifier_block *nb, 56 unsigned long action, void *data) 57 { 58 struct qemu_virt_ctrl *ctrl = container_of(nb, struct qemu_virt_ctrl, reboot_nb); 59 60 if (action == SYS_HALT) 61 virt_ctrl_write32(CMD_HALT, ctrl->base + VIRT_CTRL_REG_CMD); 62 63 return NOTIFY_DONE; 64 } 65 66 static int qemu_virt_ctrl_probe(struct platform_device *pdev) 67 { 68 struct qemu_virt_ctrl *ctrl; 69 int ret; 70 71 ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); 72 if (!ctrl) 73 return -ENOMEM; 74 75 ctrl->base = devm_platform_ioremap_resource(pdev, 0); 76 if (IS_ERR(ctrl->base)) 77 return PTR_ERR(ctrl->base); 78 79 ret = devm_register_sys_off_handler(&pdev->dev, 80 SYS_OFF_MODE_RESTART, 81 SYS_OFF_PRIO_DEFAULT, 82 qemu_virt_ctrl_restart, 83 ctrl); 84 if (ret) 85 return dev_err_probe(&pdev->dev, ret, 86 "cannot register restart handler\n"); 87 88 ret = devm_register_sys_off_handler(&pdev->dev, 89 SYS_OFF_MODE_POWER_OFF, 90 SYS_OFF_PRIO_DEFAULT, 91 qemu_virt_ctrl_power_off, 92 ctrl); 93 if (ret) 94 return dev_err_probe(&pdev->dev, ret, 95 "cannot register power-off handler\n"); 96 97 ctrl->reboot_nb.notifier_call = qemu_virt_ctrl_reboot_notify; 98 ret = devm_register_reboot_notifier(&pdev->dev, &ctrl->reboot_nb); 99 if (ret) 100 return dev_err_probe(&pdev->dev, ret, "cannot register reboot notifier\n"); 101 102 return 0; 103 } 104 105 static const struct platform_device_id qemu_virt_ctrl_id[] = { 106 { "qemu-virt-ctrl", 0 }, 107 { } 108 }; 109 MODULE_DEVICE_TABLE(platform, qemu_virt_ctrl_id); 110 111 static struct platform_driver qemu_virt_ctrl_driver = { 112 .probe = qemu_virt_ctrl_probe, 113 .driver = { 114 .name = "qemu-virt-ctrl", 115 }, 116 .id_table = qemu_virt_ctrl_id, 117 }; 118 module_platform_driver(qemu_virt_ctrl_driver); 119 120 MODULE_AUTHOR("Kuan-Wei Chiu <visitorckw@gmail.com>"); 121 MODULE_DESCRIPTION("QEMU Virt Machine System Controller Driver"); 122 MODULE_LICENSE("GPL"); 123