blob: 1fd8874047c138d7f089216eadc1cf3ab80dddb8 [file] [log] [blame]
Patrick Georgiafd4c872020-05-05 23:43:18 +02001/* Taken from depthcharge: src/base/device_tree.c */
Patrick Georgiac959032020-05-05 22:49:26 +02002/* SPDX-License-Identifier: GPL-2.0-or-later */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02003
4#include <assert.h>
Julius Werner9636a102019-05-03 17:36:43 -07005#include <commonlib/stdlib.h>
Patrick Rudolph666c1722018-04-03 09:57:33 +02006#include <console/console.h>
Joel Kitching393c71c2019-06-16 16:09:42 +08007#include <ctype.h>
Patrick Rudolph666c1722018-04-03 09:57:33 +02008#include <device_tree.h>
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02009#include <endian.h>
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020010#include <stdint.h>
Patrick Rudolph666c1722018-04-03 09:57:33 +020011#include <string.h>
12#include <stddef.h>
13#include <stdlib.h>
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020014
15/*
16 * Functions for picking apart flattened trees.
17 */
18
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020019int fdt_next_property(const void *blob, uint32_t offset,
20 struct fdt_property *prop)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020021{
Patrick Rudolph666c1722018-04-03 09:57:33 +020022 struct fdt_header *header = (struct fdt_header *)blob;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020023 uint32_t *ptr = (uint32_t *)(((uint8_t *)blob) + offset);
24
25 int index = 0;
Patrick Rudolph666c1722018-04-03 09:57:33 +020026 if (be32toh(ptr[index++]) != FDT_TOKEN_PROPERTY)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020027 return 0;
28
Patrick Rudolph666c1722018-04-03 09:57:33 +020029 uint32_t size = be32toh(ptr[index++]);
30 uint32_t name_offset = be32toh(ptr[index++]);
31 name_offset += be32toh(header->strings_offset);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020032
33 if (prop) {
34 prop->name = (char *)((uint8_t *)blob + name_offset);
35 prop->data = &ptr[index];
36 prop->size = size;
37 }
38
Patrick Rudolph666c1722018-04-03 09:57:33 +020039 index += DIV_ROUND_UP(size, sizeof(uint32_t));
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020040
Patrick Rudolph666c1722018-04-03 09:57:33 +020041 return index * sizeof(uint32_t);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020042}
43
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020044int fdt_node_name(const void *blob, uint32_t offset, const char **name)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020045{
46 uint8_t *ptr = ((uint8_t *)blob) + offset;
Julius Wernera5ea3a22019-05-07 17:38:12 -070047 if (be32dec(ptr) != FDT_TOKEN_BEGIN_NODE)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020048 return 0;
49
50 ptr += 4;
51 if (name)
52 *name = (char *)ptr;
Patrick Rudolph666c1722018-04-03 09:57:33 +020053 return ALIGN_UP(strlen((char *)ptr) + 1, sizeof(uint32_t)) + 4;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020054}
55
Julius Werner6702b682019-05-03 18:13:53 -070056static int dt_prop_is_phandle(struct device_tree_property *prop)
57{
58 return !(strcmp("phandle", prop->prop.name) &&
59 strcmp("linux,phandle", prop->prop.name));
60}
61
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020062
63
64/*
65 * Functions for printing flattened trees.
66 */
67
68static void print_indent(int depth)
69{
Julius Werner0d746532019-05-06 19:35:56 -070070 printk(BIOS_DEBUG, "%*s", depth * 8, "");
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020071}
72
Patrick Rudolph0a7d6902018-08-22 09:55:15 +020073static void print_property(const struct fdt_property *prop, int depth)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020074{
Julius Werner0d746532019-05-06 19:35:56 -070075 int is_string = prop->size > 0 &&
76 ((char *)prop->data)[prop->size - 1] == '\0';
77
78 if (is_string)
79 for (const char *c = prop->data; *c != '\0'; c++)
80 if (!isprint(*c))
81 is_string = 0;
82
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020083 print_indent(depth);
Julius Werner0d746532019-05-06 19:35:56 -070084 if (is_string) {
85 printk(BIOS_DEBUG, "%s = \"%s\";\n",
86 prop->name, (const char *)prop->data);
87 } else {
88 printk(BIOS_DEBUG, "%s = < ", prop->name);
89 for (int i = 0; i < MIN(128, prop->size); i += 4) {
90 uint32_t val = 0;
91 for (int j = 0; j < MIN(4, prop->size - i); j++)
92 val |= ((uint8_t *)prop->data)[i + j] <<
93 (24 - j * 8);
94 printk(BIOS_DEBUG, "%#.2x ", val);
95 }
96 if (prop->size > 128)
97 printk(BIOS_DEBUG, "...");
98 printk(BIOS_DEBUG, ">;\n");
Patrick Rudolph67aca3e2018-04-12 11:44:43 +020099 }
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200100}
101
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200102static int print_flat_node(const void *blob, uint32_t start_offset, int depth)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200103{
104 int offset = start_offset;
105 const char *name;
106 int size;
107
108 size = fdt_node_name(blob, offset, &name);
109 if (!size)
110 return 0;
111 offset += size;
112
113 print_indent(depth);
Julius Werner0d746532019-05-06 19:35:56 -0700114 printk(BIOS_DEBUG, "%s {\n", name);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200115
Patrick Rudolph666c1722018-04-03 09:57:33 +0200116 struct fdt_property prop;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200117 while ((size = fdt_next_property(blob, offset, &prop))) {
118 print_property(&prop, depth + 1);
119
120 offset += size;
121 }
122
Julius Werner23df4772019-05-17 22:50:18 -0700123 printk(BIOS_DEBUG, "\n"); /* empty line between props and nodes */
Julius Werner0d746532019-05-06 19:35:56 -0700124
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200125 while ((size = print_flat_node(blob, offset, depth + 1)))
126 offset += size;
127
Julius Werner0d746532019-05-06 19:35:56 -0700128 print_indent(depth);
129 printk(BIOS_DEBUG, "}\n");
130
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200131 return offset - start_offset + sizeof(uint32_t);
132}
133
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200134void fdt_print_node(const void *blob, uint32_t offset)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200135{
136 print_flat_node(blob, offset, 0);
137}
138
139
140
141/*
142 * A utility function to skip past nodes in flattened trees.
143 */
144
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200145int fdt_skip_node(const void *blob, uint32_t start_offset)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200146{
147 int offset = start_offset;
148 int size;
149
150 const char *name;
151 size = fdt_node_name(blob, offset, &name);
152 if (!size)
153 return 0;
154 offset += size;
155
156 while ((size = fdt_next_property(blob, offset, NULL)))
157 offset += size;
158
159 while ((size = fdt_skip_node(blob, offset)))
160 offset += size;
161
162 return offset - start_offset + sizeof(uint32_t);
163}
164
165
166
167/*
168 * Functions to turn a flattened tree into an unflattened one.
169 */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200170
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200171static int fdt_unflatten_node(const void *blob, uint32_t start_offset,
Julius Werner6702b682019-05-03 18:13:53 -0700172 struct device_tree *tree,
Patrick Rudolph666c1722018-04-03 09:57:33 +0200173 struct device_tree_node **new_node)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200174{
Patrick Rudolph666c1722018-04-03 09:57:33 +0200175 struct list_node *last;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200176 int offset = start_offset;
177 const char *name;
178 int size;
179
180 size = fdt_node_name(blob, offset, &name);
181 if (!size)
182 return 0;
183 offset += size;
184
Julius Werner9636a102019-05-03 17:36:43 -0700185 struct device_tree_node *node = xzalloc(sizeof(*node));
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200186 *new_node = node;
187 node->name = name;
188
Patrick Rudolph666c1722018-04-03 09:57:33 +0200189 struct fdt_property fprop;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200190 last = &node->properties;
191 while ((size = fdt_next_property(blob, offset, &fprop))) {
Julius Werner9636a102019-05-03 17:36:43 -0700192 struct device_tree_property *prop = xzalloc(sizeof(*prop));
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200193 prop->prop = fprop;
194
Julius Werner6702b682019-05-03 18:13:53 -0700195 if (dt_prop_is_phandle(prop)) {
196 node->phandle = be32dec(prop->prop.data);
197 if (node->phandle > tree->max_phandle)
198 tree->max_phandle = node->phandle;
199 }
200
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200201 list_insert_after(&prop->list_node, last);
202 last = &prop->list_node;
203
204 offset += size;
205 }
206
Patrick Rudolph666c1722018-04-03 09:57:33 +0200207 struct device_tree_node *child;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200208 last = &node->children;
Julius Werner6702b682019-05-03 18:13:53 -0700209 while ((size = fdt_unflatten_node(blob, offset, tree, &child))) {
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200210 list_insert_after(&child->list_node, last);
211 last = &child->list_node;
212
213 offset += size;
214 }
215
216 return offset - start_offset + sizeof(uint32_t);
217}
218
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200219static int fdt_unflatten_map_entry(const void *blob, uint32_t offset,
Patrick Rudolph666c1722018-04-03 09:57:33 +0200220 struct device_tree_reserve_map_entry **new)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200221{
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200222 const uint64_t *ptr = (const uint64_t *)(((uint8_t *)blob) + offset);
223 const uint64_t start = be64toh(ptr[0]);
224 const uint64_t size = be64toh(ptr[1]);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200225
226 if (!size)
227 return 0;
228
Julius Werner9636a102019-05-03 17:36:43 -0700229 struct device_tree_reserve_map_entry *entry = xzalloc(sizeof(*entry));
Patrick Rudolph666c1722018-04-03 09:57:33 +0200230 *new = entry;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200231 entry->start = start;
232 entry->size = size;
233
234 return sizeof(uint64_t) * 2;
235}
236
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200237struct device_tree *fdt_unflatten(const void *blob)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200238{
Julius Werner9636a102019-05-03 17:36:43 -0700239 struct device_tree *tree = xzalloc(sizeof(*tree));
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200240 const struct fdt_header *header = (const struct fdt_header *)blob;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200241 tree->header = header;
242
Julius Werner73eaec82019-05-03 17:58:07 -0700243 uint32_t magic = be32toh(header->magic);
244 uint32_t version = be32toh(header->version);
245 uint32_t last_comp_version = be32toh(header->last_comp_version);
246
247 if (magic != FDT_HEADER_MAGIC) {
248 printk(BIOS_DEBUG, "Invalid device tree magic %#.8x!\n", magic);
Jacob Garber698d83a2019-06-07 10:28:54 -0600249 free(tree);
Julius Werner73eaec82019-05-03 17:58:07 -0700250 return NULL;
251 }
252 if (last_comp_version > FDT_SUPPORTED_VERSION) {
253 printk(BIOS_DEBUG, "Unsupported device tree version %u(>=%u)\n",
254 version, last_comp_version);
Jacob Garber698d83a2019-06-07 10:28:54 -0600255 free(tree);
Julius Werner73eaec82019-05-03 17:58:07 -0700256 return NULL;
257 }
258 if (version > FDT_SUPPORTED_VERSION)
259 printk(BIOS_DEBUG,
260 "NOTE: FDT version %u too new, should add support!\n",
261 version);
262
Patrick Rudolph666c1722018-04-03 09:57:33 +0200263 uint32_t struct_offset = be32toh(header->structure_offset);
264 uint32_t strings_offset = be32toh(header->strings_offset);
265 uint32_t reserve_offset = be32toh(header->reserve_map_offset);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200266 uint32_t min_offset = 0;
267 min_offset = MIN(struct_offset, strings_offset);
268 min_offset = MIN(min_offset, reserve_offset);
Julius Werner23df4772019-05-17 22:50:18 -0700269 /* Assume everything up to the first non-header component is part of
270 the header and needs to be preserved. This will protect us against
271 new elements being added in the future. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200272 tree->header_size = min_offset;
273
Patrick Rudolph666c1722018-04-03 09:57:33 +0200274 struct device_tree_reserve_map_entry *entry;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200275 uint32_t offset = reserve_offset;
276 int size;
Patrick Rudolph666c1722018-04-03 09:57:33 +0200277 struct list_node *last = &tree->reserve_map;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200278 while ((size = fdt_unflatten_map_entry(blob, offset, &entry))) {
279 list_insert_after(&entry->list_node, last);
280 last = &entry->list_node;
281
282 offset += size;
283 }
284
Julius Werner6702b682019-05-03 18:13:53 -0700285 fdt_unflatten_node(blob, struct_offset, tree, &tree->root);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200286
287 return tree;
288}
289
290
291
292/*
Patrick Rudolph666c1722018-04-03 09:57:33 +0200293 * Functions to find the size of the device tree if it was flattened.
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200294 */
295
Patrick Rudolph666c1722018-04-03 09:57:33 +0200296static void dt_flat_prop_size(struct device_tree_property *prop,
297 uint32_t *struct_size, uint32_t *strings_size)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200298{
Julius Werner23df4772019-05-17 22:50:18 -0700299 /* Starting token. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200300 *struct_size += sizeof(uint32_t);
Julius Werner23df4772019-05-17 22:50:18 -0700301 /* Size. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200302 *struct_size += sizeof(uint32_t);
Julius Werner23df4772019-05-17 22:50:18 -0700303 /* Name offset. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200304 *struct_size += sizeof(uint32_t);
Julius Werner23df4772019-05-17 22:50:18 -0700305 /* Property value. */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200306 *struct_size += ALIGN_UP(prop->prop.size, sizeof(uint32_t));
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200307
Julius Werner23df4772019-05-17 22:50:18 -0700308 /* Property name. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200309 *strings_size += strlen(prop->prop.name) + 1;
310}
311
Patrick Rudolph666c1722018-04-03 09:57:33 +0200312static void dt_flat_node_size(struct device_tree_node *node,
313 uint32_t *struct_size, uint32_t *strings_size)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200314{
Julius Werner23df4772019-05-17 22:50:18 -0700315 /* Starting token. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200316 *struct_size += sizeof(uint32_t);
Julius Werner23df4772019-05-17 22:50:18 -0700317 /* Node name. */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200318 *struct_size += ALIGN_UP(strlen(node->name) + 1, sizeof(uint32_t));
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200319
Patrick Rudolph666c1722018-04-03 09:57:33 +0200320 struct device_tree_property *prop;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200321 list_for_each(prop, node->properties, list_node)
322 dt_flat_prop_size(prop, struct_size, strings_size);
323
Patrick Rudolph666c1722018-04-03 09:57:33 +0200324 struct device_tree_node *child;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200325 list_for_each(child, node->children, list_node)
326 dt_flat_node_size(child, struct_size, strings_size);
327
Julius Werner23df4772019-05-17 22:50:18 -0700328 /* End token. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200329 *struct_size += sizeof(uint32_t);
330}
331
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200332uint32_t dt_flat_size(const struct device_tree *tree)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200333{
334 uint32_t size = tree->header_size;
Patrick Rudolph666c1722018-04-03 09:57:33 +0200335 struct device_tree_reserve_map_entry *entry;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200336 list_for_each(entry, tree->reserve_map, list_node)
337 size += sizeof(uint64_t) * 2;
338 size += sizeof(uint64_t) * 2;
339
340 uint32_t struct_size = 0;
341 uint32_t strings_size = 0;
342 dt_flat_node_size(tree->root, &struct_size, &strings_size);
343
344 size += struct_size;
Julius Werner23df4772019-05-17 22:50:18 -0700345 /* End token. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200346 size += sizeof(uint32_t);
347
348 size += strings_size;
349
350 return size;
351}
352
353
354
355/*
356 * Functions to flatten a device tree.
357 */
358
Patrick Rudolph666c1722018-04-03 09:57:33 +0200359static void dt_flatten_map_entry(struct device_tree_reserve_map_entry *entry,
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200360 void **map_start)
361{
Patrick Rudolph666c1722018-04-03 09:57:33 +0200362 ((uint64_t *)*map_start)[0] = htobe64(entry->start);
363 ((uint64_t *)*map_start)[1] = htobe64(entry->size);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200364 *map_start = ((uint8_t *)*map_start) + sizeof(uint64_t) * 2;
365}
366
Patrick Rudolph666c1722018-04-03 09:57:33 +0200367static void dt_flatten_prop(struct device_tree_property *prop,
368 void **struct_start, void *strings_base,
369 void **strings_start)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200370{
371 uint8_t *dstruct = (uint8_t *)*struct_start;
372 uint8_t *dstrings = (uint8_t *)*strings_start;
373
Julius Wernera5ea3a22019-05-07 17:38:12 -0700374 be32enc(dstruct, FDT_TOKEN_PROPERTY);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200375 dstruct += sizeof(uint32_t);
376
Julius Wernera5ea3a22019-05-07 17:38:12 -0700377 be32enc(dstruct, prop->prop.size);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200378 dstruct += sizeof(uint32_t);
379
380 uint32_t name_offset = (uintptr_t)dstrings - (uintptr_t)strings_base;
Julius Wernera5ea3a22019-05-07 17:38:12 -0700381 be32enc(dstruct, name_offset);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200382 dstruct += sizeof(uint32_t);
383
384 strcpy((char *)dstrings, prop->prop.name);
385 dstrings += strlen(prop->prop.name) + 1;
386
387 memcpy(dstruct, prop->prop.data, prop->prop.size);
Patrick Rudolph666c1722018-04-03 09:57:33 +0200388 dstruct += ALIGN_UP(prop->prop.size, sizeof(uint32_t));
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200389
390 *struct_start = dstruct;
391 *strings_start = dstrings;
392}
393
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200394static void dt_flatten_node(const struct device_tree_node *node,
395 void **struct_start, void *strings_base,
396 void **strings_start)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200397{
398 uint8_t *dstruct = (uint8_t *)*struct_start;
399 uint8_t *dstrings = (uint8_t *)*strings_start;
400
Julius Wernera5ea3a22019-05-07 17:38:12 -0700401 be32enc(dstruct, FDT_TOKEN_BEGIN_NODE);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200402 dstruct += sizeof(uint32_t);
403
404 strcpy((char *)dstruct, node->name);
Patrick Rudolph666c1722018-04-03 09:57:33 +0200405 dstruct += ALIGN_UP(strlen(node->name) + 1, sizeof(uint32_t));
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200406
Patrick Rudolph666c1722018-04-03 09:57:33 +0200407 struct device_tree_property *prop;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200408 list_for_each(prop, node->properties, list_node)
409 dt_flatten_prop(prop, (void **)&dstruct, strings_base,
410 (void **)&dstrings);
411
Patrick Rudolph666c1722018-04-03 09:57:33 +0200412 struct device_tree_node *child;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200413 list_for_each(child, node->children, list_node)
414 dt_flatten_node(child, (void **)&dstruct, strings_base,
415 (void **)&dstrings);
416
Julius Wernera5ea3a22019-05-07 17:38:12 -0700417 be32enc(dstruct, FDT_TOKEN_END_NODE);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200418 dstruct += sizeof(uint32_t);
419
420 *struct_start = dstruct;
421 *strings_start = dstrings;
422}
423
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200424void dt_flatten(const struct device_tree *tree, void *start_dest)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200425{
426 uint8_t *dest = (uint8_t *)start_dest;
427
428 memcpy(dest, tree->header, tree->header_size);
Patrick Rudolph666c1722018-04-03 09:57:33 +0200429 struct fdt_header *header = (struct fdt_header *)dest;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200430 dest += tree->header_size;
431
Patrick Rudolph666c1722018-04-03 09:57:33 +0200432 struct device_tree_reserve_map_entry *entry;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200433 list_for_each(entry, tree->reserve_map, list_node)
434 dt_flatten_map_entry(entry, (void **)&dest);
435 ((uint64_t *)dest)[0] = ((uint64_t *)dest)[1] = 0;
436 dest += sizeof(uint64_t) * 2;
437
438 uint32_t struct_size = 0;
439 uint32_t strings_size = 0;
440 dt_flat_node_size(tree->root, &struct_size, &strings_size);
441
442 uint8_t *struct_start = dest;
Patrick Rudolph666c1722018-04-03 09:57:33 +0200443 header->structure_offset = htobe32(dest - (uint8_t *)start_dest);
444 header->structure_size = htobe32(struct_size);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200445 dest += struct_size;
446
Patrick Rudolph666c1722018-04-03 09:57:33 +0200447 *((uint32_t *)dest) = htobe32(FDT_TOKEN_END);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200448 dest += sizeof(uint32_t);
449
450 uint8_t *strings_start = dest;
Patrick Rudolph666c1722018-04-03 09:57:33 +0200451 header->strings_offset = htobe32(dest - (uint8_t *)start_dest);
452 header->strings_size = htobe32(strings_size);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200453 dest += strings_size;
454
455 dt_flatten_node(tree->root, (void **)&struct_start, strings_start,
456 (void **)&strings_start);
457
Patrick Rudolph666c1722018-04-03 09:57:33 +0200458 header->totalsize = htobe32(dest - (uint8_t *)start_dest);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200459}
460
461
462
463/*
464 * Functions for printing a non-flattened device tree.
465 */
466
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200467static void print_node(const struct device_tree_node *node, int depth)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200468{
469 print_indent(depth);
Julius Werner23df4772019-05-17 22:50:18 -0700470 if (depth == 0) /* root node has no name, print a starting slash */
Julius Werner0d746532019-05-06 19:35:56 -0700471 printk(BIOS_DEBUG, "/");
472 printk(BIOS_DEBUG, "%s {\n", node->name);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200473
Patrick Rudolph666c1722018-04-03 09:57:33 +0200474 struct device_tree_property *prop;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200475 list_for_each(prop, node->properties, list_node)
476 print_property(&prop->prop, depth + 1);
477
Julius Werner23df4772019-05-17 22:50:18 -0700478 printk(BIOS_DEBUG, "\n"); /* empty line between props and nodes */
Julius Werner0d746532019-05-06 19:35:56 -0700479
Patrick Rudolph666c1722018-04-03 09:57:33 +0200480 struct device_tree_node *child;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200481 list_for_each(child, node->children, list_node)
482 print_node(child, depth + 1);
Julius Werner0d746532019-05-06 19:35:56 -0700483
484 print_indent(depth);
485 printk(BIOS_DEBUG, "};\n");
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200486}
487
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200488void dt_print_node(const struct device_tree_node *node)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200489{
490 print_node(node, 0);
491}
492
493
494
495/*
496 * Functions for reading and manipulating an unflattened device tree.
497 */
498
499/*
500 * Read #address-cells and #size-cells properties from a node.
501 *
502 * @param node The device tree node to read from.
503 * @param addrcp Pointer to store #address-cells in, skipped if NULL.
504 * @param sizecp Pointer to store #size-cells in, skipped if NULL.
505 */
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200506void dt_read_cell_props(const struct device_tree_node *node, u32 *addrcp,
507 u32 *sizecp)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200508{
Patrick Rudolph666c1722018-04-03 09:57:33 +0200509 struct device_tree_property *prop;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200510 list_for_each(prop, node->properties, list_node) {
511 if (addrcp && !strcmp("#address-cells", prop->prop.name))
Julius Wernera5ea3a22019-05-07 17:38:12 -0700512 *addrcp = be32dec(prop->prop.data);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200513 if (sizecp && !strcmp("#size-cells", prop->prop.name))
Julius Wernera5ea3a22019-05-07 17:38:12 -0700514 *sizecp = be32dec(prop->prop.data);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200515 }
516}
517
518/*
519 * Find a node from a device tree path, relative to a parent node.
520 *
521 * @param parent The node from which to start the relative path lookup.
522 * @param path An array of path component strings that will be looked
Elyes HAOUASe3e3f4f2018-06-29 21:41:41 +0200523 * up in order to find the node. Must be terminated with
524 * a NULL pointer. Example: {'firmware', 'coreboot', NULL}
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200525 * @param addrcp Pointer that will be updated with any #address-cells
Elyes HAOUASe3e3f4f2018-06-29 21:41:41 +0200526 * value found in the path. May be NULL to ignore.
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200527 * @param sizecp Pointer that will be updated with any #size-cells
Elyes HAOUASe3e3f4f2018-06-29 21:41:41 +0200528 * value found in the path. May be NULL to ignore.
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200529 * @param create 1: Create node(s) if not found. 0: Return NULL instead.
530 * @return The found/created node, or NULL.
531 */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200532struct device_tree_node *dt_find_node(struct device_tree_node *parent,
533 const char **path, u32 *addrcp,
534 u32 *sizecp, int create)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200535{
Patrick Rudolph666c1722018-04-03 09:57:33 +0200536 struct device_tree_node *node, *found = NULL;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200537
Julius Werner23df4772019-05-17 22:50:18 -0700538 /* Update #address-cells and #size-cells for this level. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200539 dt_read_cell_props(parent, addrcp, sizecp);
540
541 if (!*path)
542 return parent;
543
Julius Werner23df4772019-05-17 22:50:18 -0700544 /* Find the next node in the path, if it exists. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200545 list_for_each(node, parent->children, list_node) {
546 if (!strcmp(node->name, *path)) {
547 found = node;
548 break;
549 }
550 }
551
Julius Werner23df4772019-05-17 22:50:18 -0700552 /* Otherwise create it or return NULL. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200553 if (!found) {
554 if (!create)
555 return NULL;
556
Julius Werner9636a102019-05-03 17:36:43 -0700557 found = malloc(sizeof(*found));
Patrick Rudolph666c1722018-04-03 09:57:33 +0200558 if (!found)
559 return NULL;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200560 found->name = strdup(*path);
561 if (!found->name)
562 return NULL;
563
564 list_insert_after(&found->list_node, &parent->children);
565 }
566
567 return dt_find_node(found, path + 1, addrcp, sizecp, create);
568}
569
570/*
Julius Wernerf36d53c2019-05-03 18:23:34 -0700571 * Find a node in the tree from a string device tree path.
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200572 *
Julius Wernerf36d53c2019-05-03 18:23:34 -0700573 * @param tree The device tree to search.
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200574 * @param path A string representing a path in the device tree, with
Julius Wernerfbec63d2019-05-03 18:29:28 -0700575 * nodes separated by '/'. Example: "/firmware/coreboot"
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200576 * @param addrcp Pointer that will be updated with any #address-cells
577 * value found in the path. May be NULL to ignore.
578 * @param sizecp Pointer that will be updated with any #size-cells
579 * value found in the path. May be NULL to ignore.
580 * @param create 1: Create node(s) if not found. 0: Return NULL instead.
581 * @return The found/created node, or NULL.
582 *
Julius Werner6d5695f2019-05-06 19:23:28 -0700583 * It is the caller responsibility to provide a path string that doesn't end
584 * with a '/' and doesn't contain any "//". If the path does not start with a
585 * '/', the first segment is interpreted as an alias. */
Julius Wernerf36d53c2019-05-03 18:23:34 -0700586struct device_tree_node *dt_find_node_by_path(struct device_tree *tree,
Patrick Rudolph666c1722018-04-03 09:57:33 +0200587 const char *path, u32 *addrcp,
588 u32 *sizecp, int create)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200589{
Julius Werner6d5695f2019-05-06 19:23:28 -0700590 char *sub_path;
591 char *duped_str;
592 struct device_tree_node *parent;
593 char *next_slash;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200594 /* Hopefully enough depth for any node. */
595 const char *path_array[15];
596 int i;
Patrick Rudolph666c1722018-04-03 09:57:33 +0200597 struct device_tree_node *node = NULL;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200598
Julius Werner23df4772019-05-17 22:50:18 -0700599 if (path[0] == '/') { /* regular path */
600 if (path[1] == '\0') { /* special case: "/" is root node */
Julius Werner6d5695f2019-05-06 19:23:28 -0700601 dt_read_cell_props(tree->root, addrcp, sizecp);
602 return tree->root;
603 }
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200604
Julius Werner6d5695f2019-05-06 19:23:28 -0700605 sub_path = duped_str = strdup(&path[1]);
606 if (!sub_path)
607 return NULL;
608
609 parent = tree->root;
Julius Werner23df4772019-05-17 22:50:18 -0700610 } else { /* alias */
Julius Werner6d5695f2019-05-06 19:23:28 -0700611 char *alias;
612
613 alias = duped_str = strdup(path);
614 if (!alias)
615 return NULL;
616
617 sub_path = strchr(alias, '/');
618 if (sub_path)
619 *sub_path = '\0';
620
621 parent = dt_find_node_by_alias(tree, alias);
622 if (!parent) {
623 printk(BIOS_DEBUG,
624 "Could not find node '%s', alias '%s' does not exist\n",
625 path, alias);
626 free(duped_str);
627 return NULL;
628 }
629
630 if (!sub_path) {
Julius Werner23df4772019-05-17 22:50:18 -0700631 /* it's just the alias, no sub-path */
Julius Werner6d5695f2019-05-06 19:23:28 -0700632 free(duped_str);
633 return parent;
634 }
635
636 sub_path++;
637 }
638
639 next_slash = sub_path;
640 path_array[0] = sub_path;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200641 for (i = 1; i < (ARRAY_SIZE(path_array) - 1); i++) {
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200642 next_slash = strchr(next_slash, '/');
643 if (!next_slash)
644 break;
645
646 *next_slash++ = '\0';
647 path_array[i] = next_slash;
648 }
649
650 if (!next_slash) {
651 path_array[i] = NULL;
Julius Werner6d5695f2019-05-06 19:23:28 -0700652 node = dt_find_node(parent, path_array,
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200653 addrcp, sizecp, create);
654 }
655
Julius Werner6d5695f2019-05-06 19:23:28 -0700656 free(duped_str);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200657 return node;
658}
659
Julius Werner6d5695f2019-05-06 19:23:28 -0700660/*
661 * Find a node from an alias
662 *
663 * @param tree The device tree.
664 * @param alias The alias name.
665 * @return The found node, or NULL.
666 */
667struct device_tree_node *dt_find_node_by_alias(struct device_tree *tree,
668 const char *alias)
669{
670 struct device_tree_node *node;
671 const char *alias_path;
672
673 node = dt_find_node_by_path(tree, "/aliases", NULL, NULL, 0);
674 if (!node)
675 return NULL;
676
677 alias_path = dt_find_string_prop(node, alias);
678 if (!alias_path)
679 return NULL;
680
681 return dt_find_node_by_path(tree, alias_path, NULL, NULL, 0);
682}
683
Julius Werner6702b682019-05-03 18:13:53 -0700684struct device_tree_node *dt_find_node_by_phandle(struct device_tree_node *root,
685 uint32_t phandle)
686{
687 if (!root)
688 return NULL;
689
690 if (root->phandle == phandle)
691 return root;
692
693 struct device_tree_node *node;
694 struct device_tree_node *result;
695 list_for_each(node, root->children, list_node) {
696 result = dt_find_node_by_phandle(node, phandle);
697 if (result)
698 return result;
699 }
700
701 return NULL;
702}
703
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200704/*
705 * Check if given node is compatible.
706 *
707 * @param node The node which is to be checked for compatible property.
708 * @param compat The compatible string to match.
709 * @return 1 = compatible, 0 = not compatible.
710 */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200711static int dt_check_compat_match(struct device_tree_node *node,
712 const char *compat)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200713{
Patrick Rudolph666c1722018-04-03 09:57:33 +0200714 struct device_tree_property *prop;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200715
716 list_for_each(prop, node->properties, list_node) {
717 if (!strcmp("compatible", prop->prop.name)) {
718 size_t bytes = prop->prop.size;
719 const char *str = prop->prop.data;
720 while (bytes > 0) {
721 if (!strncmp(compat, str, bytes))
722 return 1;
723 size_t len = strnlen(str, bytes) + 1;
724 if (bytes <= len)
725 break;
726 str += len;
727 bytes -= len;
728 }
729 break;
730 }
731 }
732
733 return 0;
734}
735
736/*
737 * Find a node from a compatible string, in the subtree of a parent node.
738 *
739 * @param parent The parent node under which to look.
740 * @param compat The compatible string to find.
741 * @return The found node, or NULL.
742 */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200743struct device_tree_node *dt_find_compat(struct device_tree_node *parent,
744 const char *compat)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200745{
Julius Werner23df4772019-05-17 22:50:18 -0700746 /* Check if the parent node itself is compatible. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200747 if (dt_check_compat_match(parent, compat))
748 return parent;
749
Patrick Rudolph666c1722018-04-03 09:57:33 +0200750 struct device_tree_node *child;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200751 list_for_each(child, parent->children, list_node) {
Patrick Rudolph666c1722018-04-03 09:57:33 +0200752 struct device_tree_node *found = dt_find_compat(child, compat);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200753 if (found)
754 return found;
755 }
756
757 return NULL;
758}
759
760/*
761 * Find the next compatible child of a given parent. All children upto the
762 * child passed in by caller are ignored. If child is NULL, it considers all the
763 * children to find the first child which is compatible.
764 *
765 * @param parent The parent node under which to look.
766 * @param child The child node to start search from (exclusive). If NULL
767 * consider all children.
768 * @param compat The compatible string to find.
769 * @return The found node, or NULL.
770 */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200771struct device_tree_node *
772dt_find_next_compat_child(struct device_tree_node *parent,
773 struct device_tree_node *child,
774 const char *compat)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200775{
Patrick Rudolph666c1722018-04-03 09:57:33 +0200776 struct device_tree_node *next;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200777 int ignore = 0;
778
779 if (child)
780 ignore = 1;
781
782 list_for_each(next, parent->children, list_node) {
783 if (ignore) {
784 if (child == next)
785 ignore = 0;
786 continue;
787 }
788
789 if (dt_check_compat_match(next, compat))
790 return next;
791 }
792
793 return NULL;
794}
795
796/*
797 * Find a node with matching property value, in the subtree of a parent node.
798 *
799 * @param parent The parent node under which to look.
800 * @param name The property name to look for.
801 * @param data The property value to look for.
802 * @param size The property size.
803 */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200804struct device_tree_node *dt_find_prop_value(struct device_tree_node *parent,
805 const char *name, void *data,
806 size_t size)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200807{
Patrick Rudolph666c1722018-04-03 09:57:33 +0200808 struct device_tree_property *prop;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200809
810 /* Check if parent itself has the required property value. */
811 list_for_each(prop, parent->properties, list_node) {
812 if (!strcmp(name, prop->prop.name)) {
813 size_t bytes = prop->prop.size;
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200814 const void *prop_data = prop->prop.data;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200815 if (size != bytes)
816 break;
817 if (!memcmp(data, prop_data, size))
818 return parent;
819 break;
820 }
821 }
822
Patrick Rudolph666c1722018-04-03 09:57:33 +0200823 struct device_tree_node *child;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200824 list_for_each(child, parent->children, list_node) {
Patrick Rudolph666c1722018-04-03 09:57:33 +0200825 struct device_tree_node *found = dt_find_prop_value(child, name,
826 data, size);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200827 if (found)
828 return found;
829 }
830 return NULL;
831}
832
833/*
834 * Write an arbitrary sized big-endian integer into a pointer.
835 *
836 * @param dest Pointer to the DT property data buffer to write.
Elyes HAOUAS1ec76442018-08-07 12:20:04 +0200837 * @param src The integer to write (in CPU endianness).
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200838 * @param length the length of the destination integer in bytes.
839 */
840void dt_write_int(u8 *dest, u64 src, size_t length)
841{
842 while (length--) {
843 dest[length] = (u8)src;
844 src >>= 8;
845 }
846}
847
848/*
Patrick Rudolph5ccc7312018-05-30 15:05:28 +0200849 * Delete a property by name in a given node if it exists.
850 *
851 * @param node The device tree node to operate on.
852 * @param name The name of the property to delete.
853 */
854void dt_delete_prop(struct device_tree_node *node, const char *name)
855{
856 struct device_tree_property *prop;
857
858 list_for_each(prop, node->properties, list_node) {
859 if (!strcmp(prop->prop.name, name)) {
860 list_remove(&prop->list_node);
861 return;
862 }
863 }
864}
865
866/*
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200867 * Add an arbitrary property to a node, or update it if it already exists.
868 *
869 * @param node The device tree node to add to.
870 * @param name The name of the new property.
871 * @param data The raw data blob to be stored in the property.
872 * @param size The size of data in bytes.
873 */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200874void dt_add_bin_prop(struct device_tree_node *node, const char *name,
Julius Werner0e9116f2019-05-13 17:30:31 -0700875 void *data, size_t size)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200876{
Patrick Rudolph666c1722018-04-03 09:57:33 +0200877 struct device_tree_property *prop;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200878
879 list_for_each(prop, node->properties, list_node) {
880 if (!strcmp(prop->prop.name, name)) {
881 prop->prop.data = data;
882 prop->prop.size = size;
883 return;
884 }
885 }
886
Julius Werner9636a102019-05-03 17:36:43 -0700887 prop = xzalloc(sizeof(*prop));
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200888 list_insert_after(&prop->list_node, &node->properties);
889 prop->prop.name = name;
890 prop->prop.data = data;
891 prop->prop.size = size;
892}
893
894/*
895 * Find given string property in a node and return its content.
896 *
897 * @param node The device tree node to search.
898 * @param name The name of the property.
899 * @return The found string, or NULL.
900 */
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200901const char *dt_find_string_prop(const struct device_tree_node *node,
902 const char *name)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200903{
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200904 const void *content;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200905 size_t size;
906
907 dt_find_bin_prop(node, name, &content, &size);
908
909 return content;
910}
911
912/*
913 * Find given property in a node.
914 *
915 * @param node The device tree node to search.
916 * @param name The name of the property.
917 * @param data Pointer to return raw data blob in the property.
918 * @param size Pointer to return the size of data in bytes.
919 */
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200920void dt_find_bin_prop(const struct device_tree_node *node, const char *name,
921 const void **data, size_t *size)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200922{
Patrick Rudolph666c1722018-04-03 09:57:33 +0200923 struct device_tree_property *prop;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200924
925 *data = NULL;
926 *size = 0;
927
928 list_for_each(prop, node->properties, list_node) {
929 if (!strcmp(prop->prop.name, name)) {
930 *data = prop->prop.data;
931 *size = prop->prop.size;
932 return;
933 }
934 }
935}
936
937/*
938 * Add a string property to a node, or update it if it already exists.
939 *
940 * @param node The device tree node to add to.
941 * @param name The name of the new property.
942 * @param str The zero-terminated string to be stored in the property.
943 */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200944void dt_add_string_prop(struct device_tree_node *node, const char *name,
Patrick Rudolph0a7d6902018-08-22 09:55:15 +0200945 const char *str)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200946{
Julius Werner0e9116f2019-05-13 17:30:31 -0700947 dt_add_bin_prop(node, name, (char *)str, strlen(str) + 1);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200948}
949
950/*
951 * Add a 32-bit integer property to a node, or update it if it already exists.
952 *
953 * @param node The device tree node to add to.
954 * @param name The name of the new property.
955 * @param val The integer to be stored in the property.
956 */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200957void dt_add_u32_prop(struct device_tree_node *node, const char *name, u32 val)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200958{
Julius Werner9636a102019-05-03 17:36:43 -0700959 u32 *val_ptr = xmalloc(sizeof(val));
Patrick Rudolph666c1722018-04-03 09:57:33 +0200960 *val_ptr = htobe32(val);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200961 dt_add_bin_prop(node, name, val_ptr, sizeof(*val_ptr));
962}
963
964/*
Patrick Rudolph3fca4ed2018-08-10 10:12:35 +0200965 * Add a 64-bit integer property to a node, or update it if it already exists.
966 *
967 * @param node The device tree node to add to.
968 * @param name The name of the new property.
969 * @param val The integer to be stored in the property.
970 */
971void dt_add_u64_prop(struct device_tree_node *node, const char *name, u64 val)
972{
Julius Werner9636a102019-05-03 17:36:43 -0700973 u64 *val_ptr = xmalloc(sizeof(val));
Patrick Rudolph3fca4ed2018-08-10 10:12:35 +0200974 *val_ptr = htobe64(val);
975 dt_add_bin_prop(node, name, val_ptr, sizeof(*val_ptr));
976}
977
978/*
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200979 * Add a 'reg' address list property to a node, or update it if it exists.
980 *
981 * @param node The device tree node to add to.
982 * @param addrs Array of address values to be stored in the property.
983 * @param sizes Array of corresponding size values to 'addrs'.
984 * @param count Number of values in 'addrs' and 'sizes' (must be equal).
985 * @param addr_cells Value of #address-cells property valid for this node.
986 * @param size_cells Value of #size-cells property valid for this node.
987 */
Patrick Rudolph666c1722018-04-03 09:57:33 +0200988void dt_add_reg_prop(struct device_tree_node *node, u64 *addrs, u64 *sizes,
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200989 int count, u32 addr_cells, u32 size_cells)
990{
991 int i;
992 size_t length = (addr_cells + size_cells) * sizeof(u32) * count;
Julius Werner9636a102019-05-03 17:36:43 -0700993 u8 *data = xmalloc(length);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +0200994 u8 *cur = data;
995
996 for (i = 0; i < count; i++) {
997 dt_write_int(cur, addrs[i], addr_cells * sizeof(u32));
998 cur += addr_cells * sizeof(u32);
999 dt_write_int(cur, sizes[i], size_cells * sizeof(u32));
1000 cur += size_cells * sizeof(u32);
1001 }
1002
1003 dt_add_bin_prop(node, "reg", data, length);
1004}
1005
1006/*
1007 * Fixups to apply to a kernel's device tree before booting it.
1008 */
1009
Patrick Rudolph666c1722018-04-03 09:57:33 +02001010struct list_node device_tree_fixups;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001011
Patrick Rudolph666c1722018-04-03 09:57:33 +02001012int dt_apply_fixups(struct device_tree *tree)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001013{
Patrick Rudolph666c1722018-04-03 09:57:33 +02001014 struct device_tree_fixup *fixup;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001015 list_for_each(fixup, device_tree_fixups, list_node) {
1016 assert(fixup->fixup);
1017 if (fixup->fixup(fixup, tree))
1018 return 1;
1019 }
1020 return 0;
1021}
1022
Patrick Rudolph666c1722018-04-03 09:57:33 +02001023int dt_set_bin_prop_by_path(struct device_tree *tree, const char *path,
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001024 void *data, size_t data_size, int create)
1025{
1026 char *path_copy, *prop_name;
Patrick Rudolph666c1722018-04-03 09:57:33 +02001027 struct device_tree_node *dt_node;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001028
1029 path_copy = strdup(path);
1030
1031 if (!path_copy) {
Patrick Rudolph666c1722018-04-03 09:57:33 +02001032 printk(BIOS_ERR, "Failed to allocate a copy of path %s\n",
1033 path);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001034 return 1;
1035 }
1036
1037 prop_name = strrchr(path_copy, '/');
1038 if (!prop_name) {
Patrick Rudolph679d6242018-07-11 13:53:04 +02001039 free(path_copy);
Patrick Rudolph666c1722018-04-03 09:57:33 +02001040 printk(BIOS_ERR, "Path %s does not include '/'\n", path);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001041 return 1;
1042 }
1043
1044 *prop_name++ = '\0'; /* Separate path from the property name. */
1045
Julius Wernerf36d53c2019-05-03 18:23:34 -07001046 dt_node = dt_find_node_by_path(tree, path_copy, NULL,
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001047 NULL, create);
1048
1049 if (!dt_node) {
Patrick Rudolph666c1722018-04-03 09:57:33 +02001050 printk(BIOS_ERR, "Failed to %s %s in the device tree\n",
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001051 create ? "create" : "find", path_copy);
Patrick Rudolph679d6242018-07-11 13:53:04 +02001052 free(path_copy);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001053 return 1;
1054 }
1055
1056 dt_add_bin_prop(dt_node, prop_name, data, data_size);
Patrick Rudolph679d6242018-07-11 13:53:04 +02001057 free(path_copy);
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001058
1059 return 0;
1060}
1061
1062/*
1063 * Prepare the /reserved-memory/ node.
1064 *
1065 * Technically, this can be called more than one time, to init and/or retrieve
1066 * the node. But dt_add_u32_prop() may leak a bit of memory if you do.
1067 *
1068 * @tree: Device tree to add/retrieve from.
1069 * @return: The /reserved-memory/ node (or NULL, if error).
1070 */
Patrick Rudolph666c1722018-04-03 09:57:33 +02001071struct device_tree_node *dt_init_reserved_memory_node(struct device_tree *tree)
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001072{
Patrick Rudolph666c1722018-04-03 09:57:33 +02001073 struct device_tree_node *reserved;
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001074 u32 addr = 0, size = 0;
1075
Julius Wernerfbec63d2019-05-03 18:29:28 -07001076 reserved = dt_find_node_by_path(tree, "/reserved-memory", &addr,
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001077 &size, 1);
1078 if (!reserved)
1079 return NULL;
1080
Julius Werner23df4772019-05-17 22:50:18 -07001081 /* Binding doc says this should have the same #{address,size}-cells as
1082 the root. */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001083 dt_add_u32_prop(reserved, "#address-cells", addr);
1084 dt_add_u32_prop(reserved, "#size-cells", size);
Julius Werner23df4772019-05-17 22:50:18 -07001085 /* Binding doc says this should be empty (1:1 mapping from root). */
Patrick Rudolph67aca3e2018-04-12 11:44:43 +02001086 dt_add_bin_prop(reserved, "ranges", NULL, 0);
1087
1088 return reserved;
1089}
Julius Werner735ddc92019-05-07 17:05:28 -07001090
1091/*
1092 * Increment a single phandle in prop at a given offset by a given adjustment.
1093 *
1094 * @param prop Property whose phandle should be adjusted.
1095 * @param adjustment Value that should be added to the existing phandle.
1096 * @param offset Byte offset of the phandle in the property data.
1097 *
1098 * @return New phandle value, or 0 on error.
1099 */
1100static uint32_t dt_adjust_phandle(struct device_tree_property *prop,
1101 uint32_t adjustment, uint32_t offset)
1102{
1103 if (offset + 4 > prop->prop.size)
1104 return 0;
1105
1106 uint32_t phandle = be32dec(prop->prop.data + offset);
1107 if (phandle == 0 ||
1108 phandle == FDT_PHANDLE_ILLEGAL ||
1109 phandle == 0xffffffff)
1110 return 0;
1111
1112 phandle += adjustment;
1113 if (phandle >= FDT_PHANDLE_ILLEGAL)
1114 return 0;
1115
1116 be32enc(prop->prop.data + offset, phandle);
1117 return phandle;
1118}
1119
1120/*
1121 * Adjust all phandles in subtree by adding a new base offset.
1122 *
1123 * @param node Root node of the subtree to work on.
1124 * @param base New phandle base to be added to all phandles.
1125 *
1126 * @return New highest phandle in the subtree, or 0 on error.
1127 */
1128static uint32_t dt_adjust_all_phandles(struct device_tree_node *node,
1129 uint32_t base)
1130{
Julius Werner23df4772019-05-17 22:50:18 -07001131 uint32_t new_max = MAX(base, 1); /* make sure we don't return 0 */
Julius Werner735ddc92019-05-07 17:05:28 -07001132 struct device_tree_property *prop;
1133 struct device_tree_node *child;
1134
1135 if (!node)
1136 return new_max;
1137
1138 list_for_each(prop, node->properties, list_node)
1139 if (dt_prop_is_phandle(prop)) {
1140 node->phandle = dt_adjust_phandle(prop, base, 0);
1141 if (!node->phandle)
1142 return 0;
1143 new_max = MAX(new_max, node->phandle);
Julius Werner23df4772019-05-17 22:50:18 -07001144 } /* no break -- can have more than one phandle prop */
Julius Werner735ddc92019-05-07 17:05:28 -07001145
1146 list_for_each(child, node->children, list_node)
1147 new_max = MAX(new_max, dt_adjust_all_phandles(child, base));
1148
1149 return new_max;
1150}
1151
1152/*
1153 * Apply a /__local_fixup__ subtree to the corresponding overlay subtree.
1154 *
1155 * @param node Root node of the overlay subtree to fix up.
1156 * @param node Root node of the /__local_fixup__ subtree.
1157 * @param base Adjustment that was added to phandles in the overlay.
1158 *
1159 * @return 0 on success, -1 on error.
1160 */
1161static int dt_fixup_locals(struct device_tree_node *node,
1162 struct device_tree_node *fixup, uint32_t base)
1163{
1164 struct device_tree_property *prop;
1165 struct device_tree_property *fixup_prop;
1166 struct device_tree_node *child;
1167 struct device_tree_node *fixup_child;
1168 int i;
1169
Julius Werner23df4772019-05-17 22:50:18 -07001170 /*
1171 * For local fixups the /__local_fixup__ subtree contains the same node
1172 * hierarchy as the main tree we're fixing up. Each property contains
1173 * the fixup offsets for the respective property in the main tree. For
1174 * each property in the fixup node, find the corresponding property in
1175 * the base node and apply fixups to all offsets it specifies.
1176 */
Julius Werner735ddc92019-05-07 17:05:28 -07001177 list_for_each(fixup_prop, fixup->properties, list_node) {
1178 struct device_tree_property *base_prop = NULL;
1179 list_for_each(prop, node->properties, list_node)
1180 if (!strcmp(prop->prop.name, fixup_prop->prop.name)) {
1181 base_prop = prop;
1182 break;
1183 }
1184
Julius Werner23df4772019-05-17 22:50:18 -07001185 /* We should always find a corresponding base prop for a fixup,
1186 and fixup props contain a list of 32-bit fixup offsets. */
Julius Werner735ddc92019-05-07 17:05:28 -07001187 if (!base_prop || fixup_prop->prop.size % sizeof(uint32_t))
1188 return -1;
1189
1190 for (i = 0; i < fixup_prop->prop.size; i += sizeof(uint32_t))
1191 if (!dt_adjust_phandle(base_prop, base, be32dec(
1192 fixup_prop->prop.data + i)))
1193 return -1;
1194 }
1195
Julius Werner23df4772019-05-17 22:50:18 -07001196 /* Now recursively descend both the base tree and the /__local_fixups__
1197 subtree in sync to apply all fixups. */
Julius Werner735ddc92019-05-07 17:05:28 -07001198 list_for_each(fixup_child, fixup->children, list_node) {
1199 struct device_tree_node *base_child = NULL;
1200 list_for_each(child, node->children, list_node)
1201 if (!strcmp(child->name, fixup_child->name)) {
1202 base_child = child;
1203 break;
1204 }
1205
Julius Werner23df4772019-05-17 22:50:18 -07001206 /* All fixup nodes should have a corresponding base node. */
Julius Werner735ddc92019-05-07 17:05:28 -07001207 if (!base_child)
1208 return -1;
1209
1210 if (dt_fixup_locals(base_child, fixup_child, base) < 0)
1211 return -1;
1212 }
1213
1214 return 0;
1215}
1216
1217/*
1218 * Update all /__symbols__ properties in an overlay that start with
1219 * "/fragment@X/__overlay__" with corresponding path prefix in the base tree.
1220 *
1221 * @param symbols /__symbols__ done to update.
1222 * @param fragment /fragment@X node that references to should be updated.
1223 * @param base_path Path of base tree node that the fragment overlaid.
1224 */
1225static void dt_fix_symbols(struct device_tree_node *symbols,
1226 struct device_tree_node *fragment,
1227 const char *base_path)
1228{
1229 struct device_tree_property *prop;
Julius Werner23df4772019-05-17 22:50:18 -07001230 char buf[512]; /* Should be enough for maximum DT path length? */
1231 char node_path[64]; /* easily enough for /fragment@XXXX/__overlay__ */
Julius Werner735ddc92019-05-07 17:05:28 -07001232
Julius Werner23df4772019-05-17 22:50:18 -07001233 if (!symbols) /* If the overlay has no /__symbols__ node, we're done! */
Julius Werner735ddc92019-05-07 17:05:28 -07001234 return;
1235
1236 int len = snprintf(node_path, sizeof(node_path), "/%s/__overlay__",
1237 fragment->name);
1238
1239 list_for_each(prop, symbols->properties, list_node)
1240 if (!strncmp(prop->prop.data, node_path, len)) {
1241 prop->prop.size = snprintf(buf, sizeof(buf), "%s%s",
1242 base_path, (char *)prop->prop.data + len) + 1;
1243 free(prop->prop.data);
1244 prop->prop.data = strdup(buf);
1245 }
1246}
1247
1248/*
1249 * Fix up overlay according to a property in /__fixup__. If the fixed property
1250 * is a /fragment@X:target, also update /__symbols__ references to fragment.
1251 *
1252 * @params overlay Overlay to fix up.
1253 * @params fixup /__fixup__ property.
1254 * @params phandle phandle value to insert where the fixup points to.
1255 * @params base_path Path to the base DT node that the fixup points to.
1256 * @params overlay_symbols /__symbols__ node of the overlay.
1257 *
1258 * @return 0 on success, -1 on error.
1259 */
1260static int dt_fixup_external(struct device_tree *overlay,
1261 struct device_tree_property *fixup,
1262 uint32_t phandle, const char *base_path,
1263 struct device_tree_node *overlay_symbols)
1264{
1265 struct device_tree_property *prop;
1266
Julius Werner23df4772019-05-17 22:50:18 -07001267 /* External fixup properties are encoded as "<path>:<prop>:<offset>". */
Julius Werner735ddc92019-05-07 17:05:28 -07001268 char *entry = fixup->prop.data;
1269 while ((void *)entry < fixup->prop.data + fixup->prop.size) {
Julius Werner23df4772019-05-17 22:50:18 -07001270 /* okay to destroy fixup property value, won't need it again */
Julius Werner735ddc92019-05-07 17:05:28 -07001271 char *node_path = entry;
1272 entry = strchr(node_path, ':');
1273 if (!entry)
1274 return -1;
1275 *entry++ = '\0';
1276
1277 char *prop_name = entry;
1278 entry = strchr(prop_name, ':');
1279 if (!entry)
1280 return -1;
1281 *entry++ = '\0';
1282
1283 struct device_tree_node *ovl_node = dt_find_node_by_path(
1284 overlay, node_path, NULL, NULL, 0);
1285 if (!ovl_node || !isdigit(*entry))
1286 return -1;
1287
1288 struct device_tree_property *ovl_prop = NULL;
1289 list_for_each(prop, ovl_node->properties, list_node)
1290 if (!strcmp(prop->prop.name, prop_name)) {
1291 ovl_prop = prop;
1292 break;
1293 }
1294
Julius Werner23df4772019-05-17 22:50:18 -07001295 /* Move entry to first char after number, must be a '\0'. */
Julius Werner735ddc92019-05-07 17:05:28 -07001296 uint32_t offset = skip_atoi(&entry);
1297 if (!ovl_prop || offset + 4 > ovl_prop->prop.size || entry[0])
1298 return -1;
Julius Werner23df4772019-05-17 22:50:18 -07001299 entry++; /* jump over '\0' to potential next fixup */
Julius Werner735ddc92019-05-07 17:05:28 -07001300
1301 be32enc(ovl_prop->prop.data + offset, phandle);
1302
Julius Werner23df4772019-05-17 22:50:18 -07001303 /* If this is a /fragment@X:target property, update references
1304 to this fragment in the overlay __symbols__ now. */
Julius Werner735ddc92019-05-07 17:05:28 -07001305 if (offset == 0 && !strcmp(prop_name, "target") &&
Julius Werner23df4772019-05-17 22:50:18 -07001306 !strchr(node_path + 1, '/')) /* only toplevel nodes */
Julius Werner735ddc92019-05-07 17:05:28 -07001307 dt_fix_symbols(overlay_symbols, ovl_node, base_path);
1308 }
1309
1310 return 0;
1311}
1312
1313/*
1314 * Apply all /__fixup__ properties in the overlay. This will destroy the
1315 * property data in /__fixup__ and it should not be accessed again.
1316 *
1317 * @params tree Base device tree that the overlay updates.
1318 * @params symbols /__symbols__ node of the base device tree.
1319 * @params overlay Overlay to fix up.
1320 * @params fixups /__fixup__ node in the overlay.
1321 * @params overlay_symbols /__symbols__ node of the overlay.
1322 *
1323 * @return 0 on success, -1 on error.
1324 */
1325static int dt_fixup_all_externals(struct device_tree *tree,
1326 struct device_tree_node *symbols,
1327 struct device_tree *overlay,
1328 struct device_tree_node *fixups,
1329 struct device_tree_node *overlay_symbols)
1330{
1331 struct device_tree_property *fix;
1332
Julius Werner23df4772019-05-17 22:50:18 -07001333 /* If we have any external fixups, base tree must have /__symbols__. */
Julius Werner735ddc92019-05-07 17:05:28 -07001334 if (!symbols)
1335 return -1;
1336
Julius Werner23df4772019-05-17 22:50:18 -07001337 /*
1338 * Unlike /__local_fixups__, /__fixups__ is not a whole subtree that
1339 * mirrors the node hierarchy. It's just a directory of fixup properties
1340 * that each directly contain all information necessary to apply them.
1341 */
Julius Werner735ddc92019-05-07 17:05:28 -07001342 list_for_each(fix, fixups->properties, list_node) {
Julius Werner23df4772019-05-17 22:50:18 -07001343 /* The name of a fixup property is the label of the node we want
1344 a property to phandle-reference. Look up in /__symbols__. */
Julius Werner735ddc92019-05-07 17:05:28 -07001345 const char *path = dt_find_string_prop(symbols, fix->prop.name);
1346 if (!path)
1347 return -1;
1348
Elyes HAOUAS0afaff22021-01-16 15:02:31 +01001349 /* Find node the label pointed to figure out its phandle. */
Julius Werner735ddc92019-05-07 17:05:28 -07001350 struct device_tree_node *node = dt_find_node_by_path(tree, path,
1351 NULL, NULL, 0);
1352 if (!node)
1353 return -1;
1354
Julius Werner23df4772019-05-17 22:50:18 -07001355 /* Write into the overlay property(s) pointing to that node. */
Julius Werner735ddc92019-05-07 17:05:28 -07001356 if (dt_fixup_external(overlay, fix, node->phandle,
1357 path, overlay_symbols) < 0)
1358 return -1;
1359 }
1360
1361 return 0;
1362}
1363
1364/*
1365 * Copy all nodes and properties from one DT subtree into another. This is a
1366 * shallow copy so both trees will point to the same property data afterwards.
1367 *
1368 * @params dst Destination subtree to copy into.
1369 * @params src Source subtree to copy from.
1370 * @params upd 1 to overwrite same-name properties, 0 to discard them.
1371 */
1372static void dt_copy_subtree(struct device_tree_node *dst,
1373 struct device_tree_node *src, int upd)
1374{
1375 struct device_tree_property *prop;
1376 struct device_tree_property *src_prop;
1377 list_for_each(src_prop, src->properties, list_node) {
1378 if (dt_prop_is_phandle(src_prop) ||
1379 !strcmp(src_prop->prop.name, "name")) {
1380 printk(BIOS_DEBUG,
1381 "WARNING: ignoring illegal overlay prop '%s'\n",
1382 src_prop->prop.name);
1383 continue;
1384 }
1385
1386 struct device_tree_property *dst_prop = NULL;
1387 list_for_each(prop, dst->properties, list_node)
1388 if (!strcmp(prop->prop.name, src_prop->prop.name)) {
1389 dst_prop = prop;
1390 break;
1391 }
1392
1393 if (dst_prop) {
1394 if (!upd) {
1395 printk(BIOS_DEBUG,
1396 "WARNING: ignoring prop update '%s'\n",
1397 src_prop->prop.name);
1398 continue;
1399 }
1400 } else {
1401 dst_prop = xzalloc(sizeof(*dst_prop));
1402 list_insert_after(&dst_prop->list_node,
1403 &dst->properties);
1404 }
1405
1406 dst_prop->prop = src_prop->prop;
1407 }
1408
1409 struct device_tree_node *node;
1410 struct device_tree_node *src_node;
1411 list_for_each(src_node, src->children, list_node) {
1412 struct device_tree_node *dst_node = NULL;
1413 list_for_each(node, dst->children, list_node)
1414 if (!strcmp(node->name, src_node->name)) {
1415 dst_node = node;
1416 break;
1417 }
1418
1419 if (!dst_node) {
1420 dst_node = xzalloc(sizeof(*dst_node));
1421 *dst_node = *src_node;
1422 list_insert_after(&dst_node->list_node, &dst->children);
1423 } else {
1424 dt_copy_subtree(dst_node, src_node, upd);
1425 }
1426 }
1427}
1428
1429/*
1430 * Apply an overlay /fragment@X node to a base device tree.
1431 *
1432 * @param tree Base device tree.
1433 * @param fragment /fragment@X node.
1434 * @params overlay_symbols /__symbols__ node of the overlay.
1435 *
1436 * @return 0 on success, -1 on error.
1437 */
1438static int dt_import_fragment(struct device_tree *tree,
1439 struct device_tree_node *fragment,
1440 struct device_tree_node *overlay_symbols)
1441{
Julius Werner23df4772019-05-17 22:50:18 -07001442 /* The actual overlaid nodes/props are in an __overlay__ child node. */
Julius Werner735ddc92019-05-07 17:05:28 -07001443 static const char *overlay_path[] = { "__overlay__", NULL };
1444 struct device_tree_node *overlay = dt_find_node(fragment, overlay_path,
1445 NULL, NULL, 0);
1446
Julius Werner23df4772019-05-17 22:50:18 -07001447 /* If it doesn't have an __overlay__ child, it's not a fragment. */
Julius Werner735ddc92019-05-07 17:05:28 -07001448 if (!overlay)
1449 return 0;
1450
Julius Werner23df4772019-05-17 22:50:18 -07001451 /* Target node of the fragment can be given by path or by phandle. */
Julius Werner735ddc92019-05-07 17:05:28 -07001452 struct device_tree_property *prop;
1453 struct device_tree_property *phandle = NULL;
1454 struct device_tree_property *path = NULL;
1455 list_for_each(prop, fragment->properties, list_node) {
1456 if (!strcmp(prop->prop.name, "target")) {
1457 phandle = prop;
Julius Werner23df4772019-05-17 22:50:18 -07001458 break; /* phandle target has priority, stop looking */
Julius Werner735ddc92019-05-07 17:05:28 -07001459 }
1460 if (!strcmp(prop->prop.name, "target-path"))
1461 path = prop;
1462 }
1463
1464 struct device_tree_node *target = NULL;
1465 if (phandle) {
1466 if (phandle->prop.size != sizeof(uint32_t))
1467 return -1;
1468 target = dt_find_node_by_phandle(tree->root,
1469 be32dec(phandle->prop.data));
Julius Werner23df4772019-05-17 22:50:18 -07001470 /* Symbols already updated as part of dt_fixup_external(). */
Julius Werner735ddc92019-05-07 17:05:28 -07001471 } else if (path) {
1472 target = dt_find_node_by_path(tree, path->prop.data,
1473 NULL, NULL, 0);
1474 dt_fix_symbols(overlay_symbols, fragment, path->prop.data);
1475 }
1476 if (!target)
1477 return -1;
1478
1479 dt_copy_subtree(target, overlay, 1);
1480 return 0;
1481}
1482
1483/*
1484 * Apply a device tree overlay to a base device tree. This will
1485 * destroy/incorporate the overlay data, so it should not be freed or reused.
1486 * See dtc.git/Documentation/dt-object-internal.txt for overlay format details.
1487 *
1488 * @param tree Unflattened base device tree to add the overlay into.
1489 * @param overlay Unflattened overlay device tree to apply to the base.
1490 *
1491 * @return 0 on success, -1 on error.
1492 */
1493int dt_apply_overlay(struct device_tree *tree, struct device_tree *overlay)
1494{
Julius Werner23df4772019-05-17 22:50:18 -07001495 /*
1496 * First, we need to make sure phandles inside the overlay don't clash
1497 * with those in the base tree. We just define the highest phandle value
1498 * in the base tree as the "phandle offset" for this overlay and
1499 * increment all phandles in it by that value.
1500 */
Julius Werner735ddc92019-05-07 17:05:28 -07001501 uint32_t phandle_base = tree->max_phandle;
1502 uint32_t new_max = dt_adjust_all_phandles(overlay->root, phandle_base);
1503 if (!new_max) {
1504 printk(BIOS_DEBUG, "ERROR: invalid phandles in overlay\n");
1505 return -1;
1506 }
1507 tree->max_phandle = new_max;
1508
Julius Werner23df4772019-05-17 22:50:18 -07001509 /* Now that we changed phandles in the overlay, we need to update any
1510 nodes referring to them. Those are listed in /__local_fixups__. */
Julius Werner735ddc92019-05-07 17:05:28 -07001511 struct device_tree_node *local_fixups = dt_find_node_by_path(overlay,
1512 "/__local_fixups__", NULL, NULL, 0);
1513 if (local_fixups && dt_fixup_locals(overlay->root, local_fixups,
1514 phandle_base) < 0) {
1515 printk(BIOS_DEBUG, "ERROR: invalid local fixups in overlay\n");
1516 return -1;
1517 }
1518
Julius Werner23df4772019-05-17 22:50:18 -07001519 /*
1520 * Besides local phandle references (from nodes within the overlay to
1521 * other nodes within the overlay), the overlay may also contain phandle
1522 * references to the base tree. These are stored with invalid values and
1523 * must be updated now. /__symbols__ contains a list of all labels in
1524 * the base tree, and /__fixups__ describes all nodes in the overlay
1525 * that contain external phandle references.
1526 * We also take this opportunity to update all /fragment@X/__overlay__/
1527 * prefixes in the overlay's /__symbols__ node to the correct path that
1528 * the fragment will be placed in later, since this is the only step
1529 * where we have all necessary information for that easily available.
1530 */
Julius Werner735ddc92019-05-07 17:05:28 -07001531 struct device_tree_node *symbols = dt_find_node_by_path(tree,
1532 "/__symbols__", NULL, NULL, 0);
1533 struct device_tree_node *fixups = dt_find_node_by_path(overlay,
1534 "/__fixups__", NULL, NULL, 0);
1535 struct device_tree_node *overlay_symbols = dt_find_node_by_path(overlay,
1536 "/__symbols__", NULL, NULL, 0);
1537 if (fixups && dt_fixup_all_externals(tree, symbols, overlay,
1538 fixups, overlay_symbols) < 0) {
1539 printk(BIOS_DEBUG,
1540 "ERROR: cannot match external fixups from overlay\n");
1541 return -1;
1542 }
1543
Julius Werner23df4772019-05-17 22:50:18 -07001544 /* After all this fixing up, we can finally merge overlay into the tree
1545 (one fragment at a time, because for some reason it's split up). */
Julius Werner735ddc92019-05-07 17:05:28 -07001546 struct device_tree_node *fragment;
1547 list_for_each(fragment, overlay->root->children, list_node)
1548 if (dt_import_fragment(tree, fragment, overlay_symbols) < 0) {
1549 printk(BIOS_DEBUG, "ERROR: bad DT fragment '%s'\n",
1550 fragment->name);
1551 return -1;
1552 }
1553
Julius Werner23df4772019-05-17 22:50:18 -07001554 /*
1555 * We need to also update /__symbols__ to include labels from this
1556 * overlay, in case we want to load further overlays with external
1557 * phandle references to it. If the base tree already has a /__symbols__
1558 * we merge them together, otherwise we just insert the overlay's
1559 * /__symbols__ node into the base tree root.
1560 */
Julius Werner735ddc92019-05-07 17:05:28 -07001561 if (overlay_symbols) {
1562 if (symbols)
1563 dt_copy_subtree(symbols, overlay_symbols, 0);
1564 else
1565 list_insert_after(&overlay_symbols->list_node,
1566 &tree->root->children);
1567 }
1568
1569 return 0;
1570}