xref: /aosp_15_r20/external/coreboot/src/southbridge/intel/common/rcba_pirq.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <acpi/acpi_device.h>
4 #include <console/console.h>
5 #include <device/device.h>
6 #include <device/pci.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <southbridge/intel/common/acpi_pirq_gen.h>
10 #include <southbridge/intel/common/rcba_pirq.h>
11 #include <southbridge/intel/common/rcba.h>
12 
13 #define MAX_SLOT 31
14 #define MIN_SLOT 19
15 
16 static const u32 pirq_dir_route_reg[MAX_SLOT - MIN_SLOT + 1] = {
17 	D19IR, D20IR, D21IR, D22IR, D23IR, 0, D25IR,
18 	D26IR, D27IR, D28IR, D29IR, D30IR, D31IR,
19 };
20 
map_pirq(const struct device * dev,const enum pci_pin pci_pin)21 static enum pirq map_pirq(const struct device *dev, const enum pci_pin pci_pin)
22 {
23 	u8 slot = PCI_SLOT(dev->path.pci.devfn);
24 	u8 shift = 4 * (pci_pin - PCI_INT_A);
25 	u8 pirq;
26 	u16 reg;
27 
28 	if (pci_pin < PCI_INT_A || pci_pin > PCI_INT_D) {
29 		printk(BIOS_ERR, "ACPI_PIRQ_GEN: Slot %d PCI pin %d out of bounds\n",
30 			slot, pci_pin);
31 		return PIRQ_INVALID;
32 	}
33 
34 	/* Slot 24 should not exist and has no D24IR but better be safe here */
35 	if (slot < MIN_SLOT || slot > MAX_SLOT || slot == 24) {
36 		/* non-PCH devices use 1:1 mapping. */
37 		return (enum pirq)pci_pin;
38 	}
39 
40 	reg = pirq_dir_route_reg[slot - MIN_SLOT];
41 
42 	pirq = (RCBA16(reg) >> shift) & 0x7;
43 
44 	return (enum pirq)(pirq + PIRQ_A);
45 }
46 
intel_acpi_gen_def_acpi_pirq(const struct device * lpc)47 void intel_acpi_gen_def_acpi_pirq(const struct device *lpc)
48 {
49 	struct slot_pin_irq_map *pin_irq_map;
50 	const char *lpcb_path = acpi_device_path(lpc);
51 	struct pic_pirq_map pirq_map = {0};
52 	unsigned int map_count = 0;
53 	int i;
54 
55 	if (!lpcb_path) {
56 		printk(BIOS_ERR, "ACPI_PIRQ_GEN: Missing LPCB ACPI path\n");
57 		return;
58 	}
59 
60 	printk(BIOS_DEBUG, "Generating ACPI PIRQ entries\n");
61 
62 	pin_irq_map = calloc(MAX_SLOTS * PCI_INT_MAX, sizeof(struct slot_pin_irq_map));
63 	pirq_map.type = PIRQ_SOURCE_PATH;
64 	for (i = 0; i < PIRQ_COUNT; i++)
65 		snprintf(pirq_map.source_path[i], sizeof(pirq_map.source_path[i]),
66 			 "%s.LNK%c", lpcb_path, 'A' + i);
67 
68 	for (struct device *dev = pcidev_on_root(0, 0); dev; dev = dev->sibling) {
69 		const u8 pci_dev = PCI_SLOT(dev->path.pci.devfn);
70 		const u8 int_pin = pci_read_config8(dev, PCI_INTERRUPT_PIN);
71 
72 		if (int_pin < PCI_INT_A || int_pin > PCI_INT_D)
73 			continue;
74 
75 		if (is_slot_pin_assigned(pin_irq_map, map_count, pci_dev, int_pin))
76 			continue;
77 
78 		enum pirq pirq = map_pirq(dev, int_pin);
79 		if (pirq == PIRQ_INVALID)
80 			continue;
81 
82 		pin_irq_map[map_count].slot = pci_dev;
83 		pin_irq_map[map_count].pin = (enum pci_pin)int_pin;
84 		pin_irq_map[map_count].pic_pirq = pirq;
85 		/* PIRQs are mapped to GSIs starting at 16 */
86 		pin_irq_map[map_count].apic_gsi = 16 + pirq_idx(pirq);
87 		printk(BIOS_SPEW, "ACPI_PIRQ_GEN: %s: pin=%d pirq=%zd\n",
88 		       dev_path(dev), int_pin - PCI_INT_A,
89 		       pirq_idx(pin_irq_map[map_count].pic_pirq));
90 		map_count++;
91 	}
92 
93 	intel_write_pci0_PRT(pin_irq_map, map_count, &pirq_map);
94 
95 	free(pin_irq_map);
96 }
97