1 /* 2 * ARM SBSA Reference Platform Embedded Controller 3 * 4 * A device to allow PSCI running in the secure side of sbsa-ref machine 5 * to communicate platform power states to qemu. 6 * 7 * Copyright (c) 2020 Nuvia Inc 8 * Written by Graeme Gregory <graeme@nuviainc.com> 9 * 10 * SPDX-License-Identifier: GPL-2.0-or-later 11 */ 12 13 #include "qemu/osdep.h" 14 #include "qemu/log.h" 15 #include "hw/sysbus.h" 16 #include "sysemu/runstate.h" 17 18 typedef struct SECUREECState { 19 SysBusDevice parent_obj; 20 MemoryRegion iomem; 21 } SECUREECState; 22 23 #define TYPE_SBSA_SECURE_EC "sbsa-ec" 24 OBJECT_DECLARE_SIMPLE_TYPE(SECUREECState, SBSA_SECURE_EC) 25 26 enum sbsa_ec_powerstates { 27 SBSA_EC_CMD_POWEROFF = 0x01, 28 SBSA_EC_CMD_REBOOT = 0x02, 29 }; 30 31 static uint64_t sbsa_ec_read(void *opaque, hwaddr offset, unsigned size) 32 { 33 /* No use for this currently */ 34 qemu_log_mask(LOG_GUEST_ERROR, "sbsa-ec: no readable registers"); 35 return 0; 36 } 37 38 static void sbsa_ec_write(void *opaque, hwaddr offset, 39 uint64_t value, unsigned size) 40 { 41 if (offset == 0) { /* PSCI machine power command register */ 42 switch (value) { 43 case SBSA_EC_CMD_POWEROFF: 44 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 45 break; 46 case SBSA_EC_CMD_REBOOT: 47 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 48 break; 49 default: 50 qemu_log_mask(LOG_GUEST_ERROR, 51 "sbsa-ec: unknown power command"); 52 } 53 } else { 54 qemu_log_mask(LOG_GUEST_ERROR, "sbsa-ec: unknown EC register"); 55 } 56 } 57 58 static const MemoryRegionOps sbsa_ec_ops = { 59 .read = sbsa_ec_read, 60 .write = sbsa_ec_write, 61 .endianness = DEVICE_NATIVE_ENDIAN, 62 .valid.min_access_size = 4, 63 .valid.max_access_size = 4, 64 }; 65 66 static void sbsa_ec_init(Object *obj) 67 { 68 SECUREECState *s = SBSA_SECURE_EC(obj); 69 SysBusDevice *dev = SYS_BUS_DEVICE(obj); 70 71 memory_region_init_io(&s->iomem, obj, &sbsa_ec_ops, s, "sbsa-ec", 72 0x1000); 73 sysbus_init_mmio(dev, &s->iomem); 74 } 75 76 static void sbsa_ec_class_init(ObjectClass *klass, void *data) 77 { 78 DeviceClass *dc = DEVICE_CLASS(klass); 79 80 /* No vmstate or reset required: device has no internal state */ 81 dc->user_creatable = false; 82 } 83 84 static const TypeInfo sbsa_ec_info = { 85 .name = TYPE_SBSA_SECURE_EC, 86 .parent = TYPE_SYS_BUS_DEVICE, 87 .instance_size = sizeof(SECUREECState), 88 .instance_init = sbsa_ec_init, 89 .class_init = sbsa_ec_class_init, 90 }; 91 92 static void sbsa_ec_register_type(void) 93 { 94 type_register_static(&sbsa_ec_info); 95 } 96 97 type_init(sbsa_ec_register_type); 98