/* SPDX-License-Identifier: GPL-2.0-only */ /* This file is part of the coreboot project. */ #include #include #include #include #include #include "pciehp.h" void intel_acpi_pcie_hotplug_generator(u8 *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(); } static void slot_dev_read_resources(struct device *dev) { struct resource *resource; resource = new_resource(dev, 0x10); resource->size = 1 << 23; resource->align = 22; resource->gran = 22; resource->limit = 0xffffffff; resource->flags |= IORESOURCE_MEM; resource = new_resource(dev, 0x14); resource->size = 1 << 23; resource->align = 22; resource->gran = 22; resource->limit = 0xffffffff; resource->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH; resource = new_resource(dev, 0x18); resource->size = 1 << 12; resource->align = 12; resource->gran = 12; resource->limit = 0xffff; resource->flags |= IORESOURCE_IO; } static struct device_operations slot_dev_ops = { .read_resources = slot_dev_read_resources, }; /* Add a dummy device to reserve I/O space for hotpluggable devices. */ void intel_acpi_pcie_hotplug_scan_slot(struct bus *bus) { struct device *slot; struct device_path slot_path = { .type = DEVICE_PATH_NONE }; slot = alloc_dev(bus, &slot_path); slot->ops = &slot_dev_ops; }