summaryrefslogtreecommitdiffstats
path: root/include/acpi/acpi_dp.h
blob: 0b514bce59ce038840763e566cb495e27f281b1f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Device properties, a temporary data structure for adding to ACPI code
 *
 * Copyright 2019 Google LLC
 * Mostly taken from coreboot file acpi_device.h
 */

#ifndef __ACPI_DP_H
#define __ACPI_DP_H

struct acpi_ctx;

#include <acpi/acpi_device.h>

/*
 * Writing Device Properties objects via _DSD
 *
 * This is described in ACPI 6.3 section 6.2.5
 *
 * This provides a structure to handle nested device-specific data which ends
 * up in a _DSD table.
 *
 * https://www.kernel.org/doc/html/latest/firmware-guide/acpi/DSD-properties-rules.html
 * https://uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
 * https://uefi.org/sites/default/files/resources/_DSD-hierarchical-data-extension-UUID-v1.1.pdf
 *
 * The Device Property Hierarchy can be multiple levels deep with multiple
 * children possible in each level.  In order to support this flexibility
 * the device property hierarchy must be built up before being written out.
 *
 * For example:
 *
 * Child table with string and integer:
 * struct acpi_dp *child = acpi_dp_new_table("CHLD");
 * acpi_dp_add_string(child, "childstring", "CHILD");
 * acpi_dp_add_integer(child, "childint", 100);
 *
 * _DSD table with integer and gpio and child pointer:
 * struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
 * acpi_dp_add_integer(dsd, "number1", 1);
 * acpi_dp_add_gpio(dsd, "gpio", "\_SB.PCI0.GPIO", 0, 0, 1);
 * acpi_dp_add_child(dsd, "child", child);
 *
 * Write entries into SSDT and clean up resources:
 * acpi_dp_write(dsd);
 *
 * Name(_DSD, Package() {
 *   ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
 *   Package() {
 *     Package() { "gpio", Package() { \_SB.PCI0.GPIO, 0, 0, 0 } }
 *     Package() { "number1", 1 }
 *   }
 *   ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b")
 *   Package() {
 *     Package() { "child", CHLD }
 *   }
 * }
 * Name(CHLD, Package() {
 *   ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
 *   Package() {
 *     Package() { "childstring", "CHILD" }
 *     Package() { "childint", 100 }
 *   }
 * }
 */

#define ACPI_DP_UUID		"daffd814-6eba-4d8c-8a91-bc9bbf4aa301"
#define ACPI_DP_CHILD_UUID	"dbb8e3e6-5886-4ba6-8795-1319f52a966b"

/**
 * enum acpi_dp_type - types of device property objects
 *
 * These refer to the types defined by struct acpi_dp below
 *
 * @ACPI_DP_TYPE_UNKNOWN: Unknown / do not use
 * @ACPI_DP_TYPE_INTEGER: Integer value (u64) in @integer
 * @ACPI_DP_TYPE_STRING: String value in @string
 * @ACPI_DP_TYPE_REFERENCE: Reference to another object, with value in @string
 * @ACPI_DP_TYPE_TABLE: Type for a top-level table which may have children
 * @ACPI_DP_TYPE_ARRAY: Array of items with first item in @array and following
 *	items linked from that item's @next
 * @ACPI_DP_TYPE_CHILD: Child object, with siblings in that child's @next
 */
enum acpi_dp_type {
	ACPI_DP_TYPE_UNKNOWN,
	ACPI_DP_TYPE_INTEGER,
	ACPI_DP_TYPE_STRING,
	ACPI_DP_TYPE_REFERENCE,
	ACPI_DP_TYPE_TABLE,
	ACPI_DP_TYPE_ARRAY,
	ACPI_DP_TYPE_CHILD,
};

/**
 * struct acpi_dp - ACPI device properties
 *
 * @type: Table type
 * @name: Name of object, typically _DSD but could be CHLD for a child object.
 *	This can be NULL if there is no name
 * @next: Next object in list (next array element or next sibling)
 * @child: Pointer to first child, if @type == ACPI_DP_TYPE_CHILD, else NULL
 * @array: First array element, if @type == ACPI_DP_TYPE_ARRAY, else NULL
 * @integer: Integer value of the property, if @type == ACPI_DP_TYPE_INTEGER
 * @string: String value of the property, if @type == ACPI_DP_TYPE_STRING;
 *	child name if @type == ACPI_DP_TYPE_CHILD;
 *	reference name if @type == ACPI_DP_TYPE_REFERENCE;
 */
struct acpi_dp {
	enum acpi_dp_type type;
	const char *name;
	struct acpi_dp *next;
	union {
		struct acpi_dp *child;
		struct acpi_dp *array;
	};
	union {
		u64 integer;
		const char *string;
	};
};

