1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Generation of tables for particular device types
4  *
5  * Copyright 2019 Google LLC
6  * Mostly taken from coreboot file acpi_device.c
7  */
8 
9 #include <common.h>
10 #include <dm.h>
11 #include <log.h>
12 #include <malloc.h>
13 #include <uuid.h>
14 #include <acpi/acpigen.h>
15 #include <acpi/acpi_dp.h>
16 #include <dm/acpi.h>
17 
18 static void acpi_dp_write_array(struct acpi_ctx *ctx,
19 				const struct acpi_dp *array);
20 
acpi_dp_write_value(struct acpi_ctx * ctx,const struct acpi_dp * prop)21 static void acpi_dp_write_value(struct acpi_ctx *ctx,
22 				const struct acpi_dp *prop)
23 {
24 	switch (prop->type) {
25 	case ACPI_DP_TYPE_INTEGER:
26 		acpigen_write_integer(ctx, prop->integer);
27 		break;
28 	case ACPI_DP_TYPE_STRING:
29 	case ACPI_DP_TYPE_CHILD:
30 		acpigen_write_string(ctx, prop->string);
31 		break;
32 	case ACPI_DP_TYPE_REFERENCE:
33 		acpigen_emit_namestring(ctx, prop->string);
34 		break;
35 	case ACPI_DP_TYPE_ARRAY:
36 		acpi_dp_write_array(ctx, prop->array);
37 		break;
38 	default:
39 		break;
40 	}
41 }
42 
43 /* Package (2) { "prop->name", VALUE } */
acpi_dp_write_property(struct acpi_ctx * ctx,const struct acpi_dp * prop)44 static void acpi_dp_write_property(struct acpi_ctx *ctx,
45 				   const struct acpi_dp *prop)
46 {
47 	acpigen_write_package(ctx, 2);
48 	acpigen_write_string(ctx, prop->name);
49 	acpi_dp_write_value(ctx, prop);
50 	acpigen_pop_len(ctx);
51 }
52 
53 /* Write array of Device Properties */
acpi_dp_write_array(struct acpi_ctx * ctx,const struct acpi_dp * array)54 static void acpi_dp_write_array(struct acpi_ctx *ctx,
55 				const struct acpi_dp *array)
56 {
57 	const struct acpi_dp *dp;
58 	char *pkg_count;
59 
60 	/* Package element count determined as it is populated */
61 	pkg_count = acpigen_write_package(ctx, 0);
62 
63 	/*
64 	 * Only acpi_dp of type DP_TYPE_TABLE is allowed to be an array.
65 	 * DP_TYPE_TABLE does not have a value to be written. Thus, start
66 	 * the loop from next type in the array.
67 	 */
68 	for (dp = array->next; dp; dp = dp->next) {
69 		acpi_dp_write_value(ctx, dp);
70 		(*pkg_count)++;
71 	}
72 
73 	acpigen_pop_len(ctx);
74 }
75 
acpi_dp_free(struct acpi_dp * dp)76 static void acpi_dp_free(struct acpi_dp *dp)
77 {
78 	assert(dp);
79 	while (dp) {
80 		struct acpi_dp *p = dp->next;
81 
82 		switch (dp->type) {
83 		case ACPI_DP_TYPE_CHILD:
84 			acpi_dp_free(dp->child);
85 			break;
86 		case ACPI_DP_TYPE_ARRAY:
87 			acpi_dp_free(dp->array);
88 			break;
89 		default:
90 			break;
91 		}
92 
93 		free(dp);
94 		dp = p;
95 	}
96 }
97 
acpi_dp_write_internal(struct acpi_ctx * ctx,struct acpi_dp * table)98 static int acpi_dp_write_internal(struct acpi_ctx *ctx, struct acpi_dp *table)
99 {
100 	struct acpi_dp *dp, *prop;
101 	char *dp_count, *prop_count = NULL;
102 	int child_count = 0;
103 	int ret;
104 
105 	assert(table);
106 	if (table->type != ACPI_DP_TYPE_TABLE)
107 		return 0;
108 
109 	/* Name (name) */
110 	acpigen_write_name(ctx, table->name);
111 
112 	/* Device Property list starts with the next entry */
113 	prop = table->next;
114 
115 	/* Package (DP), default to assuming no properties or children */
116 	dp_count = acpigen_write_package(ctx, 0);
117 
118 	/* Print base properties */
119 	for (dp = prop; dp; dp = dp->next) {
120 		if (dp->type == ACPI_DP_TYPE_CHILD) {
121 			child_count++;
122 		} else {
123 			/*
124 			 * The UUID and package is only added when
125 			 * we come across the first property.  This
126 			 * is to avoid creating a zero-length package
127 			 * in situations where there are only children.
128 			 */
129 			if (!prop_count) {
130 				*dp_count += 2;
131 				/* ToUUID (ACPI_DP_UUID) */
132 				ret = acpigen_write_uuid(ctx, ACPI_DP_UUID);
133 				if (ret)
134 					return log_msg_ret("touuid", ret);
135 				/*
136 				 * Package (PROP), element count determined as
137 				 * it is populated
138 				 */
139 				prop_count = acpigen_write_package(ctx, 0);
140 			}
141 			(*prop_count)++;
142 			acpi_dp_write_property(ctx, dp);
143 		}
144 	}
145 
146 	if (prop_count) {
147 		/* Package (PROP) length, if a package was written */
148 		acpigen_pop_len(ctx);
149 	}
150 
151 	if (child_count) {
152 		/* Update DP package count to 2 or 4 */
153 		*dp_count += 2;
154 		/* ToUUID (ACPI_DP_CHILD_UUID) */
155 		ret = acpigen_write_uuid(ctx, ACPI_DP_CHILD_UUID);
156 		if (ret)
157 			return log_msg_ret("child uuid", ret);
158 
159 		/* Print child pointer properties */
160 		acpigen_write_package(ctx, child_count);
161 
162 		for (dp = prop; dp; dp = dp->next)
163 			if (dp->type == ACPI_DP_TYPE_CHILD)
164 				acpi_dp_write_property(ctx, dp);
165 		/* Package (CHILD) length */
166 		acpigen_pop_len(ctx);
167 	}
168 
169 	/* Package (DP) length */
170 	acpigen_pop_len(ctx);
171 
172 	/* Recursively parse children into separate tables */
173 	for (dp = prop; dp; dp = dp->next) {
174 		if (dp->type == ACPI_DP_TYPE_CHILD) {
175 			ret = acpi_dp_write_internal(ctx, dp->child);
176 			if (ret)
177 				return log_msg_ret("dp child", ret);
178 		}
179 	}
180 
181 	return 0;
182 }
183 
acpi_dp_write(struct acpi_ctx * ctx,struct acpi_dp * table)184 int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table)
185 {
186 	int ret;
187 
188 	ret = acpi_dp_write_internal(ctx, table);
189 
190 	/* Clean up */
191 	acpi_dp_free(table);
192 
193 	if (ret)
194 		return log_msg_ret("write", ret);
195 
196 	return 0;
197 }
198 
acpi_dp_new(struct acpi_dp * dp,enum acpi_dp_type type,const char * name)199 static struct acpi_dp *acpi_dp_new(struct acpi_dp *dp, enum acpi_dp_type type,
200 				   const char *name)
201 {
202 	struct acpi_dp *new;
203 
204 	new = malloc(sizeof(struct acpi_dp));
205 	if (!new)
206 		return NULL;
207 
208 	memset(new, '\0', sizeof(*new));
209 	new->type = type;
210 	new->name = name;
211 
212 	if (dp) {
213 		/* Add to end of property list */
214 		while (dp->next)
215 			dp = dp->next;
216 		dp->next = new;
217 	}
218 
219 	return new;
220 }
221 
acpi_dp_new_table(const char * name)222 struct acpi_dp *acpi_dp_new_table(const char *name)
223 {
224 	return acpi_dp_new(NULL, ACPI_DP_TYPE_TABLE, name);
225 }
226 
acpi_dp_add_integer(struct acpi_dp * dp,const char * name,u64 value)227 struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
228 				    u64 value)
229 {
230 	struct acpi_dp *new;
231 
232 	assert(dp);
233 	new = acpi_dp_new(dp, ACPI_DP_TYPE_INTEGER, name);
234 
235 	if (new)
236 		new->integer = value;
237 
238 	return new;
239 }
240 
acpi_dp_add_string(struct acpi_dp * dp,const char * name,const char * string)241 struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
242 				   const char *string)
243 {
244 	struct acpi_dp *new;
245 
246 	assert(dp);
247 	new = acpi_dp_new(dp, ACPI_DP_TYPE_STRING, name);
248 	if (new)
249 		new->string = string;
250 
251 	return new;
252 }
253 
acpi_dp_add_reference(struct acpi_dp * dp,const char * name,const char * reference)254 struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
255 				      const char *reference)
256 {
257 	struct acpi_dp *new;
258 
259 	assert(dp);
260 	new = acpi_dp_new(dp, ACPI_DP_TYPE_REFERENCE, name);
261 	if (new)
262 		new->string = reference;
263 
264 	return new;
265 }
266 
acpi_dp_add_child(struct acpi_dp * dp,const char * name,struct acpi_dp * child)267 struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
268 				  struct acpi_dp *child)
269 {
270 	struct acpi_dp *new;
271 
272 	assert(dp);
273 	if (child->type != ACPI_DP_TYPE_TABLE)
274 		return NULL;
275 
276 	new = acpi_dp_new(dp, ACPI_DP_TYPE_CHILD, name);
277 	if (new) {
278 		new->child = child;
279 		new->string = child->name;
280 	}
281 
282 	return new;
283 }
284 
acpi_dp_add_array(struct acpi_dp * dp,struct acpi_dp * array)285 struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array)
286 {
287 	struct acpi_dp *new;
288 
289 	assert(dp);
290 	assert(array);
291 	if (array->type != ACPI_DP_TYPE_TABLE)
292 		return NULL;
293 
294 	new = acpi_dp_new(dp, ACPI_DP_TYPE_ARRAY, array->name);
295 	if (new)
296 		new->array = array;
297 
298 	return new;
299 }
300 
acpi_dp_add_integer_array(struct acpi_dp * dp,const char * name,u64 * array,int len)301 struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
302 					  u64 *array, int len)
303 {
304 	struct acpi_dp *dp_array;
305 	int i;
306 
307 	assert(dp);
308 	if (len <= 0)
309 		return NULL;
310 
311 	dp_array = acpi_dp_new_table(name);
312 	if (!dp_array)
313 		return NULL;
314 
315 	for (i = 0; i < len; i++)
316 		if (!acpi_dp_add_integer(dp_array, NULL, array[i]))
317 			break;
318 
319 	if (!acpi_dp_add_array(dp, dp_array))
320 		return NULL;
321 
322 	return dp_array;
323 }
324 
acpi_dp_add_gpio(struct acpi_dp * dp,const char * name,const char * ref,int index,int pin,enum acpi_gpio_polarity polarity)325 struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
326 				 const char *ref, int index, int pin,
327 				 enum acpi_gpio_polarity polarity)
328 {
329 	struct acpi_dp *gpio;
330 
331 	assert(dp);
332 	gpio = acpi_dp_new_table(name);
333 	if (!gpio)
334 		return NULL;
335 
336 	if (!acpi_dp_add_reference(gpio, NULL, ref) ||
337 	    !acpi_dp_add_integer(gpio, NULL, index) ||
338 	    !acpi_dp_add_integer(gpio, NULL, pin) ||
339 	    !acpi_dp_add_integer(gpio, NULL, polarity == ACPI_GPIO_ACTIVE_LOW))
340 		return NULL;
341 
342 	if (!acpi_dp_add_array(dp, gpio))
343 		return NULL;
344 
345 	return gpio;
346 }
347 
acpi_dp_ofnode_copy_int(ofnode node,struct acpi_dp * dp,const char * prop)348 int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop)
349 {
350 	int ret;
351 	u32 val = 0;
352 
353 	ret = ofnode_read_u32(node, prop, &val);
354 	if (ret)
355 		return ret;
356 	if (!acpi_dp_add_integer(dp, prop, val))
357 		return log_ret(-ENOMEM);
358 
359 	return 0;
360 }
361 
acpi_dp_ofnode_copy_str(ofnode node,struct acpi_dp * dp,const char * prop)362 int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop)
363 {
364 	const char *val;
365 
366 	val = ofnode_read_string(node, prop);
367 	if (!val)
368 		return -EINVAL;
369 	if (!acpi_dp_add_string(dp, prop, val))
370 		return log_ret(-ENOMEM);
371 
372 	return 0;
373 }
374 
acpi_dp_dev_copy_int(const struct udevice * dev,struct acpi_dp * dp,const char * prop)375 int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp,
376 			 const char *prop)
377 {
378 	int ret;
379 	u32 val = 0;
380 
381 	ret = dev_read_u32(dev, prop, &val);
382 	if (ret)
383 		return ret;
384 	if (!acpi_dp_add_integer(dp, prop, val))
385 		return log_ret(-ENOMEM);
386 
387 	return ret;
388 }
389 
acpi_dp_dev_copy_str(const struct udevice * dev,struct acpi_dp * dp,const char * prop)390 int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp,
391 			 const char *prop)
392 {
393 	const char *val;
394 
395 	val = dev_read_string(dev, prop);
396 	if (!val)
397 		return -EINVAL;
398 	if (!acpi_dp_add_string(dp, prop, val))
399 		return log_ret(-ENOMEM);
400 
401 	return 0;
402 }
403