diff --git a/src/soc/intel/xeon_sp/include/soc/irq.h b/src/soc/intel/xeon_sp/include/soc/irq.h index 4d3ad7a09f..209f69942e 100644 --- a/src/soc/intel/xeon_sp/include/soc/irq.h +++ b/src/soc/intel/xeon_sp/include/soc/irq.h @@ -6,5 +6,6 @@ #define PCH_IRQ10 10 #define PCH_IRQ11 11 #define PCH_IRQ14 14 +#define PCH_IRQ16 16 #endif /* _SOC_IRQ_H_ */ diff --git a/src/soc/intel/xeon_sp/lpc_gen6.c b/src/soc/intel/xeon_sp/lpc_gen6.c index d4045a877d..9455510118 100644 --- a/src/soc/intel/xeon_sp/lpc_gen6.c +++ b/src/soc/intel/xeon_sp/lpc_gen6.c @@ -1,9 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include +#include +#include #include #include #include +#include #include #include @@ -30,15 +33,56 @@ void lpc_soc_fill_ssdt(const struct device *dev) acpigen_write_scope_end(); /* Scope */ } +uint32_t itss_soc_get_on_chip_dev_pir(const struct device *dev) +{ + assert(is_pci(dev)); + return PCI_ITSS_PIR(PCI_SLOT(dev->path.pci.devfn)); +} + +static void soc_itss_route_irq(const struct device *irq_dev, uint8_t int_pin) +{ + uint8_t pirq = itss_get_on_chip_dev_pirq(irq_dev, int_pin); + if (pirq == PIRQ_INVALID) + return; + + uint8_t pirq_rout = pcr_read8(PID_ITSS, + PCR_ITSS_PIRQA_ROUT + pirq_idx(pirq)); + uint8_t int_line = (pirq_rout & 0x80) ? pirq_idx(pirq) + PCH_IRQ16 : pirq_rout & 0xf; + + printk(BIOS_SPEW, "routing irq: dev %s, pin %d, pirq %d, intline %d\n", + dev_path(irq_dev), int_pin, pirq, int_line); + pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line); +} + +static void soc_pch_pirq_init(void) +{ + /* Program irq pin/line for PCI devices using 8259 compatible mode */ + size_t pirq_routes; + const uint8_t *pirq_routing_legacy = lpc_get_pic_pirq_routing(&pirq_routes); + + itss_irq_init(pirq_routing_legacy); + for (int i = 0; i < PIRQ_COUNT; i++) + itss_set_irq_polarity(pirq_routing_legacy[i], 1); + + /* Route irq for end-points */ + struct device *domain = NULL; + while ((domain = dev_find_path(domain, DEVICE_PATH_DOMAIN))) { + struct device *irq_dev = NULL; + while ((irq_dev = dev_bus_each_child(domain->downstream, irq_dev))) { + if (!is_enabled_pci(irq_dev)) + continue; + uint8_t int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN); + if (int_pin < PCI_INT_A || int_pin > PCI_INT_D) + continue; + + soc_itss_route_irq(irq_dev, int_pin); + } + } +} + void lpc_soc_init(struct device *dev) { printk(BIOS_SPEW, "pch: lpc_init\n"); - /* Program irq pin/line for PCI devices by PCH convention */ - pch_pirq_init(); - - /* Explicitly set polarity low for PIRQA to PIRQH */ - for (int i = 0; i < PIRQ_COUNT; i++) { - itss_set_irq_polarity(pcr_read8(PID_ITSS, PCR_ITSS_PIRQA_ROUT + i), 1); - } + soc_pch_pirq_init(); }