summaryrefslogtreecommitdiffstats
path: root/src/soc
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc')
-rw-r--r--src/soc/intel/common/block/include/intelblocks/irq.h2
-rw-r--r--src/soc/intel/common/block/irq/Kconfig1
-rw-r--r--src/soc/intel/common/block/irq/irq.c51
3 files changed, 54 insertions, 0 deletions
diff --git a/src/soc/intel/common/block/include/intelblocks/irq.h b/src/soc/intel/common/block/include/intelblocks/irq.h
index 1c267052c82d..727020a5df7f 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 @@ struct pci_irq_entry {
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 d4d9ab1b0372..ab6fc509cb12 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 0a62bb58c926..eb4daf9a147d 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 @@ const struct pci_irq_entry *assign_pci_irqs(const struct slot_irq_constraints *c
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);
+}