10791bc02SLaurent Vivier /* 265b4c8c7SPhilippe Mathieu-Daudé * SPDX-License-Identifier: GPL-2.0-or-later 30791bc02SLaurent Vivier * 40791bc02SLaurent Vivier * Virt system Controller 50791bc02SLaurent Vivier */ 60791bc02SLaurent Vivier 70791bc02SLaurent Vivier #include "qemu/osdep.h" 80791bc02SLaurent Vivier #include "hw/qdev-properties.h" 90791bc02SLaurent Vivier #include "hw/sysbus.h" 100791bc02SLaurent Vivier #include "migration/vmstate.h" 110791bc02SLaurent Vivier #include "qemu/log.h" 120791bc02SLaurent Vivier #include "trace.h" 130791bc02SLaurent Vivier #include "sysemu/runstate.h" 140791bc02SLaurent Vivier #include "hw/misc/virt_ctrl.h" 150791bc02SLaurent Vivier 160791bc02SLaurent Vivier enum { 170791bc02SLaurent Vivier REG_FEATURES = 0x00, 180791bc02SLaurent Vivier REG_CMD = 0x04, 190791bc02SLaurent Vivier }; 200791bc02SLaurent Vivier 210791bc02SLaurent Vivier #define FEAT_POWER_CTRL 0x00000001 220791bc02SLaurent Vivier 230791bc02SLaurent Vivier enum { 240791bc02SLaurent Vivier CMD_NOOP, 250791bc02SLaurent Vivier CMD_RESET, 260791bc02SLaurent Vivier CMD_HALT, 270791bc02SLaurent Vivier CMD_PANIC, 280791bc02SLaurent Vivier }; 290791bc02SLaurent Vivier 300791bc02SLaurent Vivier static uint64_t virt_ctrl_read(void *opaque, hwaddr addr, unsigned size) 310791bc02SLaurent Vivier { 320791bc02SLaurent Vivier VirtCtrlState *s = opaque; 330791bc02SLaurent Vivier uint64_t value = 0; 340791bc02SLaurent Vivier 350791bc02SLaurent Vivier switch (addr) { 360791bc02SLaurent Vivier case REG_FEATURES: 370791bc02SLaurent Vivier value = FEAT_POWER_CTRL; 380791bc02SLaurent Vivier break; 390791bc02SLaurent Vivier default: 400791bc02SLaurent Vivier qemu_log_mask(LOG_UNIMP, 410791bc02SLaurent Vivier "%s: unimplemented register read 0x%02"HWADDR_PRIx"\n", 420791bc02SLaurent Vivier __func__, addr); 430791bc02SLaurent Vivier break; 440791bc02SLaurent Vivier } 450791bc02SLaurent Vivier 460791bc02SLaurent Vivier trace_virt_ctrl_write(s, addr, size, value); 470791bc02SLaurent Vivier 480791bc02SLaurent Vivier return value; 490791bc02SLaurent Vivier } 500791bc02SLaurent Vivier 510791bc02SLaurent Vivier static void virt_ctrl_write(void *opaque, hwaddr addr, uint64_t value, 520791bc02SLaurent Vivier unsigned size) 530791bc02SLaurent Vivier { 540791bc02SLaurent Vivier VirtCtrlState *s = opaque; 550791bc02SLaurent Vivier 560791bc02SLaurent Vivier trace_virt_ctrl_write(s, addr, size, value); 570791bc02SLaurent Vivier 580791bc02SLaurent Vivier switch (addr) { 590791bc02SLaurent Vivier case REG_CMD: 600791bc02SLaurent Vivier switch (value) { 610791bc02SLaurent Vivier case CMD_NOOP: 620791bc02SLaurent Vivier break; 630791bc02SLaurent Vivier case CMD_RESET: 640791bc02SLaurent Vivier qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 650791bc02SLaurent Vivier break; 660791bc02SLaurent Vivier case CMD_HALT: 670791bc02SLaurent Vivier qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 680791bc02SLaurent Vivier break; 690791bc02SLaurent Vivier case CMD_PANIC: 700791bc02SLaurent Vivier qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_PANIC); 710791bc02SLaurent Vivier break; 720791bc02SLaurent Vivier } 730791bc02SLaurent Vivier break; 740791bc02SLaurent Vivier default: 750791bc02SLaurent Vivier qemu_log_mask(LOG_UNIMP, 760791bc02SLaurent Vivier "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n", 770791bc02SLaurent Vivier __func__, addr); 780791bc02SLaurent Vivier break; 790791bc02SLaurent Vivier } 800791bc02SLaurent Vivier } 810791bc02SLaurent Vivier 820791bc02SLaurent Vivier static const MemoryRegionOps virt_ctrl_ops = { 830791bc02SLaurent Vivier .read = virt_ctrl_read, 840791bc02SLaurent Vivier .write = virt_ctrl_write, 850791bc02SLaurent Vivier .endianness = DEVICE_NATIVE_ENDIAN, 860791bc02SLaurent Vivier .valid.max_access_size = 4, 870791bc02SLaurent Vivier .impl.max_access_size = 4, 880791bc02SLaurent Vivier }; 890791bc02SLaurent Vivier 900791bc02SLaurent Vivier static void virt_ctrl_reset(DeviceState *dev) 910791bc02SLaurent Vivier { 920791bc02SLaurent Vivier VirtCtrlState *s = VIRT_CTRL(dev); 930791bc02SLaurent Vivier 940791bc02SLaurent Vivier trace_virt_ctrl_reset(s); 950791bc02SLaurent Vivier } 960791bc02SLaurent Vivier 970791bc02SLaurent Vivier static void virt_ctrl_realize(DeviceState *dev, Error **errp) 980791bc02SLaurent Vivier { 990791bc02SLaurent Vivier VirtCtrlState *s = VIRT_CTRL(dev); 1000791bc02SLaurent Vivier 1010791bc02SLaurent Vivier trace_virt_ctrl_instance_init(s); 1020791bc02SLaurent Vivier 1030791bc02SLaurent Vivier memory_region_init_io(&s->iomem, OBJECT(s), &virt_ctrl_ops, s, 1040791bc02SLaurent Vivier "virt-ctrl", 0x100); 1050791bc02SLaurent Vivier } 1060791bc02SLaurent Vivier 1070791bc02SLaurent Vivier static const VMStateDescription vmstate_virt_ctrl = { 1080791bc02SLaurent Vivier .name = "virt-ctrl", 1090791bc02SLaurent Vivier .version_id = 1, 1100791bc02SLaurent Vivier .minimum_version_id = 1, 111*e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 1120791bc02SLaurent Vivier VMSTATE_UINT32(irq_enabled, VirtCtrlState), 1130791bc02SLaurent Vivier VMSTATE_END_OF_LIST() 1140791bc02SLaurent Vivier } 1150791bc02SLaurent Vivier }; 1160791bc02SLaurent Vivier 1170791bc02SLaurent Vivier static void virt_ctrl_instance_init(Object *obj) 1180791bc02SLaurent Vivier { 1190791bc02SLaurent Vivier SysBusDevice *dev = SYS_BUS_DEVICE(obj); 1200791bc02SLaurent Vivier VirtCtrlState *s = VIRT_CTRL(obj); 1210791bc02SLaurent Vivier 1220791bc02SLaurent Vivier trace_virt_ctrl_instance_init(s); 1230791bc02SLaurent Vivier 1240791bc02SLaurent Vivier sysbus_init_mmio(dev, &s->iomem); 1250791bc02SLaurent Vivier sysbus_init_irq(dev, &s->irq); 1260791bc02SLaurent Vivier } 1270791bc02SLaurent Vivier 1280791bc02SLaurent Vivier static void virt_ctrl_class_init(ObjectClass *oc, void *data) 1290791bc02SLaurent Vivier { 1300791bc02SLaurent Vivier DeviceClass *dc = DEVICE_CLASS(oc); 1310791bc02SLaurent Vivier 1320791bc02SLaurent Vivier dc->reset = virt_ctrl_reset; 1330791bc02SLaurent Vivier dc->realize = virt_ctrl_realize; 1340791bc02SLaurent Vivier dc->vmsd = &vmstate_virt_ctrl; 1350791bc02SLaurent Vivier } 1360791bc02SLaurent Vivier 1370791bc02SLaurent Vivier static const TypeInfo virt_ctrl_info = { 1380791bc02SLaurent Vivier .name = TYPE_VIRT_CTRL, 1390791bc02SLaurent Vivier .parent = TYPE_SYS_BUS_DEVICE, 1400791bc02SLaurent Vivier .class_init = virt_ctrl_class_init, 1410791bc02SLaurent Vivier .instance_init = virt_ctrl_instance_init, 1420791bc02SLaurent Vivier .instance_size = sizeof(VirtCtrlState), 1430791bc02SLaurent Vivier }; 1440791bc02SLaurent Vivier 1450791bc02SLaurent Vivier static void virt_ctrl_register_types(void) 1460791bc02SLaurent Vivier { 1470791bc02SLaurent Vivier type_register_static(&virt_ctrl_info); 1480791bc02SLaurent Vivier } 1490791bc02SLaurent Vivier 1500791bc02SLaurent Vivier type_init(virt_ctrl_register_types) 151