fdt_support.c

来自「U-boot源码 ARM7启动代码」· C语言 代码 · 共 491 行

C
491
字号
/* * (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;/* * fdt points to our working device tree. */struct fdt_header *fdt;/********************************************************************//** * fdt_find_and_setprop: Find a node and set it's property * * @fdt: ptr to device tree * @node: path of node * @prop: property name * @val: ptr to new value * @len: length of new property value * @create: flag to create the property if it doesn't exist * * Convenience function to directly set a property given the path to the node. */int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,			 const void *val, int len, int create){	int nodeoff = fdt_path_offset(fdt, node);	if (nodeoff < 0)		return nodeoff;	if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL))		return 0; /* create flag not set; so exit quietly */	return fdt_setprop(fdt, nodeoff, prop, val, len);}int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force){	int   nodeoffset;	int   err;	u32   tmp;		/* used to set 32 bit integer properties */	char  *str;		/* used to set string properties */	err = fdt_check_header(fdt);	if (err < 0) {		printf("fdt_chosen: %s\n", fdt_strerror(err));		return err;	}	if (initrd_start && initrd_end) {		uint64_t addr, size;		int  total = fdt_num_mem_rsv(fdt);		int  j;		/*		 * 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 < total; j++) {			err = fdt_get_mem_rsv(fdt, j, &addr, &size);			if (addr == initrd_start) {				fdt_del_mem_rsv(fdt, j);				break;			}		}		err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);		if (err < 0) {			printf("fdt_chosen: %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("WARNING: could not create /chosen %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("WARNING: could not set bootargs %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("WARNING: "				"could not set linux,initrd-start %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("WARNING: could not set linux,initrd-end %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("WARNING: could not set linux,stdout-path %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("fdt_env: %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("fdt_env: %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("WARNING: could not create /u-boot-env %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("WARNING: could not set %s %s.\n",				lval, 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("fdt_bd_t: %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("fdt_bd_t: %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("WARNING: could not create /bd_t %s.\n",			fdt_strerror(nodeoffset));		printf("fdt_bd_t: %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("WARNING: could not set %s %s.\n",				bd_map[i].name, fdt_strerror(err));	}	/*	 * Add a couple of oddball entries...	 */	err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6);	if (err < 0)		printf("WARNING: could not set enetaddr %s.\n",			fdt_strerror(err));	err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4);	if (err < 0)		printf("WARNING: could not set ethspeed %s.\n",			fdt_strerror(err));	return 0;}#endif /* ifdef CONFIG_OF_HAS_BD_T */void do_fixup_by_path(void *fdt, const char *path, const char *prop,		      const void *val, int len, int create){#if defined(DEBUG)	int i;	debug("Updating property '%s/%s' = ", node, prop);	for (i = 0; i < len; i++)		debug(" %.2x", *(u8*)(val+i));	debug("\n");#endif	int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create);	if (rc)		printf("Unable to update property %s:%s, err=%s\n",			path, prop, fdt_strerror(rc));}void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,			  u32 val, int create){	val = cpu_to_fdt32(val);	do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create);}void do_fixup_by_prop(void *fdt,		      const char *pname, const void *pval, int plen,		      const char *prop, const void *val, int len,		      int create){	int off;#if defined(DEBUG)	int i;	debug("Updating property '%s/%s' = ", node, prop);	for (i = 0; i < len; i++)		debug(" %.2x", *(u8*)(val+i));	debug("\n");#endif	off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen);	while (off != -FDT_ERR_NOTFOUND) {		if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))			fdt_setprop(fdt, off, prop, val, len);		off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen);	}}void do_fixup_by_prop_u32(void *fdt,			  const char *pname, const void *pval, int plen,			  const char *prop, u32 val, int create){	val = cpu_to_fdt32(val);	do_fixup_by_prop(fdt, pname, pval, plen, prop, &val, 4, create);}void do_fixup_by_compat(void *fdt, const char *compat,			const char *prop, const void *val, int len, int create){	int off = -1;#if defined(DEBUG)	int i;	debug("Updating property '%s/%s' = ", node, prop);	for (i = 0; i < len; i++)		debug(" %.2x", *(u8*)(val+i));	debug("\n");#endif	off = fdt_node_offset_by_compatible(fdt, -1, compat);	while (off != -FDT_ERR_NOTFOUND) {		if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))			fdt_setprop(fdt, off, prop, val, len);		off = fdt_node_offset_by_compatible(fdt, off, compat);	}}void do_fixup_by_compat_u32(void *fdt, const char *compat,			    const char *prop, u32 val, int create){	val = cpu_to_fdt32(val);	do_fixup_by_compat(fdt, compat, prop, &val, 4, create);}void fdt_fixup_ethernet(void *fdt, bd_t *bd){	int node;	const char *path;	node = fdt_path_offset(fdt, "/aliases");	if (node >= 0) {#if defined(CONFIG_HAS_ETH0)		path = fdt_getprop(fdt, node, "ethernet0", NULL);		if (path) {			do_fixup_by_path(fdt, path, "mac-address",				bd->bi_enetaddr, 6, 0);			do_fixup_by_path(fdt, path, "local-mac-address",				bd->bi_enetaddr, 6, 1);		}#endif#if defined(CONFIG_HAS_ETH1)		path = fdt_getprop(fdt, node, "ethernet1", NULL);		if (path) {			do_fixup_by_path(fdt, path, "mac-address",				bd->bi_enet1addr, 6, 0);			do_fixup_by_path(fdt, path, "local-mac-address",				bd->bi_enet1addr, 6, 1);		}#endif#if defined(CONFIG_HAS_ETH2)		path = fdt_getprop(fdt, node, "ethernet2", NULL);		if (path) {			do_fixup_by_path(fdt, path, "mac-address",				bd->bi_enet2addr, 6, 0);			do_fixup_by_path(fdt, path, "local-mac-address",				bd->bi_enet2addr, 6, 1);		}#endif#if defined(CONFIG_HAS_ETH3)		path = fdt_getprop(fdt, node, "ethernet3", NULL);		if (path) {			do_fixup_by_path(fdt, path, "mac-address",				bd->bi_enet3addr, 6, 0);			do_fixup_by_path(fdt, path, "local-mac-address",				bd->bi_enet3addr, 6, 1);		}#endif	}}#endif /* CONFIG_OF_LIBFDT */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?