xref: /openbmc/u-boot/common/fdt_support.c (revision ff4e66e9)
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 #include <asm/global_data.h>
2864dbbd40SGerald Van Baren #include <fdt.h>
2964dbbd40SGerald Van Baren #include <libfdt.h>
3064dbbd40SGerald Van Baren #include <fdt_support.h>
31151c8b09SKumar Gala #include <exports.h>
3264dbbd40SGerald Van Baren 
3364dbbd40SGerald Van Baren /*
3464dbbd40SGerald Van Baren  * Global data (for the gd->bd)
3564dbbd40SGerald Van Baren  */
3664dbbd40SGerald Van Baren DECLARE_GLOBAL_DATA_PTR;
3764dbbd40SGerald Van Baren 
383bed2aafSKumar Gala /**
393bed2aafSKumar Gala  * fdt_getprop_u32_default - Find a node and return it's property or a default
403bed2aafSKumar Gala  *
413bed2aafSKumar Gala  * @fdt: ptr to device tree
423bed2aafSKumar Gala  * @path: path of node
433bed2aafSKumar Gala  * @prop: property name
443bed2aafSKumar Gala  * @dflt: default value if the property isn't found
453bed2aafSKumar Gala  *
463bed2aafSKumar Gala  * Convenience function to find a node and return it's property or a
473bed2aafSKumar Gala  * default value if it doesn't exist.
483bed2aafSKumar Gala  */
493bed2aafSKumar Gala u32 fdt_getprop_u32_default(void *fdt, const char *path, const char *prop,
503bed2aafSKumar Gala 				const u32 dflt)
513bed2aafSKumar Gala {
523bed2aafSKumar Gala 	const u32 *val;
533bed2aafSKumar Gala 	int off;
543bed2aafSKumar Gala 
553bed2aafSKumar Gala 	off = fdt_path_offset(fdt, path);
563bed2aafSKumar Gala 	if (off < 0)
573bed2aafSKumar Gala 		return dflt;
583bed2aafSKumar Gala 
593bed2aafSKumar Gala 	val = fdt_getprop(fdt, off, prop, NULL);
603bed2aafSKumar Gala 	if (val)
613bed2aafSKumar Gala 		return *val;
623bed2aafSKumar Gala 	else
633bed2aafSKumar Gala 		return dflt;
643bed2aafSKumar Gala }
6564dbbd40SGerald Van Baren 
66a3c2933eSKumar Gala /**
67a3c2933eSKumar Gala  * fdt_find_and_setprop: Find a node and set it's property
68a3c2933eSKumar Gala  *
69a3c2933eSKumar Gala  * @fdt: ptr to device tree
70a3c2933eSKumar Gala  * @node: path of node
71a3c2933eSKumar Gala  * @prop: property name
72a3c2933eSKumar Gala  * @val: ptr to new value
73a3c2933eSKumar Gala  * @len: length of new property value
74a3c2933eSKumar Gala  * @create: flag to create the property if it doesn't exist
75a3c2933eSKumar Gala  *
76a3c2933eSKumar Gala  * Convenience function to directly set a property given the path to the node.
77a3c2933eSKumar Gala  */
78a3c2933eSKumar Gala int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
79a3c2933eSKumar Gala 			 const void *val, int len, int create)
80a3c2933eSKumar Gala {
818d04f02fSKumar Gala 	int nodeoff = fdt_path_offset(fdt, node);
82a3c2933eSKumar Gala 
83a3c2933eSKumar Gala 	if (nodeoff < 0)
84a3c2933eSKumar Gala 		return nodeoff;
85a3c2933eSKumar Gala 
86a3c2933eSKumar Gala 	if ((!create) && (fdt_get_property(fdt, nodeoff, prop, 0) == NULL))
87a3c2933eSKumar Gala 		return 0; /* create flag not set; so exit quietly */
88a3c2933eSKumar Gala 
89a3c2933eSKumar Gala 	return fdt_setprop(fdt, nodeoff, prop, val, len);
90a3c2933eSKumar Gala }
91a3c2933eSKumar Gala 
92151c8b09SKumar Gala #ifdef CONFIG_OF_STDOUT_VIA_ALIAS
9340777812SDetlev Zundel static int fdt_fixup_stdout(void *fdt, int chosenoff)
94151c8b09SKumar Gala {
95151c8b09SKumar Gala 	int err = 0;
96151c8b09SKumar Gala #ifdef CONFIG_CONS_INDEX
97151c8b09SKumar Gala 	int node;
98151c8b09SKumar Gala 	char sername[9] = { 0 };
99151c8b09SKumar Gala 	const char *path;
100151c8b09SKumar Gala 
101151c8b09SKumar Gala 	sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
102151c8b09SKumar Gala 
103151c8b09SKumar Gala 	err = node = fdt_path_offset(fdt, "/aliases");
104151c8b09SKumar Gala 	if (node >= 0) {
105151c8b09SKumar Gala 		int len;
106151c8b09SKumar Gala 		path = fdt_getprop(fdt, node, sername, &len);
107151c8b09SKumar Gala 		if (path) {
108151c8b09SKumar Gala 			char *p = malloc(len);
109151c8b09SKumar Gala 			err = -FDT_ERR_NOSPACE;
110151c8b09SKumar Gala 			if (p) {
111151c8b09SKumar Gala 				memcpy(p, path, len);
11240777812SDetlev Zundel 				err = fdt_setprop(fdt, chosenoff,
113151c8b09SKumar Gala 					"linux,stdout-path", p, len);
114151c8b09SKumar Gala 				free(p);
115151c8b09SKumar Gala 			}
116151c8b09SKumar Gala 		} else {
117151c8b09SKumar Gala 			err = len;
118151c8b09SKumar Gala 		}
119151c8b09SKumar Gala 	}
120151c8b09SKumar Gala #endif
121151c8b09SKumar Gala 	if (err < 0)
122151c8b09SKumar Gala 		printf("WARNING: could not set linux,stdout-path %s.\n",
123151c8b09SKumar Gala 				fdt_strerror(err));
124151c8b09SKumar Gala 
125151c8b09SKumar Gala 	return err;
126151c8b09SKumar Gala }
127151c8b09SKumar Gala #endif
128151c8b09SKumar Gala 
1292a1a2cb6SKumar Gala int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end, int force)
13064dbbd40SGerald Van Baren {
13164dbbd40SGerald Van Baren 	int   nodeoffset;
1322a1a2cb6SKumar Gala 	int   err, j, total;
1332a1a2cb6SKumar Gala 	u32   tmp;
134b60af3d4SGerald Van Baren 	const char *path;
1352a1a2cb6SKumar Gala 	uint64_t addr, size;
13664dbbd40SGerald Van Baren 
1372a1a2cb6SKumar Gala 	/* Find the "chosen" node.  */
1382a1a2cb6SKumar Gala 	nodeoffset = fdt_path_offset (fdt, "/chosen");
1392a1a2cb6SKumar Gala 
1402a1a2cb6SKumar Gala 	/* If there is no "chosen" node in the blob return */
1412a1a2cb6SKumar Gala 	if (nodeoffset < 0) {
1422a1a2cb6SKumar Gala 		printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset));
1432a1a2cb6SKumar Gala 		return nodeoffset;
14464dbbd40SGerald Van Baren 	}
14564dbbd40SGerald Van Baren 
1462a1a2cb6SKumar Gala 	/* just return if initrd_start/end aren't valid */
1472a1a2cb6SKumar Gala 	if ((initrd_start == 0) || (initrd_end == 0))
1482a1a2cb6SKumar Gala 		return 0;
1492a1a2cb6SKumar Gala 
1502a1a2cb6SKumar Gala 	total = fdt_num_mem_rsv(fdt);
151c28abb9cSGerald Van Baren 
152c28abb9cSGerald Van Baren 	/*
153c28abb9cSGerald Van Baren 	 * Look for an existing entry and update it.  If we don't find
154c28abb9cSGerald Van Baren 	 * the entry, we will j be the next available slot.
155c28abb9cSGerald Van Baren 	 */
1568d04f02fSKumar Gala 	for (j = 0; j < total; j++) {
1578d04f02fSKumar Gala 		err = fdt_get_mem_rsv(fdt, j, &addr, &size);
1588d04f02fSKumar Gala 		if (addr == initrd_start) {
1598d04f02fSKumar Gala 			fdt_del_mem_rsv(fdt, j);
160c28abb9cSGerald Van Baren 			break;
161c28abb9cSGerald Van Baren 		}
162c28abb9cSGerald Van Baren 	}
1638d04f02fSKumar Gala 
1648d04f02fSKumar Gala 	err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start + 1);
16564dbbd40SGerald Van Baren 	if (err < 0) {
1662a1a2cb6SKumar Gala 		printf("fdt_initrd: %s\n", fdt_strerror(err));
16764dbbd40SGerald Van Baren 		return err;
16864dbbd40SGerald Van Baren 	}
1692a1a2cb6SKumar Gala 
1702a1a2cb6SKumar Gala 	path = fdt_getprop(fdt, nodeoffset, "linux,initrd-start", NULL);
1712a1a2cb6SKumar Gala 	if ((path == NULL) || force) {
1722a1a2cb6SKumar Gala 		tmp = __cpu_to_be32(initrd_start);
1732a1a2cb6SKumar Gala 		err = fdt_setprop(fdt, nodeoffset,
1742a1a2cb6SKumar Gala 			"linux,initrd-start", &tmp, sizeof(tmp));
1752a1a2cb6SKumar Gala 		if (err < 0) {
1762a1a2cb6SKumar Gala 			printf("WARNING: "
1772a1a2cb6SKumar Gala 				"could not set linux,initrd-start %s.\n",
1782a1a2cb6SKumar Gala 				fdt_strerror(err));
1792a1a2cb6SKumar Gala 			return err;
1802a1a2cb6SKumar Gala 		}
1812a1a2cb6SKumar Gala 		tmp = __cpu_to_be32(initrd_end);
1822a1a2cb6SKumar Gala 		err = fdt_setprop(fdt, nodeoffset,
1832a1a2cb6SKumar Gala 			"linux,initrd-end", &tmp, sizeof(tmp));
1842a1a2cb6SKumar Gala 		if (err < 0) {
1852a1a2cb6SKumar Gala 			printf("WARNING: could not set linux,initrd-end %s.\n",
1862a1a2cb6SKumar Gala 				fdt_strerror(err));
1872a1a2cb6SKumar Gala 
1882a1a2cb6SKumar Gala 			return err;
1892a1a2cb6SKumar Gala 		}
1902a1a2cb6SKumar Gala 	}
1912a1a2cb6SKumar Gala 
1922a1a2cb6SKumar Gala 	return 0;
1932a1a2cb6SKumar Gala }
1942a1a2cb6SKumar Gala 
19556844a22SHeiko Schocher int fdt_chosen(void *fdt, int force)
1962a1a2cb6SKumar Gala {
1972a1a2cb6SKumar Gala 	int   nodeoffset;
1982a1a2cb6SKumar Gala 	int   err;
1992a1a2cb6SKumar Gala 	char  *str;		/* used to set string properties */
2002a1a2cb6SKumar Gala 	const char *path;
2012a1a2cb6SKumar Gala 
2022a1a2cb6SKumar Gala 	err = fdt_check_header(fdt);
2032a1a2cb6SKumar Gala 	if (err < 0) {
2042a1a2cb6SKumar Gala 		printf("fdt_chosen: %s\n", fdt_strerror(err));
2052a1a2cb6SKumar Gala 		return err;
20664dbbd40SGerald Van Baren 	}
20764dbbd40SGerald Van Baren 
20864dbbd40SGerald Van Baren 	/*
20964dbbd40SGerald Van Baren 	 * Find the "chosen" node.
21064dbbd40SGerald Van Baren 	 */
2118d04f02fSKumar Gala 	nodeoffset = fdt_path_offset (fdt, "/chosen");
21264dbbd40SGerald Van Baren 
21364dbbd40SGerald Van Baren 	/*
214b60af3d4SGerald Van Baren 	 * If there is no "chosen" node in the blob, create it.
21564dbbd40SGerald Van Baren 	 */
21664dbbd40SGerald Van Baren 	if (nodeoffset < 0) {
21764dbbd40SGerald Van Baren 		/*
21864dbbd40SGerald Van Baren 		 * Create a new node "/chosen" (offset 0 is root level)
21964dbbd40SGerald Van Baren 		 */
22064dbbd40SGerald Van Baren 		nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
22164dbbd40SGerald Van Baren 		if (nodeoffset < 0) {
2225fe6be62SGerald Van Baren 			printf("WARNING: could not create /chosen %s.\n",
22335ec398fSGerald Van Baren 				fdt_strerror(nodeoffset));
22464dbbd40SGerald Van Baren 			return nodeoffset;
22564dbbd40SGerald Van Baren 		}
22664dbbd40SGerald Van Baren 	}
22764dbbd40SGerald Van Baren 
22864dbbd40SGerald Van Baren 	/*
229b60af3d4SGerald Van Baren 	 * Create /chosen properites that don't exist in the fdt.
230b60af3d4SGerald Van Baren 	 * If the property exists, update it only if the "force" parameter
231b60af3d4SGerald Van Baren 	 * is true.
23264dbbd40SGerald Van Baren 	 */
23364dbbd40SGerald Van Baren 	str = getenv("bootargs");
23464dbbd40SGerald Van Baren 	if (str != NULL) {
235b60af3d4SGerald Van Baren 		path = fdt_getprop(fdt, nodeoffset, "bootargs", NULL);
236b60af3d4SGerald Van Baren 		if ((path == NULL) || force) {
23735ec398fSGerald Van Baren 			err = fdt_setprop(fdt, nodeoffset,
23835ec398fSGerald Van Baren 				"bootargs", str, strlen(str)+1);
23964dbbd40SGerald Van Baren 			if (err < 0)
2405fe6be62SGerald Van Baren 				printf("WARNING: could not set bootargs %s.\n",
24135ec398fSGerald Van Baren 					fdt_strerror(err));
24264dbbd40SGerald Van Baren 		}
243b60af3d4SGerald Van Baren 	}
2442a1a2cb6SKumar Gala 
245151c8b09SKumar Gala #ifdef CONFIG_OF_STDOUT_VIA_ALIAS
246b60af3d4SGerald Van Baren 	path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
247b60af3d4SGerald Van Baren 	if ((path == NULL) || force)
248151c8b09SKumar Gala 		err = fdt_fixup_stdout(fdt, nodeoffset);
249151c8b09SKumar Gala #endif
250151c8b09SKumar Gala 
25164dbbd40SGerald Van Baren #ifdef OF_STDOUT_PATH
252b60af3d4SGerald Van Baren 	path = fdt_getprop(fdt, nodeoffset, "linux,stdout-path", NULL);
253b60af3d4SGerald Van Baren 	if ((path == NULL) || force) {
25435ec398fSGerald Van Baren 		err = fdt_setprop(fdt, nodeoffset,
25535ec398fSGerald Van Baren 			"linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
25664dbbd40SGerald Van Baren 		if (err < 0)
2575fe6be62SGerald Van Baren 			printf("WARNING: could not set linux,stdout-path %s.\n",
25835ec398fSGerald Van Baren 				fdt_strerror(err));
259b60af3d4SGerald Van Baren 	}
26064dbbd40SGerald Van Baren #endif
26164dbbd40SGerald Van Baren 
26264dbbd40SGerald Van Baren 	return err;
26364dbbd40SGerald Van Baren }
26464dbbd40SGerald Van Baren 
265e93becf8SKumar Gala void do_fixup_by_path(void *fdt, const char *path, const char *prop,
266e93becf8SKumar Gala 		      const void *val, int len, int create)
267e93becf8SKumar Gala {
268e93becf8SKumar Gala #if defined(DEBUG)
269e93becf8SKumar Gala 	int i;
270d9ad115bSKumar Gala 	debug("Updating property '%s/%s' = ", path, prop);
271e93becf8SKumar Gala 	for (i = 0; i < len; i++)
272e93becf8SKumar Gala 		debug(" %.2x", *(u8*)(val+i));
273e93becf8SKumar Gala 	debug("\n");
274e93becf8SKumar Gala #endif
275e93becf8SKumar Gala 	int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create);
276e93becf8SKumar Gala 	if (rc)
277e93becf8SKumar Gala 		printf("Unable to update property %s:%s, err=%s\n",
278e93becf8SKumar Gala 			path, prop, fdt_strerror(rc));
279e93becf8SKumar Gala }
280e93becf8SKumar Gala 
281e93becf8SKumar Gala void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,
282e93becf8SKumar Gala 			  u32 val, int create)
283e93becf8SKumar Gala {
284e93becf8SKumar Gala 	val = cpu_to_fdt32(val);
285e93becf8SKumar Gala 	do_fixup_by_path(fdt, path, prop, &val, sizeof(val), create);
286e93becf8SKumar Gala }
287e93becf8SKumar Gala 
2889eb77ceaSKumar Gala void do_fixup_by_prop(void *fdt,
2899eb77ceaSKumar Gala 		      const char *pname, const void *pval, int plen,
2909eb77ceaSKumar Gala 		      const char *prop, const void *val, int len,
2919eb77ceaSKumar Gala 		      int create)
2929eb77ceaSKumar Gala {
2939eb77ceaSKumar Gala 	int off;
2949eb77ceaSKumar Gala #if defined(DEBUG)
2959eb77ceaSKumar Gala 	int i;
296d9ad115bSKumar Gala 	debug("Updating property '%s' = ", prop);
2979eb77ceaSKumar Gala 	for (i = 0; i < len; i++)
2989eb77ceaSKumar Gala 		debug(" %.2x", *(u8*)(val+i));
2999eb77ceaSKumar Gala 	debug("\n");
3009eb77ceaSKumar Gala #endif
3019eb77ceaSKumar Gala 	off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen);
3029eb77ceaSKumar Gala 	while (off != -FDT_ERR_NOTFOUND) {
3039eb77ceaSKumar Gala 		if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))
3049eb77ceaSKumar Gala 			fdt_setprop(fdt, off, prop, val, len);
3059eb77ceaSKumar Gala 		off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen);
3069eb77ceaSKumar Gala 	}
3079eb77ceaSKumar Gala }
3089eb77ceaSKumar Gala 
3099eb77ceaSKumar Gala void do_fixup_by_prop_u32(void *fdt,
3109eb77ceaSKumar Gala 			  const char *pname, const void *pval, int plen,
3119eb77ceaSKumar Gala 			  const char *prop, u32 val, int create)
3129eb77ceaSKumar Gala {
3139eb77ceaSKumar Gala 	val = cpu_to_fdt32(val);
3149eb77ceaSKumar Gala 	do_fixup_by_prop(fdt, pname, pval, plen, prop, &val, 4, create);
3159eb77ceaSKumar Gala }
3169eb77ceaSKumar Gala 
3179eb77ceaSKumar Gala void do_fixup_by_compat(void *fdt, const char *compat,
3189eb77ceaSKumar Gala 			const char *prop, const void *val, int len, int create)
3199eb77ceaSKumar Gala {
3209eb77ceaSKumar Gala 	int off = -1;
3219eb77ceaSKumar Gala #if defined(DEBUG)
3229eb77ceaSKumar Gala 	int i;
323d9ad115bSKumar Gala 	debug("Updating property '%s' = ", prop);
3249eb77ceaSKumar Gala 	for (i = 0; i < len; i++)
3259eb77ceaSKumar Gala 		debug(" %.2x", *(u8*)(val+i));
3269eb77ceaSKumar Gala 	debug("\n");
3279eb77ceaSKumar Gala #endif
3289eb77ceaSKumar Gala 	off = fdt_node_offset_by_compatible(fdt, -1, compat);
3299eb77ceaSKumar Gala 	while (off != -FDT_ERR_NOTFOUND) {
3309eb77ceaSKumar Gala 		if (create || (fdt_get_property(fdt, off, prop, 0) != NULL))
3319eb77ceaSKumar Gala 			fdt_setprop(fdt, off, prop, val, len);
3329eb77ceaSKumar Gala 		off = fdt_node_offset_by_compatible(fdt, off, compat);
3339eb77ceaSKumar Gala 	}
3349eb77ceaSKumar Gala }
3359eb77ceaSKumar Gala 
3369eb77ceaSKumar Gala void do_fixup_by_compat_u32(void *fdt, const char *compat,
3379eb77ceaSKumar Gala 			    const char *prop, u32 val, int create)
3389eb77ceaSKumar Gala {
3399eb77ceaSKumar Gala 	val = cpu_to_fdt32(val);
3409eb77ceaSKumar Gala 	do_fixup_by_compat(fdt, compat, prop, &val, 4, create);
3419eb77ceaSKumar Gala }
3429eb77ceaSKumar Gala 
3433c927281SKumar Gala int fdt_fixup_memory(void *blob, u64 start, u64 size)
3443c927281SKumar Gala {
3453c927281SKumar Gala 	int err, nodeoffset, len = 0;
3463c927281SKumar Gala 	u8 tmp[16];
3473c927281SKumar Gala 	const u32 *addrcell, *sizecell;
3483c927281SKumar Gala 
3493c927281SKumar Gala 	err = fdt_check_header(blob);
3503c927281SKumar Gala 	if (err < 0) {
3513c927281SKumar Gala 		printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
3523c927281SKumar Gala 		return err;
3533c927281SKumar Gala 	}
3543c927281SKumar Gala 
3553c927281SKumar Gala 	/* update, or add and update /memory node */
3563c927281SKumar Gala 	nodeoffset = fdt_path_offset(blob, "/memory");
3573c927281SKumar Gala 	if (nodeoffset < 0) {
3583c927281SKumar Gala 		nodeoffset = fdt_add_subnode(blob, 0, "memory");
3593c927281SKumar Gala 		if (nodeoffset < 0)
3603c927281SKumar Gala 			printf("WARNING: could not create /memory: %s.\n",
3613c927281SKumar Gala 					fdt_strerror(nodeoffset));
3623c927281SKumar Gala 		return nodeoffset;
3633c927281SKumar Gala 	}
3643c927281SKumar Gala 	err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
3653c927281SKumar Gala 			sizeof("memory"));
3663c927281SKumar Gala 	if (err < 0) {
3673c927281SKumar Gala 		printf("WARNING: could not set %s %s.\n", "device_type",
3683c927281SKumar Gala 				fdt_strerror(err));
3693c927281SKumar Gala 		return err;
3703c927281SKumar Gala 	}
3713c927281SKumar Gala 
3723c927281SKumar Gala 	addrcell = fdt_getprop(blob, 0, "#address-cells", NULL);
3733c927281SKumar Gala 	/* use shifts and mask to ensure endianness */
3743c927281SKumar Gala 	if ((addrcell) && (*addrcell == 2)) {
3753c927281SKumar Gala 		tmp[0] = (start >> 56) & 0xff;
3763c927281SKumar Gala 		tmp[1] = (start >> 48) & 0xff;
3773c927281SKumar Gala 		tmp[2] = (start >> 40) & 0xff;
3783c927281SKumar Gala 		tmp[3] = (start >> 32) & 0xff;
3793c927281SKumar Gala 		tmp[4] = (start >> 24) & 0xff;
3803c927281SKumar Gala 		tmp[5] = (start >> 16) & 0xff;
3813c927281SKumar Gala 		tmp[6] = (start >>  8) & 0xff;
3823c927281SKumar Gala 		tmp[7] = (start      ) & 0xff;
3833c927281SKumar Gala 		len = 8;
3843c927281SKumar Gala 	} else {
3853c927281SKumar Gala 		tmp[0] = (start >> 24) & 0xff;
3863c927281SKumar Gala 		tmp[1] = (start >> 16) & 0xff;
3873c927281SKumar Gala 		tmp[2] = (start >>  8) & 0xff;
3883c927281SKumar Gala 		tmp[3] = (start      ) & 0xff;
3893c927281SKumar Gala 		len = 4;
3903c927281SKumar Gala 	}
3913c927281SKumar Gala 
3923c927281SKumar Gala 	sizecell = fdt_getprop(blob, 0, "#size-cells", NULL);
3933c927281SKumar Gala 	/* use shifts and mask to ensure endianness */
3943c927281SKumar Gala 	if ((sizecell) && (*sizecell == 2)) {
3953c927281SKumar Gala 		tmp[0+len] = (size >> 56) & 0xff;
3963c927281SKumar Gala 		tmp[1+len] = (size >> 48) & 0xff;
3973c927281SKumar Gala 		tmp[2+len] = (size >> 40) & 0xff;
3983c927281SKumar Gala 		tmp[3+len] = (size >> 32) & 0xff;
3993c927281SKumar Gala 		tmp[4+len] = (size >> 24) & 0xff;
4003c927281SKumar Gala 		tmp[5+len] = (size >> 16) & 0xff;
4013c927281SKumar Gala 		tmp[6+len] = (size >>  8) & 0xff;
4023c927281SKumar Gala 		tmp[7+len] = (size      ) & 0xff;
4033c927281SKumar Gala 		len += 8;
4043c927281SKumar Gala 	} else {
4053c927281SKumar Gala 		tmp[0+len] = (size >> 24) & 0xff;
4063c927281SKumar Gala 		tmp[1+len] = (size >> 16) & 0xff;
4073c927281SKumar Gala 		tmp[2+len] = (size >>  8) & 0xff;
4083c927281SKumar Gala 		tmp[3+len] = (size      ) & 0xff;
4093c927281SKumar Gala 		len += 4;
4103c927281SKumar Gala 	}
4113c927281SKumar Gala 
4123c927281SKumar Gala 	err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
4133c927281SKumar Gala 	if (err < 0) {
4143c927281SKumar Gala 		printf("WARNING: could not set %s %s.\n",
4153c927281SKumar Gala 				"reg", fdt_strerror(err));
4163c927281SKumar Gala 		return err;
4173c927281SKumar Gala 	}
4183c927281SKumar Gala 	return 0;
4193c927281SKumar Gala }
4203c927281SKumar Gala 
421ba37aa03SKumar Gala void fdt_fixup_ethernet(void *fdt)
422ab544633SKumar Gala {
423ba37aa03SKumar Gala 	int node, i, j;
424ba37aa03SKumar Gala 	char enet[16], *tmp, *end;
425ba37aa03SKumar Gala 	char mac[16] = "ethaddr";
426ab544633SKumar Gala 	const char *path;
427ba37aa03SKumar Gala 	unsigned char mac_addr[6];
428ab544633SKumar Gala 
429ab544633SKumar Gala 	node = fdt_path_offset(fdt, "/aliases");
430ba37aa03SKumar Gala 	if (node < 0)
431ba37aa03SKumar Gala 		return;
432ba37aa03SKumar Gala 
433ba37aa03SKumar Gala 	i = 0;
434ba37aa03SKumar Gala 	while ((tmp = getenv(mac)) != NULL) {
435ba37aa03SKumar Gala 		sprintf(enet, "ethernet%d", i);
436ba37aa03SKumar Gala 		path = fdt_getprop(fdt, node, enet, NULL);
437ba37aa03SKumar Gala 		if (!path) {
438ba37aa03SKumar Gala 			debug("No alias for %s\n", enet);
439ba37aa03SKumar Gala 			sprintf(mac, "eth%daddr", ++i);
440ba37aa03SKumar Gala 			continue;
441ba37aa03SKumar Gala 		}
442ba37aa03SKumar Gala 
443ba37aa03SKumar Gala 		for (j = 0; j < 6; j++) {
444ba37aa03SKumar Gala 			mac_addr[j] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
445ba37aa03SKumar Gala 			if (tmp)
446ba37aa03SKumar Gala 				tmp = (*end) ? end+1 : end;
447ba37aa03SKumar Gala 		}
448ba37aa03SKumar Gala 
449ba37aa03SKumar Gala 		do_fixup_by_path(fdt, path, "mac-address", &mac_addr, 6, 0);
450ab544633SKumar Gala 		do_fixup_by_path(fdt, path, "local-mac-address",
451ba37aa03SKumar Gala 				&mac_addr, 6, 1);
452ba37aa03SKumar Gala 
453ba37aa03SKumar Gala 		sprintf(mac, "eth%daddr", ++i);
454ab544633SKumar Gala 	}
455ab544633SKumar Gala }
45618e69a35SAnton Vorontsov 
45718e69a35SAnton Vorontsov #ifdef CONFIG_HAS_FSL_DR_USB
45818e69a35SAnton Vorontsov void fdt_fixup_dr_usb(void *blob, bd_t *bd)
45918e69a35SAnton Vorontsov {
46018e69a35SAnton Vorontsov 	char *mode;
461015b27b9SAnton Vorontsov 	char *type;
46218e69a35SAnton Vorontsov 	const char *compat = "fsl-usb2-dr";
463015b27b9SAnton Vorontsov 	const char *prop_mode = "dr_mode";
464015b27b9SAnton Vorontsov 	const char *prop_type = "phy_type";
46518e69a35SAnton Vorontsov 	int node_offset;
46618e69a35SAnton Vorontsov 	int err;
46718e69a35SAnton Vorontsov 
46818e69a35SAnton Vorontsov 	mode = getenv("usb_dr_mode");
469015b27b9SAnton Vorontsov 	type = getenv("usb_phy_type");
470015b27b9SAnton Vorontsov 	if (!mode && !type)
47118e69a35SAnton Vorontsov 		return;
47218e69a35SAnton Vorontsov 
47318e69a35SAnton Vorontsov 	node_offset = fdt_node_offset_by_compatible(blob, 0, compat);
474015b27b9SAnton Vorontsov 	if (node_offset < 0) {
47518e69a35SAnton Vorontsov 		printf("WARNING: could not find compatible node %s: %s.\n",
47618e69a35SAnton Vorontsov 			compat, fdt_strerror(node_offset));
477015b27b9SAnton Vorontsov 		return;
478015b27b9SAnton Vorontsov 	}
47918e69a35SAnton Vorontsov 
480015b27b9SAnton Vorontsov 	if (mode) {
481015b27b9SAnton Vorontsov 		err = fdt_setprop(blob, node_offset, prop_mode, mode,
482015b27b9SAnton Vorontsov 				  strlen(mode) + 1);
48318e69a35SAnton Vorontsov 		if (err < 0)
48418e69a35SAnton Vorontsov 			printf("WARNING: could not set %s for %s: %s.\n",
485015b27b9SAnton Vorontsov 			       prop_mode, compat, fdt_strerror(err));
486015b27b9SAnton Vorontsov 	}
487015b27b9SAnton Vorontsov 
488015b27b9SAnton Vorontsov 	if (type) {
489015b27b9SAnton Vorontsov 		err = fdt_setprop(blob, node_offset, prop_type, type,
490015b27b9SAnton Vorontsov 				  strlen(type) + 1);
491015b27b9SAnton Vorontsov 		if (err < 0)
492015b27b9SAnton Vorontsov 			printf("WARNING: could not set %s for %s: %s.\n",
493015b27b9SAnton Vorontsov 			       prop_type, compat, fdt_strerror(err));
494015b27b9SAnton Vorontsov 	}
49518e69a35SAnton Vorontsov }
49618e69a35SAnton Vorontsov #endif /* CONFIG_HAS_FSL_DR_USB */
4976b70ffb9SKim Phillips 
4986b70ffb9SKim Phillips #if defined(CONFIG_MPC83XX) || defined(CONFIG_MPC85xx)
4996b70ffb9SKim Phillips /*
5006b70ffb9SKim Phillips  * update crypto node properties to a specified revision of the SEC
5016b70ffb9SKim Phillips  * called with sec_rev == 0 if not on an mpc8xxxE processor
5026b70ffb9SKim Phillips  */
5036b70ffb9SKim Phillips void fdt_fixup_crypto_node(void *blob, int sec_rev)
5046b70ffb9SKim Phillips {
5056b70ffb9SKim Phillips 	const struct sec_rev_prop {
5066b70ffb9SKim Phillips 		u32 sec_rev;
5076b70ffb9SKim Phillips 		u32 num_channels;
5086b70ffb9SKim Phillips 		u32 channel_fifo_len;
5096b70ffb9SKim Phillips 		u32 exec_units_mask;
5106b70ffb9SKim Phillips 		u32 descriptor_types_mask;
5116b70ffb9SKim Phillips 	} sec_rev_prop_list [] = {
5126b70ffb9SKim Phillips 		{ 0x0200, 4, 24, 0x07e, 0x01010ebf }, /* SEC 2.0 */
5136b70ffb9SKim Phillips 		{ 0x0201, 4, 24, 0x0fe, 0x012b0ebf }, /* SEC 2.1 */
5146b70ffb9SKim Phillips 		{ 0x0202, 1, 24, 0x04c, 0x0122003f }, /* SEC 2.2 */
5156b70ffb9SKim Phillips 		{ 0x0204, 4, 24, 0x07e, 0x012b0ebf }, /* SEC 2.4 */
5166b70ffb9SKim Phillips 		{ 0x0300, 4, 24, 0x9fe, 0x03ab0ebf }, /* SEC 3.0 */
5176b70ffb9SKim Phillips 		{ 0x0303, 4, 24, 0x97c, 0x03ab0abf }, /* SEC 3.3 */
5186b70ffb9SKim Phillips 	};
5196b70ffb9SKim Phillips 	char compat_strlist[ARRAY_SIZE(sec_rev_prop_list) *
5206b70ffb9SKim Phillips 			    sizeof("fsl,secX.Y")];
5216b70ffb9SKim Phillips 	int crypto_node, sec_idx, err;
5226b70ffb9SKim Phillips 	char *p;
5236b70ffb9SKim Phillips 	u32 val;
5246b70ffb9SKim Phillips 
5256b70ffb9SKim Phillips 	/* locate crypto node based on lowest common compatible */
5266b70ffb9SKim Phillips 	crypto_node = fdt_node_offset_by_compatible(blob, -1, "fsl,sec2.0");
5276b70ffb9SKim Phillips 	if (crypto_node == -FDT_ERR_NOTFOUND)
5286b70ffb9SKim Phillips 		return;
5296b70ffb9SKim Phillips 
5306b70ffb9SKim Phillips 	/* delete it if not on an E-processor */
5316b70ffb9SKim Phillips 	if (crypto_node > 0 && !sec_rev) {
5326b70ffb9SKim Phillips 		fdt_del_node(blob, crypto_node);
5336b70ffb9SKim Phillips 		return;
5346b70ffb9SKim Phillips 	}
5356b70ffb9SKim Phillips 
5366b70ffb9SKim Phillips 	/* else we got called for possible uprev */
5376b70ffb9SKim Phillips 	for (sec_idx = 0; sec_idx < ARRAY_SIZE(sec_rev_prop_list); sec_idx++)
5386b70ffb9SKim Phillips 		if (sec_rev_prop_list[sec_idx].sec_rev == sec_rev)
5396b70ffb9SKim Phillips 			break;
5406b70ffb9SKim Phillips 
5416b70ffb9SKim Phillips 	if (sec_idx == ARRAY_SIZE(sec_rev_prop_list)) {
5426b70ffb9SKim Phillips 		puts("warning: unknown SEC revision number\n");
5436b70ffb9SKim Phillips 		return;
5446b70ffb9SKim Phillips 	}
5456b70ffb9SKim Phillips 
5466b70ffb9SKim Phillips 	val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].num_channels);
5476b70ffb9SKim Phillips 	err = fdt_setprop(blob, crypto_node, "fsl,num-channels", &val, 4);
5486b70ffb9SKim Phillips 	if (err < 0)
5496b70ffb9SKim Phillips 		printf("WARNING: could not set crypto property: %s\n",
5506b70ffb9SKim Phillips 		       fdt_strerror(err));
5516b70ffb9SKim Phillips 
5526b70ffb9SKim Phillips 	val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].descriptor_types_mask);
5536b70ffb9SKim Phillips 	err = fdt_setprop(blob, crypto_node, "fsl,descriptor-types-mask", &val, 4);
5546b70ffb9SKim Phillips 	if (err < 0)
5556b70ffb9SKim Phillips 		printf("WARNING: could not set crypto property: %s\n",
5566b70ffb9SKim Phillips 		       fdt_strerror(err));
5576b70ffb9SKim Phillips 
5586b70ffb9SKim Phillips 	val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].exec_units_mask);
5596b70ffb9SKim Phillips 	err = fdt_setprop(blob, crypto_node, "fsl,exec-units-mask", &val, 4);
5606b70ffb9SKim Phillips 	if (err < 0)
5616b70ffb9SKim Phillips 		printf("WARNING: could not set crypto property: %s\n",
5626b70ffb9SKim Phillips 		       fdt_strerror(err));
5636b70ffb9SKim Phillips 
5646b70ffb9SKim Phillips 	val = cpu_to_fdt32(sec_rev_prop_list[sec_idx].channel_fifo_len);
5656b70ffb9SKim Phillips 	err = fdt_setprop(blob, crypto_node, "fsl,channel-fifo-len", &val, 4);
5666b70ffb9SKim Phillips 	if (err < 0)
5676b70ffb9SKim Phillips 		printf("WARNING: could not set crypto property: %s\n",
5686b70ffb9SKim Phillips 		       fdt_strerror(err));
5696b70ffb9SKim Phillips 
5706b70ffb9SKim Phillips 	val = 0;
5716b70ffb9SKim Phillips 	while (sec_idx >= 0) {
5726b70ffb9SKim Phillips 		p = compat_strlist + val;
5736b70ffb9SKim Phillips 		val += sprintf(p, "fsl,sec%d.%d",
5746b70ffb9SKim Phillips 			(sec_rev_prop_list[sec_idx].sec_rev & 0xff00) >> 8,
5756b70ffb9SKim Phillips 			sec_rev_prop_list[sec_idx].sec_rev & 0x00ff) + 1;
5766b70ffb9SKim Phillips 		sec_idx--;
5776b70ffb9SKim Phillips 	}
5786b70ffb9SKim Phillips 	err = fdt_setprop(blob, crypto_node, "compatible", &compat_strlist, val);
5796b70ffb9SKim Phillips 	if (err < 0)
5806b70ffb9SKim Phillips 		printf("WARNING: could not set crypto property: %s\n",
5816b70ffb9SKim Phillips 		       fdt_strerror(err));
5826b70ffb9SKim Phillips }
5836b70ffb9SKim Phillips #endif /* defined(CONFIG_MPC83XX) || defined(CONFIG_MPC85xx) */
5843082d234SKumar Gala 
5853082d234SKumar Gala /* Resize the fdt to its actual size + a bit of padding */
5863082d234SKumar Gala int fdt_resize(void *blob)
5873082d234SKumar Gala {
5883082d234SKumar Gala 	int i;
5893082d234SKumar Gala 	uint64_t addr, size;
5903082d234SKumar Gala 	int total, ret;
5913082d234SKumar Gala 	uint actualsize;
5923082d234SKumar Gala 
5933082d234SKumar Gala 	if (!blob)
5943082d234SKumar Gala 		return 0;
5953082d234SKumar Gala 
5963082d234SKumar Gala 	total = fdt_num_mem_rsv(blob);
5973082d234SKumar Gala 	for (i = 0; i < total; i++) {
5983082d234SKumar Gala 		fdt_get_mem_rsv(blob, i, &addr, &size);
5993082d234SKumar Gala 		if (addr == (uint64_t)(u32)blob) {
6003082d234SKumar Gala 			fdt_del_mem_rsv(blob, i);
6013082d234SKumar Gala 			break;
6023082d234SKumar Gala 		}
6033082d234SKumar Gala 	}
6043082d234SKumar Gala 
605f242a088SPeter Korsgaard 	/*
606f242a088SPeter Korsgaard 	 * Calculate the actual size of the fdt
607f242a088SPeter Korsgaard 	 * plus the size needed for fdt_add_mem_rsv
608f242a088SPeter Korsgaard 	 */
6093082d234SKumar Gala 	actualsize = fdt_off_dt_strings(blob) +
610f242a088SPeter Korsgaard 		fdt_size_dt_strings(blob) + sizeof(struct fdt_reserve_entry);
6113082d234SKumar Gala 
6123082d234SKumar Gala 	/* Make it so the fdt ends on a page boundary */
613c088a108SPeter Korsgaard 	actualsize = ALIGN(actualsize + ((uint)blob & 0xfff), 0x1000);
6143082d234SKumar Gala 	actualsize = actualsize - ((uint)blob & 0xfff);
6153082d234SKumar Gala 
6163082d234SKumar Gala 	/* Change the fdt header to reflect the correct size */
6173082d234SKumar Gala 	fdt_set_totalsize(blob, actualsize);
6183082d234SKumar Gala 
6193082d234SKumar Gala 	/* Add the new reservation */
6203082d234SKumar Gala 	ret = fdt_add_mem_rsv(blob, (uint)blob, actualsize);
6213082d234SKumar Gala 	if (ret < 0)
6223082d234SKumar Gala 		return ret;
6233082d234SKumar Gala 
6243082d234SKumar Gala 	return actualsize;
6253082d234SKumar Gala }
6268ab451c4SKumar Gala 
6278ab451c4SKumar Gala #ifdef CONFIG_PCI
6288ab451c4SKumar Gala #define CONFIG_SYS_PCI_NR_INBOUND_WIN 3
6298ab451c4SKumar Gala 
6308ab451c4SKumar Gala #define FDT_PCI_PREFETCH	(0x40000000)
6318ab451c4SKumar Gala #define FDT_PCI_MEM32		(0x02000000)
6328ab451c4SKumar Gala #define FDT_PCI_IO		(0x01000000)
6338ab451c4SKumar Gala #define FDT_PCI_MEM64		(0x03000000)
6348ab451c4SKumar Gala 
6358ab451c4SKumar Gala int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
6368ab451c4SKumar Gala 
6378ab451c4SKumar Gala 	int addrcell, sizecell, len, r;
6388ab451c4SKumar Gala 	u32 *dma_range;
6398ab451c4SKumar Gala 	/* sized based on pci addr cells, size-cells, & address-cells */
6408ab451c4SKumar Gala 	u32 dma_ranges[(3 + 2 + 2) * CONFIG_SYS_PCI_NR_INBOUND_WIN];
6418ab451c4SKumar Gala 
6428ab451c4SKumar Gala 	addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1);
6438ab451c4SKumar Gala 	sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1);
6448ab451c4SKumar Gala 
6458ab451c4SKumar Gala 	dma_range = &dma_ranges[0];
6468ab451c4SKumar Gala 	for (r = 0; r < hose->region_count; r++) {
6478ab451c4SKumar Gala 		u64 bus_start, phys_start, size;
6488ab451c4SKumar Gala 
649*ff4e66e9SKumar Gala 		/* skip if !PCI_REGION_SYS_MEMORY */
650*ff4e66e9SKumar Gala 		if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY))
6518ab451c4SKumar Gala 			continue;
6528ab451c4SKumar Gala 
6538ab451c4SKumar Gala 		bus_start = (u64)hose->regions[r].bus_start;
6548ab451c4SKumar Gala 		phys_start = (u64)hose->regions[r].phys_start;
6558ab451c4SKumar Gala 		size = (u64)hose->regions[r].size;
6568ab451c4SKumar Gala 
6578ab451c4SKumar Gala 		dma_range[0] = 0;
6588ab451c4SKumar Gala 		if (size > 0x100000000ull)
6598ab451c4SKumar Gala 			dma_range[0] |= FDT_PCI_MEM64;
6608ab451c4SKumar Gala 		else
6618ab451c4SKumar Gala 			dma_range[0] |= FDT_PCI_MEM32;
6628ab451c4SKumar Gala 		if (hose->regions[r].flags & PCI_REGION_PREFETCH)
6638ab451c4SKumar Gala 			dma_range[0] |= FDT_PCI_PREFETCH;
6648ab451c4SKumar Gala #ifdef CONFIG_SYS_PCI_64BIT
6658ab451c4SKumar Gala 		dma_range[1] = bus_start >> 32;
6668ab451c4SKumar Gala #else
6678ab451c4SKumar Gala 		dma_range[1] = 0;
6688ab451c4SKumar Gala #endif
6698ab451c4SKumar Gala 		dma_range[2] = bus_start & 0xffffffff;
6708ab451c4SKumar Gala 
6718ab451c4SKumar Gala 		if (addrcell == 2) {
6728ab451c4SKumar Gala 			dma_range[3] = phys_start >> 32;
6738ab451c4SKumar Gala 			dma_range[4] = phys_start & 0xffffffff;
6748ab451c4SKumar Gala 		} else {
6758ab451c4SKumar Gala 			dma_range[3] = phys_start & 0xffffffff;
6768ab451c4SKumar Gala 		}
6778ab451c4SKumar Gala 
6788ab451c4SKumar Gala 		if (sizecell == 2) {
6798ab451c4SKumar Gala 			dma_range[3 + addrcell + 0] = size >> 32;
6808ab451c4SKumar Gala 			dma_range[3 + addrcell + 1] = size & 0xffffffff;
6818ab451c4SKumar Gala 		} else {
6828ab451c4SKumar Gala 			dma_range[3 + addrcell + 0] = size & 0xffffffff;
6838ab451c4SKumar Gala 		}
6848ab451c4SKumar Gala 
6858ab451c4SKumar Gala 		dma_range += (3 + addrcell + sizecell);
6868ab451c4SKumar Gala 	}
6878ab451c4SKumar Gala 
6888ab451c4SKumar Gala 	len = dma_range - &dma_ranges[0];
6898ab451c4SKumar Gala 	if (len)
6908ab451c4SKumar Gala 		fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4);
6918ab451c4SKumar Gala 
6928ab451c4SKumar Gala 	return 0;
6938ab451c4SKumar Gala }
6948ab451c4SKumar Gala #endif
695