xref: /dpdk/drivers/common/dpaax/dpaa_of.c (revision 8c83f28cc8a4dc7ee0fab676051dd483695d4140)
1 /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2  *
3  * Copyright 2010-2016 Freescale Semiconductor Inc.
4  * Copyright 2017 NXP
5  *
6  */
7 
8 #include <dpaa_of.h>
9 #include <assert.h>
10 #include <rte_string_fns.h>
11 #include <dpaax_logs.h>
12 
13 static int alive;
14 static struct dt_dir root_dir;
15 static const char *base_dir;
16 static COMPAT_LIST_HEAD(linear);
17 
18 static int
of_open_dir(const char * relative_path,struct dirent *** d)19 of_open_dir(const char *relative_path, struct dirent ***d)
20 {
21 	int ret;
22 	char full_path[PATH_MAX];
23 
24 	snprintf(full_path, PATH_MAX, "%s/%s", base_dir, relative_path);
25 	ret = scandir(full_path, d, 0, versionsort);
26 	if (ret < 0)
27 		DPAAX_LOG(ERR, "Failed to open directory %s",
28 			     full_path);
29 	return ret;
30 }
31 
32 static void
of_close_dir(struct dirent ** d,int num)33 of_close_dir(struct dirent **d, int num)
34 {
35 	while (num--)
36 		free(d[num]);
37 	free(d);
38 }
39 
40 static int
of_open_file(const char * relative_path)41 of_open_file(const char *relative_path)
42 {
43 	int ret;
44 	char full_path[PATH_MAX];
45 
46 	snprintf(full_path, PATH_MAX, "%s/%s", base_dir, relative_path);
47 	ret = open(full_path, O_RDONLY);
48 	if (ret < 0)
49 		DPAAX_LOG(ERR, "Failed to open directory %s",
50 			     full_path);
51 	return ret;
52 }
53 
54 static void
process_file(struct dirent * dent,struct dt_dir * parent)55 process_file(struct dirent *dent, struct dt_dir *parent)
56 {
57 	int fd;
58 	struct dt_file *f = malloc(sizeof(*f));
59 
60 	if (!f) {
61 		DPAAX_LOG(DEBUG, "Unable to allocate memory for file node");
62 		return;
63 	}
64 	f->node.is_file = 1;
65 	strlcpy(f->node.node.name, dent->d_name, NAME_MAX);
66 	snprintf(f->node.node.full_name, PATH_MAX, "%s/%s",
67 		 parent->node.node.full_name, dent->d_name);
68 	f->parent = parent;
69 	fd = of_open_file(f->node.node.full_name);
70 	if (fd < 0) {
71 		DPAAX_LOG(DEBUG, "Unable to open file node");
72 		free(f);
73 		return;
74 	}
75 	f->len = read(fd, f->buf, OF_FILE_BUF_MAX);
76 	close(fd);
77 	if (f->len < 0) {
78 		DPAAX_LOG(DEBUG, "Unable to read file node");
79 		free(f);
80 		return;
81 	}
82 	list_add_tail(&f->node.list, &parent->files);
83 }
84 
85 static const struct dt_dir *
node2dir(const struct device_node * n)86 node2dir(const struct device_node *n)
87 {
88 	struct dt_node *dn = container_of((struct device_node *)n,
89 					  struct dt_node, node);
90 	const struct dt_dir *d = container_of(dn, struct dt_dir, node);
91 
92 	assert(!dn->is_file);
93 	return d;
94 }
95 
96 /* process_dir() calls iterate_dir(), but the latter will also call the former
97  * when recursing into sub-directories, so a predeclaration is needed.
98  */
99 static int process_dir(const char *relative_path, struct dt_dir *dt);
100 
101 static int
iterate_dir(struct dirent ** d,int num,struct dt_dir * dt)102 iterate_dir(struct dirent **d, int num, struct dt_dir *dt)
103 {
104 	int loop;
105 	/* Iterate the directory contents */
106 	for (loop = 0; loop < num; loop++) {
107 		struct dt_dir *subdir;
108 		int ret;
109 		/* Ignore dot files of all types (especially "..") */
110 		if (d[loop]->d_name[0] == '.')
111 			continue;
112 		switch (d[loop]->d_type) {
113 		case DT_REG:
114 			process_file(d[loop], dt);
115 			break;
116 		case DT_DIR:
117 			subdir = malloc(sizeof(*subdir));
118 			if (!subdir) {
119 				perror("malloc");
120 				return -ENOMEM;
121 			}
122 			strlcpy(subdir->node.node.name, d[loop]->d_name,
123 				NAME_MAX);
124 			snprintf(subdir->node.node.full_name, PATH_MAX,
125 				 "%s/%s", dt->node.node.full_name,
126 				 d[loop]->d_name);
127 			subdir->parent = dt;
128 			ret = process_dir(subdir->node.node.full_name, subdir);
129 			if (ret)
130 				return ret;
131 			list_add_tail(&subdir->node.list, &dt->subdirs);
132 			break;
133 		default:
134 			DPAAX_LOG(DEBUG, "Ignoring invalid dt entry %s/%s",
135 				     dt->node.node.full_name, d[loop]->d_name);
136 		}
137 	}
138 	return 0;
139 }
140 
141 static int
process_dir(const char * relative_path,struct dt_dir * dt)142 process_dir(const char *relative_path, struct dt_dir *dt)
143 {
144 	struct dirent **d;
145 	int ret, num;
146 
147 	dt->node.is_file = 0;
148 	INIT_LIST_HEAD(&dt->subdirs);
149 	INIT_LIST_HEAD(&dt->files);
150 	ret = of_open_dir(relative_path, &d);
151 	if (ret < 0)
152 		return ret;
153 	num = ret;
154 	ret = iterate_dir(d, num, dt);
155 	of_close_dir(d, num);
156 	return (ret < 0) ? ret : 0;
157 }
158 
159 static void
linear_dir(struct dt_dir * d)160 linear_dir(struct dt_dir *d)
161 {
162 	struct dt_file *f;
163 	struct dt_dir *dd;
164 
165 	d->compatible = NULL;
166 	d->status = NULL;
167 	d->lphandle = NULL;
168 	d->a_cells = NULL;
169 	d->s_cells = NULL;
170 	d->reg = NULL;
171 	list_for_each_entry(f, &d->files, node.list) {
172 		if (!strcmp(f->node.node.name, "compatible")) {
173 			if (d->compatible)
174 				DPAAX_LOG(DEBUG, "Duplicate compatible in"
175 					     " %s", d->node.node.full_name);
176 			d->compatible = f;
177 		} else if (!strcmp(f->node.node.name, "status")) {
178 			if (d->status)
179 				DPAAX_LOG(DEBUG, "Duplicate status in %s",
180 					     d->node.node.full_name);
181 			d->status = f;
182 		} else if (!strcmp(f->node.node.name, "linux,phandle")) {
183 			if (d->lphandle)
184 				DPAAX_LOG(DEBUG, "Duplicate lphandle in %s",
185 					     d->node.node.full_name);
186 			d->lphandle = f;
187 		} else if (!strcmp(f->node.node.name, "phandle")) {
188 			if (d->lphandle)
189 				DPAAX_LOG(DEBUG, "Duplicate lphandle in %s",
190 					     d->node.node.full_name);
191 			d->lphandle = f;
192 		} else if (!strcmp(f->node.node.name, "#address-cells")) {
193 			if (d->a_cells)
194 				DPAAX_LOG(DEBUG, "Duplicate a_cells in %s",
195 					     d->node.node.full_name);
196 			d->a_cells = f;
197 		} else if (!strcmp(f->node.node.name, "#size-cells")) {
198 			if (d->s_cells)
199 				DPAAX_LOG(DEBUG, "Duplicate s_cells in %s",
200 					     d->node.node.full_name);
201 			d->s_cells = f;
202 		} else if (!strcmp(f->node.node.name, "reg")) {
203 			if (d->reg)
204 				DPAAX_LOG(DEBUG, "Duplicate reg in %s",
205 					     d->node.node.full_name);
206 			d->reg = f;
207 		}
208 	}
209 
210 	list_for_each_entry(dd, &d->subdirs, node.list) {
211 		list_add_tail(&dd->linear, &linear);
212 		linear_dir(dd);
213 	}
214 }
215 
216 int
of_init_path(const char * dt_path)217 of_init_path(const char *dt_path)
218 {
219 	int ret;
220 
221 	base_dir = dt_path;
222 
223 	/* This needs to be singleton initialization */
224 	DPAAX_HWWARN(alive, "Double-init of device-tree driver!");
225 
226 	/* Prepare root node (the remaining fields are set in process_dir()) */
227 	root_dir.node.node.name[0] = '\0';
228 	root_dir.node.node.full_name[0] = '\0';
229 	INIT_LIST_HEAD(&root_dir.node.list);
230 	root_dir.parent = NULL;
231 
232 	/* Kick things off... */
233 	ret = process_dir("", &root_dir);
234 	if (ret) {
235 		DPAAX_LOG(ERR, "Unable to parse device tree");
236 		return ret;
237 	}
238 
239 	/* Now make a flat, linear list of directories */
240 	linear_dir(&root_dir);
241 	alive = 1;
242 	return 0;
243 }
244 
245 static void
destroy_dir(struct dt_dir * d)246 destroy_dir(struct dt_dir *d)
247 {
248 	struct dt_file *f, *tmpf;
249 	struct dt_dir *dd, *tmpd;
250 
251 	list_for_each_entry_safe(f, tmpf, &d->files, node.list) {
252 		list_del(&f->node.list);
253 		free(f);
254 	}
255 	list_for_each_entry_safe(dd, tmpd, &d->subdirs, node.list) {
256 		destroy_dir(dd);
257 		list_del(&dd->node.list);
258 		free(dd);
259 	}
260 }
261 
262 void
of_finish(void)263 of_finish(void)
264 {
265 	DPAAX_HWWARN(!alive, "Double-finish of device-tree driver!");
266 
267 	destroy_dir(&root_dir);
268 	INIT_LIST_HEAD(&linear);
269 	alive = 0;
270 }
271 
272 static const struct dt_dir *
next_linear(const struct dt_dir * f)273 next_linear(const struct dt_dir *f)
274 {
275 	if (f->linear.next == &linear)
276 		return NULL;
277 	return list_entry(f->linear.next, struct dt_dir, linear);
278 }
279 
280 static int
check_compatible(const struct dt_file * f,const char * compatible)281 check_compatible(const struct dt_file *f, const char *compatible)
282 {
283 	const char *c = (char *)f->buf;
284 	unsigned int len, remains = f->len;
285 
286 	while (remains) {
287 		len = strlen(c);
288 		if (!strcmp(c, compatible))
289 			return 1;
290 
291 		if (remains < len + 1)
292 			break;
293 
294 		c += (len + 1);
295 		remains -= (len + 1);
296 	}
297 	return 0;
298 }
299 
300 const struct device_node *
of_find_compatible_node(const struct device_node * from,const char * type __rte_unused,const char * compatible)301 of_find_compatible_node(const struct device_node *from,
302 			const char *type __rte_unused,
303 			const char *compatible)
304 {
305 	const struct dt_dir *d;
306 
307 	DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
308 
309 	if (list_empty(&linear))
310 		return NULL;
311 	if (!from)
312 		d = list_entry(linear.next, struct dt_dir, linear);
313 	else
314 		d = node2dir(from);
315 	for (d = next_linear(d); d && (!d->compatible ||
316 				       !check_compatible(d->compatible,
317 				       compatible));
318 			d = next_linear(d))
319 		;
320 	if (d)
321 		return &d->node.node;
322 	return NULL;
323 }
324 
325 const void *
of_get_property(const struct device_node * from,const char * name,size_t * lenp)326 of_get_property(const struct device_node *from, const char *name,
327 		size_t *lenp)
328 {
329 	const struct dt_dir *d;
330 	const struct dt_file *f;
331 
332 	DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
333 
334 	d = node2dir(from);
335 	list_for_each_entry(f, &d->files, node.list)
336 		if (!strcmp(f->node.node.name, name)) {
337 			if (lenp)
338 				*lenp = f->len;
339 			return f->buf;
340 		}
341 	return NULL;
342 }
343 
344 bool
of_device_is_available(const struct device_node * dev_node)345 of_device_is_available(const struct device_node *dev_node)
346 {
347 	const struct dt_dir *d;
348 
349 	DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
350 	d = node2dir(dev_node);
351 	if (!d->status)
352 		return true;
353 	if (!strcmp((char *)d->status->buf, "okay"))
354 		return true;
355 	if (!strcmp((char *)d->status->buf, "ok"))
356 		return true;
357 	return false;
358 }
359 
360 const struct device_node *
of_find_node_by_phandle(uint64_t ph)361 of_find_node_by_phandle(uint64_t ph)
362 {
363 	const struct dt_dir *d;
364 
365 	DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
366 	list_for_each_entry(d, &linear, linear)
367 		if (d->lphandle && (d->lphandle->len == 4) &&
368 		    !memcmp(d->lphandle->buf, &ph, 4))
369 			return &d->node.node;
370 	return NULL;
371 }
372 
373 const struct device_node *
of_get_parent(const struct device_node * dev_node)374 of_get_parent(const struct device_node *dev_node)
375 {
376 	const struct dt_dir *d;
377 
378 	DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
379 
380 	if (!dev_node)
381 		return NULL;
382 	d = node2dir(dev_node);
383 	if (!d->parent)
384 		return NULL;
385 	return &d->parent->node.node;
386 }
387 
388 const struct device_node *
of_get_next_child(const struct device_node * dev_node,const struct device_node * prev)389 of_get_next_child(const struct device_node *dev_node,
390 		  const struct device_node *prev)
391 {
392 	const struct dt_dir *p, *c;
393 
394 	DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
395 
396 	if (!dev_node)
397 		return NULL;
398 	p = node2dir(dev_node);
399 	if (prev) {
400 		c = node2dir(prev);
401 		DPAAX_HWWARN((c->parent != p), "Parent/child mismatch");
402 		if (c->parent != p)
403 			return NULL;
404 		if (c->node.list.next == &p->subdirs)
405 			/* prev was the last child */
406 			return NULL;
407 		c = list_entry(c->node.list.next, struct dt_dir, node.list);
408 		return &c->node.node;
409 	}
410 	/* Return first child */
411 	if (list_empty(&p->subdirs))
412 		return NULL;
413 	c = list_entry(p->subdirs.next, struct dt_dir, node.list);
414 	return &c->node.node;
415 }
416 
417 uint32_t
of_n_addr_cells(const struct device_node * dev_node)418 of_n_addr_cells(const struct device_node *dev_node)
419 {
420 	const struct dt_dir *d;
421 
422 	DPAAX_HWWARN(!alive, "Device-tree driver not initialised");
423 	if (!dev_node)
424 		return OF_DEFAULT_NA;
425 	d = node2dir(dev_node);
426 	while ((d = d->parent))
427 		if (d->a_cells) {
428 			unsigned char *buf =
429 				(unsigned char *)&d->a_cells->buf[0];
430 			assert(d->a_cells->len == 4);
431 			return ((uint32_t)buf[0] << 24) |
432 				((uint32_t)buf[1] << 16) |
433 				((uint32_t)buf[2] << 8) |
434 				(uint32_t)buf[3];
435 		}
436 	return OF_DEFAULT_NA;
437 }
438 
439 uint32_t
of_n_size_cells(const struct device_node * dev_node)440 of_n_size_cells(const struct device_node *dev_node)
441 {
442 	const struct dt_dir *d;
443 
444 	DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
445 	if (!dev_node)
446 		return OF_DEFAULT_NA;
447 	d = node2dir(dev_node);
448 	while ((d = d->parent))
449 		if (d->s_cells) {
450 			unsigned char *buf =
451 				(unsigned char *)&d->s_cells->buf[0];
452 			assert(d->s_cells->len == 4);
453 			return ((uint32_t)buf[0] << 24) |
454 				((uint32_t)buf[1] << 16) |
455 				((uint32_t)buf[2] << 8) |
456 				(uint32_t)buf[3];
457 		}
458 	return OF_DEFAULT_NS;
459 }
460 
461 const uint32_t *
of_get_address(const struct device_node * dev_node,size_t idx,uint64_t * size,uint32_t * flags __rte_unused)462 of_get_address(const struct device_node *dev_node, size_t idx,
463 	       uint64_t *size, uint32_t *flags __rte_unused)
464 {
465 	const struct dt_dir *d;
466 	const unsigned char *buf;
467 	uint32_t na = of_n_addr_cells(dev_node);
468 	uint32_t ns = of_n_size_cells(dev_node);
469 
470 	if (!dev_node)
471 		d = &root_dir;
472 	else
473 		d = node2dir(dev_node);
474 	if (!d->reg)
475 		return NULL;
476 	assert(d->reg->len % ((na + ns) * 4) == 0);
477 	assert(d->reg->len / ((na + ns) * 4) > (unsigned int) idx);
478 	buf = (const unsigned char *)&d->reg->buf[0];
479 	buf += (na + ns) * idx * 4;
480 	if (size)
481 		for (*size = 0; ns > 0; ns--, na++)
482 			*size = (*size << 32) +
483 				(((uint32_t)buf[4 * na] << 24) |
484 				((uint32_t)buf[4 * na + 1] << 16) |
485 				((uint32_t)buf[4 * na + 2] << 8) |
486 				(uint32_t)buf[4 * na + 3]);
487 	return (const uint32_t *)buf;
488 }
489 
490 uint64_t
of_translate_address(const struct device_node * dev_node,const uint32_t * addr)491 of_translate_address(const struct device_node *dev_node,
492 		     const uint32_t *addr)
493 {
494 	uint64_t phys_addr, tmp_addr;
495 	const struct device_node *parent;
496 	const uint32_t *ranges;
497 	size_t rlen;
498 	uint32_t na, pna;
499 
500 	DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
501 	assert(dev_node != NULL);
502 
503 	na = of_n_addr_cells(dev_node);
504 	phys_addr = of_read_number(addr, na);
505 
506 	dev_node = of_get_parent(dev_node);
507 	if (!dev_node)
508 		return 0;
509 	else if (node2dir(dev_node) == &root_dir)
510 		return phys_addr;
511 
512 	do {
513 		pna = of_n_addr_cells(dev_node);
514 		parent = of_get_parent(dev_node);
515 		if (!parent)
516 			return 0;
517 
518 		ranges = of_get_property(dev_node, "ranges", &rlen);
519 		/* "ranges" property is missing. Translation breaks */
520 		if (!ranges)
521 			return 0;
522 		/* "ranges" property is empty. Do 1:1 translation */
523 		else if (rlen == 0)
524 			continue;
525 		else
526 			tmp_addr = of_read_number(ranges + na, pna);
527 
528 		na = pna;
529 		dev_node = parent;
530 		phys_addr += tmp_addr;
531 	} while (node2dir(parent) != &root_dir);
532 
533 	return phys_addr;
534 }
535 
536 bool
of_device_is_compatible(const struct device_node * dev_node,const char * compatible)537 of_device_is_compatible(const struct device_node *dev_node,
538 			const char *compatible)
539 {
540 	const struct dt_dir *d;
541 
542 	DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
543 	if (!dev_node)
544 		d = &root_dir;
545 	else
546 		d = node2dir(dev_node);
547 	if (d->compatible && check_compatible(d->compatible, compatible))
548 		return true;
549 	return false;
550 }
551 
of_get_mac_addr(const struct device_node * np,const char * name)552 static const void *of_get_mac_addr(const struct device_node *np,
553 		const char *name)
554 {
555 	return of_get_property(np, name, NULL);
556 }
557 
558 /**
559  * Search the device tree for the best MAC address to use.  'mac-address' is
560  * checked first, because that is supposed to contain to "most recent" MAC
561  * address. If that isn't set, then 'local-mac-address' is checked next,
562  * because that is the default address.  If that isn't set, then the obsolete
563  * 'address' is checked, just in case we're using an old device tree.
564  *
565  * Note that the 'address' property is supposed to contain a virtual address of
566  * the register set, but some DTS files have redefined that property to be the
567  * MAC address.
568  *
569  * All-zero MAC addresses are rejected, because those could be properties that
570  * exist in the device tree, but were not set by U-Boot.  For example, the
571  * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
572  * addresses.  Some older U-Boots only initialized 'local-mac-address'.  In
573  * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
574  * but is all zeros.
575  */
of_get_mac_address(const struct device_node * np)576 const void *of_get_mac_address(const struct device_node *np)
577 {
578 	const void *addr;
579 
580 	addr = of_get_mac_addr(np, "mac-address");
581 	if (addr)
582 		return addr;
583 
584 	addr = of_get_mac_addr(np, "local-mac-address");
585 	if (addr)
586 		return addr;
587 
588 	return of_get_mac_addr(np, "address");
589 }
590