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