1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Device properties, a temporary data structure for adding to ACPI code
4 *
5 * Copyright 2019 Google LLC
6 * Mostly taken from coreboot file acpi_device.h
7 */
8
9#ifndef __ACPI_DP_H
10#define __ACPI_DP_H
11
12struct acpi_ctx;
13
14#include <acpi/acpi_device.h>
15
16/*
17 * Writing Device Properties objects via _DSD
18 *
19 * This is described in ACPI 6.3 section 6.2.5
20 *
21 * This provides a structure to handle nested device-specific data which ends
22 * up in a _DSD table.
23 *
24 * https://www.kernel.org/doc/html/latest/firmware-guide/acpi/DSD-properties-rules.html
25 * https://uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
26 * https://uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf
27 *
28 * The Device Property Hierarchy can be multiple levels deep with multiple
29 * children possible in each level.  In order to support this flexibility
30 * the device property hierarchy must be built up before being written out.
31 *
32 * For example:
33 *
34 * Child table with string and integer:
35 * struct acpi_dp *child = acpi_dp_new_table("CHLD");
36 * acpi_dp_add_string(child, "childstring", "CHILD");
37 * acpi_dp_add_integer(child, "childint", 100);
38 *
39 * _DSD table with integer and gpio and child pointer:
40 * struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
41 * acpi_dp_add_integer(dsd, "number1", 1);
42 * acpi_dp_add_gpio(dsd, "gpio", "\_SB.PCI0.GPIO", 0, 0, 1);
43 * acpi_dp_add_child(dsd, "child", child);
44 *
45 * Write entries into SSDT and clean up resources:
46 * acpi_dp_write(dsd);
47 *
48 * Name(_DSD, Package() {
49 *   ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
50 *   Package() {
51 *     Package() { "gpio", Package() { \_SB.PCI0.GPIO, 0, 0, 0 } }
52 *     Package() { "number1", 1 }
53 *   }
54 *   ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b")
55 *   Package() {
56 *     Package() { "child", CHLD }
57 *   }
58 * }
59 * Name(CHLD, Package() {
60 *   ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
61 *   Package() {
62 *     Package() { "childstring", "CHILD" }
63 *     Package() { "childint", 100 }
64 *   }
65 * }
66 */
67
68#define ACPI_DP_UUID		"daffd814-6eba-4d8c-8a91-bc9bbf4aa301"
69#define ACPI_DP_CHILD_UUID	"dbb8e3e6-5886-4ba6-8795-1319f52a966b"
70
71/**
72 * enum acpi_dp_type - types of device property objects
73 *
74 * These refer to the types defined by struct acpi_dp below
75 *
76 * @ACPI_DP_TYPE_UNKNOWN: Unknown / do not use
77 * @ACPI_DP_TYPE_INTEGER: Integer value (u64) in @integer
78 * @ACPI_DP_TYPE_STRING: String value in @string
79 * @ACPI_DP_TYPE_REFERENCE: Reference to another object, with value in @string
80 * @ACPI_DP_TYPE_TABLE: Type for a top-level table which may have children
81 * @ACPI_DP_TYPE_ARRAY: Array of items with first item in @array and following
82 *	items linked from that item's @next
83 * @ACPI_DP_TYPE_CHILD: Child object, with siblings in that child's @next
84 */
85enum acpi_dp_type {
86	ACPI_DP_TYPE_UNKNOWN,
87	ACPI_DP_TYPE_INTEGER,
88	ACPI_DP_TYPE_STRING,
89	ACPI_DP_TYPE_REFERENCE,
90	ACPI_DP_TYPE_TABLE,
91	ACPI_DP_TYPE_ARRAY,
92	ACPI_DP_TYPE_CHILD,
93};
94
95/**
96 * struct acpi_dp - ACPI device properties
97 *
98 * @type: Table type
99 * @name: Name of object, typically _DSD but could be CHLD for a child object.
100 *	This can be NULL if there is no name
101 * @next: Next object in list (next array element or next sibling)
102 * @child: Pointer to first child, if @type == ACPI_DP_TYPE_CHILD, else NULL
103 * @array: First array element, if @type == ACPI_DP_TYPE_ARRAY, else NULL
104 * @integer: Integer value of the property, if @type == ACPI_DP_TYPE_INTEGER
105 * @string: String value of the property, if @type == ACPI_DP_TYPE_STRING;
106 *	child name if @type == ACPI_DP_TYPE_CHILD;
107 *	reference name if @type == ACPI_DP_TYPE_REFERENCE;
108 */
109struct acpi_dp {
110	enum acpi_dp_type type;
111	const char *name;
112	struct acpi_dp *next;
113	union {
114		struct acpi_dp *child;
115		struct acpi_dp *array;
116	};
117	union {
118		u64 integer;
119		const char *string;
120	};
121};
122
123/**
124 * acpi_dp_new_table() - Start a new Device Property table
125 *
126 * @ref: ACPI reference (e.g. "_DSD")
127 * Return: pointer to table, or NULL if out of memory
128 */
129struct acpi_dp *acpi_dp_new_table(const char *ref);
130
131/**
132 * acpi_dp_add_integer() - Add integer Device Property
133 *
134 * A new node is added to the end of the property list of @dp
135 *
136 * @dp: Table to add this property to
137 * @name: Name of property, or NULL for none
138 * @value: Integer value
139 * Return: pointer to new node, or NULL if out of memory
140 */
141struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
142				    u64 value);
143
144/**
145 * acpi_dp_add_string() - Add string Device Property
146 *
147 * A new node is added to the end of the property list of @dp
148 *
149 * @dp: Table to add this property to
150 * @name: Name of property, or NULL for none
151 * @string: String value
152 * Return: pointer to new node, or NULL if out of memory
153 */
154struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
155				   const char *string);
156
157/**
158 * acpi_dp_add_reference() - Add reference Device Property
159 *
160 * A new node is added to the end of the property list of @dp
161 *
162 * @dp: Table to add this property to
163 * @name: Name of property, or NULL for none
164 * @reference: Reference value
165 * Return: pointer to new node, or NULL if out of memory
166 */
167struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
168				      const char *reference);
169
170/**
171 * acpi_dp_add_array() - Add array Device Property
172 *
173 * A new node is added to the end of the property list of @dp, with the array
174 * attached to that.
175 *
176 * @dp: Table to add this property to
177 * @name: Name of property, or NULL for none
178 * Return: pointer to new node, or NULL if out of memory
179 */
180struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array);
181
182/**
183 * acpi_dp_add_integer_array() - Add an array of integers
184 *
185 * A new node is added to the end of the property list of @dp, with the array
186 * attached to that. Each element of the array becomes a new node.
187 *
188 * @dp: Table to add this property to
189 * @name: Name of property, or NULL for none
190 * Return: pointer to new array node, or NULL if out of memory
191 */
192struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
193					  u64 *array, int len);
194
195/**
196 * acpi_dp_add_child() - Add a child table of Device Properties
197 *
198 * A new node is added as a child of @dp
199 *
200 * @dp: Table to add this child to
201 * @name: Name of child, or NULL for none
202 * @child: Child node to add
203 * Return: pointer to new child node, or NULL if out of memory
204 */
205struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
206				  struct acpi_dp *child);
207
208/**
209 * acpi_dp_add_gpio() - Add a GPIO to a list of Device Properties
210 *
211 * A new node is added to the end of the property list of @dp, with the
212 * GPIO properties added to the the new node
213 *
214 * @dp: Table to add this property to
215 * @name: Name of property
216 * @ref: Reference to device with a _CRS containing GpioIO or GpioInt
217 * @index: Index of the GPIO resource in _CRS starting from zero
218 * @pin: Pin in the GPIO resource, typically zero
219 * @polarity: GPIO polarity. Note that ACPI_IRQ_ACTIVE_BOTH is not supported
220 * Return: pointer to new node, or NULL if out of memory
221 */
222struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
223				 const char *ref, int index, int pin,
224				 enum acpi_gpio_polarity polarity);
225
226/**
227 * acpi_dp_write() - Write Device Property hierarchy and clean up resources
228 *
229 * This writes the table using acpigen and then frees it
230 *
231 * @ctx: ACPI context
232 * @table: Table to write
233 * Return: 0 if OK, -ve on error
234 */
235int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table);
236
237/**
238 * acpi_dp_ofnode_copy_int() - Copy a property from device tree to DP
239 *
240 * This copies an integer property from the device tree to the ACPI DP table.
241 *
242 * @node: Node to copy from
243 * @dp: DP to copy to
244 * @prop: Property name to copy
245 * Return: 0 if OK, -ve on error
246 */
247int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop);
248
249/**
250 * acpi_dp_ofnode_copy_str() - Copy a property from device tree to DP
251 *
252 * This copies a string property from the device tree to the ACPI DP table.
253 *
254 * @node: Node to copy from
255 * @dp: DP to copy to
256 * @prop: Property name to copy
257 * Return: 0 if OK, -ve on error
258 */
259int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop);
260
261/**
262 * acpi_dp_dev_copy_int() - Copy a property from device tree to DP
263 *
264 * This copies an integer property from the device tree to the ACPI DP table.
265 *
266 * @dev: Device to copy from
267 * @dp: DP to copy to
268 * @prop: Property name to copy
269 * Return: 0 if OK, -ve on error
270 */
271int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp,
272			 const char *prop);
273
274/**
275 * acpi_dp_dev_copy_str() - Copy a property from device tree to DP
276 *
277 * This copies a string property from the device tree to the ACPI DP table.
278 *
279 * @dev: Device to copy from
280 * @dp: DP to copy to
281 * @prop: Property name to copy
282 * Return: 0 if OK, -ve on error
283 */
284int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp,
285			 const char *prop);
286
287#endif
288