1 /*
2  *
3  * Copyright (c) 2018 Intel Corporation
4  * Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd
5  * Written by Samuel Ortiz, Shameer Kolothum
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU General Public License,
9  * version 2 or later, as published by the Free Software Foundation.
10  *
11  * The ACPI Generic Event Device (GED) is a hardware-reduced specific
12  * device[ACPI v6.1 Section 5.6.9] that handles all platform events,
13  * including the hotplug ones. Generic Event Device allows platforms
14  * to handle interrupts in ACPI ASL statements. It follows a very
15  * similar approach like the _EVT method from GPIO events. All
16  * interrupts are listed in  _CRS and the handler is written in _EVT
17  * method. Here, we use a single interrupt for the GED device, relying
18  * on IO memory region to communicate the type of device affected by
19  * the interrupt. This way, we can support up to 32 events with a
20  * unique interrupt.
21  *
22  * Here is an example.
23  *
24  * Device (\_SB.GED)
25  * {
26  *     Name (_HID, "ACPI0013")
27  *     Name (_UID, Zero)
28  *     Name (_CRS, ResourceTemplate ()
29  *     {
30  *         Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, )
31  *         {
32  *              0x00000029,
33  *         }
34  *     })
35  *     OperationRegion (EREG, SystemMemory, 0x09080000, 0x04)
36  *     Field (EREG, DWordAcc, NoLock, WriteAsZeros)
37  *     {
38  *         ESEL,   32
39  *     }
40  *
41  *     Method (_EVT, 1, Serialized)  // _EVT: Event
42  *     {
43  *         Local0 = ESEL // ESEL = IO memory region which specifies the
44  *                       // device type.
45  *         If (((Local0 & One) == One))
46  *         {
47  *             MethodEvent1()
48  *         }
49  *         If ((Local0 & 0x2) == 0x2)
50  *         {
51  *             MethodEvent2()
52  *         }
53  *         ...
54  *     }
55  * }
56  *
57  */
58 
59 #ifndef HW_ACPI_GENERIC_EVENT_DEVICE_H
60 #define HW_ACPI_GENERIC_EVENT_DEVICE_H
61 
62 #include "hw/sysbus.h"
63 #include "hw/acpi/memory_hotplug.h"
64 #include "hw/acpi/ghes.h"
65 #include "hw/acpi/cpu.h"
66 #include "qom/object.h"
67 
68 #define ACPI_POWER_BUTTON_DEVICE "PWRB"
69 
70 #define TYPE_ACPI_GED "acpi-ged"
71 OBJECT_DECLARE_SIMPLE_TYPE(AcpiGedState, ACPI_GED)
72 
73 #define ACPI_GED_EVT_SEL_OFFSET    0x0
74 #define ACPI_GED_EVT_SEL_LEN       0x4
75 
76 #define ACPI_GED_REG_SLEEP_CTL     0x00
77 #define ACPI_GED_REG_SLEEP_STS     0x01
78 #define ACPI_GED_REG_RESET         0x02
79 #define ACPI_GED_REG_COUNT         0x03
80 
81 /* ACPI_GED_REG_RESET value for reset*/
82 #define ACPI_GED_RESET_VALUE       0x42
83 
84 /* [ACPI 5.0 Chapter 4.8.3.7] Sleep Control and Status Register */
85 #define ACPI_GED_SLP_TYP_POS       0x2   /* SLP_TYPx Bit Offset */
86 #define ACPI_GED_SLP_TYP_MASK      0x07  /* SLP_TYPx 3-bit mask */
87 #define ACPI_GED_SLP_TYP_S5        0x05  /* System _S5 State (Soft Off) */
88 #define ACPI_GED_SLP_EN            0x20  /* SLP_EN write-only bit */
89 
90 #define GED_DEVICE      "GED"
91 #define AML_GED_EVT_REG "EREG"
92 #define AML_GED_EVT_SEL "ESEL"
93 #define AML_GED_EVT_CPU_SCAN_METHOD "\\_SB.GED.CSCN"
94 
95 /*
96  * Platforms need to specify the GED event bitmap
97  * to describe what kind of events they want to support
98  * through GED.
99  */
100 #define ACPI_GED_MEM_HOTPLUG_EVT   0x1
101 #define ACPI_GED_PWR_DOWN_EVT      0x2
102 #define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4
103 #define ACPI_GED_CPU_HOTPLUG_EVT    0x8
104 
105 typedef struct GEDState {
106     MemoryRegion evt;
107     MemoryRegion regs;
108     uint32_t     sel;
109 } GEDState;
110 
111 struct AcpiGedState {
112     SysBusDevice parent_obj;
113     MemHotplugState memhp_state;
114     MemoryRegion container_memhp;
115     CPUHotplugState cpuhp_state;
116     MemoryRegion container_cpuhp;
117     GEDState ged_state;
118     uint32_t ged_event_bitmap;
119     qemu_irq irq;
120     AcpiGhesState ghes_state;
121 };
122 
123 void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev,
124                    uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base);
125 void acpi_dsdt_add_power_button(Aml *scope);
126 
127 #endif
128