1 /* 2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* Helper functions to offer easier navigation of Device Tree Blob */ 8 9 #include <assert.h> 10 #include <debug.h> 11 #include <fdt_wrappers.h> 12 #include <libfdt.h> 13 #include <string.h> 14 15 /* 16 * Read cells from a given property of the given node. At most 2 cells of the 17 * property are read, and pointer is updated. Returns 0 on success, and -1 upon 18 * error 19 */ 20 int fdtw_read_cells(const void *dtb, int node, const char *prop, 21 unsigned int cells, void *value) 22 { 23 const uint32_t *value_ptr; 24 uint32_t hi = 0, lo; 25 int value_len; 26 27 assert(dtb != NULL); 28 assert(prop != NULL); 29 assert(value != NULL); 30 assert(node >= 0); 31 32 /* We expect either 1 or 2 cell property */ 33 assert(cells <= 2U); 34 35 /* Access property and obtain its length (in bytes) */ 36 value_ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), 37 &value_len); 38 if (value_ptr == NULL) { 39 WARN("Couldn't find property %s in dtb\n", prop); 40 return -1; 41 } 42 43 /* Verify that property length accords with cell length */ 44 if (NCELLS((unsigned int)value_len) != cells) { 45 WARN("Property length mismatch\n"); 46 return -1; 47 } 48 49 if (cells == 2U) { 50 hi = fdt32_to_cpu(*value_ptr); 51 value_ptr++; 52 } 53 54 lo = fdt32_to_cpu(*value_ptr); 55 56 if (cells == 2U) 57 *((uint64_t *) value) = ((uint64_t) hi << 32) | lo; 58 else 59 *((uint32_t *) value) = lo; 60 61 return 0; 62 } 63 64 /* 65 * Read cells from a given property of the given node. Any number of 32-bit 66 * cells of the property can be read. The fdt pointer is updated. Returns 0 on 67 * success, and -1 on error. 68 */ 69 int fdtw_read_array(const void *dtb, int node, const char *prop, 70 unsigned int cells, void *value) 71 { 72 const uint32_t *value_ptr; 73 int value_len; 74 75 assert(dtb != NULL); 76 assert(prop != NULL); 77 assert(value != NULL); 78 assert(node >= 0); 79 80 /* Access property and obtain its length (in bytes) */ 81 value_ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), 82 &value_len); 83 if (value_ptr == NULL) { 84 WARN("Couldn't find property %s in dtb\n", prop); 85 return -1; 86 } 87 88 /* Verify that property length accords with cell length */ 89 if (NCELLS((unsigned int)value_len) != cells) { 90 WARN("Property length mismatch\n"); 91 return -1; 92 } 93 94 uint32_t *dst = value; 95 96 for (unsigned int i = 0U; i < cells; i++) { 97 dst[i] = fdt32_to_cpu(value_ptr[i]); 98 } 99 100 return 0; 101 } 102 103 /* 104 * Read string from a given property of the given node. Up to 'size - 1' 105 * characters are read, and a NUL terminator is added. Returns 0 on success, 106 * and -1 upon error. 107 */ 108 int fdtw_read_string(const void *dtb, int node, const char *prop, 109 char *str, size_t size) 110 { 111 const char *ptr; 112 size_t len; 113 114 assert(dtb != NULL); 115 assert(node >= 0); 116 assert(prop != NULL); 117 assert(str != NULL); 118 assert(size > 0U); 119 120 ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), NULL); 121 if (ptr == NULL) { 122 WARN("Couldn't find property %s in dtb\n", prop); 123 return -1; 124 } 125 126 len = strlcpy(str, ptr, size); 127 if (len >= size) { 128 WARN("String of property %s in dtb has been truncated\n", prop); 129 return -1; 130 } 131 132 return 0; 133 } 134 135 /* 136 * Write cells in place to a given property of the given node. At most 2 cells 137 * of the property are written. Returns 0 on success, and -1 upon error. 138 */ 139 int fdtw_write_inplace_cells(void *dtb, int node, const char *prop, 140 unsigned int cells, void *value) 141 { 142 int err, len; 143 144 assert(dtb != NULL); 145 assert(prop != NULL); 146 assert(value != NULL); 147 assert(node >= 0); 148 149 /* We expect either 1 or 2 cell property */ 150 assert(cells <= 2U); 151 152 if (cells == 2U) 153 *(uint64_t *)value = cpu_to_fdt64(*(uint64_t *)value); 154 else 155 *(uint32_t *)value = cpu_to_fdt32(*(uint32_t *)value); 156 157 len = (int)cells * 4; 158 159 /* Set property value in place */ 160 err = fdt_setprop_inplace(dtb, node, prop, value, len); 161 if (err != 0) { 162 WARN("Modify property %s failed with error %d\n", prop, err); 163 return -1; 164 } 165 166 return 0; 167 } 168