1 // SPDX-License-Identifier: GPL-2.0
3 * Generation of tables for particular device types
5 * Copyright 2019 Google LLC
6 * Mostly taken from coreboot file acpi_device.c
14 #include <acpi/acpigen.h>
15 #include <acpi/acpi_dp.h>
18 static void acpi_dp_write_array(struct acpi_ctx *ctx,
19 const struct acpi_dp *array);
21 static void acpi_dp_write_value(struct acpi_ctx *ctx,
22 const struct acpi_dp *prop)
25 case ACPI_DP_TYPE_INTEGER:
26 acpigen_write_integer(ctx, prop->integer);
28 case ACPI_DP_TYPE_STRING:
29 case ACPI_DP_TYPE_CHILD:
30 acpigen_write_string(ctx, prop->string);
32 case ACPI_DP_TYPE_REFERENCE:
33 acpigen_emit_namestring(ctx, prop->string);
35 case ACPI_DP_TYPE_ARRAY:
36 acpi_dp_write_array(ctx, prop->array);
43 /* Package (2) { "prop->name", VALUE } */
44 static void acpi_dp_write_property(struct acpi_ctx *ctx,
45 const struct acpi_dp *prop)
47 acpigen_write_package(ctx, 2);
48 acpigen_write_string(ctx, prop->name);
49 acpi_dp_write_value(ctx, prop);
53 /* Write array of Device Properties */
54 static void acpi_dp_write_array(struct acpi_ctx *ctx,
55 const struct acpi_dp *array)
57 const struct acpi_dp *dp;
60 /* Package element count determined as it is populated */
61 pkg_count = acpigen_write_package(ctx, 0);
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.
68 for (dp = array->next; dp; dp = dp->next) {
69 acpi_dp_write_value(ctx, dp);
76 static void acpi_dp_free(struct acpi_dp *dp)
80 struct acpi_dp *p = dp->next;
83 case ACPI_DP_TYPE_CHILD:
84 acpi_dp_free(dp->child);
86 case ACPI_DP_TYPE_ARRAY:
87 acpi_dp_free(dp->array);
98 static int acpi_dp_write_internal(struct acpi_ctx *ctx, struct acpi_dp *table)
100 struct acpi_dp *dp, *prop;
101 char *dp_count, *prop_count = NULL;
106 if (table->type != ACPI_DP_TYPE_TABLE)
110 acpigen_write_name(ctx, table->name);
112 /* Device Property list starts with the next entry */
115 /* Package (DP), default to assuming no properties or children */
116 dp_count = acpigen_write_package(ctx, 0);
118 /* Print base properties */
119 for (dp = prop; dp; dp = dp->next) {
120 if (dp->type == ACPI_DP_TYPE_CHILD) {
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.
131 /* ToUUID (ACPI_DP_UUID) */
132 ret = acpigen_write_uuid(ctx, ACPI_DP_UUID);
134 return log_msg_ret("touuid", ret);
136 * Package (PROP), element count determined as
139 prop_count = acpigen_write_package(ctx, 0);
142 acpi_dp_write_property(ctx, dp);
147 /* Package (PROP) length, if a package was written */
148 acpigen_pop_len(ctx);
152 /* Update DP package count to 2 or 4 */
154 /* ToUUID (ACPI_DP_CHILD_UUID) */
155 ret = acpigen_write_uuid(ctx, ACPI_DP_CHILD_UUID);
157 return log_msg_ret("child uuid", ret);
159 /* Print child pointer properties */
160 acpigen_write_package(ctx, child_count);
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);
169 /* Package (DP) length */
170 acpigen_pop_len(ctx);
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);
177 return log_msg_ret("dp child", ret);
184 int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table)
188 ret = acpi_dp_write_internal(ctx, table);
194 return log_msg_ret("write", ret);
199 static struct acpi_dp *acpi_dp_new(struct acpi_dp *dp, enum acpi_dp_type type,
204 new = malloc(sizeof(struct acpi_dp));
208 memset(new, '\0', sizeof(*new));
213 /* Add to end of property list */
222 struct acpi_dp *acpi_dp_new_table(const char *name)
224 return acpi_dp_new(NULL, ACPI_DP_TYPE_TABLE, name);
227 struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
233 new = acpi_dp_new(dp, ACPI_DP_TYPE_INTEGER, name);
236 new->integer = value;
241 struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
247 new = acpi_dp_new(dp, ACPI_DP_TYPE_STRING, name);
249 new->string = string;
254 struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
255 const char *reference)
260 new = acpi_dp_new(dp, ACPI_DP_TYPE_REFERENCE, name);
262 new->string = reference;
267 struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
268 struct acpi_dp *child)
273 if (child->type != ACPI_DP_TYPE_TABLE)
276 new = acpi_dp_new(dp, ACPI_DP_TYPE_CHILD, name);
279 new->string = child->name;
285 struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array)
291 if (array->type != ACPI_DP_TYPE_TABLE)
294 new = acpi_dp_new(dp, ACPI_DP_TYPE_ARRAY, array->name);
301 struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
304 struct acpi_dp *dp_array;
311 dp_array = acpi_dp_new_table(name);
315 for (i = 0; i < len; i++)
316 if (!acpi_dp_add_integer(dp_array, NULL, array[i]))
319 if (!acpi_dp_add_array(dp, dp_array))
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)
329 struct acpi_dp *gpio;
332 gpio = acpi_dp_new_table(name);
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))
342 if (!acpi_dp_add_array(dp, gpio))
348 int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop)
353 ret = ofnode_read_u32(node, prop, &val);
356 if (!acpi_dp_add_integer(dp, prop, val))
357 return log_ret(-ENOMEM);
362 int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop)
366 val = ofnode_read_string(node, prop);
369 if (!acpi_dp_add_string(dp, prop, val))
370 return log_ret(-ENOMEM);
375 int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp,
381 ret = dev_read_u32(dev, prop, &val);
384 if (!acpi_dp_add_integer(dp, prop, val))
385 return log_ret(-ENOMEM);
390 int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp,
395 val = dev_read_string(dev, prop);
398 if (!acpi_dp_add_string(dp, prop, val))
399 return log_ret(-ENOMEM);