xref: /rk3399_ARM-atf/common/fdt_wrappers.c (revision 73f1ac6c8ee4a688ed8e1fddc040b882171d3453)
1e5674e1fSSoby Mathew /*
2e5674e1fSSoby Mathew  * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3e5674e1fSSoby Mathew  *
4e5674e1fSSoby Mathew  * SPDX-License-Identifier: BSD-3-Clause
5e5674e1fSSoby Mathew  */
6e5674e1fSSoby Mathew 
7e5674e1fSSoby Mathew /* Helper functions to offer easier navigation of Device Tree Blob */
8e5674e1fSSoby Mathew 
9e5674e1fSSoby Mathew #include <assert.h>
10e5674e1fSSoby Mathew #include <debug.h>
11e5674e1fSSoby Mathew #include <fdt_wrappers.h>
12e5674e1fSSoby Mathew #include <libfdt.h>
1327473620SAntonio Nino Diaz #include <string.h>
14e5674e1fSSoby Mathew 
15e5674e1fSSoby Mathew /*
16e5674e1fSSoby Mathew  * Read cells from a given property of the given node. At most 2 cells of the
17e5674e1fSSoby Mathew  * property are read, and pointer is updated. Returns 0 on success, and -1 upon
18e5674e1fSSoby Mathew  * error
19e5674e1fSSoby Mathew  */
20e5674e1fSSoby Mathew int fdtw_read_cells(const void *dtb, int node, const char *prop,
21e5674e1fSSoby Mathew 		unsigned int cells, void *value)
22e5674e1fSSoby Mathew {
23e5674e1fSSoby Mathew 	const uint32_t *value_ptr;
24e5674e1fSSoby Mathew 	uint32_t hi = 0, lo;
25e5674e1fSSoby Mathew 	int value_len;
26e5674e1fSSoby Mathew 
27da5f2745SSoby Mathew 	assert(dtb != NULL);
28da5f2745SSoby Mathew 	assert(prop != NULL);
29da5f2745SSoby Mathew 	assert(value != NULL);
30e5674e1fSSoby Mathew 	assert(node >= 0);
31e5674e1fSSoby Mathew 
32e5674e1fSSoby Mathew 	/* We expect either 1 or 2 cell property */
33da5f2745SSoby Mathew 	assert(cells <= 2U);
34e5674e1fSSoby Mathew 
35e5674e1fSSoby Mathew 	/* Access property and obtain its length (in bytes) */
36da5f2745SSoby Mathew 	value_ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop),
37e5674e1fSSoby Mathew 			&value_len);
38e5674e1fSSoby Mathew 	if (value_ptr == NULL) {
39e5674e1fSSoby Mathew 		WARN("Couldn't find property %s in dtb\n", prop);
40e5674e1fSSoby Mathew 		return -1;
41e5674e1fSSoby Mathew 	}
42e5674e1fSSoby Mathew 
43e5674e1fSSoby Mathew 	/* Verify that property length accords with cell length */
44da5f2745SSoby Mathew 	if (NCELLS((unsigned int)value_len) != cells) {
45e5674e1fSSoby Mathew 		WARN("Property length mismatch\n");
46e5674e1fSSoby Mathew 		return -1;
47e5674e1fSSoby Mathew 	}
48e5674e1fSSoby Mathew 
49da5f2745SSoby Mathew 	if (cells == 2U) {
50e5674e1fSSoby Mathew 		hi = fdt32_to_cpu(*value_ptr);
51e5674e1fSSoby Mathew 		value_ptr++;
52e5674e1fSSoby Mathew 	}
53e5674e1fSSoby Mathew 
54e5674e1fSSoby Mathew 	lo = fdt32_to_cpu(*value_ptr);
55e5674e1fSSoby Mathew 
56da5f2745SSoby Mathew 	if (cells == 2U)
57e5674e1fSSoby Mathew 		*((uint64_t *) value) = ((uint64_t) hi << 32) | lo;
58e5674e1fSSoby Mathew 	else
59e5674e1fSSoby Mathew 		*((uint32_t *) value) = lo;
60e5674e1fSSoby Mathew 
61e5674e1fSSoby Mathew 	return 0;
62e5674e1fSSoby Mathew }
63e5674e1fSSoby Mathew 
64e5674e1fSSoby Mathew /*
65*73f1ac6cSAntonio Nino Diaz  * Read cells from a given property of the given node. Any number of 32-bit
66*73f1ac6cSAntonio Nino Diaz  * cells of the property can be read. The fdt pointer is updated. Returns 0 on
67*73f1ac6cSAntonio Nino Diaz  * success, and -1 on error.
68*73f1ac6cSAntonio Nino Diaz  */
69*73f1ac6cSAntonio Nino Diaz int fdtw_read_array(const void *dtb, int node, const char *prop,
70*73f1ac6cSAntonio Nino Diaz 		unsigned int cells, void *value)
71*73f1ac6cSAntonio Nino Diaz {
72*73f1ac6cSAntonio Nino Diaz 	const uint32_t *value_ptr;
73*73f1ac6cSAntonio Nino Diaz 	int value_len;
74*73f1ac6cSAntonio Nino Diaz 
75*73f1ac6cSAntonio Nino Diaz 	assert(dtb != NULL);
76*73f1ac6cSAntonio Nino Diaz 	assert(prop != NULL);
77*73f1ac6cSAntonio Nino Diaz 	assert(value != NULL);
78*73f1ac6cSAntonio Nino Diaz 	assert(node >= 0);
79*73f1ac6cSAntonio Nino Diaz 
80*73f1ac6cSAntonio Nino Diaz 	/* Access property and obtain its length (in bytes) */
81*73f1ac6cSAntonio Nino Diaz 	value_ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop),
82*73f1ac6cSAntonio Nino Diaz 			&value_len);
83*73f1ac6cSAntonio Nino Diaz 	if (value_ptr == NULL) {
84*73f1ac6cSAntonio Nino Diaz 		WARN("Couldn't find property %s in dtb\n", prop);
85*73f1ac6cSAntonio Nino Diaz 		return -1;
86*73f1ac6cSAntonio Nino Diaz 	}
87*73f1ac6cSAntonio Nino Diaz 
88*73f1ac6cSAntonio Nino Diaz 	/* Verify that property length accords with cell length */
89*73f1ac6cSAntonio Nino Diaz 	if (NCELLS((unsigned int)value_len) != cells) {
90*73f1ac6cSAntonio Nino Diaz 		WARN("Property length mismatch\n");
91*73f1ac6cSAntonio Nino Diaz 		return -1;
92*73f1ac6cSAntonio Nino Diaz 	}
93*73f1ac6cSAntonio Nino Diaz 
94*73f1ac6cSAntonio Nino Diaz 	uint32_t *dst = value;
95*73f1ac6cSAntonio Nino Diaz 
96*73f1ac6cSAntonio Nino Diaz 	for (unsigned int i = 0U; i < cells; i++) {
97*73f1ac6cSAntonio Nino Diaz 		dst[i] = fdt32_to_cpu(value_ptr[i]);
98*73f1ac6cSAntonio Nino Diaz 	}
99*73f1ac6cSAntonio Nino Diaz 
100*73f1ac6cSAntonio Nino Diaz 	return 0;
101*73f1ac6cSAntonio Nino Diaz }
102*73f1ac6cSAntonio Nino Diaz 
103*73f1ac6cSAntonio Nino Diaz /*
10427473620SAntonio Nino Diaz  * Read string from a given property of the given node. Up to 'size - 1'
10527473620SAntonio Nino Diaz  * characters are read, and a NUL terminator is added. Returns 0 on success,
10627473620SAntonio Nino Diaz  * and -1 upon error.
10727473620SAntonio Nino Diaz  */
10827473620SAntonio Nino Diaz int fdtw_read_string(const void *dtb, int node, const char *prop,
10927473620SAntonio Nino Diaz 		char *str, size_t size)
11027473620SAntonio Nino Diaz {
11127473620SAntonio Nino Diaz 	const char *ptr;
11227473620SAntonio Nino Diaz 	size_t len;
11327473620SAntonio Nino Diaz 
11427473620SAntonio Nino Diaz 	assert(dtb != NULL);
11527473620SAntonio Nino Diaz 	assert(node >= 0);
11627473620SAntonio Nino Diaz 	assert(prop != NULL);
11727473620SAntonio Nino Diaz 	assert(str != NULL);
11827473620SAntonio Nino Diaz 	assert(size > 0U);
11927473620SAntonio Nino Diaz 
12027473620SAntonio Nino Diaz 	ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), NULL);
12127473620SAntonio Nino Diaz 	if (ptr == NULL) {
12227473620SAntonio Nino Diaz 		WARN("Couldn't find property %s in dtb\n", prop);
12327473620SAntonio Nino Diaz 		return -1;
12427473620SAntonio Nino Diaz 	}
12527473620SAntonio Nino Diaz 
12627473620SAntonio Nino Diaz 	len = strlcpy(str, ptr, size);
12727473620SAntonio Nino Diaz 	if (len >= size) {
12827473620SAntonio Nino Diaz 		WARN("String of property %s in dtb has been truncated\n", prop);
12927473620SAntonio Nino Diaz 		return -1;
13027473620SAntonio Nino Diaz 	}
13127473620SAntonio Nino Diaz 
13227473620SAntonio Nino Diaz 	return 0;
13327473620SAntonio Nino Diaz }
13427473620SAntonio Nino Diaz 
13527473620SAntonio Nino Diaz /*
136e5674e1fSSoby Mathew  * Write cells in place to a given property of the given node. At most 2 cells
137e5674e1fSSoby Mathew  * of the property are written. Returns 0 on success, and -1 upon error.
138e5674e1fSSoby Mathew  */
139e5674e1fSSoby Mathew int fdtw_write_inplace_cells(void *dtb, int node, const char *prop,
140e5674e1fSSoby Mathew 		unsigned int cells, void *value)
141e5674e1fSSoby Mathew {
142e5674e1fSSoby Mathew 	int err, len;
143e5674e1fSSoby Mathew 
144da5f2745SSoby Mathew 	assert(dtb != NULL);
145da5f2745SSoby Mathew 	assert(prop != NULL);
146da5f2745SSoby Mathew 	assert(value != NULL);
147e5674e1fSSoby Mathew 	assert(node >= 0);
148e5674e1fSSoby Mathew 
149e5674e1fSSoby Mathew 	/* We expect either 1 or 2 cell property */
150da5f2745SSoby Mathew 	assert(cells <= 2U);
151e5674e1fSSoby Mathew 
152da5f2745SSoby Mathew 	if (cells == 2U)
153e5674e1fSSoby Mathew 		*(uint64_t *)value = cpu_to_fdt64(*(uint64_t *)value);
154e5674e1fSSoby Mathew 	else
155e5674e1fSSoby Mathew 		*(uint32_t *)value = cpu_to_fdt32(*(uint32_t *)value);
156e5674e1fSSoby Mathew 
157da5f2745SSoby Mathew 	len = (int)cells * 4;
158e5674e1fSSoby Mathew 
159e5674e1fSSoby Mathew 	/* Set property value in place */
160e5674e1fSSoby Mathew 	err = fdt_setprop_inplace(dtb, node, prop, value, len);
161e5674e1fSSoby Mathew 	if (err != 0) {
162e5674e1fSSoby Mathew 		WARN("Modify property %s failed with error %d\n", prop, err);
163e5674e1fSSoby Mathew 		return -1;
164e5674e1fSSoby Mathew 	}
165e5674e1fSSoby Mathew 
166e5674e1fSSoby Mathew 	return 0;
167e5674e1fSSoby Mathew }
168