blob: a23b84c39f7dde358712e0bf07a3cf58f6146f05 [file] [log] [blame]
Tim Wawrzynczakd40a4c22021-02-25 13:14:49 -07001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <acpi/acpigen.h>
4#include <acpi/acpigen_pci.h>
5#include <assert.h>
6#include <device/device.h>
7#include <device/pci_def.h>
8#include <device/pci_type.h>
9#include <types.h>
10
11void acpigen_write_ADR_pci_devfn(pci_devfn_t devfn)
12{
13 /*
14 * _ADR for PCI Bus is encoded as follows:
15 * [63:32] - unused
16 * [31:16] - device #
17 * [15:0] - function #
18 */
19 acpigen_write_ADR(PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn));
20}
21
22void acpigen_write_ADR_pci_device(const struct device *dev)
23{
24 assert(dev->path.type == DEVICE_PATH_PCI);
25 acpigen_write_ADR_pci_devfn(dev->path.pci.devfn);
26}
Tim Wawrzynczak290979f2021-02-26 10:54:15 -070027
28void acpigen_write_PRT_GSI_entry(unsigned int pci_dev, unsigned int acpi_pin, unsigned int gsi)
29{
30 acpigen_write_package(4);
31 acpigen_write_dword((pci_dev << 16) | 0xffff);
32 acpigen_write_byte(acpi_pin);
33
34 /* Source */
35 acpigen_write_byte(0);
36
37 /* Source Index */
38 acpigen_write_dword(gsi);
39
40 acpigen_pop_len(); /* Package */
41}
42
43void acpigen_write_PRT_source_entry(unsigned int pci_dev, unsigned int acpi_pin,
44 const char *source_path, unsigned int index)
45{
46 acpigen_write_package(4);
47 acpigen_write_dword((pci_dev << 16) | 0xffff);
48 acpigen_write_byte(acpi_pin);
49
50 /* Source */
51 acpigen_emit_namestring(source_path);
52
53 /* Source Index */
54 acpigen_write_dword(index);
55
56 acpigen_pop_len(); /* Package */
57}
Shuo Liuf4a12e12024-03-21 21:22:03 +080058
59#define PCI_HOST_BRIDGE_OSC_UUID "33db4d5b-1ff7-401c-9657-7441c03dd766"
60#define CXL_HOST_BRIDGE_OSC_UUID "68f2d50b-c469-4d8a-bd3d-941a103fd3fc"
61
62#define OSC_RET_FAILURE 0x02
63#define OSC_RET_UNRECOGNIZED_UUID 0x04
64#define OSC_RET_UNRECOGNIZED_REV 0x08
65#define OSC_RET_CAPABILITIES_MASKED 0x10
66
67#define OSC_QUERY_SUPPORT_SET 0x01
68
69#define ASL_UUID_UNHANDLED 0x00
70#define ASL_UUID_HANDLED 0x01
71
72static void acpigen_OSC_handle_pcie_request(const struct device *domain);
73static void acpigen_OSC_handle_cxl_request(const struct device *domain);
74
75/*
76 * acpigen_write_OSC_pci_domain
77 *
78 * Reference:
79 * 6.2.11 in https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/06_Device_Configuration/Device_Configuration.html
80 *
81 * _OSC ASL Arguments: (4)
82 * Arg0 - A Buffer containing a UUID
83 * Arg1 - An Integer containing a Revision ID of the buffer format
84 * Arg2 - An Integer containing a count of entries in Arg3
85 * Arg3 - A Buffer containing a list of DWORD capabilities
86 *
87 * _OSC ASL Return Value:
88 * A Buffer containing a list of capabilities
89 *
90 * Local Variables Assignment:
91 * Local0 - Temp assigned
92 * Local1 - Temp assigned
93 * Local2 - Not used
94 * Local3 - Not used
95 * Local4 - Not used
96 * Local5 - Not used
97 * Local6 - Record whether the UUID is handled
98 * Local7 - Backs up the input value of Arg3
99 *
100 * Field Definitions:
101 * Name - Width Source Offset Description
102 * --------------------------------
103 * QSUP - DWord Local7 0x00 Query support
104 * RETE - DWord Arg3 0x00 Returned errors
105 * SUPP - Dword Arg3 0x04 PCIe Features that OS supported
106 * CTRL - Dword Arg3 0x08 PCIe Features that firmware grant control to OS
107 * OTRL - Dword Local7 0x08 PCIe Features that OS requests for control
108 * SUPC - Dword Arg3 0x0C CXL Features that OS supported
109 * CTRC - Dword Arg3 0x10 CXL Features that firmware grant control to OS
110 * OTRC - Dword Local7 0x10 CXL Features that OS requests for control
111 */
112void acpigen_write_OSC_pci_domain(const struct device *domain, const bool is_cxl_domain)
113{
114 /*
115 * Method (_OSC, 4, NotSerialized)
116 * {
117 */
118 acpigen_write_method("_OSC", 4);
119
120 /*
121 * //
122 * // Check revision ID
123 * //
124 * If (Arg1 != 1)
125 * {
126 * RETE = OSC_RET_UNRECOGNIZED_REV
127 * Return (Arg3)
128 * }
129 */
130 acpigen_write_if();
131 acpigen_emit_byte(LNOT_OP);
132 acpigen_emit_byte(LEQUAL_OP);
133 acpigen_emit_byte(ARG1_OP);
134 acpigen_write_integer(0x1);
135
136 acpigen_write_store_int_to_namestr(OSC_RET_UNRECOGNIZED_REV, "RETE");
137 acpigen_write_return_op(ARG3_OP);
138
139 acpigen_write_if_end();
140
141 /*
142 * //
143 * // Setup up local variables
144 * //
145 * Local7 = Arg3
146 * CreateDwordField (Local7, 0x00, QSUP)
147 * CreateDWordField (Arg3, 0x00, RETE)
148 * RETE = 0x0
149 * Local6 = ASL_UUID_UNHANDLED
150 */
151 acpigen_write_store_ops(ARG3_OP, LOCAL7_OP);
152 acpigen_write_create_dword_field(LOCAL7_OP, 0x00, "QSUP");
153 acpigen_write_create_dword_field(ARG3_OP, 0x00, "RETE");
154 acpigen_write_store_int_to_namestr(0x0, "RETE");
155 acpigen_write_store_int_to_op(ASL_UUID_UNHANDLED, LOCAL6_OP);
156
157 /*
158 * //
159 * // Refer to CXL-3.1-Specification, 9.18.2
160 * // A CXL Host Bridge also originates a PCIe hierarchy and will have a
161 * // _CID of EISAID("PNP0A08"). As such, a CXL Host Bridge device may expose
162 * // both CXL _OSC and PCIe _OSC.
163 * //
164 *
165 * If (Arg0 == ToUUID (PCI_HOST_BRIDGE_OSC_UUID))
166 * {
167 * //
168 * // Handle PCIe _OSC request
169 * // Mark UUID handled
170 * //
171 * }
172 */
173 acpigen_write_if();
174 acpigen_emit_byte(LEQUAL_OP);
175 acpigen_emit_byte(ARG0_OP);
176 acpigen_write_uuid(PCI_HOST_BRIDGE_OSC_UUID);
177
178 acpigen_OSC_handle_pcie_request(domain);
179 acpigen_write_store_int_to_op(ASL_UUID_HANDLED, LOCAL6_OP);
180
181 acpigen_write_if_end();
182
183 if (is_cxl_domain) {
184 /*
185 * If (Arg0 == ToUUID (CXL_HOST_BRIDGE_OSC_UUID))
186 * {
187 * //
188 * // Handle CXL _OSC request
189 * // Mark UUID handled
190 * //
191 * }
192 */
193 acpigen_write_if();
194 acpigen_emit_byte(LEQUAL_OP);
195 acpigen_emit_byte(ARG0_OP);
196 acpigen_write_uuid(CXL_HOST_BRIDGE_OSC_UUID);
197
198 acpigen_OSC_handle_cxl_request(domain);
199 acpigen_write_store_int_to_op(ASL_UUID_HANDLED, LOCAL6_OP);
200
201 acpigen_write_if_end();
202 }
203
204 /*
205 * //
206 * // Handle unrecognized UUID
207 * //
208 * If (Local6 == ASL_UUID_UNHANDLED)
209 * {
210 * RETE = OSC_RET_UNRECOGNIZED_UUID
211 * }
212 */
213 acpigen_write_if_lequal_op_int(LOCAL6_OP, ASL_UUID_UNHANDLED);
214 acpigen_write_store_int_to_namestr(OSC_RET_UNRECOGNIZED_UUID, "RETE");
215 acpigen_write_if_end();
216
217 /*
218 * //
219 * // All done, return
220 * //
221 * Return (Arg3)
222 */
223 acpigen_write_return_op(ARG3_OP);
224
225 /*
226 * } // Method (_OSC, 4, NotSerialized)
227 */
228 acpigen_pop_len();
229
230}
231
232void acpigen_OSC_handle_pcie_request(const struct device *domain)
233{
234 uint32_t osc_features = soc_get_granted_pci_features(domain);
235
236 /*
237 * If (Arg2 < 2))
238 * {
239 * RETE = OSC_RET_FAILURE
240 * Return (Arg3)
241 * }
242 */
243 acpigen_write_if();
244 acpigen_emit_byte(LLESS_OP);
245 acpigen_emit_byte(ARG2_OP);
246 acpigen_write_integer(0x2);
247
248 acpigen_write_store_int_to_namestr(OSC_RET_FAILURE, "RETE");
249 acpigen_write_return_op(ARG3_OP);
250
251 acpigen_write_if_end();
252
253 /*
254 * CreateDWordField (Arg3, 0x04, SUPP)
255 * CreateDWordField (Arg3, 0x08, CTRL)
256 * CreateDWordField (Local7, 0x08, OTRL)
257 */
258 acpigen_write_create_dword_field(ARG3_OP, 0x04, "SUPP");
259 acpigen_write_create_dword_field(ARG3_OP, 0x08, "CTRL");
260 acpigen_write_create_dword_field(LOCAL7_OP, 0x08, "OTRL");
261
262 /*
263 * // Grant PCIe feature controls to OS
264 * CTRL &= osc_features
265 */
266 acpigen_write_to_integer_from_namestring("CTRL", LOCAL0_OP);
267 acpigen_write_store_int_to_op(osc_features, LOCAL1_OP);
268 acpigen_write_and(LOCAL0_OP, LOCAL1_OP, LOCAL0_OP);
269 acpigen_write_store_op_to_namestr(LOCAL0_OP, "CTRL");
270
271 /*
272 * If (CTRL != OTRL)
273 * {
274 * RETE = OSC_RET_CAPABILITIES_MASKED
275 * }
276 */
277 acpigen_write_if();
278 acpigen_emit_byte(LNOT_OP);
279 acpigen_emit_byte(LEQUAL_OP);
280 acpigen_emit_namestring("CTRL");
281 acpigen_emit_namestring("OTRL");
282 acpigen_write_store_int_to_namestr(OSC_RET_CAPABILITIES_MASKED, "RETE");
283 acpigen_write_if_end();
284};
285
286void acpigen_OSC_handle_cxl_request(const struct device *domain)
287{
288 uint32_t osc_features = soc_get_granted_cxl_features(domain);
289
290 /*
291 * If (Arg2 < 4))
292 * {
293 * RETE = OSC_RET_FAILURE
294 * Return (Arg3)
295 * }
296 */
297 acpigen_write_if();
298 acpigen_emit_byte(LLESS_OP);
299 acpigen_emit_byte(ARG2_OP);
300 acpigen_write_integer(0x4);
301
302 acpigen_write_store_int_to_namestr(OSC_RET_FAILURE, "RETE");
303 acpigen_write_return_op(ARG3_OP);
304
305 acpigen_write_if_end();
306
307 /*
308 * CreateDWordField (Arg3, 0x0C, SUPC)
309 * CreateDWordField (Arg3, 0x10, CTRC)
310 * CreateDWordField (Local7, 0x10, OTRC)
311 */
312 acpigen_write_create_dword_field(ARG3_OP, 0x0C, "SUPC");
313 acpigen_write_create_dword_field(ARG3_OP, 0x10, "CTRC");
314 acpigen_write_create_dword_field(LOCAL7_OP, 0x10, "OTRC");
315
316 /*
317 * // Grant CXL feature controls to OS
318 * CTRC &= osc_features
319 */
320 acpigen_write_to_integer_from_namestring("CTRC", LOCAL0_OP);
321 acpigen_write_store_int_to_op(osc_features, LOCAL1_OP);
322 acpigen_write_and(LOCAL0_OP, LOCAL1_OP, LOCAL0_OP);
323 acpigen_write_store_op_to_namestr(LOCAL0_OP, "CTRC");
324
325 /*
326 * If (CTRC != OTRC)
327 * {
328 * RETE = OSC_RET_CAPABILITIES_MASKED
329 * }
330 */
331 acpigen_write_if();
332 acpigen_emit_byte(LNOT_OP);
333 acpigen_emit_byte(LEQUAL_OP);
334 acpigen_emit_namestring("CTRC");
335 acpigen_emit_namestring("OTRC");
336 acpigen_write_store_int_to_namestr(OSC_RET_CAPABILITIES_MASKED, "RETE");
337 acpigen_write_if_end();
338};
339
340__weak uint32_t soc_get_granted_pci_features(const struct device *domain)
341{
342 /*
343 * By default grant no features to OS, which equals to the case where _OSC
344 * is absent.
345 *
346 * Refer to PCI firmware specification, revision 3.1.
347 * If the _OSC control method is absent from the scope of a host bridge device, then
348 * the operating system must not enable or attempt to use any features defined in this
349 * section for the hierarchy originated by the host bridge. Doing so could contend with
350 * platform firmware operations or produce undesired results.
351 */
352 return 0;
353}
354
355__weak uint32_t soc_get_granted_cxl_features(const struct device *domain)
356{
357 /*
358 * By default grant no features to OS, which equals to the case where _OSC
359 * is absent.
360 */
361 return 0;
362}