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 #ifdef CONFIG_OF_BOARD_SETUP 36 void ft_board_setup(void *blob, bd_t *bd); 37 #endif 38 39 /* 40 * Global data (for the gd->bd) 41 */ 42 DECLARE_GLOBAL_DATA_PTR; 43 44 /* 45 * fdt points to our working device tree. 46 */ 47 struct fdt_header *fdt; 48 49 /********************************************************************/ 50 51 int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) 52 { 53 bd_t *bd = gd->bd; 54 int nodeoffset; 55 int err; 56 u32 tmp; /* used to set 32 bit integer properties */ 57 char *str; /* used to set string properties */ 58 59 err = fdt_check_header(fdt); 60 if (err < 0) { 61 printf("libfdt: %s\n", fdt_strerror(err)); 62 return err; 63 } 64 65 #ifdef CONFIG_OF_BOARD_SETUP 66 /* 67 * ft_board_setup() sets various board-specific properties to 68 * the proper values. 69 * 70 * STRICTLY SPEAKING, this is out of place, but it isn't clear 71 * where a better place would be. 72 */ 73 ft_board_setup(fdt, bd); 74 #endif 75 76 if (initrd_start && initrd_end) { 77 struct fdt_reserve_entry re; 78 int used; 79 int total; 80 int j; 81 82 err = fdt_num_reservemap(fdt, &used, &total); 83 if (err < 0) { 84 printf("libfdt: %s\n", fdt_strerror(err)); 85 return err; 86 } 87 if (used >= total) { 88 printf("WARNING fdt_chosen: " 89 "no room in the reserved map (%d of %d)\n", 90 used, total); 91 return -1; 92 } 93 /* 94 * Look for an existing entry and update it. If we don't find 95 * the entry, we will j be the next available slot. 96 */ 97 for (j = 0; j < used; j++) { 98 err = fdt_get_reservemap(fdt, j, &re); 99 if (re.address == initrd_start) { 100 break; 101 } 102 } 103 err = fdt_replace_reservemap_entry(fdt, j, 104 initrd_start, initrd_end - initrd_start + 1); 105 if (err < 0) { 106 printf("libfdt: %s\n", fdt_strerror(err)); 107 return err; 108 } 109 } 110 111 /* 112 * Find the "chosen" node. 113 */ 114 nodeoffset = fdt_find_node_by_path (fdt, "/chosen"); 115 116 /* 117 * If we have a "chosen" node already the "force the writing" 118 * is not set, our job is done. 119 */ 120 if ((nodeoffset >= 0) && !force) 121 return 0; 122 123 /* 124 * No "chosen" node in the blob: create it. 125 */ 126 if (nodeoffset < 0) { 127 /* 128 * Create a new node "/chosen" (offset 0 is root level) 129 */ 130 nodeoffset = fdt_add_subnode(fdt, 0, "chosen"); 131 if (nodeoffset < 0) { 132 printf("WARNING fdt_chosen: " 133 "could not create the \"/chosen node\" " 134 "(libfdt error %s).\n", 135 fdt_strerror(nodeoffset)); 136 return nodeoffset; 137 } 138 } 139 140 /* 141 * Update pre-existing properties, create them if non-existant. 142 */ 143 str = getenv("bootargs"); 144 if (str != NULL) { 145 err = fdt_setprop(fdt, nodeoffset, 146 "bootargs", str, strlen(str)+1); 147 if (err < 0) 148 printf("WARNING fdt_chosen: " 149 "could not set \"bootargs\" " 150 "(libfdt error %s).\n", 151 fdt_strerror(err)); 152 } 153 if (initrd_start && initrd_end) { 154 tmp = __cpu_to_be32(initrd_start); 155 err = fdt_setprop(fdt, nodeoffset, 156 "linux,initrd-start", &tmp, sizeof(tmp)); 157 if (err < 0) 158 printf("WARNING fdt_chosen: " 159 "could not set \"linux,initrd-start\" " 160 "(libfdt error %s).\n", 161 fdt_strerror(err)); 162 tmp = __cpu_to_be32(initrd_end); 163 err = fdt_setprop(fdt, nodeoffset, 164 "linux,initrd-end", &tmp, sizeof(tmp)); 165 if (err < 0) 166 printf("WARNING fdt_chosen: " 167 "could not set \"linux,initrd-end\" " 168 "(libfdt error %s).\n", 169 fdt_strerror(err)); 170 } 171 #ifdef OF_STDOUT_PATH 172 err = fdt_setprop(fdt, nodeoffset, 173 "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1); 174 if (err < 0) 175 printf("WARNING fdt_chosen: " 176 "could not set \"linux,stdout-path\" " 177 "(libfdt error %s).\n", 178 fdt_strerror(err)); 179 #endif 180 181 return err; 182 } 183 184 /********************************************************************/ 185 186 #ifdef CONFIG_OF_HAS_UBOOT_ENV 187 188 /* Function that returns a character from the environment */ 189 extern uchar(*env_get_char) (int); 190 191 192 int fdt_env(void *fdt) 193 { 194 int nodeoffset; 195 int err; 196 int k, nxt; 197 int i; 198 static char tmpenv[256]; 199 200 err = fdt_check_header(fdt); 201 if (err < 0) { 202 printf("libfdt: %s\n", fdt_strerror(err)); 203 return err; 204 } 205 206 /* 207 * See if we already have a "u-boot-env" node, delete it if so. 208 * Then create a new empty node. 209 */ 210 nodeoffset = fdt_find_node_by_path (fdt, "/u-boot-env"); 211 if (nodeoffset >= 0) { 212 err = fdt_del_node(fdt, nodeoffset); 213 if (err < 0) { 214 printf("libfdt: %s\n", fdt_strerror(err)); 215 return err; 216 } 217 } 218 /* 219 * Create a new node "/u-boot-env" (offset 0 is root level) 220 */ 221 nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env"); 222 if (nodeoffset < 0) { 223 printf("WARNING fdt_env: " 224 "could not create the \"/u-boot-env node\" " 225 "(libfdt error %s).\n", 226 fdt_strerror(nodeoffset)); 227 return nodeoffset; 228 } 229 230 for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { 231 char *s, *lval, *rval; 232 233 /* 234 * Find the end of the name=definition 235 */ 236 for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) 237 ; 238 s = tmpenv; 239 for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k) 240 *s++ = env_get_char(k); 241 *s++ = '\0'; 242 lval = tmpenv; 243 /* 244 * Find the first '=': it separates the name from the value 245 */ 246 s = strchr(tmpenv, '='); 247 if (s != NULL) { 248 *s++ = '\0'; 249 rval = s; 250 } else 251 continue; 252 err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1); 253 if (err < 0) { 254 printf("WARNING fdt_env: " 255 "could not set \"%s\" " 256 "(libfdt error %s).\n", 257 lval, fdt_strerror(err)); 258 return err; 259 } 260 } 261 return 0; 262 } 263 #endif /* ifdef CONFIG_OF_HAS_UBOOT_ENV */ 264 265 /********************************************************************/ 266 267 #ifdef CONFIG_OF_HAS_BD_T 268 269 #define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) } 270 271 static const struct { 272 const char *name; 273 int offset; 274 } bd_map[] = { 275 BDM(memstart), 276 BDM(memsize), 277 BDM(flashstart), 278 BDM(flashsize), 279 BDM(flashoffset), 280 BDM(sramstart), 281 BDM(sramsize), 282 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \ 283 || defined(CONFIG_E500) 284 BDM(immr_base), 285 #endif 286 #if defined(CONFIG_MPC5xxx) 287 BDM(mbar_base), 288 #endif 289 #if defined(CONFIG_MPC83XX) 290 BDM(immrbar), 291 #endif 292 #if defined(CONFIG_MPC8220) 293 BDM(mbar_base), 294 BDM(inpfreq), 295 BDM(pcifreq), 296 BDM(pevfreq), 297 BDM(flbfreq), 298 BDM(vcofreq), 299 #endif 300 BDM(bootflags), 301 BDM(ip_addr), 302 BDM(intfreq), 303 BDM(busfreq), 304 #ifdef CONFIG_CPM2 305 BDM(cpmfreq), 306 BDM(brgfreq), 307 BDM(sccfreq), 308 BDM(vco), 309 #endif 310 #if defined(CONFIG_MPC5xxx) 311 BDM(ipbfreq), 312 BDM(pcifreq), 313 #endif 314 BDM(baudrate), 315 }; 316 317 318 int fdt_bd_t(void *fdt) 319 { 320 bd_t *bd = gd->bd; 321 int nodeoffset; 322 int err; 323 u32 tmp; /* used to set 32 bit integer properties */ 324 int i; 325 326 err = fdt_check_header(fdt); 327 if (err < 0) { 328 printf("libfdt: %s\n", fdt_strerror(err)); 329 return err; 330 } 331 332 /* 333 * See if we already have a "bd_t" node, delete it if so. 334 * Then create a new empty node. 335 */ 336 nodeoffset = fdt_find_node_by_path (fdt, "/bd_t"); 337 if (nodeoffset >= 0) { 338 err = fdt_del_node(fdt, nodeoffset); 339 if (err < 0) { 340 printf("libfdt: %s\n", fdt_strerror(err)); 341 return err; 342 } 343 } 344 /* 345 * Create a new node "/bd_t" (offset 0 is root level) 346 */ 347 nodeoffset = fdt_add_subnode(fdt, 0, "bd_t"); 348 if (nodeoffset < 0) { 349 printf("WARNING fdt_bd_t: " 350 "could not create the \"/bd_t node\" " 351 "(libfdt error %s).\n", 352 fdt_strerror(nodeoffset)); 353 printf("libfdt: %s\n", fdt_strerror(nodeoffset)); 354 return nodeoffset; 355 } 356 /* 357 * Use the string/pointer structure to create the entries... 358 */ 359 for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) { 360 tmp = cpu_to_be32(getenv("bootargs")); 361 err = fdt_setprop(fdt, nodeoffset, 362 bd_map[i].name, &tmp, sizeof(tmp)); 363 if (err < 0) 364 printf("WARNING fdt_bd_t: " 365 "could not set \"%s\" " 366 "(libfdt error %s).\n", 367 bd_map[i].name, fdt_strerror(err)); 368 } 369 /* 370 * Add a couple of oddball entries... 371 */ 372 err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6); 373 if (err < 0) 374 printf("WARNING fdt_bd_t: " 375 "could not set \"enetaddr\" " 376 "(libfdt error %s).\n", 377 fdt_strerror(err)); 378 err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4); 379 if (err < 0) 380 printf("WARNING fdt_bd_t: " 381 "could not set \"ethspeed\" " 382 "(libfdt error %s).\n", 383 fdt_strerror(err)); 384 return 0; 385 } 386 #endif /* ifdef CONFIG_OF_HAS_BD_T */ 387 388 #endif /* CONFIG_OF_LIBFDT */ 389