xref: /rk3399_ARM-atf/common/fdt_wrappers.c (revision 6e3a89f449fa5b4c0153990a64124211197f426a)
1e5674e1fSSoby Mathew /*
20a2ab6e6SAlexei Fedorov  * Copyright (c) 2018-2020, 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>
1027473620SAntonio Nino Diaz #include <string.h>
11e5674e1fSSoby Mathew 
1209d40e0eSAntonio Nino Diaz #include <libfdt.h>
1309d40e0eSAntonio Nino Diaz 
1409d40e0eSAntonio Nino Diaz #include <common/debug.h>
1509d40e0eSAntonio Nino Diaz #include <common/fdt_wrappers.h>
1609d40e0eSAntonio Nino Diaz 
17e5674e1fSSoby Mathew /*
18e5674e1fSSoby Mathew  * Read cells from a given property of the given node. At most 2 cells of the
19e5674e1fSSoby Mathew  * property are read, and pointer is updated. Returns 0 on success, and -1 upon
20e5674e1fSSoby Mathew  * error
21e5674e1fSSoby Mathew  */
22e5674e1fSSoby Mathew int fdtw_read_cells(const void *dtb, int node, const char *prop,
23e5674e1fSSoby Mathew 		unsigned int cells, void *value)
24e5674e1fSSoby Mathew {
25e5674e1fSSoby Mathew 	const uint32_t *value_ptr;
26e5674e1fSSoby Mathew 	uint32_t hi = 0, lo;
27e5674e1fSSoby Mathew 	int value_len;
28e5674e1fSSoby Mathew 
29da5f2745SSoby Mathew 	assert(dtb != NULL);
30da5f2745SSoby Mathew 	assert(prop != NULL);
31da5f2745SSoby Mathew 	assert(value != NULL);
32e5674e1fSSoby Mathew 	assert(node >= 0);
33e5674e1fSSoby Mathew 
34e5674e1fSSoby Mathew 	/* We expect either 1 or 2 cell property */
35da5f2745SSoby Mathew 	assert(cells <= 2U);
36e5674e1fSSoby Mathew 
37e5674e1fSSoby Mathew 	/* Access property and obtain its length (in bytes) */
38da5f2745SSoby Mathew 	value_ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop),
39e5674e1fSSoby Mathew 			&value_len);
40e5674e1fSSoby Mathew 	if (value_ptr == NULL) {
41e5674e1fSSoby Mathew 		WARN("Couldn't find property %s in dtb\n", prop);
42e5674e1fSSoby Mathew 		return -1;
43e5674e1fSSoby Mathew 	}
44e5674e1fSSoby Mathew 
45e5674e1fSSoby Mathew 	/* Verify that property length accords with cell length */
46da5f2745SSoby Mathew 	if (NCELLS((unsigned int)value_len) != cells) {
47e5674e1fSSoby Mathew 		WARN("Property length mismatch\n");
48e5674e1fSSoby Mathew 		return -1;
49e5674e1fSSoby Mathew 	}
50e5674e1fSSoby Mathew 
51da5f2745SSoby Mathew 	if (cells == 2U) {
52e5674e1fSSoby Mathew 		hi = fdt32_to_cpu(*value_ptr);
53e5674e1fSSoby Mathew 		value_ptr++;
54e5674e1fSSoby Mathew 	}
55e5674e1fSSoby Mathew 
56e5674e1fSSoby Mathew 	lo = fdt32_to_cpu(*value_ptr);
57e5674e1fSSoby Mathew 
58da5f2745SSoby Mathew 	if (cells == 2U)
59e5674e1fSSoby Mathew 		*((uint64_t *) value) = ((uint64_t) hi << 32) | lo;
60e5674e1fSSoby Mathew 	else
61e5674e1fSSoby Mathew 		*((uint32_t *) value) = lo;
62e5674e1fSSoby Mathew 
63e5674e1fSSoby Mathew 	return 0;
64e5674e1fSSoby Mathew }
65e5674e1fSSoby Mathew 
66e5674e1fSSoby Mathew /*
6773f1ac6cSAntonio Nino Diaz  * Read cells from a given property of the given node. Any number of 32-bit
68*6e3a89f4SAndre Przywara  * cells of the property can be read. Returns 0 on success, or a negative
69*6e3a89f4SAndre Przywara  * FDT error value otherwise.
7073f1ac6cSAntonio Nino Diaz  */
71*6e3a89f4SAndre Przywara int fdt_read_uint32_array(const void *dtb, int node, const char *prop_name,
72*6e3a89f4SAndre Przywara 			  unsigned int cells, uint32_t *value)
7373f1ac6cSAntonio Nino Diaz {
74*6e3a89f4SAndre Przywara 	const fdt32_t *prop;
7573f1ac6cSAntonio Nino Diaz 	int value_len;
7673f1ac6cSAntonio Nino Diaz 
7773f1ac6cSAntonio Nino Diaz 	assert(dtb != NULL);
78*6e3a89f4SAndre Przywara 	assert(prop_name != NULL);
7973f1ac6cSAntonio Nino Diaz 	assert(value != NULL);
8073f1ac6cSAntonio Nino Diaz 	assert(node >= 0);
8173f1ac6cSAntonio Nino Diaz 
8273f1ac6cSAntonio Nino Diaz 	/* Access property and obtain its length (in bytes) */
83*6e3a89f4SAndre Przywara 	prop = fdt_getprop(dtb, node, prop_name, &value_len);
84*6e3a89f4SAndre Przywara 	if (prop == NULL) {
85*6e3a89f4SAndre Przywara 		WARN("Couldn't find property %s in dtb\n", prop_name);
86*6e3a89f4SAndre Przywara 		return -FDT_ERR_NOTFOUND;
8773f1ac6cSAntonio Nino Diaz 	}
8873f1ac6cSAntonio Nino Diaz 
89*6e3a89f4SAndre Przywara 	/* Verify that property length can fill the entire array. */
90*6e3a89f4SAndre Przywara 	if (NCELLS((unsigned int)value_len) < cells) {
9173f1ac6cSAntonio Nino Diaz 		WARN("Property length mismatch\n");
92*6e3a89f4SAndre Przywara 		return -FDT_ERR_BADVALUE;
9373f1ac6cSAntonio Nino Diaz 	}
9473f1ac6cSAntonio Nino Diaz 
9573f1ac6cSAntonio Nino Diaz 	for (unsigned int i = 0U; i < cells; i++) {
96*6e3a89f4SAndre Przywara 		value[i] = fdt32_to_cpu(prop[i]);
9773f1ac6cSAntonio Nino Diaz 	}
9873f1ac6cSAntonio Nino Diaz 
9973f1ac6cSAntonio Nino Diaz 	return 0;
10073f1ac6cSAntonio Nino Diaz }
10173f1ac6cSAntonio Nino Diaz 
10273f1ac6cSAntonio Nino Diaz /*
1030a2ab6e6SAlexei Fedorov  * Read bytes from a given property of the given node. Any number of
1040a2ab6e6SAlexei Fedorov  * bytes of the property can be read. The fdt pointer is updated.
1050a2ab6e6SAlexei Fedorov  * Returns 0 on success, and -1 on error.
1060a2ab6e6SAlexei Fedorov  */
1070a2ab6e6SAlexei Fedorov int fdtw_read_bytes(const void *dtb, int node, const char *prop,
1080a2ab6e6SAlexei Fedorov 		    unsigned int length, void *value)
1090a2ab6e6SAlexei Fedorov {
1100a2ab6e6SAlexei Fedorov 	const void *ptr;
1110a2ab6e6SAlexei Fedorov 	int value_len;
1120a2ab6e6SAlexei Fedorov 
1130a2ab6e6SAlexei Fedorov 	assert(dtb != NULL);
1140a2ab6e6SAlexei Fedorov 	assert(prop != NULL);
1150a2ab6e6SAlexei Fedorov 	assert(value != NULL);
1160a2ab6e6SAlexei Fedorov 	assert(node >= 0);
1170a2ab6e6SAlexei Fedorov 
1180a2ab6e6SAlexei Fedorov 	/* Access property and obtain its length (in bytes) */
1190a2ab6e6SAlexei Fedorov 	ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop),
1200a2ab6e6SAlexei Fedorov 					&value_len);
1210a2ab6e6SAlexei Fedorov 	if (ptr == NULL) {
1220a2ab6e6SAlexei Fedorov 		WARN("Couldn't find property %s in dtb\n", prop);
1230a2ab6e6SAlexei Fedorov 		return -1;
1240a2ab6e6SAlexei Fedorov 	}
1250a2ab6e6SAlexei Fedorov 
1260a2ab6e6SAlexei Fedorov 	/* Verify that property length is not less than number of bytes */
1270a2ab6e6SAlexei Fedorov 	if ((unsigned int)value_len < length) {
1280a2ab6e6SAlexei Fedorov 		WARN("Property length mismatch\n");
1290a2ab6e6SAlexei Fedorov 		return -1;
1300a2ab6e6SAlexei Fedorov 	}
1310a2ab6e6SAlexei Fedorov 
1320a2ab6e6SAlexei Fedorov 	(void)memcpy(value, ptr, length);
1330a2ab6e6SAlexei Fedorov 
1340a2ab6e6SAlexei Fedorov 	return 0;
1350a2ab6e6SAlexei Fedorov }
1360a2ab6e6SAlexei Fedorov 
1370a2ab6e6SAlexei Fedorov /*
13827473620SAntonio Nino Diaz  * Read string from a given property of the given node. Up to 'size - 1'
13927473620SAntonio Nino Diaz  * characters are read, and a NUL terminator is added. Returns 0 on success,
14027473620SAntonio Nino Diaz  * and -1 upon error.
14127473620SAntonio Nino Diaz  */
14227473620SAntonio Nino Diaz int fdtw_read_string(const void *dtb, int node, const char *prop,
14327473620SAntonio Nino Diaz 		char *str, size_t size)
14427473620SAntonio Nino Diaz {
14527473620SAntonio Nino Diaz 	const char *ptr;
14627473620SAntonio Nino Diaz 	size_t len;
14727473620SAntonio Nino Diaz 
14827473620SAntonio Nino Diaz 	assert(dtb != NULL);
14927473620SAntonio Nino Diaz 	assert(node >= 0);
15027473620SAntonio Nino Diaz 	assert(prop != NULL);
15127473620SAntonio Nino Diaz 	assert(str != NULL);
15227473620SAntonio Nino Diaz 	assert(size > 0U);
15327473620SAntonio Nino Diaz 
15427473620SAntonio Nino Diaz 	ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), NULL);
15527473620SAntonio Nino Diaz 	if (ptr == NULL) {
15627473620SAntonio Nino Diaz 		WARN("Couldn't find property %s in dtb\n", prop);
15727473620SAntonio Nino Diaz 		return -1;
15827473620SAntonio Nino Diaz 	}
15927473620SAntonio Nino Diaz 
16027473620SAntonio Nino Diaz 	len = strlcpy(str, ptr, size);
16127473620SAntonio Nino Diaz 	if (len >= size) {
16227473620SAntonio Nino Diaz 		WARN("String of property %s in dtb has been truncated\n", prop);
16327473620SAntonio Nino Diaz 		return -1;
16427473620SAntonio Nino Diaz 	}
16527473620SAntonio Nino Diaz 
16627473620SAntonio Nino Diaz 	return 0;
16727473620SAntonio Nino Diaz }
16827473620SAntonio Nino Diaz 
16927473620SAntonio Nino Diaz /*
170e5674e1fSSoby Mathew  * Write cells in place to a given property of the given node. At most 2 cells
171e5674e1fSSoby Mathew  * of the property are written. Returns 0 on success, and -1 upon error.
172e5674e1fSSoby Mathew  */
173e5674e1fSSoby Mathew int fdtw_write_inplace_cells(void *dtb, int node, const char *prop,
174e5674e1fSSoby Mathew 		unsigned int cells, void *value)
175e5674e1fSSoby Mathew {
176e5674e1fSSoby Mathew 	int err, len;
177e5674e1fSSoby Mathew 
178da5f2745SSoby Mathew 	assert(dtb != NULL);
179da5f2745SSoby Mathew 	assert(prop != NULL);
180da5f2745SSoby Mathew 	assert(value != NULL);
181e5674e1fSSoby Mathew 	assert(node >= 0);
182e5674e1fSSoby Mathew 
183e5674e1fSSoby Mathew 	/* We expect either 1 or 2 cell property */
184da5f2745SSoby Mathew 	assert(cells <= 2U);
185e5674e1fSSoby Mathew 
186da5f2745SSoby Mathew 	if (cells == 2U)
187e5674e1fSSoby Mathew 		*(uint64_t *)value = cpu_to_fdt64(*(uint64_t *)value);
188e5674e1fSSoby Mathew 	else
189e5674e1fSSoby Mathew 		*(uint32_t *)value = cpu_to_fdt32(*(uint32_t *)value);
190e5674e1fSSoby Mathew 
191da5f2745SSoby Mathew 	len = (int)cells * 4;
192e5674e1fSSoby Mathew 
193e5674e1fSSoby Mathew 	/* Set property value in place */
194e5674e1fSSoby Mathew 	err = fdt_setprop_inplace(dtb, node, prop, value, len);
195e5674e1fSSoby Mathew 	if (err != 0) {
196e5674e1fSSoby Mathew 		WARN("Modify property %s failed with error %d\n", prop, err);
197e5674e1fSSoby Mathew 		return -1;
198e5674e1fSSoby Mathew 	}
199e5674e1fSSoby Mathew 
200e5674e1fSSoby Mathew 	return 0;
201e5674e1fSSoby Mathew }
2020a2ab6e6SAlexei Fedorov 
2030a2ab6e6SAlexei Fedorov /*
2040a2ab6e6SAlexei Fedorov  * Write bytes in place to a given property of the given node.
2050a2ab6e6SAlexei Fedorov  * Any number of bytes of the property can be written.
2060a2ab6e6SAlexei Fedorov  * Returns 0 on success, and < 0 on error.
2070a2ab6e6SAlexei Fedorov  */
2080a2ab6e6SAlexei Fedorov int fdtw_write_inplace_bytes(void *dtb, int node, const char *prop,
2090a2ab6e6SAlexei Fedorov 			     unsigned int length, const void *data)
2100a2ab6e6SAlexei Fedorov {
2110a2ab6e6SAlexei Fedorov 	const void *ptr;
2120a2ab6e6SAlexei Fedorov 	int namelen, value_len, err;
2130a2ab6e6SAlexei Fedorov 
2140a2ab6e6SAlexei Fedorov 	assert(dtb != NULL);
2150a2ab6e6SAlexei Fedorov 	assert(prop != NULL);
2160a2ab6e6SAlexei Fedorov 	assert(data != NULL);
2170a2ab6e6SAlexei Fedorov 	assert(node >= 0);
2180a2ab6e6SAlexei Fedorov 
2190a2ab6e6SAlexei Fedorov 	namelen = (int)strlen(prop);
2200a2ab6e6SAlexei Fedorov 
2210a2ab6e6SAlexei Fedorov 	/* Access property and obtain its length in bytes */
2220a2ab6e6SAlexei Fedorov 	ptr = fdt_getprop_namelen(dtb, node, prop, namelen, &value_len);
2230a2ab6e6SAlexei Fedorov 	if (ptr == NULL) {
2240a2ab6e6SAlexei Fedorov 		WARN("Couldn't find property %s in dtb\n", prop);
2250a2ab6e6SAlexei Fedorov 		return -1;
2260a2ab6e6SAlexei Fedorov 	}
2270a2ab6e6SAlexei Fedorov 
2280a2ab6e6SAlexei Fedorov 	/* Verify that property length is not less than number of bytes */
2290a2ab6e6SAlexei Fedorov 	if ((unsigned int)value_len < length) {
2300a2ab6e6SAlexei Fedorov 		WARN("Property length mismatch\n");
2310a2ab6e6SAlexei Fedorov 		return -1;
2320a2ab6e6SAlexei Fedorov 	}
2330a2ab6e6SAlexei Fedorov 
2340a2ab6e6SAlexei Fedorov 	/* Set property value in place */
2350a2ab6e6SAlexei Fedorov 	err = fdt_setprop_inplace_namelen_partial(dtb, node, prop,
2360a2ab6e6SAlexei Fedorov 						  namelen, 0,
2370a2ab6e6SAlexei Fedorov 						  data, (int)length);
2380a2ab6e6SAlexei Fedorov 	if (err != 0) {
2390a2ab6e6SAlexei Fedorov 		WARN("Set property %s failed with error %d\n", prop, err);
2400a2ab6e6SAlexei Fedorov 	}
2410a2ab6e6SAlexei Fedorov 
2420a2ab6e6SAlexei Fedorov 	return err;
2430a2ab6e6SAlexei Fedorov }
244