]>
Commit | Line | Data |
---|---|---|
5b85eabe GH |
1 | #include "qemu/osdep.h" |
2 | #include "hw/acpi/aml-build.h" | |
3 | #include "hw/pci-host/gpex.h" | |
6f9765fb YM |
4 | #include "hw/arm/virt.h" |
5 | #include "hw/pci/pci_bus.h" | |
6 | #include "hw/pci/pci_bridge.h" | |
7 | #include "hw/pci/pcie_host.h" | |
5b85eabe | 8 | |
a0e2905b | 9 | static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq) |
5b85eabe | 10 | { |
a0e2905b | 11 | Aml *method, *crs; |
5b85eabe GH |
12 | int i, slot_no; |
13 | ||
5b85eabe GH |
14 | /* Declare the PCI Routing Table. */ |
15 | Aml *rt_pkg = aml_varpackage(PCI_SLOT_MAX * PCI_NUM_PINS); | |
16 | for (slot_no = 0; slot_no < PCI_SLOT_MAX; slot_no++) { | |
17 | for (i = 0; i < PCI_NUM_PINS; i++) { | |
18 | int gsi = (i + slot_no) % PCI_NUM_PINS; | |
19 | Aml *pkg = aml_package(4); | |
20 | aml_append(pkg, aml_int((slot_no << 16) | 0xFFFF)); | |
21 | aml_append(pkg, aml_int(i)); | |
22 | aml_append(pkg, aml_name("GSI%d", gsi)); | |
23 | aml_append(pkg, aml_int(0)); | |
24 | aml_append(rt_pkg, pkg); | |
25 | } | |
26 | } | |
27 | aml_append(dev, aml_name_decl("_PRT", rt_pkg)); | |
28 | ||
29 | /* Create GSI link device */ | |
30 | for (i = 0; i < PCI_NUM_PINS; i++) { | |
a0e2905b | 31 | uint32_t irqs = irq + i; |
5b85eabe GH |
32 | Aml *dev_gsi = aml_device("GSI%d", i); |
33 | aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F"))); | |
34 | aml_append(dev_gsi, aml_name_decl("_UID", aml_int(i))); | |
35 | crs = aml_resource_template(); | |
36 | aml_append(crs, | |
37 | aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, | |
38 | AML_EXCLUSIVE, &irqs, 1)); | |
39 | aml_append(dev_gsi, aml_name_decl("_PRS", crs)); | |
40 | crs = aml_resource_template(); | |
41 | aml_append(crs, | |
42 | aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, | |
43 | AML_EXCLUSIVE, &irqs, 1)); | |
44 | aml_append(dev_gsi, aml_name_decl("_CRS", crs)); | |
45 | method = aml_method("_SRS", 1, AML_NOTSERIALIZED); | |
46 | aml_append(dev_gsi, method); | |
47 | aml_append(dev, dev_gsi); | |
48 | } | |
a0e2905b | 49 | } |
5b85eabe | 50 | |
a0e2905b YM |
51 | static void acpi_dsdt_add_pci_osc(Aml *dev) |
52 | { | |
53 | Aml *method, *UUID, *ifctx, *ifctx1, *elsectx, *buf; | |
5b85eabe GH |
54 | |
55 | /* Declare an _OSC (OS Control Handoff) method */ | |
56 | aml_append(dev, aml_name_decl("SUPP", aml_int(0))); | |
57 | aml_append(dev, aml_name_decl("CTRL", aml_int(0))); | |
58 | method = aml_method("_OSC", 4, AML_NOTSERIALIZED); | |
59 | aml_append(method, | |
60 | aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); | |
61 | ||
62 | /* PCI Firmware Specification 3.0 | |
63 | * 4.5.1. _OSC Interface for PCI Host Bridge Devices | |
64 | * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is | |
65 | * identified by the Universal Unique IDentifier (UUID) | |
66 | * 33DB4D5B-1FF7-401C-9657-7441C03DD766 | |
67 | */ | |
68 | UUID = aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"); | |
69 | ifctx = aml_if(aml_equal(aml_arg(0), UUID)); | |
70 | aml_append(ifctx, | |
71 | aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); | |
72 | aml_append(ifctx, | |
73 | aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); | |
74 | aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP"))); | |
75 | aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL"))); | |
76 | ||
77 | /* | |
78 | * Allow OS control for all 5 features: | |
79 | * PCIeHotplug SHPCHotplug PME AER PCIeCapability. | |
80 | */ | |
81 | aml_append(ifctx, aml_and(aml_name("CTRL"), aml_int(0x1F), | |
82 | aml_name("CTRL"))); | |
83 | ||
84 | ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); | |
85 | aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x08), | |
86 | aml_name("CDW1"))); | |
87 | aml_append(ifctx, ifctx1); | |
88 | ||
89 | ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL")))); | |
90 | aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x10), | |
91 | aml_name("CDW1"))); | |
92 | aml_append(ifctx, ifctx1); | |
93 | ||
94 | aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3"))); | |
95 | aml_append(ifctx, aml_return(aml_arg(3))); | |
96 | aml_append(method, ifctx); | |
97 | ||
98 | elsectx = aml_else(); | |
99 | aml_append(elsectx, aml_or(aml_name("CDW1"), aml_int(4), | |
100 | aml_name("CDW1"))); | |
101 | aml_append(elsectx, aml_return(aml_arg(3))); | |
102 | aml_append(method, elsectx); | |
103 | aml_append(dev, method); | |
104 | ||
105 | method = aml_method("_DSM", 4, AML_NOTSERIALIZED); | |
106 | ||
107 | /* PCI Firmware Specification 3.0 | |
108 | * 4.6.1. _DSM for PCI Express Slot Information | |
109 | * The UUID in _DSM in this context is | |
110 | * {E5C937D0-3553-4D7A-9117-EA4D19C3434D} | |
111 | */ | |
112 | UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D"); | |
113 | ifctx = aml_if(aml_equal(aml_arg(0), UUID)); | |
114 | ifctx1 = aml_if(aml_equal(aml_arg(2), aml_int(0))); | |
40c3472a MT |
115 | uint8_t byte_list[1] = {1}; |
116 | buf = aml_buffer(1, byte_list); | |
5b85eabe | 117 | aml_append(ifctx1, aml_return(buf)); |
0cf8882f | 118 | aml_append(ifctx, ifctx1); |
5b85eabe GH |
119 | aml_append(method, ifctx); |
120 | ||
121 | byte_list[0] = 0; | |
122 | buf = aml_buffer(1, byte_list); | |
123 | aml_append(method, aml_return(buf)); | |
124 | aml_append(dev, method); | |
a0e2905b YM |
125 | } |
126 | ||
127 | void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) | |
128 | { | |
129 | int nr_pcie_buses = cfg->ecam.size / PCIE_MMCFG_SIZE_MIN; | |
130 | Aml *method, *crs, *dev, *rbuf; | |
6f9765fb YM |
131 | PCIBus *bus = cfg->bus; |
132 | CrsRangeSet crs_range_set; | |
aee519c2 JC |
133 | CrsRangeEntry *entry; |
134 | int i; | |
6f9765fb YM |
135 | |
136 | /* start to construct the tables for pxb */ | |
137 | crs_range_set_init(&crs_range_set); | |
138 | if (bus) { | |
139 | QLIST_FOREACH(bus, &bus->child, sibling) { | |
140 | uint8_t bus_num = pci_bus_num(bus); | |
141 | uint8_t numa_node = pci_bus_numa_node(bus); | |
142 | ||
143 | if (!pci_bus_is_root(bus)) { | |
144 | continue; | |
145 | } | |
146 | ||
147 | /* | |
148 | * 0 - (nr_pcie_buses - 1) is the bus range for the main | |
149 | * host-bridge and it equals the MIN of the | |
150 | * busNr defined for pxb-pcie. | |
151 | */ | |
152 | if (bus_num < nr_pcie_buses) { | |
153 | nr_pcie_buses = bus_num; | |
154 | } | |
155 | ||
156 | dev = aml_device("PC%.02X", bus_num); | |
157 | aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08"))); | |
158 | aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03"))); | |
159 | aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); | |
160 | aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); | |
161 | aml_append(dev, aml_name_decl("_STR", aml_unicode("pxb Device"))); | |
b48088d6 | 162 | aml_append(dev, aml_name_decl("_CCA", aml_int(1))); |
6f9765fb YM |
163 | if (numa_node != NUMA_NODE_UNASSIGNED) { |
164 | aml_append(dev, aml_name_decl("_PXM", aml_int(numa_node))); | |
165 | } | |
166 | ||
167 | acpi_dsdt_add_pci_route_table(dev, cfg->irq); | |
168 | ||
169 | /* | |
170 | * Resources defined for PXBs are composed by the folling parts: | |
171 | * 1. The resources the pci-brige/pcie-root-port need. | |
172 | * 2. The resources the devices behind pxb need. | |
173 | */ | |
e41ee855 JC |
174 | crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent), &crs_range_set, |
175 | cfg->pio.base, 0, 0, 0); | |
6f9765fb YM |
176 | aml_append(dev, aml_name_decl("_CRS", crs)); |
177 | ||
178 | acpi_dsdt_add_pci_osc(dev); | |
179 | ||
180 | aml_append(scope, dev); | |
181 | } | |
182 | } | |
a0e2905b | 183 | |
6f9765fb | 184 | /* tables for the main */ |
a0e2905b YM |
185 | dev = aml_device("%s", "PCI0"); |
186 | aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08"))); | |
187 | aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03"))); | |
188 | aml_append(dev, aml_name_decl("_SEG", aml_int(0))); | |
189 | aml_append(dev, aml_name_decl("_BBN", aml_int(0))); | |
190 | aml_append(dev, aml_name_decl("_UID", aml_int(0))); | |
191 | aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device"))); | |
192 | aml_append(dev, aml_name_decl("_CCA", aml_int(1))); | |
193 | ||
194 | acpi_dsdt_add_pci_route_table(dev, cfg->irq); | |
195 | ||
196 | method = aml_method("_CBA", 0, AML_NOTSERIALIZED); | |
197 | aml_append(method, aml_return(aml_int(cfg->ecam.base))); | |
198 | aml_append(dev, method); | |
199 | ||
aee519c2 JC |
200 | /* |
201 | * At this point crs_range_set has all the ranges used by pci | |
202 | * busses *other* than PCI0. These ranges will be excluded from | |
203 | * the PCI0._CRS. | |
204 | */ | |
a0e2905b YM |
205 | rbuf = aml_resource_template(); |
206 | aml_append(rbuf, | |
207 | aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, | |
208 | 0x0000, 0x0000, nr_pcie_buses - 1, 0x0000, | |
209 | nr_pcie_buses)); | |
210 | if (cfg->mmio32.size) { | |
aee519c2 JC |
211 | crs_replace_with_free_ranges(crs_range_set.mem_ranges, |
212 | cfg->mmio32.base, | |
213 | cfg->mmio32.base + cfg->mmio32.size - 1); | |
214 | for (i = 0; i < crs_range_set.mem_ranges->len; i++) { | |
215 | entry = g_ptr_array_index(crs_range_set.mem_ranges, i); | |
216 | aml_append(rbuf, | |
217 | aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, | |
218 | AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, | |
219 | entry->base, entry->limit, | |
220 | 0x0000, entry->limit - entry->base + 1)); | |
221 | } | |
a0e2905b YM |
222 | } |
223 | if (cfg->pio.size) { | |
aee519c2 JC |
224 | crs_replace_with_free_ranges(crs_range_set.io_ranges, |
225 | 0x0000, | |
226 | cfg->pio.size - 1); | |
227 | for (i = 0; i < crs_range_set.io_ranges->len; i++) { | |
228 | entry = g_ptr_array_index(crs_range_set.io_ranges, i); | |
229 | aml_append(rbuf, | |
230 | aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, | |
231 | AML_ENTIRE_RANGE, 0x0000, entry->base, | |
232 | entry->limit, cfg->pio.base, | |
233 | entry->limit - entry->base + 1)); | |
234 | } | |
a0e2905b YM |
235 | } |
236 | if (cfg->mmio64.size) { | |
aee519c2 JC |
237 | crs_replace_with_free_ranges(crs_range_set.mem_64bit_ranges, |
238 | cfg->mmio64.base, | |
239 | cfg->mmio64.base + cfg->mmio64.size - 1); | |
240 | for (i = 0; i < crs_range_set.mem_64bit_ranges->len; i++) { | |
241 | entry = g_ptr_array_index(crs_range_set.mem_64bit_ranges, i); | |
242 | aml_append(rbuf, | |
243 | aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, | |
244 | AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, | |
245 | entry->base, | |
246 | entry->limit, 0x0000, | |
247 | entry->limit - entry->base + 1)); | |
248 | } | |
a0e2905b YM |
249 | } |
250 | aml_append(dev, aml_name_decl("_CRS", rbuf)); | |
251 | ||
252 | acpi_dsdt_add_pci_osc(dev); | |
5b85eabe GH |
253 | |
254 | Aml *dev_res0 = aml_device("%s", "RES0"); | |
255 | aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02"))); | |
256 | crs = aml_resource_template(); | |
257 | aml_append(crs, | |
258 | aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, | |
259 | AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, | |
260 | cfg->ecam.base, | |
261 | cfg->ecam.base + cfg->ecam.size - 1, | |
262 | 0x0000, | |
263 | cfg->ecam.size)); | |
264 | aml_append(dev_res0, aml_name_decl("_CRS", crs)); | |
265 | aml_append(dev, dev_res0); | |
266 | aml_append(scope, dev); | |
aee519c2 JC |
267 | |
268 | crs_range_set_free(&crs_range_set); | |
5b85eabe | 269 | } |