1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 #include <acpi/acpi.h>
4 #include <acpi/acpigen.h>
5 #include <acpi/acpigen_pci.h>
6 #include <amdblocks/amd_pci_util.h>
7 #include <arch/ioapic.h>
8 #include <device/device.h>
9
10 /* GNB IO-APIC is located after the FCH IO-APIC */
11 #define FCH_IOAPIC_INTERRUPTS 24
12 #define GNB_GSI_BASE FCH_IOAPIC_INTERRUPTS
13
acpigen_write_PRT_GSI(const struct pci_routing_info * routing_info)14 static void acpigen_write_PRT_GSI(const struct pci_routing_info *routing_info)
15 {
16 unsigned int irq;
17
18 acpigen_write_package(4); /* Package - APIC Routing */
19 for (unsigned int i = 0; i < 4; ++i) {
20 irq = pci_calculate_irq(routing_info, i);
21
22 acpigen_write_PRT_GSI_entry(
23 0, /* There is only one device attached to the bridge */
24 i, /* pin */
25 GNB_GSI_BASE + irq);
26 }
27 acpigen_pop_len(); /* Package - APIC Routing */
28 }
29
acpigen_write_PRT_PIC(const struct pci_routing_info * routing_info)30 static void acpigen_write_PRT_PIC(const struct pci_routing_info *routing_info)
31 {
32 unsigned int irq;
33 char link_template[] = "\\_SB.INTX";
34
35 acpigen_write_package(4); /* Package - PIC Routing */
36 for (unsigned int i = 0; i < 4; ++i) {
37 irq = pci_calculate_irq(routing_info, i);
38
39 link_template[8] = 'A' + (irq % 8);
40
41 acpigen_write_PRT_source_entry(
42 0, /* There is only one device attached to the bridge */
43 i, /* pin */
44 link_template /* Source */,
45 0 /* Source Index */);
46 }
47 acpigen_pop_len(); /* Package - PIC Routing */
48 }
49
50 /*
51 * This method writes a PCI _PRT table that uses the GNB IO-APIC / PIC :
52 * Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table
53 * {
54 * If (PICM)
55 * {
56 * Return (Package (0x04)
57 * {
58 * Package (0x04)
59 * {
60 * 0x0000FFFF,
61 * 0x00,
62 * 0x00,
63 * 0x00000034
64 * },
65 *
66 * Package (0x04)
67 * {
68 * 0x0000FFFF,
69 * 0x01,
70 * 0x00,
71 * 0x00000035
72 * },
73 *
74 * Package (0x04)
75 * {
76 * 0x0000FFFF,
77 * 0x02,
78 * 0x00,
79 * 0x00000036
80 * },
81 *
82 * Package (0x04)
83 * {
84 * 0x0000FFFF,
85 * 0x03,
86 * 0x00,
87 * 0x00000037
88 * }
89 * })
90 * }
91 * Else
92 * {
93 * Return (Package (0x04)
94 * {
95 * Package (0x04)
96 * {
97 * 0x0000FFFF,
98 * 0x00,
99 * \_SB.INTA,
100 * 0x00000000
101 * },
102 *
103 * Package (0x04)
104 * {
105 * 0x0000FFFF,
106 * 0x01,
107 * \_SB.INTB,
108 * 0x00000000
109 * },
110 *
111 * Package (0x04)
112 * {
113 * 0x0000FFFF,
114 * 0x02,
115 * \_SB.INTC,
116 * 0x00000000
117 * },
118 *
119 * Package (0x04)
120 * {
121 * 0x0000FFFF,
122 * 0x03,
123 * \_SB.INTD,
124 * 0x00000000
125 * }
126 * })
127 * }
128 * }
129 */
acpigen_write_pci_GNB_PRT(const struct device * dev)130 void acpigen_write_pci_GNB_PRT(const struct device *dev)
131 {
132 const struct pci_routing_info *routing_info =
133 get_pci_routing_info(dev->path.pci.devfn);
134
135 if (!routing_info)
136 return;
137
138 acpigen_write_method("_PRT", 0);
139
140 /* If (PICM) */
141 acpigen_write_if();
142 acpigen_emit_namestring("PICM");
143
144 /* Return (Package{...}) */
145 acpigen_emit_byte(RETURN_OP);
146 acpigen_write_PRT_GSI(routing_info);
147
148 /* Else */
149 acpigen_write_else();
150
151 /* Return (Package{...}) */
152 acpigen_emit_byte(RETURN_OP);
153 acpigen_write_PRT_PIC(routing_info);
154
155 acpigen_pop_len(); /* End Else */
156
157 acpigen_pop_len(); /* Method */
158 }
159
160 /*
161 * This method writes a PCI _PRT table that uses the FCH IO-APIC / PIC :
162 * Name (_PRT, Package (0x04)
163 * {
164 * Package (0x04)
165 * {
166 * 0x0000FFFF,
167 * 0x00,
168 * \_SB.INTA,
169 * 0x00000000
170 * },
171 *
172 * Package (0x04)
173 * {
174 * 0x0000FFFF,
175 * 0x01,
176 * \_SB.INTB,
177 * 0x00000000
178 * },
179 *
180 * Package (0x04)
181 * {
182 * 0x0000FFFF,
183 * 0x02,
184 * \_SB.INTC,
185 * 0x00000000
186 * },
187 *
188 * Package (0x04)
189 * {
190 * 0x0000FFFF,
191 * 0x03,
192 * \_SB.INTD,
193 * 0x00000000
194 * }
195 * })
196 */
acpigen_write_pci_FCH_PRT(const struct device * dev)197 void acpigen_write_pci_FCH_PRT(const struct device *dev)
198 {
199 const struct pci_routing_info *routing_info =
200 get_pci_routing_info(dev->path.pci.devfn);
201
202 if (!routing_info)
203 return;
204
205 acpigen_write_name("_PRT");
206 acpigen_write_PRT_PIC(routing_info);
207 }
208