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