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