| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <string.h> |
| #include <acpi/acpigen.h> |
| #include <device/device.h> |
| #include <device/pci.h> |
| #include <stdbool.h> |
| |
| #include "pciehp.h" |
| |
| void intel_acpi_pcie_hotplug_generator(bool *hotplug_map, int port_number) |
| { |
| int port; |
| int have_hotplug = 0; |
| |
| for (port = 0; port < port_number; port++) { |
| if (hotplug_map[port]) { |
| have_hotplug = 1; |
| } |
| } |
| |
| if (!have_hotplug) { |
| return; |
| } |
| |
| for (port = 0; port < port_number; port++) { |
| if (hotplug_map[port]) { |
| char scope_name[] = "\\_SB.PCI0.RP0x"; |
| scope_name[sizeof("\\_SB.PCI0.RP0x") - 2] = '1' + port; |
| acpigen_write_scope(scope_name); |
| |
| /* |
| Device (SLOT) |
| { |
| Name (_ADR, 0x00) |
| Method (_RMV, 0, NotSerialized) |
| { |
| Return (0x01) |
| } |
| } |
| */ |
| |
| acpigen_write_device("SLOT"); |
| |
| acpigen_write_name_byte("_ADR", 0x00); |
| |
| acpigen_write_method("_RMV", 0); |
| /* ReturnOp */ |
| acpigen_emit_byte(0xa4); |
| /* One */ |
| acpigen_emit_byte(0x01); |
| acpigen_pop_len(); |
| acpigen_pop_len(); |
| acpigen_pop_len(); |
| } |
| } |
| |
| /* Method (_L01, 0, NotSerialized) |
| { |
| If (\_SB.PCI0.RP04.HPCS) |
| { |
| Sleep (100) |
| Store (0x01, \_SB.PCI0.RP04.HPCS) |
| If (\_SB.PCI0.RP04.PDC) |
| { |
| Store (0x01, \_SB.PCI0.RP04.PDC) |
| Notify (\_SB.PCI0.RP04, 0x00) |
| } |
| } |
| } |
| |
| */ |
| acpigen_write_scope("\\_GPE"); |
| acpigen_write_method("_L01", 0); |
| for (port = 0; port < port_number; port++) { |
| if (hotplug_map[port]) { |
| char reg_name[] = "\\_SB.PCI0.RP0x.HPCS"; |
| reg_name[sizeof("\\_SB.PCI0.RP0x") - 2] = '1' + port; |
| acpigen_emit_byte(0xa0); /* IfOp. */ |
| acpigen_write_len_f(); |
| acpigen_emit_namestring(reg_name); |
| |
| /* Sleep (100) */ |
| acpigen_emit_byte(0x5b); /* SleepOp. */ |
| acpigen_emit_byte(0x22); |
| acpigen_write_byte(100); |
| |
| /* Store (0x01, \_SB.PCI0.RP04.HPCS) */ |
| acpigen_emit_byte(0x70); |
| acpigen_emit_byte(0x01); |
| acpigen_emit_namestring(reg_name); |
| |
| memcpy(reg_name + sizeof("\\_SB.PCI0.RP0x.") - 1, "PDC", 4); |
| |
| /* If (\_SB.PCI0.RP04.PDC) */ |
| acpigen_emit_byte(0xa0); /* IfOp. */ |
| acpigen_write_len_f(); |
| acpigen_emit_namestring(reg_name); |
| |
| /* Store (0x01, \_SB.PCI0.RP04.PDC) */ |
| acpigen_emit_byte(0x70); |
| acpigen_emit_byte(0x01); |
| acpigen_emit_namestring(reg_name); |
| |
| reg_name[sizeof("\\_SB.PCI0.RP0x") - 1] = '\0'; |
| |
| /* Notify(\_SB.PCI0.RP04, 0x00) */ |
| acpigen_emit_byte(0x86); |
| acpigen_emit_namestring(reg_name); |
| acpigen_emit_byte(0x00); |
| acpigen_pop_len(); |
| acpigen_pop_len(); |
| } |
| } |
| acpigen_pop_len(); |
| acpigen_pop_len(); |
| } |