1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * This file does the necessary interface mapping between the bootwrapper 4 * device tree operations and the interface provided by shared source 5 * files flatdevicetree.[ch]. 6 * 7 * Copyright 2007 David Gibson, IBM Corporation. 8 */ 9 10 #include <stddef.h> 11 #include <stdio.h> 12 #include <page.h> 13 #include <libfdt.h> 14 #include "ops.h" 15 16 #define DEBUG 0 17 #define BAD_ERROR(err) (((err) < 0) \ 18 && ((err) != -FDT_ERR_NOTFOUND) \ 19 && ((err) != -FDT_ERR_EXISTS)) 20 21 #define check_err(err) \ 22 ({ \ 23 if (BAD_ERROR(err) || ((err < 0) && DEBUG)) \ 24 printf("%s():%d %s\n\r", __func__, __LINE__, \ 25 fdt_strerror(err)); \ 26 if (BAD_ERROR(err)) \ 27 exit(); \ 28 (err < 0) ? -1 : 0; \ 29 }) 30 31 #define offset_devp(off) \ 32 ({ \ 33 unsigned long _offset = (off); \ 34 check_err(_offset) ? NULL : (void *)(_offset+1); \ 35 }) 36 37 #define devp_offset_find(devp) (((unsigned long)(devp))-1) 38 #define devp_offset(devp) (devp ? ((unsigned long)(devp))-1 : 0) 39 40 static void *fdt; 41 static void *buf; /* = NULL */ 42 43 #define EXPAND_GRANULARITY 1024 44 45 static void expand_buf(int minexpand) 46 { 47 int size = fdt_totalsize(fdt); 48 int rc; 49 50 size = _ALIGN(size + minexpand, EXPAND_GRANULARITY); 51 buf = platform_ops.realloc(buf, size); 52 if (!buf) 53 fatal("Couldn't find %d bytes to expand device tree\n\r", size); 54 rc = fdt_open_into(fdt, buf, size); 55 if (rc != 0) 56 fatal("Couldn't expand fdt into new buffer: %s\n\r", 57 fdt_strerror(rc)); 58 59 fdt = buf; 60 } 61 62 static void *fdt_wrapper_finddevice(const char *path) 63 { 64 return offset_devp(fdt_path_offset(fdt, path)); 65 } 66 67 static int fdt_wrapper_getprop(const void *devp, const char *name, 68 void *buf, const int buflen) 69 { 70 const void *p; 71 int len; 72 73 p = fdt_getprop(fdt, devp_offset(devp), name, &len); 74 if (!p) 75 return check_err(len); 76 memcpy(buf, p, min(len, buflen)); 77 return len; 78 } 79 80 static int fdt_wrapper_setprop(const void *devp, const char *name, 81 const void *buf, const int len) 82 { 83 int rc; 84 85 rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len); 86 if (rc == -FDT_ERR_NOSPACE) { 87 expand_buf(len + 16); 88 rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len); 89 } 90 91 return check_err(rc); 92 } 93 94 static int fdt_wrapper_del_node(const void *devp) 95 { 96 return fdt_del_node(fdt, devp_offset(devp)); 97 } 98 99 static void *fdt_wrapper_get_parent(const void *devp) 100 { 101 return offset_devp(fdt_parent_offset(fdt, devp_offset(devp))); 102 } 103 104 static void *fdt_wrapper_create_node(const void *devp, const char *name) 105 { 106 int offset; 107 108 offset = fdt_add_subnode(fdt, devp_offset(devp), name); 109 if (offset == -FDT_ERR_NOSPACE) { 110 expand_buf(strlen(name) + 16); 111 offset = fdt_add_subnode(fdt, devp_offset(devp), name); 112 } 113 114 return offset_devp(offset); 115 } 116 117 static void *fdt_wrapper_find_node_by_prop_value(const void *prev, 118 const char *name, 119 const char *val, 120 int len) 121 { 122 int offset = fdt_node_offset_by_prop_value(fdt, devp_offset_find(prev), 123 name, val, len); 124 return offset_devp(offset); 125 } 126 127 static void *fdt_wrapper_find_node_by_compatible(const void *prev, 128 const char *val) 129 { 130 int offset = fdt_node_offset_by_compatible(fdt, devp_offset_find(prev), 131 val); 132 return offset_devp(offset); 133 } 134 135 static char *fdt_wrapper_get_path(const void *devp, char *buf, int len) 136 { 137 int rc; 138 139 rc = fdt_get_path(fdt, devp_offset(devp), buf, len); 140 if (check_err(rc)) 141 return NULL; 142 return buf; 143 } 144 145 static unsigned long fdt_wrapper_finalize(void) 146 { 147 int rc; 148 149 rc = fdt_pack(fdt); 150 if (rc != 0) 151 fatal("Couldn't pack flat tree: %s\n\r", 152 fdt_strerror(rc)); 153 return (unsigned long)fdt; 154 } 155 156 void fdt_init(void *blob) 157 { 158 int err; 159 int bufsize; 160 161 dt_ops.finddevice = fdt_wrapper_finddevice; 162 dt_ops.getprop = fdt_wrapper_getprop; 163 dt_ops.setprop = fdt_wrapper_setprop; 164 dt_ops.get_parent = fdt_wrapper_get_parent; 165 dt_ops.create_node = fdt_wrapper_create_node; 166 dt_ops.find_node_by_prop_value = fdt_wrapper_find_node_by_prop_value; 167 dt_ops.find_node_by_compatible = fdt_wrapper_find_node_by_compatible; 168 dt_ops.del_node = fdt_wrapper_del_node; 169 dt_ops.get_path = fdt_wrapper_get_path; 170 dt_ops.finalize = fdt_wrapper_finalize; 171 172 /* Make sure the dt blob is the right version and so forth */ 173 fdt = blob; 174 bufsize = fdt_totalsize(fdt) + EXPAND_GRANULARITY; 175 buf = malloc(bufsize); 176 if(!buf) 177 fatal("malloc failed. can't relocate the device tree\n\r"); 178 179 err = fdt_open_into(fdt, buf, bufsize); 180 181 if (err != 0) 182 fatal("fdt_init(): %s\n\r", fdt_strerror(err)); 183 184 fdt = buf; 185 } 186