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 (%s).\n", 134 fdt_strerror(nodeoffset)); 135 return nodeoffset; 136 } 137 } 138 139 /* 140 * Update pre-existing properties, create them if non-existant. 141 */ 142 str = getenv("bootargs"); 143 if (str != NULL) { 144 err = fdt_setprop(fdt, nodeoffset, 145 "bootargs", str, strlen(str)+1); 146 if (err < 0) 147 printf("WARNING fdt_chosen: " 148 "could not set bootargs (%s).\n", 149 fdt_strerror(err)); 150 } 151 if (initrd_start && initrd_end) { 152 tmp = __cpu_to_be32(initrd_start); 153 err = fdt_setprop(fdt, nodeoffset, 154 "linux,initrd-start", &tmp, sizeof(tmp)); 155 if (err < 0) 156 printf("WARNING fdt_chosen: " 157 "could not set linux,initrd-start (%s).\n", 158 fdt_strerror(err)); 159 tmp = __cpu_to_be32(initrd_end); 160 err = fdt_setprop(fdt, nodeoffset, 161 "linux,initrd-end", &tmp, sizeof(tmp)); 162 if (err < 0) 163 printf("WARNING fdt_chosen: " 164 "could not set linux,initrd-end (%s).\n", 165 fdt_strerror(err)); 166 } 167 #ifdef OF_STDOUT_PATH 168 err = fdt_setprop(fdt, nodeoffset, 169 "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1); 170 if (err < 0) 171 printf("WARNING fdt_chosen: " 172 "could not set linux,stdout-path (%s).\n", 173 fdt_strerror(err)); 174 #endif 175 176 return err; 177 } 178 179 /********************************************************************/ 180 181 #ifdef CONFIG_OF_HAS_UBOOT_ENV 182 183 /* Function that returns a character from the environment */ 184 extern uchar(*env_get_char) (int); 185 186 187 int fdt_env(void *fdt) 188 { 189 int nodeoffset; 190 int err; 191 int k, nxt; 192 int i; 193 static char tmpenv[256]; 194 195 err = fdt_check_header(fdt); 196 if (err < 0) { 197 printf("libfdt: %s\n", fdt_strerror(err)); 198 return err; 199 } 200 201 /* 202 * See if we already have a "u-boot-env" node, delete it if so. 203 * Then create a new empty node. 204 */ 205 nodeoffset = fdt_find_node_by_path (fdt, "/u-boot-env"); 206 if (nodeoffset >= 0) { 207 err = fdt_del_node(fdt, nodeoffset); 208 if (err < 0) { 209 printf("libfdt: %s\n", fdt_strerror(err)); 210 return err; 211 } 212 } 213 /* 214 * Create a new node "/u-boot-env" (offset 0 is root level) 215 */ 216 nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env"); 217 if (nodeoffset < 0) { 218 printf("WARNING fdt_env: " 219 "could not create the /u-boot-env node (%s).\n", 220 fdt_strerror(nodeoffset)); 221 return nodeoffset; 222 } 223 224 for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { 225 char *s, *lval, *rval; 226 227 /* 228 * Find the end of the name=definition 229 */ 230 for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) 231 ; 232 s = tmpenv; 233 for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k) 234 *s++ = env_get_char(k); 235 *s++ = '\0'; 236 lval = tmpenv; 237 /* 238 * Find the first '=': it separates the name from the value 239 */ 240 s = strchr(tmpenv, '='); 241 if (s != NULL) { 242 *s++ = '\0'; 243 rval = s; 244 } else 245 continue; 246 err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1); 247 if (err < 0) { 248 printf("WARNING fdt_env: " 249 "could not set %s (%s).\n", 250 lval, fdt_strerror(err)); 251 return err; 252 } 253 } 254 return 0; 255 } 256 #endif /* ifdef CONFIG_OF_HAS_UBOOT_ENV */ 257 258 /********************************************************************/ 259 260 #ifdef CONFIG_OF_HAS_BD_T 261 262 #define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) } 263 264 static const struct { 265 const char *name; 266 int offset; 267 } bd_map[] = { 268 BDM(memstart), 269 BDM(memsize), 270 BDM(flashstart), 271 BDM(flashsize), 272 BDM(flashoffset), 273 BDM(sramstart), 274 BDM(sramsize), 275 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \ 276 || defined(CONFIG_E500) 277 BDM(immr_base), 278 #endif 279 #if defined(CONFIG_MPC5xxx) 280 BDM(mbar_base), 281 #endif 282 #if defined(CONFIG_MPC83XX) 283 BDM(immrbar), 284 #endif 285 #if defined(CONFIG_MPC8220) 286 BDM(mbar_base), 287 BDM(inpfreq), 288 BDM(pcifreq), 289 BDM(pevfreq), 290 BDM(flbfreq), 291 BDM(vcofreq), 292 #endif 293 BDM(bootflags), 294 BDM(ip_addr), 295 BDM(intfreq), 296 BDM(busfreq), 297 #ifdef CONFIG_CPM2 298 BDM(cpmfreq), 299 BDM(brgfreq), 300 BDM(sccfreq), 301 BDM(vco), 302 #endif 303 #if defined(CONFIG_MPC5xxx) 304 BDM(ipbfreq), 305 BDM(pcifreq), 306 #endif 307 BDM(baudrate), 308 }; 309 310 311 int fdt_bd_t(void *fdt) 312 { 313 bd_t *bd = gd->bd; 314 int nodeoffset; 315 int err; 316 u32 tmp; /* used to set 32 bit integer properties */ 317 int i; 318 319 err = fdt_check_header(fdt); 320 if (err < 0) { 321 printf("libfdt: %s\n", fdt_strerror(err)); 322 return err; 323 } 324 325 /* 326 * See if we already have a "bd_t" node, delete it if so. 327 * Then create a new empty node. 328 */ 329 nodeoffset = fdt_find_node_by_path (fdt, "/bd_t"); 330 if (nodeoffset >= 0) { 331 err = fdt_del_node(fdt, nodeoffset); 332 if (err < 0) { 333 printf("libfdt: %s\n", fdt_strerror(err)); 334 return err; 335 } 336 } 337 /* 338 * Create a new node "/bd_t" (offset 0 is root level) 339 */ 340 nodeoffset = fdt_add_subnode(fdt, 0, "bd_t"); 341 if (nodeoffset < 0) { 342 printf("WARNING fdt_bd_t: " 343 "could not create the /bd_t node (%s).\n", 344 fdt_strerror(nodeoffset)); 345 printf("libfdt: %s\n", fdt_strerror(nodeoffset)); 346 return nodeoffset; 347 } 348 /* 349 * Use the string/pointer structure to create the entries... 350 */ 351 for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) { 352 tmp = cpu_to_be32(getenv("bootargs")); 353 err = fdt_setprop(fdt, nodeoffset, 354 bd_map[i].name, &tmp, sizeof(tmp)); 355 if (err < 0) 356 printf("WARNING fdt_bd_t: " 357 "could not set %s (%s).\n", 358 bd_map[i].name, fdt_strerror(err)); 359 } 360 /* 361 * Add a couple of oddball entries... 362 */ 363 err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6); 364 if (err < 0) 365 printf("WARNING fdt_bd_t: " 366 "could not set enetaddr (%s).\n", 367 fdt_strerror(err)); 368 err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4); 369 if (err < 0) 370 printf("WARNING fdt_bd_t: " 371 "could not set ethspeed (%s).\n", 372 fdt_strerror(err)); 373 return 0; 374 } 375 #endif /* ifdef CONFIG_OF_HAS_BD_T */ 376 377 #endif /* CONFIG_OF_LIBFDT */ 378