Merge tag 'efi-2022-01-rc4-4' of https://source.denx.de/u-boot/custodians/u-boot-efi
[platform/kernel/u-boot.git] / lib / acpi / acpi_dp.c
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
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 } */
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 */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }