1 /* 2 * (C) Copyright 2007 3 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 #include <common.h> 25 #include <linux/ctype.h> 26 #include <linux/types.h> 27 28 #ifdef CONFIG_OF_LIBFDT 29 30 #include <asm/global_data.h> 31 #include <fdt.h> 32 #include <libfdt.h> 33 #include <fdt_support.h> 34 35 /* 36 * Global data (for the gd->bd) 37 */ 38 DECLARE_GLOBAL_DATA_PTR; 39 40 /* 41 * fdt points to our working device tree. 42 */ 43 struct fdt_header *fdt; 44 45 /********************************************************************/ 46 47 /** 48 * fdt_find_and_setprop: Find a node and set it's property 49 * 50 * @fdt: ptr to device tree 51 * @node: path of node 52 * @prop: property name 53 * @val: ptr to new value 54 * @len: length of new property value 55 * @create: flag to create the property if it doesn't exist 56 * 57 * Convenience function to directly set a property given the path to the node. 58 */ 59 int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, 60 const void *val, int len, int create) 61 { 62 int nodeoff = fdt_find_node_by_path(fdt, node); 63 64 if (nodeoff < 0) 65 return nodeoff; 66 67 if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL)) 68 return 0; /* create flag not set; so exit quietly */ 69 70 return fdt_setprop(fdt, nodeoff, prop, val, len); 71 } 72 73 int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) 74 { 75 int nodeoffset; 76 int err; 77 u32 tmp; /* used to set 32 bit integer properties */ 78 char *str; /* used to set string properties */ 79 80 err = fdt_check_header(fdt); 81 if (err < 0) { 82 printf("fdt_chosen: %s\n", fdt_strerror(err)); 83 return err; 84 } 85 86 if (initrd_start && initrd_end) { 87 struct fdt_reserve_entry re; 88 int used; 89 int total; 90 int j; 91 92 err = fdt_num_reservemap(fdt, &used, &total); 93 if (err < 0) { 94 printf("fdt_chosen: %s\n", fdt_strerror(err)); 95 return err; 96 } 97 if (used >= total) { 98 printf("WARNING: " 99 "no room in the reserved map (%d of %d)\n", 100 used, total); 101 return -1; 102 } 103 /* 104 * Look for an existing entry and update it. If we don't find 105 * the entry, we will j be the next available slot. 106 */ 107 for (j = 0; j < used; j++) { 108 err = fdt_get_reservemap(fdt, j, &re); 109 if (re.address == initrd_start) { 110 break; 111 } 112 } 113 err = fdt_replace_reservemap_entry(fdt, j, 114 initrd_start, initrd_end - initrd_start + 1); 115 if (err < 0) { 116 printf("fdt_chosen: %s\n", fdt_strerror(err)); 117 return err; 118 } 119 } 120 121 /* 122 * Find the "chosen" node. 123 */ 124 nodeoffset = fdt_find_node_by_path (fdt, "/chosen"); 125 126 /* 127 * If we have a "chosen" node already the "force the writing" 128 * is not set, our job is done. 129 */ 130 if ((nodeoffset >= 0) && !force) 131 return 0; 132 133 /* 134 * No "chosen" node in the blob: create it. 135 */ 136 if (nodeoffset < 0) { 137 /* 138 * Create a new node "/chosen" (offset 0 is root level) 139 */ 140 nodeoffset = fdt_add_subnode(fdt, 0, "chosen"); 141 if (nodeoffset < 0) { 142 printf("WARNING: could not create /chosen %s.\n", 143 fdt_strerror(nodeoffset)); 144 return nodeoffset; 145 } 146 } 147 148 /* 149 * Update pre-existing properties, create them if non-existant. 150 */ 151 str = getenv("bootargs"); 152 if (str != NULL) { 153 err = fdt_setprop(fdt, nodeoffset, 154 "bootargs", str, strlen(str)+1); 155 if (err < 0) 156 printf("WARNING: could not set bootargs %s.\n", 157 fdt_strerror(err)); 158 } 159 if (initrd_start && initrd_end) { 160 tmp = __cpu_to_be32(initrd_start); 161 err = fdt_setprop(fdt, nodeoffset, 162 "linux,initrd-start", &tmp, sizeof(tmp)); 163 if (err < 0) 164 printf("WARNING: " 165 "could not set linux,initrd-start %s.\n", 166 fdt_strerror(err)); 167 tmp = __cpu_to_be32(initrd_end); 168 err = fdt_setprop(fdt, nodeoffset, 169 "linux,initrd-end", &tmp, sizeof(tmp)); 170 if (err < 0) 171 printf("WARNING: could not set linux,initrd-end %s.\n", 172 fdt_strerror(err)); 173 } 174 #ifdef OF_STDOUT_PATH 175 err = fdt_setprop(fdt, nodeoffset, 176 "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1); 177 if (err < 0) 178 printf("WARNING: could not set linux,stdout-path %s.\n", 179 fdt_strerror(err)); 180 #endif 181 182 return err; 183 } 184 185 /********************************************************************/ 186 187 #ifdef CONFIG_OF_HAS_UBOOT_ENV 188 189 /* Function that returns a character from the environment */ 190 extern uchar(*env_get_char) (int); 191 192 193 int fdt_env(void *fdt) 194 { 195 int nodeoffset; 196 int err; 197 int k, nxt; 198 int i; 199 static char tmpenv[256]; 200 201 err = fdt_check_header(fdt); 202 if (err < 0) { 203 printf("fdt_env: %s\n", fdt_strerror(err)); 204 return err; 205 } 206 207 /* 208 * See if we already have a "u-boot-env" node, delete it if so. 209 * Then create a new empty node. 210 */ 211 nodeoffset = fdt_find_node_by_path (fdt, "/u-boot-env"); 212 if (nodeoffset >= 0) { 213 err = fdt_del_node(fdt, nodeoffset); 214 if (err < 0) { 215 printf("fdt_env: %s\n", fdt_strerror(err)); 216 return err; 217 } 218 } 219 /* 220 * Create a new node "/u-boot-env" (offset 0 is root level) 221 */ 222 nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env"); 223 if (nodeoffset < 0) { 224 printf("WARNING: could not create /u-boot-env %s.\n", 225 fdt_strerror(nodeoffset)); 226 return nodeoffset; 227 } 228 229 for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { 230 char *s, *lval, *rval; 231 232 /* 233 * Find the end of the name=definition 234 */ 235 for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) 236 ; 237 s = tmpenv; 238 for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k) 239 *s++ = env_get_char(k); 240 *s++ = '\0'; 241 lval = tmpenv; 242 /* 243 * Find the first '=': it separates the name from the value 244 */ 245 s = strchr(tmpenv, '='); 246 if (s != NULL) { 247 *s++ = '\0'; 248 rval = s; 249 } else 250 continue; 251 err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1); 252 if (err < 0) { 253 printf("WARNING: could not set %s %s.\n", 254 lval, fdt_strerror(err)); 255 return err; 256 } 257 } 258 return 0; 259 } 260 #endif /* ifdef CONFIG_OF_HAS_UBOOT_ENV */ 261 262 /********************************************************************/ 263 264 #ifdef CONFIG_OF_HAS_BD_T 265 266 #define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) } 267 268 static const struct { 269 const char *name; 270 int offset; 271 } bd_map[] = { 272 BDM(memstart), 273 BDM(memsize), 274 BDM(flashstart), 275 BDM(flashsize), 276 BDM(flashoffset), 277 BDM(sramstart), 278 BDM(sramsize), 279 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \ 280 || defined(CONFIG_E500) 281 BDM(immr_base), 282 #endif 283 #if defined(CONFIG_MPC5xxx) 284 BDM(mbar_base), 285 #endif 286 #if defined(CONFIG_MPC83XX) 287 BDM(immrbar), 288 #endif 289 #if defined(CONFIG_MPC8220) 290 BDM(mbar_base), 291 BDM(inpfreq), 292 BDM(pcifreq), 293 BDM(pevfreq), 294 BDM(flbfreq), 295 BDM(vcofreq), 296 #endif 297 BDM(bootflags), 298 BDM(ip_addr), 299 BDM(intfreq), 300 BDM(busfreq), 301 #ifdef CONFIG_CPM2 302 BDM(cpmfreq), 303 BDM(brgfreq), 304 BDM(sccfreq), 305 BDM(vco), 306 #endif 307 #if defined(CONFIG_MPC5xxx) 308 BDM(ipbfreq), 309 BDM(pcifreq), 310 #endif 311 BDM(baudrate), 312 }; 313 314 315 int fdt_bd_t(void *fdt) 316 { 317 bd_t *bd = gd->bd; 318 int nodeoffset; 319 int err; 320 u32 tmp; /* used to set 32 bit integer properties */ 321 int i; 322 323 err = fdt_check_header(fdt); 324 if (err < 0) { 325 printf("fdt_bd_t: %s\n", fdt_strerror(err)); 326 return err; 327 } 328 329 /* 330 * See if we already have a "bd_t" node, delete it if so. 331 * Then create a new empty node. 332 */ 333 nodeoffset = fdt_find_node_by_path (fdt, "/bd_t"); 334 if (nodeoffset >= 0) { 335 err = fdt_del_node(fdt, nodeoffset); 336 if (err < 0) { 337 printf("fdt_bd_t: %s\n", fdt_strerror(err)); 338 return err; 339 } 340 } 341 /* 342 * Create a new node "/bd_t" (offset 0 is root level) 343 */ 344 nodeoffset = fdt_add_subnode(fdt, 0, "bd_t"); 345 if (nodeoffset < 0) { 346 printf("WARNING: could not create /bd_t %s.\n", 347 fdt_strerror(nodeoffset)); 348 printf("fdt_bd_t: %s\n", fdt_strerror(nodeoffset)); 349 return nodeoffset; 350 } 351 /* 352 * Use the string/pointer structure to create the entries... 353 */ 354 for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) { 355 tmp = cpu_to_be32(getenv("bootargs")); 356 err = fdt_setprop(fdt, nodeoffset, 357 bd_map[i].name, &tmp, sizeof(tmp)); 358 if (err < 0) 359 printf("WARNING: could not set %s %s.\n", 360 bd_map[i].name, fdt_strerror(err)); 361 } 362 /* 363 * Add a couple of oddball entries... 364 */ 365 err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6); 366 if (err < 0) 367 printf("WARNING: could not set enetaddr %s.\n", 368 fdt_strerror(err)); 369 err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4); 370 if (err < 0) 371 printf("WARNING: could not set ethspeed %s.\n", 372 fdt_strerror(err)); 373 return 0; 374 } 375 #endif /* ifdef CONFIG_OF_HAS_BD_T */ 376 377 void do_fixup_by_path(void *fdt, const char *path, const char *prop, 378 const void *val, int len, int create) 379 { 380 #if defined(DEBUG) 381 int i; 382 debug("Updating property '%s/%s' = ", node, prop); 383 for (i = 0; i < len; i++) 384 debug(" %.2x", *(u8*)(val+i)); 385 debug("\n"); 386 #endif 387 int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create); 388 if (rc) 389 printf("Unable to update property %s:%s, err=%s\n", 390 path, prop, fdt_strerror(rc)); 391 } 392 393 void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop, 394 u32 val, int create) 395 { 396 val = cpu_to_fdt32(val); 397 do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create); 398 } 399 400 #endif /* CONFIG_OF_LIBFDT */ 401