soc/intel/xeon_sp: Improve PCI INTx IRQ routing for Gen6

1. Route IRQ for on-chip end-points only (e.g. 00:1f.4
   i801_smbus)

   IRQ routing for devices under root ports needs additional
   swizzle per decided by root port configurations, which will
   postponed to later till there is actual usage.

2. Route IRQ based on FSP programmed end-point device ID <->
   PIRQ mapping.

TESTED=Build and boot on intel/avenuecity CRB

Change-Id: Ibeb7c8fb3432e5cb240ac3b09c19d2c361e4b45a
Signed-off-by: Shuo Liu <shuo.liu@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/85153
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
This commit is contained in:
Shuo Liu 2024-11-15 19:41:01 +08:00 committed by Lean Sheng Tan
commit e5b5fc345a
2 changed files with 52 additions and 7 deletions

View file

@ -6,5 +6,6 @@
#define PCH_IRQ10 10
#define PCH_IRQ11 11
#define PCH_IRQ14 14
#define PCH_IRQ16 16
#endif /* _SOC_IRQ_H_ */

View file

@ -1,9 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <console/console.h>
#include <device/pci.h>
#include <device/pci_ops.h>
#include <intelblocks/itss.h>
#include <intelblocks/lpc_lib.h>
#include <intelblocks/pcr.h>
#include <soc/irq.h>
#include <soc/pcr_ids.h>
#include <acpi/acpigen.h>
@ -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();
}