xref: /rk3399_ARM-atf/common/fdt_wrappers.c (revision 0a2ab6e63520dceb81b622dd6b7f4ff30cfed08e)
1e5674e1fSSoby Mathew /*
2*0a2ab6e6SAlexei 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
6873f1ac6cSAntonio Nino Diaz  * cells of the property can be read. The fdt pointer is updated. Returns 0 on
6973f1ac6cSAntonio Nino Diaz  * success, and -1 on error.
7073f1ac6cSAntonio Nino Diaz  */
7173f1ac6cSAntonio Nino Diaz int fdtw_read_array(const void *dtb, int node, const char *prop,
7273f1ac6cSAntonio Nino Diaz 		unsigned int cells, void *value)
7373f1ac6cSAntonio Nino Diaz {
7473f1ac6cSAntonio Nino Diaz 	const uint32_t *value_ptr;
7573f1ac6cSAntonio Nino Diaz 	int value_len;
7673f1ac6cSAntonio Nino Diaz 
7773f1ac6cSAntonio Nino Diaz 	assert(dtb != NULL);
7873f1ac6cSAntonio Nino Diaz 	assert(prop != 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) */
8373f1ac6cSAntonio Nino Diaz 	value_ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop),
8473f1ac6cSAntonio Nino Diaz 			&value_len);
8573f1ac6cSAntonio Nino Diaz 	if (value_ptr == NULL) {
8673f1ac6cSAntonio Nino Diaz 		WARN("Couldn't find property %s in dtb\n", prop);
8773f1ac6cSAntonio Nino Diaz 		return -1;
8873f1ac6cSAntonio Nino Diaz 	}
8973f1ac6cSAntonio Nino Diaz 
9073f1ac6cSAntonio Nino Diaz 	/* Verify that property length accords with cell length */
9173f1ac6cSAntonio Nino Diaz 	if (NCELLS((unsigned int)value_len) != cells) {
9273f1ac6cSAntonio Nino Diaz 		WARN("Property length mismatch\n");
9373f1ac6cSAntonio Nino Diaz 		return -1;
9473f1ac6cSAntonio Nino Diaz 	}
9573f1ac6cSAntonio Nino Diaz 
9673f1ac6cSAntonio Nino Diaz 	uint32_t *dst = value;
9773f1ac6cSAntonio Nino Diaz 
9873f1ac6cSAntonio Nino Diaz 	for (unsigned int i = 0U; i < cells; i++) {
9973f1ac6cSAntonio Nino Diaz 		dst[i] = fdt32_to_cpu(value_ptr[i]);
10073f1ac6cSAntonio Nino Diaz 	}
10173f1ac6cSAntonio Nino Diaz 
10273f1ac6cSAntonio Nino Diaz 	return 0;
10373f1ac6cSAntonio Nino Diaz }
10473f1ac6cSAntonio Nino Diaz 
10573f1ac6cSAntonio Nino Diaz /*
106*0a2ab6e6SAlexei Fedorov  * Read bytes from a given property of the given node. Any number of
107*0a2ab6e6SAlexei Fedorov  * bytes of the property can be read. The fdt pointer is updated.
108*0a2ab6e6SAlexei Fedorov  * Returns 0 on success, and -1 on error.
109*0a2ab6e6SAlexei Fedorov  */
110*0a2ab6e6SAlexei Fedorov int fdtw_read_bytes(const void *dtb, int node, const char *prop,
111*0a2ab6e6SAlexei Fedorov 		    unsigned int length, void *value)
112*0a2ab6e6SAlexei Fedorov {
113*0a2ab6e6SAlexei Fedorov 	const void *ptr;
114*0a2ab6e6SAlexei Fedorov 	int value_len;
115*0a2ab6e6SAlexei Fedorov 
116*0a2ab6e6SAlexei Fedorov 	assert(dtb != NULL);
117*0a2ab6e6SAlexei Fedorov 	assert(prop != NULL);
118*0a2ab6e6SAlexei Fedorov 	assert(value != NULL);
119*0a2ab6e6SAlexei Fedorov 	assert(node >= 0);
120*0a2ab6e6SAlexei Fedorov 
121*0a2ab6e6SAlexei Fedorov 	/* Access property and obtain its length (in bytes) */
122*0a2ab6e6SAlexei Fedorov 	ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop),
123*0a2ab6e6SAlexei Fedorov 					&value_len);
124*0a2ab6e6SAlexei Fedorov 	if (ptr == NULL) {
125*0a2ab6e6SAlexei Fedorov 		WARN("Couldn't find property %s in dtb\n", prop);
126*0a2ab6e6SAlexei Fedorov 		return -1;
127*0a2ab6e6SAlexei Fedorov 	}
128*0a2ab6e6SAlexei Fedorov 
129*0a2ab6e6SAlexei Fedorov 	/* Verify that property length is not less than number of bytes */
130*0a2ab6e6SAlexei Fedorov 	if ((unsigned int)value_len < length) {
131*0a2ab6e6SAlexei Fedorov 		WARN("Property length mismatch\n");
132*0a2ab6e6SAlexei Fedorov 		return -1;
133*0a2ab6e6SAlexei Fedorov 	}
134*0a2ab6e6SAlexei Fedorov 
135*0a2ab6e6SAlexei Fedorov 	(void)memcpy(value, ptr, length);
136*0a2ab6e6SAlexei Fedorov 
137*0a2ab6e6SAlexei Fedorov 	return 0;
138*0a2ab6e6SAlexei Fedorov }
139*0a2ab6e6SAlexei Fedorov 
140*0a2ab6e6SAlexei Fedorov /*
14127473620SAntonio Nino Diaz  * Read string from a given property of the given node. Up to 'size - 1'
14227473620SAntonio Nino Diaz  * characters are read, and a NUL terminator is added. Returns 0 on success,
14327473620SAntonio Nino Diaz  * and -1 upon error.
14427473620SAntonio Nino Diaz  */
14527473620SAntonio Nino Diaz int fdtw_read_string(const void *dtb, int node, const char *prop,
14627473620SAntonio Nino Diaz 		char *str, size_t size)
14727473620SAntonio Nino Diaz {
14827473620SAntonio Nino Diaz 	const char *ptr;
14927473620SAntonio Nino Diaz 	size_t len;
15027473620SAntonio Nino Diaz 
15127473620SAntonio Nino Diaz 	assert(dtb != NULL);
15227473620SAntonio Nino Diaz 	assert(node >= 0);
15327473620SAntonio Nino Diaz 	assert(prop != NULL);
15427473620SAntonio Nino Diaz 	assert(str != NULL);
15527473620SAntonio Nino Diaz 	assert(size > 0U);
15627473620SAntonio Nino Diaz 
15727473620SAntonio Nino Diaz 	ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), NULL);
15827473620SAntonio Nino Diaz 	if (ptr == NULL) {
15927473620SAntonio Nino Diaz 		WARN("Couldn't find property %s in dtb\n", prop);
16027473620SAntonio Nino Diaz 		return -1;
16127473620SAntonio Nino Diaz 	}
16227473620SAntonio Nino Diaz 
16327473620SAntonio Nino Diaz 	len = strlcpy(str, ptr, size);
16427473620SAntonio Nino Diaz 	if (len >= size) {
16527473620SAntonio Nino Diaz 		WARN("String of property %s in dtb has been truncated\n", prop);
16627473620SAntonio Nino Diaz 		return -1;
16727473620SAntonio Nino Diaz 	}
16827473620SAntonio Nino Diaz 
16927473620SAntonio Nino Diaz 	return 0;
17027473620SAntonio Nino Diaz }
17127473620SAntonio Nino Diaz 
17227473620SAntonio Nino Diaz /*
173e5674e1fSSoby Mathew  * Write cells in place to a given property of the given node. At most 2 cells
174e5674e1fSSoby Mathew  * of the property are written. Returns 0 on success, and -1 upon error.
175e5674e1fSSoby Mathew  */
176e5674e1fSSoby Mathew int fdtw_write_inplace_cells(void *dtb, int node, const char *prop,
177e5674e1fSSoby Mathew 		unsigned int cells, void *value)
178e5674e1fSSoby Mathew {
179e5674e1fSSoby Mathew 	int err, len;
180e5674e1fSSoby Mathew 
181da5f2745SSoby Mathew 	assert(dtb != NULL);
182da5f2745SSoby Mathew 	assert(prop != NULL);
183da5f2745SSoby Mathew 	assert(value != NULL);
184e5674e1fSSoby Mathew 	assert(node >= 0);
185e5674e1fSSoby Mathew 
186e5674e1fSSoby Mathew 	/* We expect either 1 or 2 cell property */
187da5f2745SSoby Mathew 	assert(cells <= 2U);
188e5674e1fSSoby Mathew 
189da5f2745SSoby Mathew 	if (cells == 2U)
190e5674e1fSSoby Mathew 		*(uint64_t *)value = cpu_to_fdt64(*(uint64_t *)value);
191e5674e1fSSoby Mathew 	else
192e5674e1fSSoby Mathew 		*(uint32_t *)value = cpu_to_fdt32(*(uint32_t *)value);
193e5674e1fSSoby Mathew 
194da5f2745SSoby Mathew 	len = (int)cells * 4;
195e5674e1fSSoby Mathew 
196e5674e1fSSoby Mathew 	/* Set property value in place */
197e5674e1fSSoby Mathew 	err = fdt_setprop_inplace(dtb, node, prop, value, len);
198e5674e1fSSoby Mathew 	if (err != 0) {
199e5674e1fSSoby Mathew 		WARN("Modify property %s failed with error %d\n", prop, err);
200e5674e1fSSoby Mathew 		return -1;
201e5674e1fSSoby Mathew 	}
202e5674e1fSSoby Mathew 
203e5674e1fSSoby Mathew 	return 0;
204e5674e1fSSoby Mathew }
205*0a2ab6e6SAlexei Fedorov 
206*0a2ab6e6SAlexei Fedorov /*
207*0a2ab6e6SAlexei Fedorov  * Write bytes in place to a given property of the given node.
208*0a2ab6e6SAlexei Fedorov  * Any number of bytes of the property can be written.
209*0a2ab6e6SAlexei Fedorov  * Returns 0 on success, and < 0 on error.
210*0a2ab6e6SAlexei Fedorov  */
211*0a2ab6e6SAlexei Fedorov int fdtw_write_inplace_bytes(void *dtb, int node, const char *prop,
212*0a2ab6e6SAlexei Fedorov 			     unsigned int length, const void *data)
213*0a2ab6e6SAlexei Fedorov {
214*0a2ab6e6SAlexei Fedorov 	const void *ptr;
215*0a2ab6e6SAlexei Fedorov 	int namelen, value_len, err;
216*0a2ab6e6SAlexei Fedorov 
217*0a2ab6e6SAlexei Fedorov 	assert(dtb != NULL);
218*0a2ab6e6SAlexei Fedorov 	assert(prop != NULL);
219*0a2ab6e6SAlexei Fedorov 	assert(data != NULL);
220*0a2ab6e6SAlexei Fedorov 	assert(node >= 0);
221*0a2ab6e6SAlexei Fedorov 
222*0a2ab6e6SAlexei Fedorov 	namelen = (int)strlen(prop);
223*0a2ab6e6SAlexei Fedorov 
224*0a2ab6e6SAlexei Fedorov 	/* Access property and obtain its length in bytes */
225*0a2ab6e6SAlexei Fedorov 	ptr = fdt_getprop_namelen(dtb, node, prop, namelen, &value_len);
226*0a2ab6e6SAlexei Fedorov 	if (ptr == NULL) {
227*0a2ab6e6SAlexei Fedorov 		WARN("Couldn't find property %s in dtb\n", prop);
228*0a2ab6e6SAlexei Fedorov 		return -1;
229*0a2ab6e6SAlexei Fedorov 	}
230*0a2ab6e6SAlexei Fedorov 
231*0a2ab6e6SAlexei Fedorov 	/* Verify that property length is not less than number of bytes */
232*0a2ab6e6SAlexei Fedorov 	if ((unsigned int)value_len < length) {
233*0a2ab6e6SAlexei Fedorov 		WARN("Property length mismatch\n");
234*0a2ab6e6SAlexei Fedorov 		return -1;
235*0a2ab6e6SAlexei Fedorov 	}
236*0a2ab6e6SAlexei Fedorov 
237*0a2ab6e6SAlexei Fedorov 	/* Set property value in place */
238*0a2ab6e6SAlexei Fedorov 	err = fdt_setprop_inplace_namelen_partial(dtb, node, prop,
239*0a2ab6e6SAlexei Fedorov 						  namelen, 0,
240*0a2ab6e6SAlexei Fedorov 						  data, (int)length);
241*0a2ab6e6SAlexei Fedorov 	if (err != 0) {
242*0a2ab6e6SAlexei Fedorov 		WARN("Set property %s failed with error %d\n", prop, err);
243*0a2ab6e6SAlexei Fedorov 	}
244*0a2ab6e6SAlexei Fedorov 
245*0a2ab6e6SAlexei Fedorov 	return err;
246*0a2ab6e6SAlexei Fedorov }
247