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
13 #include <acpi/acpigen.h>
14 #include <acpi/acpi_dp.h>
17 static void acpi_dp_write_array(struct acpi_ctx *ctx,
18 const struct acpi_dp *array);
20 static void acpi_dp_write_value(struct acpi_ctx *ctx,
21 const struct acpi_dp *prop)
24 case ACPI_DP_TYPE_INTEGER:
25 acpigen_write_integer(ctx, prop->integer);
27 case ACPI_DP_TYPE_STRING:
28 case ACPI_DP_TYPE_CHILD:
29 acpigen_write_string(ctx, prop->string);
31 case ACPI_DP_TYPE_REFERENCE:
32 acpigen_emit_namestring(ctx, prop->string);
34 case ACPI_DP_TYPE_ARRAY:
35 acpi_dp_write_array(ctx, prop->array);
42 /* Package (2) { "prop->name", VALUE } */
43 static void acpi_dp_write_property(struct acpi_ctx *ctx,
44 const struct acpi_dp *prop)
46 acpigen_write_package(ctx, 2);
47 acpigen_write_string(ctx, prop->name);
48 acpi_dp_write_value(ctx, prop);
52 /* Write array of Device Properties */
53 static void acpi_dp_write_array(struct acpi_ctx *ctx,
54 const struct acpi_dp *array)
56 const struct acpi_dp *dp;
59 /* Package element count determined as it is populated */
60 pkg_count = acpigen_write_package(ctx, 0);
63 * Only acpi_dp of type DP_TYPE_TABLE is allowed to be an array.
64 * DP_TYPE_TABLE does not have a value to be written. Thus, start
65 * the loop from next type in the array.
67 for (dp = array->next; dp; dp = dp->next) {
68 acpi_dp_write_value(ctx, dp);
75 static void acpi_dp_free(struct acpi_dp *dp)
79 struct acpi_dp *p = dp->next;
82 case ACPI_DP_TYPE_CHILD:
83 acpi_dp_free(dp->child);
85 case ACPI_DP_TYPE_ARRAY:
86 acpi_dp_free(dp->array);
97 static int acpi_dp_write_internal(struct acpi_ctx *ctx, struct acpi_dp *table)
99 struct acpi_dp *dp, *prop;
100 char *dp_count, *prop_count = NULL;
105 if (table->type != ACPI_DP_TYPE_TABLE)
109 acpigen_write_name(ctx, table->name);
111 /* Device Property list starts with the next entry */
114 /* Package (DP), default to assuming no properties or children */
115 dp_count = acpigen_write_package(ctx, 0);
117 /* Print base properties */
118 for (dp = prop; dp; dp = dp->next) {
119 if (dp->type == ACPI_DP_TYPE_CHILD) {
123 * The UUID and package is only added when
124 * we come across the first property. This
125 * is to avoid creating a zero-length package
126 * in situations where there are only children.
130 /* ToUUID (ACPI_DP_UUID) */
131 ret = acpigen_write_uuid(ctx, ACPI_DP_UUID);
133 return log_msg_ret("touuid", ret);
135 * Package (PROP), element count determined as
138 prop_count = acpigen_write_package(ctx, 0);
141 acpi_dp_write_property(ctx, dp);
146 /* Package (PROP) length, if a package was written */
147 acpigen_pop_len(ctx);
151 /* Update DP package count to 2 or 4 */
153 /* ToUUID (ACPI_DP_CHILD_UUID) */
154 ret = acpigen_write_uuid(ctx, ACPI_DP_CHILD_UUID);
156 return log_msg_ret("child uuid", ret);
158 /* Print child pointer properties */
159 acpigen_write_package(ctx, child_count);
161 for (dp = prop; dp; dp = dp->next)
162 if (dp->type == ACPI_DP_TYPE_CHILD)
163 acpi_dp_write_property(ctx, dp);
164 /* Package (CHILD) length */
165 acpigen_pop_len(ctx);
168 /* Package (DP) length */
169 acpigen_pop_len(ctx);
171 /* Recursively parse children into separate tables */
172 for (dp = prop; dp; dp = dp->next) {
173 if (dp->type == ACPI_DP_TYPE_CHILD) {
174 ret = acpi_dp_write_internal(ctx, dp->child);
176 return log_msg_ret("dp child", ret);
183 int acpi_dp_write(struct acpi_ctx *ctx, struct acpi_dp *table)
187 ret = acpi_dp_write_internal(ctx, table);
193 return log_msg_ret("write", ret);
198 static struct acpi_dp *acpi_dp_new(struct acpi_dp *dp, enum acpi_dp_type type,
203 new = malloc(sizeof(struct acpi_dp));
207 memset(new, '\0', sizeof(*new));
212 /* Add to end of property list */
221 struct acpi_dp *acpi_dp_new_table(const char *name)
223 return acpi_dp_new(NULL, ACPI_DP_TYPE_TABLE, name);
226 struct acpi_dp *acpi_dp_add_integer(struct acpi_dp *dp, const char *name,
232 new = acpi_dp_new(dp, ACPI_DP_TYPE_INTEGER, name);
235 new->integer = value;
240 struct acpi_dp *acpi_dp_add_string(struct acpi_dp *dp, const char *name,
246 new = acpi_dp_new(dp, ACPI_DP_TYPE_STRING, name);
248 new->string = string;
253 struct acpi_dp *acpi_dp_add_reference(struct acpi_dp *dp, const char *name,
254 const char *reference)
259 new = acpi_dp_new(dp, ACPI_DP_TYPE_REFERENCE, name);
261 new->string = reference;
266 struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
267 struct acpi_dp *child)
272 if (child->type != ACPI_DP_TYPE_TABLE)
275 new = acpi_dp_new(dp, ACPI_DP_TYPE_CHILD, name);
278 new->string = child->name;
284 struct acpi_dp *acpi_dp_add_array(struct acpi_dp *dp, struct acpi_dp *array)
290 if (array->type != ACPI_DP_TYPE_TABLE)
293 new = acpi_dp_new(dp, ACPI_DP_TYPE_ARRAY, array->name);
300 struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
303 struct acpi_dp *dp_array;
310 dp_array = acpi_dp_new_table(name);
314 for (i = 0; i < len; i++)
315 if (!acpi_dp_add_integer(dp_array, NULL, array[i]))
318 if (!acpi_dp_add_array(dp, dp_array))
324 struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
325 const char *ref, int index, int pin,
326 enum acpi_gpio_polarity polarity)
328 struct acpi_dp *gpio;
331 gpio = acpi_dp_new_table(name);
335 if (!acpi_dp_add_reference(gpio, NULL, ref) ||
336 !acpi_dp_add_integer(gpio, NULL, index) ||
337 !acpi_dp_add_integer(gpio, NULL, pin) ||
338 !acpi_dp_add_integer(gpio, NULL, polarity == ACPI_GPIO_ACTIVE_LOW))
341 if (!acpi_dp_add_array(dp, gpio))
347 int acpi_dp_ofnode_copy_int(ofnode node, struct acpi_dp *dp, const char *prop)
352 ret = ofnode_read_u32(node, prop, &val);
355 if (!acpi_dp_add_integer(dp, prop, val))
356 return log_ret(-ENOMEM);
361 int acpi_dp_ofnode_copy_str(ofnode node, struct acpi_dp *dp, const char *prop)
365 val = ofnode_read_string(node, prop);
368 if (!acpi_dp_add_string(dp, prop, val))
369 return log_ret(-ENOMEM);
374 int acpi_dp_dev_copy_int(const struct udevice *dev, struct acpi_dp *dp,
380 ret = dev_read_u32(dev, prop, &val);
383 if (!acpi_dp_add_integer(dp, prop, val))
384 return log_ret(-ENOMEM);
389 int acpi_dp_dev_copy_str(const struct udevice *dev, struct acpi_dp *dp,
394 val = dev_read_string(dev, prop);
397 if (!acpi_dp_add_string(dp, prop, val))
398 return log_ret(-ENOMEM);