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