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