10791bc02SLaurent Vivier /*
2*65b4c8c7SPhilippe 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
virt_ctrl_read(void * opaque,hwaddr addr,unsigned size)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
virt_ctrl_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)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
virt_ctrl_reset(DeviceState * dev)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
virt_ctrl_realize(DeviceState * dev,Error ** errp)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,
1110791bc02SLaurent Vivier .fields = (VMStateField[]) {
1120791bc02SLaurent Vivier VMSTATE_UINT32(irq_enabled, VirtCtrlState),
1130791bc02SLaurent Vivier VMSTATE_END_OF_LIST()
1140791bc02SLaurent Vivier }
1150791bc02SLaurent Vivier };
1160791bc02SLaurent Vivier
virt_ctrl_instance_init(Object * obj)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
virt_ctrl_class_init(ObjectClass * oc,void * data)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
virt_ctrl_register_types(void)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