164dbbd40SGerald Van Baren /* 264dbbd40SGerald Van Baren * (C) Copyright 2007 364dbbd40SGerald Van Baren * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com 464dbbd40SGerald Van Baren * 564dbbd40SGerald Van Baren * See file CREDITS for list of people who contributed to this 664dbbd40SGerald Van Baren * project. 764dbbd40SGerald Van Baren * 864dbbd40SGerald Van Baren * This program is free software; you can redistribute it and/or 964dbbd40SGerald Van Baren * modify it under the terms of the GNU General Public License as 1064dbbd40SGerald Van Baren * published by the Free Software Foundation; either version 2 of 1164dbbd40SGerald Van Baren * the License, or (at your option) any later version. 1264dbbd40SGerald Van Baren * 1364dbbd40SGerald Van Baren * This program is distributed in the hope that it will be useful, 1464dbbd40SGerald Van Baren * but WITHOUT ANY WARRANTY; without even the implied warranty of 1564dbbd40SGerald Van Baren * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1664dbbd40SGerald Van Baren * GNU General Public License for more details. 1764dbbd40SGerald Van Baren * 1864dbbd40SGerald Van Baren * You should have received a copy of the GNU General Public License 1964dbbd40SGerald Van Baren * along with this program; if not, write to the Free Software 2064dbbd40SGerald Van Baren * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 2164dbbd40SGerald Van Baren * MA 02111-1307 USA 2264dbbd40SGerald Van Baren */ 2364dbbd40SGerald Van Baren 2464dbbd40SGerald Van Baren #include <common.h> 2564dbbd40SGerald Van Baren #include <linux/ctype.h> 2664dbbd40SGerald Van Baren #include <linux/types.h> 2764dbbd40SGerald Van Baren 2864dbbd40SGerald Van Baren #ifdef CONFIG_OF_LIBFDT 2964dbbd40SGerald Van Baren 3064dbbd40SGerald Van Baren #include <asm/global_data.h> 3164dbbd40SGerald Van Baren #include <fdt.h> 3264dbbd40SGerald Van Baren #include <libfdt.h> 3364dbbd40SGerald Van Baren #include <fdt_support.h> 3464dbbd40SGerald Van Baren 3564dbbd40SGerald Van Baren /* 3664dbbd40SGerald Van Baren * Global data (for the gd->bd) 3764dbbd40SGerald Van Baren */ 3864dbbd40SGerald Van Baren DECLARE_GLOBAL_DATA_PTR; 3964dbbd40SGerald Van Baren 40bb930e76SGerald Van Baren /* 41bb930e76SGerald Van Baren * fdt points to our working device tree. 42bb930e76SGerald Van Baren */ 43bb930e76SGerald Van Baren struct fdt_header *fdt; 44bb930e76SGerald Van Baren 4564dbbd40SGerald Van Baren /********************************************************************/ 4664dbbd40SGerald Van Baren 4764dbbd40SGerald Van Baren int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) 4864dbbd40SGerald Van Baren { 4964dbbd40SGerald Van Baren bd_t *bd = gd->bd; 5064dbbd40SGerald Van Baren int nodeoffset; 5164dbbd40SGerald Van Baren int err; 5264dbbd40SGerald Van Baren u32 tmp; /* used to set 32 bit integer properties */ 5364dbbd40SGerald Van Baren char *str; /* used to set string properties */ 5464dbbd40SGerald Van Baren 5564dbbd40SGerald Van Baren err = fdt_check_header(fdt); 5664dbbd40SGerald Van Baren if (err < 0) { 57*5fe6be62SGerald Van Baren printf("fdt_chosen: %s\n", fdt_strerror(err)); 5864dbbd40SGerald Van Baren return err; 5964dbbd40SGerald Van Baren } 6064dbbd40SGerald Van Baren 6164dbbd40SGerald Van Baren if (initrd_start && initrd_end) { 627651f8bdSGerald Van Baren struct fdt_reserve_entry re; 63c28abb9cSGerald Van Baren int used; 64c28abb9cSGerald Van Baren int total; 65c28abb9cSGerald Van Baren int j; 66c28abb9cSGerald Van Baren 67c28abb9cSGerald Van Baren err = fdt_num_reservemap(fdt, &used, &total); 68c28abb9cSGerald Van Baren if (err < 0) { 69*5fe6be62SGerald Van Baren printf("fdt_chosen: %s\n", fdt_strerror(err)); 70c28abb9cSGerald Van Baren return err; 71c28abb9cSGerald Van Baren } 72c28abb9cSGerald Van Baren if (used >= total) { 73*5fe6be62SGerald Van Baren printf("WARNING: " 7435ec398fSGerald Van Baren "no room in the reserved map (%d of %d)\n", 75c28abb9cSGerald Van Baren used, total); 76c28abb9cSGerald Van Baren return -1; 77c28abb9cSGerald Van Baren } 78c28abb9cSGerald Van Baren /* 79c28abb9cSGerald Van Baren * Look for an existing entry and update it. If we don't find 80c28abb9cSGerald Van Baren * the entry, we will j be the next available slot. 81c28abb9cSGerald Van Baren */ 82c28abb9cSGerald Van Baren for (j = 0; j < used; j++) { 83c28abb9cSGerald Van Baren err = fdt_get_reservemap(fdt, j, &re); 847651f8bdSGerald Van Baren if (re.address == initrd_start) { 85c28abb9cSGerald Van Baren break; 86c28abb9cSGerald Van Baren } 87c28abb9cSGerald Van Baren } 88c28abb9cSGerald Van Baren err = fdt_replace_reservemap_entry(fdt, j, 8964dbbd40SGerald Van Baren initrd_start, initrd_end - initrd_start + 1); 9064dbbd40SGerald Van Baren if (err < 0) { 91*5fe6be62SGerald Van Baren printf("fdt_chosen: %s\n", fdt_strerror(err)); 9264dbbd40SGerald Van Baren return err; 9364dbbd40SGerald Van Baren } 9464dbbd40SGerald Van Baren } 9564dbbd40SGerald Van Baren 9664dbbd40SGerald Van Baren /* 9764dbbd40SGerald Van Baren * Find the "chosen" node. 9864dbbd40SGerald Van Baren */ 991a861169SGerald Van Baren nodeoffset = fdt_find_node_by_path (fdt, "/chosen"); 10064dbbd40SGerald Van Baren 10164dbbd40SGerald Van Baren /* 10264dbbd40SGerald Van Baren * If we have a "chosen" node already the "force the writing" 10364dbbd40SGerald Van Baren * is not set, our job is done. 10464dbbd40SGerald Van Baren */ 10564dbbd40SGerald Van Baren if ((nodeoffset >= 0) && !force) 10664dbbd40SGerald Van Baren return 0; 10764dbbd40SGerald Van Baren 10864dbbd40SGerald Van Baren /* 10964dbbd40SGerald Van Baren * No "chosen" node in the blob: create it. 11064dbbd40SGerald Van Baren */ 11164dbbd40SGerald Van Baren if (nodeoffset < 0) { 11264dbbd40SGerald Van Baren /* 11364dbbd40SGerald Van Baren * Create a new node "/chosen" (offset 0 is root level) 11464dbbd40SGerald Van Baren */ 11564dbbd40SGerald Van Baren nodeoffset = fdt_add_subnode(fdt, 0, "chosen"); 11664dbbd40SGerald Van Baren if (nodeoffset < 0) { 117*5fe6be62SGerald Van Baren printf("WARNING: could not create /chosen %s.\n", 11835ec398fSGerald Van Baren fdt_strerror(nodeoffset)); 11964dbbd40SGerald Van Baren return nodeoffset; 12064dbbd40SGerald Van Baren } 12164dbbd40SGerald Van Baren } 12264dbbd40SGerald Van Baren 12364dbbd40SGerald Van Baren /* 12464dbbd40SGerald Van Baren * Update pre-existing properties, create them if non-existant. 12564dbbd40SGerald Van Baren */ 12664dbbd40SGerald Van Baren str = getenv("bootargs"); 12764dbbd40SGerald Van Baren if (str != NULL) { 12835ec398fSGerald Van Baren err = fdt_setprop(fdt, nodeoffset, 12935ec398fSGerald Van Baren "bootargs", str, strlen(str)+1); 13064dbbd40SGerald Van Baren if (err < 0) 131*5fe6be62SGerald Van Baren printf("WARNING: could not set bootargs %s.\n", 13235ec398fSGerald Van Baren fdt_strerror(err)); 13364dbbd40SGerald Van Baren } 13464dbbd40SGerald Van Baren if (initrd_start && initrd_end) { 13564dbbd40SGerald Van Baren tmp = __cpu_to_be32(initrd_start); 13635ec398fSGerald Van Baren err = fdt_setprop(fdt, nodeoffset, 13735ec398fSGerald Van Baren "linux,initrd-start", &tmp, sizeof(tmp)); 13864dbbd40SGerald Van Baren if (err < 0) 139*5fe6be62SGerald Van Baren printf("WARNING: " 140*5fe6be62SGerald Van Baren "could not set linux,initrd-start %s.\n", 14135ec398fSGerald Van Baren fdt_strerror(err)); 14264dbbd40SGerald Van Baren tmp = __cpu_to_be32(initrd_end); 14335ec398fSGerald Van Baren err = fdt_setprop(fdt, nodeoffset, 14435ec398fSGerald Van Baren "linux,initrd-end", &tmp, sizeof(tmp)); 14564dbbd40SGerald Van Baren if (err < 0) 146*5fe6be62SGerald Van Baren printf("WARNING: could not set linux,initrd-end %s.\n", 14735ec398fSGerald Van Baren fdt_strerror(err)); 14864dbbd40SGerald Van Baren } 14964dbbd40SGerald Van Baren #ifdef OF_STDOUT_PATH 15035ec398fSGerald Van Baren err = fdt_setprop(fdt, nodeoffset, 15135ec398fSGerald Van Baren "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1); 15264dbbd40SGerald Van Baren if (err < 0) 153*5fe6be62SGerald Van Baren printf("WARNING: could not set linux,stdout-path %s.\n", 15435ec398fSGerald Van Baren fdt_strerror(err)); 15564dbbd40SGerald Van Baren #endif 15664dbbd40SGerald Van Baren 15764dbbd40SGerald Van Baren return err; 15864dbbd40SGerald Van Baren } 15964dbbd40SGerald Van Baren 16064dbbd40SGerald Van Baren /********************************************************************/ 16164dbbd40SGerald Van Baren 16264dbbd40SGerald Van Baren #ifdef CONFIG_OF_HAS_UBOOT_ENV 16364dbbd40SGerald Van Baren 16464dbbd40SGerald Van Baren /* Function that returns a character from the environment */ 16564dbbd40SGerald Van Baren extern uchar(*env_get_char) (int); 16664dbbd40SGerald Van Baren 16764dbbd40SGerald Van Baren 16864dbbd40SGerald Van Baren int fdt_env(void *fdt) 16964dbbd40SGerald Van Baren { 17064dbbd40SGerald Van Baren int nodeoffset; 17164dbbd40SGerald Van Baren int err; 17264dbbd40SGerald Van Baren int k, nxt; 17364dbbd40SGerald Van Baren int i; 17464dbbd40SGerald Van Baren static char tmpenv[256]; 17564dbbd40SGerald Van Baren 17664dbbd40SGerald Van Baren err = fdt_check_header(fdt); 17764dbbd40SGerald Van Baren if (err < 0) { 178*5fe6be62SGerald Van Baren printf("fdt_env: %s\n", fdt_strerror(err)); 17964dbbd40SGerald Van Baren return err; 18064dbbd40SGerald Van Baren } 18164dbbd40SGerald Van Baren 18264dbbd40SGerald Van Baren /* 18364dbbd40SGerald Van Baren * See if we already have a "u-boot-env" node, delete it if so. 18464dbbd40SGerald Van Baren * Then create a new empty node. 18564dbbd40SGerald Van Baren */ 1861a861169SGerald Van Baren nodeoffset = fdt_find_node_by_path (fdt, "/u-boot-env"); 18764dbbd40SGerald Van Baren if (nodeoffset >= 0) { 18864dbbd40SGerald Van Baren err = fdt_del_node(fdt, nodeoffset); 18964dbbd40SGerald Van Baren if (err < 0) { 190*5fe6be62SGerald Van Baren printf("fdt_env: %s\n", fdt_strerror(err)); 19164dbbd40SGerald Van Baren return err; 19264dbbd40SGerald Van Baren } 19364dbbd40SGerald Van Baren } 19464dbbd40SGerald Van Baren /* 19564dbbd40SGerald Van Baren * Create a new node "/u-boot-env" (offset 0 is root level) 19664dbbd40SGerald Van Baren */ 19764dbbd40SGerald Van Baren nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env"); 19864dbbd40SGerald Van Baren if (nodeoffset < 0) { 199*5fe6be62SGerald Van Baren printf("WARNING: could not create /u-boot-env %s.\n", 20035ec398fSGerald Van Baren fdt_strerror(nodeoffset)); 20164dbbd40SGerald Van Baren return nodeoffset; 20264dbbd40SGerald Van Baren } 20364dbbd40SGerald Van Baren 20464dbbd40SGerald Van Baren for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { 20564dbbd40SGerald Van Baren char *s, *lval, *rval; 20664dbbd40SGerald Van Baren 20764dbbd40SGerald Van Baren /* 20864dbbd40SGerald Van Baren * Find the end of the name=definition 20964dbbd40SGerald Van Baren */ 21064dbbd40SGerald Van Baren for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) 21164dbbd40SGerald Van Baren ; 21264dbbd40SGerald Van Baren s = tmpenv; 21364dbbd40SGerald Van Baren for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k) 21464dbbd40SGerald Van Baren *s++ = env_get_char(k); 21564dbbd40SGerald Van Baren *s++ = '\0'; 21664dbbd40SGerald Van Baren lval = tmpenv; 21764dbbd40SGerald Van Baren /* 21864dbbd40SGerald Van Baren * Find the first '=': it separates the name from the value 21964dbbd40SGerald Van Baren */ 22064dbbd40SGerald Van Baren s = strchr(tmpenv, '='); 22164dbbd40SGerald Van Baren if (s != NULL) { 22264dbbd40SGerald Van Baren *s++ = '\0'; 22364dbbd40SGerald Van Baren rval = s; 22464dbbd40SGerald Van Baren } else 22564dbbd40SGerald Van Baren continue; 22664dbbd40SGerald Van Baren err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1); 22764dbbd40SGerald Van Baren if (err < 0) { 228*5fe6be62SGerald Van Baren printf("WARNING: could not set %s %s.\n", 22935ec398fSGerald Van Baren lval, fdt_strerror(err)); 23064dbbd40SGerald Van Baren return err; 23164dbbd40SGerald Van Baren } 23264dbbd40SGerald Van Baren } 23364dbbd40SGerald Van Baren return 0; 23464dbbd40SGerald Van Baren } 235c28abb9cSGerald Van Baren #endif /* ifdef CONFIG_OF_HAS_UBOOT_ENV */ 23664dbbd40SGerald Van Baren 23764dbbd40SGerald Van Baren /********************************************************************/ 23864dbbd40SGerald Van Baren 23964dbbd40SGerald Van Baren #ifdef CONFIG_OF_HAS_BD_T 24064dbbd40SGerald Van Baren 24164dbbd40SGerald Van Baren #define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) } 24264dbbd40SGerald Van Baren 24364dbbd40SGerald Van Baren static const struct { 24464dbbd40SGerald Van Baren const char *name; 24564dbbd40SGerald Van Baren int offset; 24664dbbd40SGerald Van Baren } bd_map[] = { 24764dbbd40SGerald Van Baren BDM(memstart), 24864dbbd40SGerald Van Baren BDM(memsize), 24964dbbd40SGerald Van Baren BDM(flashstart), 25064dbbd40SGerald Van Baren BDM(flashsize), 25164dbbd40SGerald Van Baren BDM(flashoffset), 25264dbbd40SGerald Van Baren BDM(sramstart), 25364dbbd40SGerald Van Baren BDM(sramsize), 25464dbbd40SGerald Van Baren #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \ 25564dbbd40SGerald Van Baren || defined(CONFIG_E500) 25664dbbd40SGerald Van Baren BDM(immr_base), 25764dbbd40SGerald Van Baren #endif 25864dbbd40SGerald Van Baren #if defined(CONFIG_MPC5xxx) 25964dbbd40SGerald Van Baren BDM(mbar_base), 26064dbbd40SGerald Van Baren #endif 26164dbbd40SGerald Van Baren #if defined(CONFIG_MPC83XX) 26264dbbd40SGerald Van Baren BDM(immrbar), 26364dbbd40SGerald Van Baren #endif 26464dbbd40SGerald Van Baren #if defined(CONFIG_MPC8220) 26564dbbd40SGerald Van Baren BDM(mbar_base), 26664dbbd40SGerald Van Baren BDM(inpfreq), 26764dbbd40SGerald Van Baren BDM(pcifreq), 26864dbbd40SGerald Van Baren BDM(pevfreq), 26964dbbd40SGerald Van Baren BDM(flbfreq), 27064dbbd40SGerald Van Baren BDM(vcofreq), 27164dbbd40SGerald Van Baren #endif 27264dbbd40SGerald Van Baren BDM(bootflags), 27364dbbd40SGerald Van Baren BDM(ip_addr), 27464dbbd40SGerald Van Baren BDM(intfreq), 27564dbbd40SGerald Van Baren BDM(busfreq), 27664dbbd40SGerald Van Baren #ifdef CONFIG_CPM2 27764dbbd40SGerald Van Baren BDM(cpmfreq), 27864dbbd40SGerald Van Baren BDM(brgfreq), 27964dbbd40SGerald Van Baren BDM(sccfreq), 28064dbbd40SGerald Van Baren BDM(vco), 28164dbbd40SGerald Van Baren #endif 28264dbbd40SGerald Van Baren #if defined(CONFIG_MPC5xxx) 28364dbbd40SGerald Van Baren BDM(ipbfreq), 28464dbbd40SGerald Van Baren BDM(pcifreq), 28564dbbd40SGerald Van Baren #endif 28664dbbd40SGerald Van Baren BDM(baudrate), 28764dbbd40SGerald Van Baren }; 28864dbbd40SGerald Van Baren 28964dbbd40SGerald Van Baren 29064dbbd40SGerald Van Baren int fdt_bd_t(void *fdt) 29164dbbd40SGerald Van Baren { 29264dbbd40SGerald Van Baren bd_t *bd = gd->bd; 29364dbbd40SGerald Van Baren int nodeoffset; 29464dbbd40SGerald Van Baren int err; 29564dbbd40SGerald Van Baren u32 tmp; /* used to set 32 bit integer properties */ 29664dbbd40SGerald Van Baren int i; 29764dbbd40SGerald Van Baren 29864dbbd40SGerald Van Baren err = fdt_check_header(fdt); 29964dbbd40SGerald Van Baren if (err < 0) { 300*5fe6be62SGerald Van Baren printf("fdt_bd_t: %s\n", fdt_strerror(err)); 30164dbbd40SGerald Van Baren return err; 30264dbbd40SGerald Van Baren } 30364dbbd40SGerald Van Baren 30464dbbd40SGerald Van Baren /* 30564dbbd40SGerald Van Baren * See if we already have a "bd_t" node, delete it if so. 30664dbbd40SGerald Van Baren * Then create a new empty node. 30764dbbd40SGerald Van Baren */ 3081a861169SGerald Van Baren nodeoffset = fdt_find_node_by_path (fdt, "/bd_t"); 30964dbbd40SGerald Van Baren if (nodeoffset >= 0) { 31064dbbd40SGerald Van Baren err = fdt_del_node(fdt, nodeoffset); 31164dbbd40SGerald Van Baren if (err < 0) { 312*5fe6be62SGerald Van Baren printf("fdt_bd_t: %s\n", fdt_strerror(err)); 31364dbbd40SGerald Van Baren return err; 31464dbbd40SGerald Van Baren } 31564dbbd40SGerald Van Baren } 31664dbbd40SGerald Van Baren /* 31764dbbd40SGerald Van Baren * Create a new node "/bd_t" (offset 0 is root level) 31864dbbd40SGerald Van Baren */ 31964dbbd40SGerald Van Baren nodeoffset = fdt_add_subnode(fdt, 0, "bd_t"); 32064dbbd40SGerald Van Baren if (nodeoffset < 0) { 321*5fe6be62SGerald Van Baren printf("WARNING: could not create /bd_t %s.\n", 32235ec398fSGerald Van Baren fdt_strerror(nodeoffset)); 323*5fe6be62SGerald Van Baren printf("fdt_bd_t: %s\n", fdt_strerror(nodeoffset)); 32464dbbd40SGerald Van Baren return nodeoffset; 32564dbbd40SGerald Van Baren } 32664dbbd40SGerald Van Baren /* 32764dbbd40SGerald Van Baren * Use the string/pointer structure to create the entries... 32864dbbd40SGerald Van Baren */ 32964dbbd40SGerald Van Baren for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) { 33064dbbd40SGerald Van Baren tmp = cpu_to_be32(getenv("bootargs")); 33135ec398fSGerald Van Baren err = fdt_setprop(fdt, nodeoffset, 33235ec398fSGerald Van Baren bd_map[i].name, &tmp, sizeof(tmp)); 33364dbbd40SGerald Van Baren if (err < 0) 334*5fe6be62SGerald Van Baren printf("WARNING: could not set %s %s.\n", 33535ec398fSGerald Van Baren bd_map[i].name, fdt_strerror(err)); 33664dbbd40SGerald Van Baren } 33764dbbd40SGerald Van Baren /* 33864dbbd40SGerald Van Baren * Add a couple of oddball entries... 33964dbbd40SGerald Van Baren */ 34064dbbd40SGerald Van Baren err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6); 34164dbbd40SGerald Van Baren if (err < 0) 342*5fe6be62SGerald Van Baren printf("WARNING: could not set enetaddr %s.\n", 34335ec398fSGerald Van Baren fdt_strerror(err)); 34464dbbd40SGerald Van Baren err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4); 34564dbbd40SGerald Van Baren if (err < 0) 346*5fe6be62SGerald Van Baren printf("WARNING: could not set ethspeed %s.\n", 34735ec398fSGerald Van Baren fdt_strerror(err)); 34864dbbd40SGerald Van Baren return 0; 34964dbbd40SGerald Van Baren } 350c28abb9cSGerald Van Baren #endif /* ifdef CONFIG_OF_HAS_BD_T */ 35164dbbd40SGerald Van Baren 35264dbbd40SGerald Van Baren #endif /* CONFIG_OF_LIBFDT */ 353