summaryrefslogtreecommitdiff
path: root/include/acpi/acpi_dp.h
blob: a82330856a5996a4262c1f834cd18dbea06ccdb1 (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
/* 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;

/*
 * 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_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);

#endif