/**
 * acpi_dp_new_table() - Start a new Device Property table
 *
 * @ref: ACPI reference (e.g. "_DSD")
 * @return pointer to table, or NULL if out of memory
 */
struct acpi_dp *acpi_dp_new_table(const char *ref);

/**
 * acpi_dp_add_integer() - Add integer Device Property
 *
 * A new node is added to the end of the property list of @dp
 *
 * @dp: Table to add this property to
 * @name: Name of property, or NULL for none
 * @value: Integer value
 * @return pointer to new node, or NULL if out of memory
 */
struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
				    u64 value);

/**
 * acpi_dp_add_string() - Add string Device Property
 *
 * A new node is added to the end of the property list of @dp
 *
 * @dp: Table to add this property to
 * @name: Name of property, or NULL for none
 * @string: String value
 * @return pointer to new node, or NULL if out of memory
 */
struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
				   const char *string);

/**
 * acpi_dp_add_reference() - Add reference Device Property
 *
 * A new node is added to the end of the property list of @dp
 *
 * @dp: Table to add this property to
 * @name: Name of property, or NULL for none
 * @reference: Reference value
 * @return pointer to new node, or NULL if out of memory
 */
struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
				      const char *reference);

/**
 * acpi_dp_add_array() - Add array Device Property
 *
 * A new node is added to the end of the property list of @dp, with the array
 * attached to that.
 *
 * @dp: Table to add this property to
 * @name: Name of property, or NULL for none
 * @return pointer to new node, or NULL if out of memory
 */
struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array);

/**
 * acpi_dp_add_integer_array() - Add an array of integers
 *
 * A new node is added to the end of the property list of @dp, with the array
 * attached to that. Each element of the array becomes a new node.
 *
 * @dp: Table to add this property to
 * @name: Name of property, or NULL for none
 * @return pointer to new array node, or NULL if out of memory
 */
struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
					  u64 *array, int len);

/**
 * acpi_dp_add_child() - Add a child table of Device Properties
 *
 * A new node is added as a child of @dp
 *
 * @dp: Table to add this child to
 * @name: Name of child, or NULL for none
 * @child: Child node to add
 * @return pointer to new child node, or NULL if out of memory
 */
struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
				  struct acpi_dp *child);

/**
 * acpi_dp_add_gpio() - Add a GPIO to a list of Device Properties
 *
 * A new node is added to the end of the property list of @dp, with the
 * GPIO properties added to the the new node
 *
 * @dp: Table to add this property to
 * @name: Name of property
 * @ref: Reference to device with a _CRS containing GpioIO or GpioInt
 * @index: Index of the GPIO resource in _CRS starting from zero
 * @pin: Pin in the GPIO resource, typically zero
 * @polarity: GPIO polarity. Note that ACPI_IRQ_ACTIVE_BOTH is not supported
 * @return pointer to new node, or NULL if out of memory
 */
struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
				 const char *ref, int index, int pin,
				 enum acpi_irq_polarity polarity);

/**
 * acpi_dp_write() - Write Device Property hierarchy and clean up resources
 *
 * This writes the table using acpigen and then frees it
 *
 * @ctx: ACPI context
 * @table: Table to write
 * @return 0 if OK, -ve on error
 */
int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table);

/**
 * acpi_dp_ofnode_copy_int() - Copy a property from device tree to DP
 *
 * This copies an integer property from the device tree to the ACPI DP table.
 *
 * @node: Node to copy from
 * @dp: DP to copy to
 * @prop: Property name to copy
 * @return 0 if OK, -ve on error
 */
int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop);

/**
 * acpi_dp_ofnode_copy_str() - Copy a property from device tree to DP
 *
 * This copies a string property from the device tree to the ACPI DP table.
 *
 * @node: Node to copy from
 * @dp: DP to copy to
 * @prop: Property name to copy
 * @return 0 if OK, -ve on error
 */
int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop);

/**
 * acpi_dp_dev_copy_int() - Copy a property from device tree to DP
 *
 * This copies an integer property from the device tree to the ACPI DP table.
 *
 * @dev: Device to copy from
 * @dp: DP to copy to
 * @prop: Property name to copy
 * @return 0 if OK, -ve on error
 */
int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp,
			 const char *prop);

/**
 * acpi_dp_dev_copy_str() - Copy a property from device tree to DP
 *
 * This copies a string property from the device tree to the ACPI DP table.
 *
 * @dev: Device to copy from
 * @dp: DP to copy to
 * @prop: Property name to copy
 * @return 0 if OK, -ve on error
 */
int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp,
			 const char *prop);

#endif