From 64dbbd40c58349b64f43fd33dbb5ca0adb67d642 Mon Sep 17 00:00:00 2001 From: Gerald Van Baren Date: Fri, 6 Apr 2007 14:19:43 -0400 Subject: Moved fdt command support code to fdt_support.c ...in preparation for improving the bootm command's handling of fdt blobs. Also cleaned up some coding sloppiness. --- common/fdt_support.c | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 common/fdt_support.c (limited to 'common/fdt_support.c') diff --git a/common/fdt_support.c b/common/fdt_support.c new file mode 100644 index 0000000..14a4df5 --- /dev/null +++ b/common/fdt_support.c @@ -0,0 +1,323 @@ +/* + * (C) Copyright 2007 + * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +#ifdef CONFIG_OF_LIBFDT + +#include +#include +#include +#include + +/* + * Global data (for the gd->bd) + */ +DECLARE_GLOBAL_DATA_PTR; + + +/********************************************************************/ + +int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) +{ + bd_t *bd = gd->bd; + int nodeoffset; + int err; + u32 tmp; /* used to set 32 bit integer properties */ + char *str; /* used to set string properties */ + ulong clock; + + err = fdt_check_header(fdt); + if (err < 0) { + printf("libfdt: %s\n", fdt_strerror(err)); + return err; + } + +#warning "Don't double-add the reserved map" + if (initrd_start && initrd_end) { + err = fdt_add_reservemap_entry(fdt, + initrd_start, initrd_end - initrd_start + 1); + if (err < 0) { + printf("libfdt: %s\n", fdt_strerror(err)); + return err; + } + } + + /* + * Find the "chosen" node. + */ + nodeoffset = fdt_path_offset (fdt, "/chosen"); + + /* + * If we have a "chosen" node already the "force the writing" + * is not set, our job is done. + */ + if ((nodeoffset >= 0) && !force) + return 0; + + /* + * No "chosen" node in the blob: create it. + */ + if (nodeoffset < 0) { + /* + * Create a new node "/chosen" (offset 0 is root level) + */ + nodeoffset = fdt_add_subnode(fdt, 0, "chosen"); + if (nodeoffset < 0) { + printf("libfdt: %s\n", fdt_strerror(nodeoffset)); + return nodeoffset; + } + } + + /* + * Update pre-existing properties, create them if non-existant. + */ + str = getenv("bootargs"); + if (str != NULL) { + err = fdt_setprop(fdt, nodeoffset, "bootargs", str, strlen(str)+1); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + } + if (initrd_start && initrd_end) { + tmp = __cpu_to_be32(initrd_start); + err = fdt_setprop(fdt, nodeoffset, "linux,initrd-start", &tmp, sizeof(tmp)); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + tmp = __cpu_to_be32(initrd_end); + err = fdt_setprop(fdt, nodeoffset, "linux,initrd-end", &tmp, sizeof(tmp)); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + } +#ifdef OF_STDOUT_PATH + err = fdt_setprop(fdt, nodeoffset, "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); +#endif + + nodeoffset = fdt_path_offset (fdt, "/cpus"); + if (nodeoffset >= 0) { + clock = cpu_to_be32(bd->bi_intfreq); + err = fdt_setprop(fdt, nodeoffset, "clock-frequency", &clock, 4); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + } +#ifdef OF_TBCLK + nodeoffset = fdt_path_offset (fdt, "/cpus/" OF_CPU "/timebase-frequency"); + if (nodeoffset >= 0) { + clock = cpu_to_be32(OF_TBCLK); + err = fdt_setprop(fdt, nodeoffset, "clock-frequency", &clock, 4); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + } +#endif + return err; +} + +/********************************************************************/ + +#ifdef CONFIG_OF_HAS_UBOOT_ENV + +/* Function that returns a character from the environment */ +extern uchar(*env_get_char) (int); + + +int fdt_env(void *fdt) +{ + int nodeoffset; + int err; + int k, nxt; + int i; + static char tmpenv[256]; + + err = fdt_check_header(fdt); + if (err < 0) { + printf("libfdt: %s\n", fdt_strerror(err)); + return err; + } + + /* + * See if we already have a "u-boot-env" node, delete it if so. + * Then create a new empty node. + */ + nodeoffset = fdt_path_offset (fdt, "/u-boot-env"); + if (nodeoffset >= 0) { + err = fdt_del_node(fdt, nodeoffset); + if (err < 0) { + printf("libfdt: %s\n", fdt_strerror(err)); + return err; + } + } + /* + * Create a new node "/u-boot-env" (offset 0 is root level) + */ + nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env"); + if (nodeoffset < 0) { + printf("libfdt: %s\n", fdt_strerror(nodeoffset)); + return nodeoffset; + } + + for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { + char *s, *lval, *rval; + + /* + * Find the end of the name=definition + */ + for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) + ; + s = tmpenv; + for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k) + *s++ = env_get_char(k); + *s++ = '\0'; + lval = tmpenv; + /* + * Find the first '=': it separates the name from the value + */ + s = strchr(tmpenv, '='); + if (s != NULL) { + *s++ = '\0'; + rval = s; + } else + continue; + err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1); + if (err < 0) { + printf("libfdt: %s\n", lval, fdt_strerror(err)); + return err; + } + } + return 0; +} +#endif /* CONFIG_OF_HAS_UBOOT_ENV */ + +/********************************************************************/ + +#ifdef CONFIG_OF_HAS_BD_T + +#define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) } + +static const struct { + const char *name; + int offset; +} bd_map[] = { + BDM(memstart), + BDM(memsize), + BDM(flashstart), + BDM(flashsize), + BDM(flashoffset), + BDM(sramstart), + BDM(sramsize), +#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \ + || defined(CONFIG_E500) + BDM(immr_base), +#endif +#if defined(CONFIG_MPC5xxx) + BDM(mbar_base), +#endif +#if defined(CONFIG_MPC83XX) + BDM(immrbar), +#endif +#if defined(CONFIG_MPC8220) + BDM(mbar_base), + BDM(inpfreq), + BDM(pcifreq), + BDM(pevfreq), + BDM(flbfreq), + BDM(vcofreq), +#endif + BDM(bootflags), + BDM(ip_addr), + BDM(intfreq), + BDM(busfreq), +#ifdef CONFIG_CPM2 + BDM(cpmfreq), + BDM(brgfreq), + BDM(sccfreq), + BDM(vco), +#endif +#if defined(CONFIG_MPC5xxx) + BDM(ipbfreq), + BDM(pcifreq), +#endif + BDM(baudrate), +}; + + +int fdt_bd_t(void *fdt) +{ + bd_t *bd = gd->bd; + int nodeoffset; + int err; + u32 tmp; /* used to set 32 bit integer properties */ + int i; + + err = fdt_check_header(fdt); + if (err < 0) { + printf("libfdt: %s\n", fdt_strerror(err)); + return err; + } + + /* + * See if we already have a "bd_t" node, delete it if so. + * Then create a new empty node. + */ + nodeoffset = fdt_path_offset (fdt, "/bd_t"); + if (nodeoffset >= 0) { + err = fdt_del_node(fdt, nodeoffset); + if (err < 0) { + printf("libfdt: %s\n", fdt_strerror(err)); + return err; + } + } + /* + * Create a new node "/bd_t" (offset 0 is root level) + */ + nodeoffset = fdt_add_subnode(fdt, 0, "bd_t"); + if (nodeoffset < 0) { + printf("libfdt: %s\n", fdt_strerror(nodeoffset)); + return nodeoffset; + } + /* + * Use the string/pointer structure to create the entries... + */ + for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) { + tmp = cpu_to_be32(getenv("bootargs")); + err = fdt_setprop(fdt, nodeoffset, bd_map[i].name, &tmp, sizeof(tmp)); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + } + /* + * Add a couple of oddball entries... + */ + err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4); + if (err < 0) + printf("libfdt: %s\n", fdt_strerror(err)); + + return 0; +} +#endif /* CONFIG_OF_HAS_BD_T */ + +#endif /* CONFIG_OF_LIBFDT */ -- cgit v1.1 From c28abb9c614f65ce2096cc4a66fc886c77d0e5a4 Mon Sep 17 00:00:00 2001 From: Gerald Van Baren Date: Sat, 14 Apr 2007 22:51:24 -0400 Subject: Improve the bootm command for CONFIG_OF_LIBFDT In bootm, create the "/chosen" node only if it doesn't already exist (better matches the previous behavior). Update for proper reserved memory map handling for initrd. --- common/fdt_support.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'common/fdt_support.c') diff --git a/common/fdt_support.c b/common/fdt_support.c index 14a4df5..91b729f 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -55,9 +55,33 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) return err; } -#warning "Don't double-add the reserved map" if (initrd_start && initrd_end) { - err = fdt_add_reservemap_entry(fdt, + struct fdt_reserve_entry *re; + int used; + int total; + int j; + + err = fdt_num_reservemap(fdt, &used, &total); + if (err < 0) { + printf("libfdt: %s\n", fdt_strerror(err)); + return err; + } + if (used >= total) { + printf("fdt_chosen: no room in the reserved map (%d of %d)\n", + used, total); + return -1; + } + /* + * Look for an existing entry and update it. If we don't find + * the entry, we will j be the next available slot. + */ + for (j = 0; j < used; j++) { + err = fdt_get_reservemap(fdt, j, &re); + if (re->address == initrd_start) { + break; + } + } + err = fdt_replace_reservemap_entry(fdt, j, initrd_start, initrd_end - initrd_start + 1); if (err < 0) { printf("libfdt: %s\n", fdt_strerror(err)); @@ -202,13 +226,13 @@ int fdt_env(void *fdt) continue; err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1); if (err < 0) { - printf("libfdt: %s\n", lval, fdt_strerror(err)); + printf("libfdt: %s\n", fdt_strerror(err)); return err; } } return 0; } -#endif /* CONFIG_OF_HAS_UBOOT_ENV */ +#endif /* ifdef CONFIG_OF_HAS_UBOOT_ENV */ /********************************************************************/ @@ -318,6 +342,6 @@ int fdt_bd_t(void *fdt) return 0; } -#endif /* CONFIG_OF_HAS_BD_T */ +#endif /* ifdef CONFIG_OF_HAS_BD_T */ #endif /* CONFIG_OF_LIBFDT */ -- cgit v1.1 From 7651f8bdbba03bb0b4f241e2d2c4cb65b230bd56 Mon Sep 17 00:00:00 2001 From: Gerald Van Baren Date: Thu, 19 Apr 2007 23:14:39 -0400 Subject: Fix serious pointer bug with bootm and reserve map. What was suppose to be a stack variable was declared as a pointer, overwriting random memory. Also moved the libfdt.a requirement into the main Makefile. That is The U-Boot Way. --- common/fdt_support.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'common/fdt_support.c') diff --git a/common/fdt_support.c b/common/fdt_support.c index 91b729f..69099c4 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -56,7 +56,7 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) } if (initrd_start && initrd_end) { - struct fdt_reserve_entry *re; + struct fdt_reserve_entry re; int used; int total; int j; @@ -77,7 +77,7 @@ int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force) */ for (j = 0; j < used; j++) { err = fdt_get_reservemap(fdt, j, &re); - if (re->address == initrd_start) { + if (re.address == initrd_start) { break; } } -- cgit v1.1