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