| 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/core/sysbus.h" |
| 63 | #include "hw/acpi/memory_hotplug.h" |
| 64 | #include "hw/acpi/ghes.h" |
| 65 | #include "hw/acpi/cpu.h" |
| 66 | #include "hw/acpi/pcihp.h" |
| 67 | #include "qom/object.h" |
| 68 | |
| 69 | #define ACPI_POWER_BUTTON_DEVICE "PWRB" |
| 70 | |
| 71 | #define TYPE_ACPI_GED "acpi-ged" |
| 72 | OBJECT_DECLARE_TYPE(AcpiGedState, AcpiGedClass, ACPI_GED) |
| 73 | |
| 74 | #define ACPI_GED_EVT_SEL_OFFSET 0x0 |
| 75 | #define ACPI_GED_EVT_SEL_LEN 0x4 |
| 76 | |
| 77 | #define ACPI_GED_REG_SLEEP_CTL 0x00 |
| 78 | #define ACPI_GED_REG_SLEEP_STS 0x01 |
| 79 | #define ACPI_GED_REG_RESET 0x02 |
| 80 | #define ACPI_GED_REG_COUNT 0x03 |
| 81 | |
| 82 | /* ACPI_GED_REG_RESET value for reset*/ |
| 83 | #define ACPI_GED_RESET_VALUE 0x42 |
| 84 | |
| 85 | /* [ACPI 5.0 Chapter 4.8.3.7] Sleep Control and Status Register */ |
| 86 | #define ACPI_GED_SLP_TYP_POS 0x2 /* SLP_TYPx Bit Offset */ |
| 87 | #define ACPI_GED_SLP_TYP_MASK 0x07 /* SLP_TYPx 3-bit mask */ |
| 88 | #define ACPI_GED_SLP_TYP_S5 0x05 /* System _S5 State (Soft Off) */ |
| 89 | #define ACPI_GED_SLP_EN 0x20 /* SLP_EN write-only bit */ |
| 90 | |
| 91 | #define GED_DEVICE "GED" |
| 92 | #define AML_GED_EVT_REG "EREG" |
| 93 | #define AML_GED_EVT_SEL "ESEL" |
| 94 | #define AML_GED_EVT_CPU_SCAN_METHOD "\\_SB.GED.CSCN" |
| 95 | |
| 96 | /* |
| 97 | * Platforms need to specify the GED event bitmap |
| 98 | * to describe what kind of events they want to support |
| 99 | * through GED. |
| 100 | */ |
| 101 | #define ACPI_GED_MEM_HOTPLUG_EVT 0x1 |
| 102 | #define ACPI_GED_PWR_DOWN_EVT 0x2 |
| 103 | #define ACPI_GED_NVDIMM_HOTPLUG_EVT 0x4 |
| 104 | #define ACPI_GED_CPU_HOTPLUG_EVT 0x8 |
| 105 | #define ACPI_GED_PCI_HOTPLUG_EVT 0x10 |
| 106 | #define ACPI_GED_ERROR_EVT 0x20 |
| 107 | |
| 108 | typedef struct GEDState { |
| 109 | MemoryRegion evt; |
| 110 | MemoryRegion regs; |
| 111 | uint32_t sel; |
| 112 | } GEDState; |
| 113 | |
| 114 | #define ACPI_PCIHP_REGION_NAME "pcihp container" |
| 115 | #define ACPI_MEMHP_REGION_NAME "memhp container" |
| 116 | |
| 117 | struct AcpiGedState { |
| 118 | SysBusDevice parent_obj; |
| 119 | MemHotplugState memhp_state; |
| 120 | MemoryRegion container_memhp; |
| 121 | CPUHotplugState cpuhp_state; |
| 122 | MemoryRegion container_cpuhp; |
| 123 | AcpiPciHpState pcihp_state; |
| 124 | MemoryRegion container_pcihp; |
| 125 | GEDState ged_state; |
| 126 | uint32_t ged_event_bitmap; |
| 127 | qemu_irq irq; |
| 128 | AcpiGhesState ghes_state; |
| 129 | }; |
| 130 | |
| 131 | typedef struct AcpiGedClass { |
| 132 | /* <private> */ |
| 133 | SysBusDeviceClass parent_class; |
| 134 | |
| 135 | /*< public >*/ |
| 136 | ResettablePhases parent_phases; |
| 137 | } AcpiGedClass; |
| 138 | |
| 139 | void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev, |
| 140 | uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base); |
| 141 | void acpi_dsdt_add_power_button(Aml *scope); |
| 142 | |
| 143 | #endif |