1 /*
2  * Copyright (c) 2023 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #ifndef ZEPHYR_INCLUDE_DRIVERS_ACPI_H_
7 #define ZEPHYR_INCLUDE_DRIVERS_ACPI_H_
8 #include <acpica/source/include/acpi.h>
9 #include <zephyr/drivers/pcie/pcie.h>
10 
11 #define ACPI_RES_INVALID ACPI_RESOURCE_TYPE_MAX
12 
13 #define ACPI_DRHD_FLAG_INCLUDE_PCI_ALL			BIT(0)
14 #define ACPI_DMAR_FLAG_INTR_REMAP				BIT(0)
15 #define ACPI_DMAR_FLAG_X2APIC_OPT_OUT			BIT(1)
16 #define ACPI_DMAR_FLAG_DMA_CTRL_PLATFORM_OPT_IN	BIT(2)
17 
18 #define ACPI_MMIO_GET(res) (res)->reg_base[0].mmio
19 #define ACPI_IO_GET(res) (res)->reg_base[0].port
20 #define ACPI_RESOURCE_SIZE_GET(res) (res)->reg_base[0].length
21 #define ACPI_RESOURCE_TYPE_GET(res) (res)->reg_base[0].type
22 
23 #define ACPI_MULTI_MMIO_GET(res, idx) (res)->reg_base[idx].mmio
24 #define ACPI_MULTI_IO_GET(res, idx) (res)->reg_base[idx].port
25 #define ACPI_MULTI_RESOURCE_SIZE_GET(res, idx) (res)->reg_base[idx].length
26 #define ACPI_MULTI_RESOURCE_TYPE_GET(res, idx) (res)->reg_base[idx].type
27 
28 #define ACPI_RESOURCE_COUNT_GET(res) (res)->mmio_max
29 
30 enum acpi_res_type {
31 	/** IO mapped Resource type */
32 	ACPI_RES_TYPE_IO,
33 	/** Memory mapped Resource type */
34 	ACPI_RES_TYPE_MEM,
35 	/** Unknown Resource type */
36 	ACPI_RES_TYPE_UNKNOWN,
37 };
38 
39 struct acpi_dev {
40 	ACPI_HANDLE handle;
41 	char *path;
42 	ACPI_RESOURCE *res_lst;
43 	int res_type;
44 	ACPI_DEVICE_INFO *dev_info;
45 };
46 
47 union acpi_dmar_id {
48 	struct {
49 		uint16_t function: 3;
50 		uint16_t device: 5;
51 		uint16_t bus: 8;
52 	} bits;
53 
54 	uint16_t raw;
55 };
56 
57 struct acpi_mcfg {
58 	ACPI_TABLE_HEADER header;
59 	uint64_t _reserved;
60 	ACPI_MCFG_ALLOCATION pci_segs[];
61 } __packed;
62 
63 struct acpi_irq_resource {
64 	uint32_t flags;
65 	uint8_t irq_vector_max;
66 	uint16_t *irqs;
67 };
68 
69 struct acpi_reg_base {
70 	enum acpi_res_type type;
71 	union {
72 		uintptr_t mmio;
73 		uintptr_t port;
74 	};
75 	uint32_t length;
76 };
77 
78 struct acpi_mmio_resource {
79 	uint8_t mmio_max;
80 	struct acpi_reg_base *reg_base;
81 };
82 
83 /**
84  * @brief Get the ACPI HID for a node
85  *
86  * @param node_id DTS node identifier
87  * @return The HID of the ACPI node
88  */
89 #define ACPI_DT_HID(node_id) DT_PROP(node_id, acpi_hid)
90 
91 /**
92  * @brief Get the ACPI UID for a node if one exist
93  *
94  * @param node_id DTS node identifier
95  * @return The UID of the ACPI node else NULL if does not exist
96  */
97 #define ACPI_DT_UID(node_id) DT_PROP_OR(node_id, acpi_uid, NULL)
98 
99 /**
100  * @brief check whether the node has ACPI HID property or not
101  *
102  * @param node_id DTS node identifier
103  * @return 1 if the node has the HID, 0 otherwise.
104  */
105 #define ACPI_DT_HAS_HID(node_id) DT_NODE_HAS_PROP(node_id, acpi_hid)
106 
107 /**
108  * @brief check whether the node has ACPI UID property or not
109  *
110  * @param node_id DTS node identifier
111  * @return 1 if the node has the UID, 0 otherwise.
112  */
113 #define ACPI_DT_HAS_UID(node_id) DT_NODE_HAS_PROP(node_id, acpi_uid)
114 
115 /**
116  * @brief Init legacy interrupt routing table information from ACPI.
117  * Currently assume platform have only one PCI bus.
118  *
119  * @param hid the hardware id of the ACPI child device
120  * @param uid the unique id of the ACPI child device. The uid can be
121  * NULL if only one device with given hid present in the platform.
122  * @return return 0 on success or error code
123  */
124 int acpi_legacy_irq_init(const char *hid, const char *uid);
125 
126 /**
127  * @brief Retrieve a legacy interrupt number for a PCI device.
128  *
129  * @param bdf the BDF of endpoint/PCI device
130  * @return return IRQ number or UINT_MAX if not found
131  */
132 uint32_t acpi_legacy_irq_get(pcie_bdf_t bdf);
133 
134 /**
135  * @brief Retrieve the current resource settings of a device.
136  *
137  * @param dev_name the name of the device
138  * @param res the list of acpi resource list
139  * @return return 0 on success or error code
140  */
141 int acpi_current_resource_get(char *dev_name, ACPI_RESOURCE **res);
142 
143 /**
144  * @brief Retrieve possible resource settings of a device.
145  *
146  * @param dev_name the name of the device
147  * @param res the list of acpi resource list
148  * @return return 0 on success or error code
149  */
150 int acpi_possible_resource_get(char *dev_name, ACPI_RESOURCE **res);
151 
152 /**
153  * @brief Free current resource list memory which is retrieved by
154  * acpi_current_resource_get().
155  *
156  * @param res the list of acpi resource list
157  * @return return 0 on success or error code
158  */
159 int acpi_current_resource_free(ACPI_RESOURCE *res);
160 
161 /**
162  * @brief Parse resource table for a given resource type.
163  *
164  * @param res the list of acpi resource list
165  * @param res_type the acpi resource type
166  * @return resource list for the given type on success or NULL
167  */
168 ACPI_RESOURCE *acpi_resource_parse(ACPI_RESOURCE *res, int res_type);
169 
170 /**
171  * @brief Retrieve ACPI device info for given hardware id and unique id.
172  *
173  * @param hid the hardware id of the ACPI child device
174  * @param uid the unique id of the ACPI child device. The uid can be
175  * NULL if only one device with given HID present in the platform.
176  * @return ACPI child device info on success or NULL
177  */
178 struct acpi_dev *acpi_device_get(const char *hid, const char *uid);
179 
180 /**
181  * @brief Retrieve acpi device info from the index.
182  *
183  * @param index the device index of an acpi child device
184  * @return acpi child device info on success or NULL
185  */
186 struct acpi_dev *acpi_device_by_index_get(int index);
187 
188 /**
189  * @brief Parse resource table for irq info.
190  *
191  * @param res_lst the list of acpi resource list
192  * @return irq resource list on success or NULL
193  */
acpi_irq_res_get(ACPI_RESOURCE * res_lst)194 static inline ACPI_RESOURCE_IRQ *acpi_irq_res_get(ACPI_RESOURCE *res_lst)
195 {
196 	ACPI_RESOURCE *res = acpi_resource_parse(res_lst, ACPI_RESOURCE_TYPE_IRQ);
197 
198 	return res ? &res->Data.Irq : NULL;
199 }
200 
201 /**
202  * @brief Parse resource table for irq info.
203  *
204  * @param child_dev the device object of the ACPI node
205  * @param irq_res irq resource info
206  * @return return 0 on success or error code
207  */
208 int acpi_device_irq_get(struct acpi_dev *child_dev, struct acpi_irq_resource *irq_res);
209 
210 /**
211  * @brief Parse resource table for MMIO info.
212  *
213  * @param child_dev the device object of the ACPI node
214  * @param mmio_res MMIO resource info
215  * @return return 0 on success or error code
216  */
217 int acpi_device_mmio_get(struct acpi_dev *child_dev, struct acpi_mmio_resource *mmio_res);
218 
219 /**
220  * @brief Parse resource table for identify resource type.
221  *
222  * @param res the list of acpi resource list
223  * @return resource type on success or invalid resource type
224  */
225 int acpi_device_type_get(ACPI_RESOURCE *res);
226 
227 /**
228  * @brief Retrieve acpi table for the given signature.
229  *
230  * @param signature pointer to the 4-character ACPI signature for the requested table
231  * @param inst instance number for the requested table
232  * @return acpi_table pointer to the acpi table on success else return NULL
233  */
234 void *acpi_table_get(char *signature, int inst);
235 
236 /**
237  * @brief retrieve acpi MAD table for the given type.
238  *
239  * @param type type of requested MAD table
240  * @param tables pointer to the MAD table
241  * @param num_inst number of instance for the requested table
242  * @return return 0 on success or error code
243  */
244 int acpi_madt_entry_get(int type, ACPI_SUBTABLE_HEADER **tables, int *num_inst);
245 
246 /**
247  * @brief retrieve DMA remapping structure for the given type.
248  *
249  * @param type type of remapping structure
250  * @param tables pointer to the dmar id structure
251  * @return return 0 on success or error code
252  */
253 int acpi_dmar_entry_get(enum AcpiDmarType type, ACPI_SUBTABLE_HEADER **tables);
254 
255 /**
256  * @brief retrieve acpi DRHD info for the given scope.
257  *
258  * @param scope scope of requested DHRD table
259  * @param dev_scope pointer to the sub table (optional)
260  * @param dmar_id pointer to the DHRD info
261  * @param num_inst number of instance for the requested table
262  * @param max_inst maximum number of entry for the given dmar_id buffer
263  * @return return 0 on success or error code
264  */
265 int acpi_drhd_get(enum AcpiDmarScopeType scope, ACPI_DMAR_DEVICE_SCOPE *dev_scope,
266 		  union acpi_dmar_id *dmar_id, int *num_inst, int max_inst);
267 
268 typedef void (*dmar_foreach_subtable_func_t)(ACPI_DMAR_HEADER *subtable, void *arg);
269 typedef void (*dmar_foreach_devscope_func_t)(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg);
270 
271 void acpi_dmar_foreach_subtable(ACPI_TABLE_DMAR *dmar, dmar_foreach_subtable_func_t func,
272 				void *arg);
273 void acpi_dmar_foreach_devscope(ACPI_DMAR_HARDWARE_UNIT *hu,
274 				dmar_foreach_devscope_func_t func, void *arg);
275 
276 /**
277  * @brief Retrieve IOAPIC id
278  *
279  * @param ioapic_id IOAPIC id
280  * @return return 0 on success or error code
281  */
282 int acpi_dmar_ioapic_get(uint16_t *ioapic_id);
283 
284 /**
285  * @brief Retrieve the 'n'th enabled local apic info.
286  *
287  * @param cpu_num the cpu number
288  * @return local apic info on success or NULL otherwise
289  */
290 ACPI_MADT_LOCAL_APIC *acpi_local_apic_get(int cpu_num);
291 
292 /**
293  * @brief invoke an ACPI method and return the result.
294  *
295  * @param path the path name of the ACPI object
296  * @param arg_list the list of arguments to be pass down
297  * @param ret_obj the ACPI result to be return
298  * @return return 0 on success or error code
299  */
300 int acpi_invoke_method(char *path, ACPI_OBJECT_LIST *arg_list, ACPI_OBJECT *ret_obj);
301 
302 #endif
303