99 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			99 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * ARM SBSA Reference Platform Embedded Controller | ||
|  |  * | ||
|  |  * A device to allow PSCI running in the secure side of sbsa-ref machine | ||
|  |  * to communicate platform power states to qemu. | ||
|  |  * | ||
|  |  * Copyright (c) 2020 Nuvia Inc | ||
|  |  * Written by Graeme Gregory <graeme@nuviainc.com> | ||
|  |  * | ||
|  |  * SPDX-License-Identifer: GPL-2.0-or-later | ||
|  |  */ | ||
|  | 
 | ||
|  | #include "qemu/osdep.h"
 | ||
|  | #include "qemu-common.h"
 | ||
|  | #include "qemu/log.h"
 | ||
|  | #include "hw/sysbus.h"
 | ||
|  | #include "sysemu/runstate.h"
 | ||
|  | 
 | ||
|  | typedef struct { | ||
|  |     SysBusDevice parent_obj; | ||
|  |     MemoryRegion iomem; | ||
|  | } SECUREECState; | ||
|  | 
 | ||
|  | #define TYPE_SBSA_EC      "sbsa-ec"
 | ||
|  | #define SECURE_EC(obj) OBJECT_CHECK(SECUREECState, (obj), TYPE_SBSA_EC)
 | ||
|  | 
 | ||
|  | enum sbsa_ec_powerstates { | ||
|  |     SBSA_EC_CMD_POWEROFF = 0x01, | ||
|  |     SBSA_EC_CMD_REBOOT = 0x02, | ||
|  | }; | ||
|  | 
 | ||
|  | static uint64_t sbsa_ec_read(void *opaque, hwaddr offset, unsigned size) | ||
|  | { | ||
|  |     /* No use for this currently */ | ||
|  |     qemu_log_mask(LOG_GUEST_ERROR, "sbsa-ec: no readable registers"); | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | static void sbsa_ec_write(void *opaque, hwaddr offset, | ||
|  |                      uint64_t value, unsigned size) | ||
|  | { | ||
|  |     if (offset == 0) { /* PSCI machine power command register */ | ||
|  |         switch (value) { | ||
|  |         case SBSA_EC_CMD_POWEROFF: | ||
|  |             qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); | ||
|  |             break; | ||
|  |         case SBSA_EC_CMD_REBOOT: | ||
|  |             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); | ||
|  |             break; | ||
|  |         default: | ||
|  |             qemu_log_mask(LOG_GUEST_ERROR, | ||
|  |                           "sbsa-ec: unknown power command"); | ||
|  |         } | ||
|  |     } else { | ||
|  |         qemu_log_mask(LOG_GUEST_ERROR, "sbsa-ec: unknown EC register"); | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | static const MemoryRegionOps sbsa_ec_ops = { | ||
|  |     .read = sbsa_ec_read, | ||
|  |     .write = sbsa_ec_write, | ||
|  |     .endianness = DEVICE_NATIVE_ENDIAN, | ||
|  |     .valid.min_access_size = 4, | ||
|  |     .valid.max_access_size = 4, | ||
|  | }; | ||
|  | 
 | ||
|  | static void sbsa_ec_init(Object *obj) | ||
|  | { | ||
|  |     SECUREECState *s = SECURE_EC(obj); | ||
|  |     SysBusDevice *dev = SYS_BUS_DEVICE(obj); | ||
|  | 
 | ||
|  |     memory_region_init_io(&s->iomem, obj, &sbsa_ec_ops, s, "sbsa-ec", | ||
|  |                           0x1000); | ||
|  |     sysbus_init_mmio(dev, &s->iomem); | ||
|  | } | ||
|  | 
 | ||
|  | static void sbsa_ec_class_init(ObjectClass *klass, void *data) | ||
|  | { | ||
|  |     DeviceClass *dc = DEVICE_CLASS(klass); | ||
|  | 
 | ||
|  |     /* No vmstate or reset required: device has no internal state */ | ||
|  |     dc->user_creatable = false; | ||
|  | } | ||
|  | 
 | ||
|  | static const TypeInfo sbsa_ec_info = { | ||
|  |     .name          = TYPE_SBSA_EC, | ||
|  |     .parent        = TYPE_SYS_BUS_DEVICE, | ||
|  |     .instance_size = sizeof(SECUREECState), | ||
|  |     .instance_init = sbsa_ec_init, | ||
|  |     .class_init    = sbsa_ec_class_init, | ||
|  | }; | ||
|  | 
 | ||
|  | static void sbsa_ec_register_type(void) | ||
|  | { | ||
|  |     type_register_static(&sbsa_ec_info); | ||
|  | } | ||
|  | 
 | ||
|  | type_init(sbsa_ec_register_type); |