xref: /qemu/hw/misc/sbsa_ec.c (revision dccb92b5caee973cb10f3f429741efe5cf747feb)
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