diff options
Diffstat (limited to 'common/fdt_support.c')
| -rw-r--r-- | common/fdt_support.c | 347 | 
1 files changed, 347 insertions, 0 deletions
| diff --git a/common/fdt_support.c b/common/fdt_support.c new file mode 100644 index 000000000..69099c427 --- /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 */ |