soc/intel/common/block/irq: Add support for intel_write_pci0_PRT

Add a new function to fill out the data structures necessary to generate
a _PRT table.

BUG=b:130217151, b:171580862, b:176858827

Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Change-Id: I21a4835890ca03bff83ed0e8791441b3af54cb62
Reviewed-on: https://review.coreboot.org/c/coreboot/+/51159
Reviewed-by: Furquan Shaikh <furquan@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/soc/intel/common/block/include/intelblocks/irq.h b/src/soc/intel/common/block/include/intelblocks/irq.h
index 1c26705..727020a 100644
--- a/src/soc/intel/common/block/include/intelblocks/irq.h
+++ b/src/soc/intel/common/block/include/intelblocks/irq.h
@@ -44,4 +44,6 @@
 const struct pci_irq_entry *assign_pci_irqs(const struct slot_irq_constraints *constraints,
 					    size_t num_slots);
 
+void generate_pin_irq_map(const struct pci_irq_entry *entries);
+
 #endif /* SOC_INTEL_COMMON_IRQ_H */
diff --git a/src/soc/intel/common/block/irq/Kconfig b/src/soc/intel/common/block/irq/Kconfig
index d4d9ab1..ab6fc50 100644
--- a/src/soc/intel/common/block/irq/Kconfig
+++ b/src/soc/intel/common/block/irq/Kconfig
@@ -1,6 +1,7 @@
 config SOC_INTEL_COMMON_BLOCK_IRQ
 	bool
 	select SOC_INTEL_COMMON_BLOCK_GPIO
+	select SOUTHBRIDGE_INTEL_COMMON_PIRQ_ACPI_GEN
 	help
 	  Intel common block support for assigning PCI IRQs dynamically. This
 	  allows coreboot to control the IRQ assignments. They are passed to the
diff --git a/src/soc/intel/common/block/irq/irq.c b/src/soc/intel/common/block/irq/irq.c
index 0a62bb5..eb4daf9 100644
--- a/src/soc/intel/common/block/irq/irq.c
+++ b/src/soc/intel/common/block/irq/irq.c
@@ -6,6 +6,7 @@
 #include <device/pci_def.h>
 #include <intelblocks/gpio.h>
 #include <intelblocks/irq.h>
+#include <intelblocks/lpc_lib.h>
 #include <southbridge/intel/common/acpi_pirq_gen.h>
 #include <stdlib.h>
 #include <string.h>
@@ -343,3 +344,53 @@
 
 	return entries;
 }
+
+static enum pirq irq_to_pirq(unsigned int irq)
+{
+	if (irq >= MIN_SHARED_IRQ && irq <= MAX_SHARED_IRQ)
+		return (enum pirq)(irq - MIN_SHARED_IRQ + PIRQ_A);
+	else
+		/*
+		 * Unknown if devices that require unique IRQs will
+		 * even work in legacy PIC mode, given they cannot map
+		 * to a PIRQ, therefore skip adding an entry.
+		 */
+		return PIRQ_INVALID;
+}
+
+void generate_pin_irq_map(const struct pci_irq_entry *entries)
+{
+	struct slot_pin_irq_map *pin_irq_map;
+	const uint8_t *legacy_pirq_routing;
+	struct pic_pirq_map pirq_map = {0};
+	size_t map_count = 0;
+	size_t pirq_routes;
+	size_t i;
+
+	pin_irq_map = calloc(MAX_SLOTS, sizeof(struct slot_pin_irq_map) * PCI_INT_MAX);
+
+	pirq_map.type = PIRQ_GSI;
+	legacy_pirq_routing = lpc_get_pic_pirq_routing(&pirq_routes);
+	for (i = 0; i < PIRQ_COUNT && i < pirq_routes; i++)
+		pirq_map.gsi[i] = legacy_pirq_routing[i];
+
+	const struct pci_irq_entry *entry = entries;
+	while (entry) {
+		const unsigned int slot = PCI_SLOT(entry->devfn);
+
+		if (is_slot_pin_assigned(pin_irq_map, map_count, slot, entry->pin)) {
+			entry = entry->next;
+			continue;
+		}
+
+		pin_irq_map[map_count].slot = slot;
+		pin_irq_map[map_count].pin = entry->pin;
+		pin_irq_map[map_count].apic_gsi = entry->irq;
+		pin_irq_map[map_count].pic_pirq = irq_to_pirq(entry->irq);
+		map_count++;
+		entry = entry->next;
+	}
+
+	intel_write_pci0_PRT(pin_irq_map, map_count, &pirq_map);
+	free(pin_irq_map);
+}