diff options
-rw-r--r-- | board/mpc8360emds/mpc8360emds.c | 16 | ||||
-rw-r--r-- | common/Makefile | 2 | ||||
-rw-r--r-- | common/cmd_bootm.c | 58 | ||||
-rw-r--r-- | common/cmd_fdt.c | 301 | ||||
-rw-r--r-- | common/fdt_support.c | 347 | ||||
-rw-r--r-- | cpu/mpc83xx/cpu.c | 188 | ||||
-rw-r--r-- | include/fdt.h | 19 | ||||
-rw-r--r-- | include/fdt_support.h | 42 | ||||
-rw-r--r-- | include/libfdt.h | 12 | ||||
-rw-r--r-- | include/libfdt_env.h | 20 | ||||
-rw-r--r-- | libfdt/fdt.c | 4 | ||||
-rw-r--r-- | libfdt/fdt_ro.c | 76 | ||||
-rw-r--r-- | libfdt/fdt_rw.c | 2 | ||||
-rw-r--r-- | libfdt/fdt_wip.c | 26 |
14 files changed, 770 insertions, 343 deletions
diff --git a/board/mpc8360emds/mpc8360emds.c b/board/mpc8360emds/mpc8360emds.c index deadb5f..5cabe47 100644 --- a/board/mpc8360emds/mpc8360emds.c +++ b/board/mpc8360emds/mpc8360emds.c @@ -664,19 +664,28 @@ U_BOOT_CMD(ecc, 4, 0, do_ecc, #if (defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT)) \ && defined(CONFIG_OF_BOARD_SETUP) + +/* + * Prototypes of functions that we use. + */ +void ft_cpu_setup(void *blob, bd_t *bd); + +#ifdef CONFIG_PCI +void ft_pci_setup(void *blob, bd_t *bd); +#endif + void ft_board_setup(void *blob, bd_t *bd) { #if defined(CONFIG_OF_LIBFDT) int nodeoffset; - int err; int tmp[2]; nodeoffset = fdt_path_offset (fdt, "/memory"); if (nodeoffset >= 0) { tmp[0] = cpu_to_be32(bd->bi_memstart); tmp[1] = cpu_to_be32(bd->bi_memsize); - err = fdt_setprop(fdt, nodeoffset, "reg", tmp, sizeof(tmp)); + fdt_setprop(fdt, nodeoffset, "reg", tmp, sizeof(tmp)); } #else u32 *p; @@ -694,4 +703,5 @@ ft_board_setup(void *blob, bd_t *bd) #endif ft_cpu_setup(blob, bd); } -#endif +#endif /* CONFIG_OF_x */ + diff --git a/common/Makefile b/common/Makefile index 74a6af2..5dfd3a8 100644 --- a/common/Makefile +++ b/common/Makefile @@ -45,7 +45,7 @@ COBJS = main.o ACEX1K.o altera.o bedbug.o circbuf.o cmd_autoscript.o \ env_nand.o env_dataflash.o env_flash.o env_eeprom.o \ env_nvram.o env_nowhere.o \ exports.o \ - flash.o fpga.o ft_build.o \ + fdt_support.o flash.o fpga.o ft_build.o \ hush.o kgdb.o lcd.o lists.o lynxkdi.o \ memsize.o miiphybb.o miiphyutil.o \ s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o spartan3.o \ diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 2721216b..32c29e5 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -37,6 +37,7 @@ #if defined(CONFIG_OF_LIBFDT) #include <fdt.h> #include <libfdt.h> +#include <fdt_support.h> #endif #if defined(CONFIG_OF_FLAT_TREE) #include <ft_build.h> @@ -748,7 +749,7 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, of_flat_tree = (char *) simple_strtoul(argv[3], NULL, 16); hdr = (image_header_t *)of_flat_tree; #if defined(CONFIG_OF_LIBFDT) - if (be32_to_cpu(fdt_magic(of_flat_tree)) == FDT_MAGIC) { + if (fdt_check_header(of_flat_tree) == 0) { #else if (*(ulong *)of_flat_tree == OF_DT_HEADER) { #endif @@ -795,7 +796,7 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, return; } #if defined(CONFIG_OF_LIBFDT) - if (be32_to_cpu(fdt_magic(of_flat_tree + sizeof(image_header_t))) != FDT_MAGIC) { + if (fdt_check_header(of_flat_tree + sizeof(image_header_t)) == 0) { #else if (*((ulong *)(of_flat_tree + sizeof(image_header_t))) != OF_DT_HEADER) { #endif @@ -836,7 +837,7 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, } #if defined(CONFIG_OF_LIBFDT) - if (be32_to_cpu(fdt_magic(of_data)) != FDT_MAGIC) { + if (fdt_check_header((void *)of_data) != 0) { #else if (((struct boot_param_header *)of_data)->magic != OF_DT_HEADER) { #endif @@ -937,23 +938,44 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, if (of_data) { int err; ulong of_start, of_len; + of_len = be32_to_cpu(fdt_totalsize(of_data)); - /* provide extra 8k pad */ + /* position on a 4K boundary before the initrd/kbd */ if (initrd_start) - of_start = initrd_start - of_len - 8192; + of_start = initrd_start - of_len; else - of_start = (ulong)kbd - of_len - 8192; + of_start = (ulong)kbd - of_len; of_start &= ~(4096 - 1); /* align on page */ debug ("## device tree at 0x%08lX ... 0x%08lX (len=%ld=0x%lX)\n", of_data, of_data + of_len - 1, of_len, of_len); - + of_flat_tree = (char *)of_start; printf (" Loading Device Tree to %08lx, end %08lx ... ", of_start, of_start + of_len - 1); - err = fdt_open_into(of_start, of_data, of_len); + err = fdt_open_into((void *)of_start, (void *)of_data, of_len); if (err != 0) { - printf ("libfdt: %s\n", fdt_strerror(err)); + printf ("libfdt: %s " __FILE__ " %d\n", fdt_strerror(err), __LINE__); } + /* + * Add the chosen node if it doesn't exist, add the env and bd_t + * if the user wants it (the logic is in the subroutines). + */ + if (fdt_chosen(of_flat_tree, initrd_start, initrd_end, 0) < 0) { + printf("Failed creating the /chosen node (0x%08X), aborting.\n", of_flat_tree); + return; + } +#ifdef CONFIG_OF_HAS_UBOOT_ENV + if (fdt_env(of_flat_tree) < 0) { + printf("Failed creating the /u-boot-env node, aborting.\n"); + return; + } +#endif +#ifdef CONFIG_OF_HAS_BD_T + if (fdt_bd_t(of_flat_tree) < 0) { + printf("Failed creating the /bd_t node, aborting.\n"); + return; + } +#endif } #endif #if defined(CONFIG_OF_FLAT_TREE) @@ -1004,6 +1026,24 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag, ft_setup(of_flat_tree, kbd, initrd_start, initrd_end); /* ft_dump_blob(of_flat_tree); */ #endif +#if defined(CONFIG_OF_LIBFDT) + if (fdt_chosen(of_flat_tree, initrd_start, initrd_end, 0) < 0) { + printf("Failed creating the /chosen node (0x%08X), aborting.\n", of_flat_tree); + return; + } +#ifdef CONFIG_OF_HAS_UBOOT_ENV + if (fdt_env(of_flat_tree) < 0) { + printf("Failed creating the /u-boot-env node, aborting.\n"); + return; + } +#endif +#ifdef CONFIG_OF_HAS_BD_T + if (fdt_bd_t(of_flat_tree) < 0) { + printf("Failed creating the /bd_t node, aborting.\n"); + return; + } +#endif +#endif /* if defined(CONFIG_OF_LIBFDT) */ (*kernel) ((bd_t *)of_flat_tree, (ulong)kernel, 0, 0, 0); #endif diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index 968bade..08fe351 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -30,9 +30,11 @@ #include <linux/types.h> #ifdef CONFIG_OF_LIBFDT + #include <asm/global_data.h> #include <fdt.h> #include <libfdt.h> +#include <fdt_support.h> #define MAX_LEVEL 32 /* how deeply nested we will go */ #define SCRATCHPAD 1024 /* bytes of scratchpad memory */ @@ -53,9 +55,6 @@ static char data[SCRATCHPAD]; */ static int fdt_valid(void); static void print_data(const void *data, int len); -static int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end); -static int fdt_env(void *fdt); -static int fdt_bd_t(void *fdt); /* @@ -437,7 +436,7 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) * Create a chosen node ********************************************************************/ } else if (op == 'c') { - fdt_chosen(fdt, 0, 0); + fdt_chosen(fdt, 0, 0, 1); /******************************************************************** * Create a u-boot-env node @@ -466,25 +465,36 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) static int fdt_valid(void) { + int err; + if (fdt == NULL) { - printf ("The address of the fdt is invalid.\n"); - return 0; - } - if (!fdt || (fdt_magic(fdt) != FDT_MAGIC)) { - fdt = NULL; - printf ("Unrecognized fdt: bad magic\n"); - return 0; - } - if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) { - printf ("Unsupported fdt version: $d < %d\n", - FDT_FIRST_SUPPORTED_VERSION, fdt_version(fdt)); - fdt = NULL; + printf ("The address of the fdt is invalid (NULL).\n"); return 0; } - if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) { - printf ("Unsupported fdt version: $d > %d\n", - fdt_version(fdt), FDT_LAST_SUPPORTED_VERSION); - fdt = NULL; + + err = fdt_check_header(fdt); + if (err == 0) + return 1; /* valid */ + + if (err < 0) { + printf("libfdt: %s", fdt_strerror(err)); + /* + * Be more informative on bad version. + */ + if (err == -FDT_ERR_BADVERSION) { + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) { + printf (" - too old, fdt $d < %d", + fdt_version(fdt), FDT_FIRST_SUPPORTED_VERSION); + fdt = NULL; + } + if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) { + printf (" - too new, fdt $d > %d", + fdt_version(fdt), FDT_LAST_SUPPORTED_VERSION); + fdt = NULL; + } + return 0; + } + printf("\n"); return 0; } return 1; @@ -593,255 +603,6 @@ static void print_data(const void *data, int len) /********************************************************************/ -static int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end) -{ - 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; - - 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; - } - } - - /* - * See if we already have a "chosen" node, create it if not. - */ - nodeoffset = fdt_path_offset (fdt, "/chosen"); - 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; - } - } - - 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 -} - -/********************************************************************/ - -#ifdef CONFIG_OF_HAS_BD_T - -/* Function that returns a character from the environment */ -extern uchar(*env_get_char) (int); - -#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), -}; - -static int fdt_env(void *fdt) -{ - int nodeoffset; - int err; - int k, nxt; - int i; - static char tmpenv[256]; - - /* - * 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("\"%s\" - libfdt: %s\n", lval, fdt_strerror(err)); - return err; - } - } - return 0; -} -#endif /* CONFIG_OF_HAS_UBOOT_ENV */ - -/********************************************************************/ - -#ifdef CONFIG_OF_HAS_BD_T -static 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; - - /* - * 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)); - -#ifdef CONFIG_OF_BOARD_SETUP - ft_board_setup(fdt, bd); -#endif - - return 0; -} -#endif /* CONFIG_OF_HAS_BD_T */ - -/********************************************************************/ - U_BOOT_CMD( fdt, 5, 0, do_fdt, "fdt - flattened device tree utility commands\n", @@ -871,4 +632,4 @@ U_BOOT_CMD( " fdt set /cpus \"#address-cells\" \"[00 00 00 01]\"\n" ); -#endif /* CONFIG_OF_FLAT_TREE */ +#endif /* CONFIG_OF_LIBFDT */ diff --git a/common/fdt_support.c b/common/fdt_support.c new file mode 100644 index 0000000..91b729f --- /dev/null +++ b/common/fdt_support.c @@ -0,0 +1,347 @@ +/* + * (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 <common.h> +#include <linux/ctype.h> +#include <linux/types.h> + +#ifdef CONFIG_OF_LIBFDT + +#include <asm/global_data.h> +#include <fdt.h> +#include <libfdt.h> +#include <fdt_support.h> + +/* + * 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; + } + + if (initrd_start && initrd_end) { + 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)); + 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", fdt_strerror(err)); + return err; + } + } + return 0; +} +#endif /* ifdef 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 /* ifdef CONFIG_OF_HAS_BD_T */ + +#endif /* CONFIG_OF_LIBFDT */ diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c index 21b1646..e934ba6 100644 --- a/cpu/mpc83xx/cpu.c +++ b/cpu/mpc83xx/cpu.c @@ -300,92 +300,174 @@ void watchdog_reset (void) #if defined(CONFIG_OF_LIBFDT) /* + * "Setter" functions used to add/modify FDT entries. + */ +static int fdt_set_eth0(void *fdt, int nodeoffset, const char *name, bd_t *bd) +{ + /* + * Fix it up if it exists, don't create it if it doesn't exist. + */ + if (fdt_get_property(fdt, nodeoffset, name, 0)) { + return fdt_setprop(fdt, nodeoffset, name, bd->bi_enetaddr, 6); + } + return -FDT_ERR_NOTFOUND; +} +#ifdef CONFIG_HAS_ETH1 +/* second onboard ethernet port */ +static int fdt_set_eth1(void *fdt, int nodeoffset, const char *name, bd_t *bd) +{ + /* + * Fix it up if it exists, don't create it if it doesn't exist. + */ + if (fdt_get_property(fdt, nodeoffset, name, 0)) { + return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet1addr, 6); + } + return -FDT_ERR_NOTFOUND; +} +#endif +#ifdef CONFIG_HAS_ETH2 +/* third onboard ethernet port */ +static int fdt_set_eth2(void *fdt, int nodeoffset, const char *name, bd_t *bd) +{ + /* + * Fix it up if it exists, don't create it if it doesn't exist. + */ + if (fdt_get_property(fdt, nodeoffset, name, 0)) { + return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet2addr, 6); + } + return -FDT_ERR_NOTFOUND; +} +#endif +#ifdef CONFIG_HAS_ETH3 +/* fourth onboard ethernet port */ +static int fdt_set_eth3(void *fdt, int nodeoffset, const char *name, bd_t *bd) +{ + /* + * Fix it up if it exists, don't create it if it doesn't exist. + */ + if (fdt_get_property(fdt, nodeoffset, name, 0)) { + return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet3addr, 6); + } + return -FDT_ERR_NOTFOUND; +} +#endif + +static int fdt_set_busfreq(void *fdt, int nodeoffset, const char *name, bd_t *bd) +{ + u32 tmp; + /* + * Create or update the property. + */ + tmp = cpu_to_be32(bd->bi_busfreq); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + +/* * Fixups to the fdt. If "create" is TRUE, the node is created * unconditionally. If "create" is FALSE, the node is updated * only if it already exists. */ -#define FT_UPDATE 0x00000000 /* update existing property only */ -#define FT_CREATE 0x00000001 /* create property if it doesn't exist */ -#define FT_BUSFREQ 0x00000002 /* source is bd->bi_busfreq */ -#define FT_ENETADDR 0x00000004 /* source is bd->bi_enetaddr */ static const struct { - int createflags; char *node; char *prop; + int (*set_fn)(void *fdt, int nodeoffset, const char *name, bd_t *bd); } fixup_props[] = { - { FT_CREATE | FT_BUSFREQ, - "/cpus/" OF_CPU, + { "/cpus/" OF_CPU, "bus-frequency", + fdt_set_busfreq }, - { FT_CREATE | FT_BUSFREQ, - "/cpus/" OF_SOC, - "bus-frequency" + { "/cpus/" OF_SOC, + "bus-frequency", + fdt_set_busfreq }, - { FT_CREATE | FT_BUSFREQ, - "/" OF_SOC "/serial@4500/", - "clock-frequency" + { "/" OF_SOC "/serial@4500/", + "clock-frequency", + fdt_set_busfreq }, - { FT_CREATE | FT_BUSFREQ, - "/" OF_SOC "/serial@4600/", - "clock-frequency" + { "/" OF_SOC "/serial@4600/", + "clock-frequency", + fdt_set_busfreq }, #ifdef CONFIG_MPC83XX_TSEC1 - { FT_UPDATE | FT_ENETADDR, - "/" OF_SOC "/ethernet@24000, + { "/" OF_SOC "/ethernet@24000, "mac-address", + fdt_set_eth0 }, - { FT_UPDATE | FT_ENETADDR, - "/" OF_SOC "/ethernet@24000, + { "/" OF_SOC "/ethernet@24000, "local-mac-address", + fdt_set_eth0 }, #endif #ifdef CONFIG_MPC83XX_TSEC2 - { FT_UPDATE | FT_ENETADDR, - "/" OF_SOC "/ethernet@25000, + { "/" OF_SOC "/ethernet@25000, + "mac-address", + fdt_set_eth1 + }, + { "/" OF_SOC "/ethernet@25000, + "local-mac-address", + fdt_set_eth1 + }, +#endif +#ifdef CONFIG_UEC_ETH1 +#if CFG_UEC1_UCC_NUM == 0 /* UCC1 */ + { "/" OF_QE "/ucc@2000/mac-address", + "mac-address", + fdt_set_eth0 + }, + { "/" OF_QE "/ucc@2000/mac-address", + "local-mac-address", + fdt_set_eth0 + }, +#elif CFG_UEC1_UCC_NUM == 2 /* UCC3 */ + { "/" OF_QE "/ucc@2200/mac-address", + "mac-address", + fdt_set_eth0 + }, + { "/" OF_QE "/ucc@2200/mac-address", + "local-mac-address", + fdt_set_eth0 + }, +#endif +#endif +#ifdef CONFIG_UEC_ETH2 +#if CFG_UEC2_UCC_NUM == 1 /* UCC2 */ + { "/" OF_QE "/ucc@3000/mac-address", "mac-address", + fdt_set_eth1 }, - { FT_UPDATE | FT_ENETADDR, - "/" OF_SOC "/ethernet@25000, + { "/" OF_QE "/ucc@3000/mac-address", "local-mac-address", + fdt_set_eth1 + }, +#elif CFG_UEC1_UCC_NUM == 3 /* UCC4 */ + { "/" OF_QE "/ucc@3200/mac-address", + "mac-address", + fdt_set_eth1 }, + { "/" OF_QE "/ucc@3200/mac-address", + "local-mac-address", + fdt_set_eth1 + }, +#endif #endif }; void ft_cpu_setup(void *blob, bd_t *bd) { - int nodeoffset; - int err; - int j; + int nodeoffset; + int err; + int j; for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) { - nodeoffset = fdt_path_offset (fdt, fixup_props[j].node); + nodeoffset = fdt_path_offset(fdt, fixup_props[j].node); if (nodeoffset >= 0) { - /* - * If unconditional create or the property already exists... - */ - if ((fixup_props[j].createflags & FT_CREATE) || - (fdt_get_property(fdt, nodeoffset, fixup_props[j].prop, 0))) { - if (fixup_props[j].createflags & FT_BUSFREQ) { - u32 tmp; - - tmp = cpu_to_be32(bd->bi_busfreq); - err = fdt_setprop(fdt, nodeoffset, - fixup_props[j].prop, &tmp, sizeof(tmp)); - } else if (fixup_props[j].createflags & FT_ENETADDR) { - err = fdt_setprop(fdt, nodeoffset, - fixup_props[j].prop, bd->bi_enetaddr, 6); - } else { - printf("ft_cpu_setup: %s %s has no flag for the value to set\n", - fixup_props[j].node, - fixup_props[j].prop); - } - if (err < 0) - printf("libfdt: %s %s returned %s\n", - fixup_props[j].node, - fixup_props[j].prop, - fdt_strerror(err)); - } + err = (*fixup_props[j].set_fn)(blob, nodeoffset, fixup_props[j].prop, bd); + if (err < 0) + printf("set_fn/libfdt: %s %s returned %s\n", + fixup_props[j].node, + fixup_props[j].prop, + fdt_strerror(err)); } } } diff --git a/include/fdt.h b/include/fdt.h index 48ccfd9..3dd3aca 100644 --- a/include/fdt.h +++ b/include/fdt.h @@ -1,3 +1,22 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + #ifndef _FDT_H #define _FDT_H diff --git a/include/fdt_support.h b/include/fdt_support.h new file mode 100644 index 0000000..a276834 --- /dev/null +++ b/include/fdt_support.h @@ -0,0 +1,42 @@ +/* + * (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 + */ + +#ifndef __FDT_SUPPORT_H +#define __FDT_SUPPORT_H + +#ifdef CONFIG_OF_LIBFDT + +#include <fdt.h> + +int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force); + +#ifdef CONFIG_OF_HAS_UBOOT_ENV +int fdt_env(void *fdt); +#endif + +#ifdef CONFIG_OF_HAS_BD_T +int fdt_bd_t(void *fdt); +#endif + +#endif /* ifdef CONFIG_OF_LIBFDT */ +#endif /* ifndef __FDT_SUPPORT_H */ diff --git a/include/libfdt.h b/include/libfdt.h index a0b4d55..f8bac73 100644 --- a/include/libfdt.h +++ b/include/libfdt.h @@ -1,5 +1,3 @@ -#ifndef _LIBFDT_H -#define _LIBFDT_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. @@ -19,6 +17,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef _LIBFDT_H +#define _LIBFDT_H + #include <fdt.h> #include <libfdt_env.h> @@ -60,6 +61,8 @@ #define fdt_set_header(fdt, field, val) \ ((struct fdt_header *)(fdt))->field = cpu_to_fdt32(val) +int fdt_check_header(const void *fdt); + void *fdt_offset_ptr(const void *fdt, int offset, int checklen); #define fdt_offset_ptr_typed(fdt, offset, var) \ @@ -83,6 +86,8 @@ void *fdt_getprop(const void *fdt, int nodeoffset, uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset, char **namep); +int fdt_num_reservemap(void *fdt, int *used, int *total); +int fdt_get_reservemap(void *fdt, int n, struct fdt_reserve_entry *re); /* Write-in-place functions */ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, @@ -96,6 +101,8 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, int fdt_nop_property(void *fdt, int nodeoffset, const char *name); int fdt_nop_node(void *fdt, int nodeoffset); +int fdt_insert_reservemap_entry(void *fdt, int n, uint64_t addr, uint64_t size); + /* Sequential-write functions */ int fdt_create(void *buf, int bufsize); @@ -112,6 +119,7 @@ int fdt_property(void *fdt, const char *name, const void *val, int len); fdt_property(fdt, name, str, strlen(str)+1) int fdt_end_node(void *fdt); int fdt_finish(void *fdt); +int fdt_replace_reservemap_entry(void *fdt, int n, uint64_t addr, uint64_t size); /* Read-write functions */ int fdt_open_into(void *fdt, void *buf, int bufsize); diff --git a/include/libfdt_env.h b/include/libfdt_env.h index 6c77852..e746314 100644 --- a/include/libfdt_env.h +++ b/include/libfdt_env.h @@ -1,3 +1,23 @@ +/* + * libfdt - Flat Device Tree manipulation (build/run environment adaptation) + * Copyright (C) 2007 Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com + * Original version written by David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + #ifndef _LIBFDT_ENV_H #define _LIBFDT_ENV_H diff --git a/libfdt/fdt.c b/libfdt/fdt.c index 4b1c8ab..212b838 100644 --- a/libfdt/fdt.c +++ b/libfdt/fdt.c @@ -23,7 +23,7 @@ #include "libfdt_internal.h" -int _fdt_check_header(const void *fdt) +int fdt_check_header(const void *fdt) { if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ @@ -72,7 +72,7 @@ const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) int fdt_move(const void *fdt, void *buf, int bufsize) { - int err = _fdt_check_header(fdt); + int err = fdt_check_header(fdt); if (err) return err; diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index ce01dc7..af33336 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -25,7 +25,7 @@ #define CHECK_HEADER(fdt) { \ int err; \ - if ((err = _fdt_check_header(fdt)) != 0) \ + if ((err = fdt_check_header(fdt)) != 0) \ return err; \ } @@ -188,7 +188,7 @@ struct fdt_property *fdt_get_property(const void *fdt, int offset, nextoffset; int err; - if ((err = _fdt_check_header(fdt)) != 0) + if ((err = fdt_check_header(fdt)) != 0) goto fail; err = -FDT_ERR_BADOFFSET; @@ -329,3 +329,75 @@ uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset, char **namep return tag; } + +/* + * Return the number of used reserve map entries and total slots available. + */ +int fdt_num_reservemap(void *fdt, int *used, int *total) +{ + struct fdt_reserve_entry *re; + int start; + int end; + int err = fdt_check_header(fdt); + + if (err != 0) + return err; + + start = fdt_off_mem_rsvmap(fdt); + + /* + * Convention is that the reserve map is before the dt_struct, + * but it does not have to be. + */ + end = fdt_totalsize(fdt); + if (end > fdt_off_dt_struct(fdt)) + end = fdt_off_dt_struct(fdt); + if (end > fdt_off_dt_strings(fdt)) + end = fdt_off_dt_strings(fdt); + + /* + * Since the reserved area list is zero terminated, you get one fewer. + */ + if (total) + *total = ((end - start) / sizeof(struct fdt_reserve_entry)) - 1; + + if (used) { + *used = 0; + while (start < end) { + re = (struct fdt_reserve_entry *)(fdt + start); + if (re->size == 0) + return 0; /* zero size terminates the list */ + + *used += 1; + start += sizeof(struct fdt_reserve_entry); + } + /* + * If we get here, there was no zero size termination. + */ + return -FDT_ERR_BADLAYOUT; + } + return 0; +} + +/* + * Return the nth reserve map entry. + */ +int fdt_get_reservemap(void *fdt, int n, struct fdt_reserve_entry *re) +{ + int used; + int total; + int err; + + err = fdt_num_reservemap(fdt, &used, &total); + if (err != 0) + return err; + + if (n >= total) + return -FDT_ERR_NOSPACE; + if (re) { + *re = *(struct fdt_reserve_entry *) + _fdt_offset_ptr(fdt, n * sizeof(struct fdt_reserve_entry)); + } + return 0; +} + diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c index b33fbf4..aaafc53 100644 --- a/libfdt/fdt_rw.c +++ b/libfdt/fdt_rw.c @@ -27,7 +27,7 @@ static int rw_check_header(void *fdt) { int err; - if ((err = _fdt_check_header(fdt))) + if ((err = fdt_check_header(fdt))) return err; if (fdt_version(fdt) < 0x11) return -FDT_ERR_BADVERSION; diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c index 261b9b0..cf81183 100644 --- a/libfdt/fdt_wip.c +++ b/libfdt/fdt_wip.c @@ -110,3 +110,29 @@ int fdt_nop_node(void *fdt, int nodeoffset) nop_region(fdt_offset_ptr(fdt, nodeoffset, 0), endoffset - nodeoffset); return 0; } + +/* + * Replace a reserve map entry in the nth slot. + */ +int fdt_replace_reservemap_entry(void *fdt, int n, uint64_t addr, uint64_t size) +{ + struct fdt_reserve_entry *re; + int used; + int total; + int err; + + err = fdt_num_reservemap(fdt, &used, &total); + if (err != 0) + return err; + + if (n >= total) + return -FDT_ERR_NOSPACE; + re = (struct fdt_reserve_entry *) + (fdt + fdt_off_mem_rsvmap(fdt) + + (n * sizeof(struct fdt_reserve_entry))); + re->address = cpu_to_fdt64(addr); + re->size = cpu_to_fdt64(size); + + return 0; +} + |