1 #include <asm/setup.h>
2 #include <libfdt.h>
3 
node_offset(void * fdt,const char * node_path)4 static int node_offset(void *fdt, const char *node_path)
5 {
6 	int offset = fdt_path_offset(fdt, node_path);
7 	if (offset == -FDT_ERR_NOTFOUND)
8 		offset = fdt_add_subnode(fdt, 0, node_path);
9 	return offset;
10 }
11 
setprop(void * fdt,const char * node_path,const char * property,uint32_t * val_array,int size)12 static int setprop(void *fdt, const char *node_path, const char *property,
13 		   uint32_t *val_array, int size)
14 {
15 	int offset = node_offset(fdt, node_path);
16 	if (offset < 0)
17 		return offset;
18 	return fdt_setprop(fdt, offset, property, val_array, size);
19 }
20 
setprop_string(void * fdt,const char * node_path,const char * property,const char * string)21 static int setprop_string(void *fdt, const char *node_path,
22 			  const char *property, const char *string)
23 {
24 	int offset = node_offset(fdt, node_path);
25 	if (offset < 0)
26 		return offset;
27 	return fdt_setprop_string(fdt, offset, property, string);
28 }
29 
setprop_cell(void * fdt,const char * node_path,const char * property,uint32_t val)30 static int setprop_cell(void *fdt, const char *node_path,
31 			const char *property, uint32_t val)
32 {
33 	int offset = node_offset(fdt, node_path);
34 	if (offset < 0)
35 		return offset;
36 	return fdt_setprop_cell(fdt, offset, property, val);
37 }
38 
39 /*
40  * Convert and fold provided ATAGs into the provided FDT.
41  *
42  * REturn values:
43  *    = 0 -> pretend success
44  *    = 1 -> bad ATAG (may retry with another possible ATAG pointer)
45  *    < 0 -> error from libfdt
46  */
atags_to_fdt(void * atag_list,void * fdt,int total_space)47 int atags_to_fdt(void *atag_list, void *fdt, int total_space)
48 {
49 	struct tag *atag = atag_list;
50 	uint32_t mem_reg_property[2 * NR_BANKS];
51 	int memcount = 0;
52 	int ret;
53 
54 	/* make sure we've got an aligned pointer */
55 	if ((u32)atag_list & 0x3)
56 		return 1;
57 
58 	/* if we get a DTB here we're done already */
59 	if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC))
60 	       return 0;
61 
62 	/* validate the ATAG */
63 	if (atag->hdr.tag != ATAG_CORE ||
64 	    (atag->hdr.size != tag_size(tag_core) &&
65 	     atag->hdr.size != 2))
66 		return 1;
67 
68 	/* let's give it all the room it could need */
69 	ret = fdt_open_into(fdt, fdt, total_space);
70 	if (ret < 0)
71 		return ret;
72 
73 	for_each_tag(atag, atag_list) {
74 		if (atag->hdr.tag == ATAG_CMDLINE) {
75 			setprop_string(fdt, "/chosen", "bootargs",
76 					atag->u.cmdline.cmdline);
77 		} else if (atag->hdr.tag == ATAG_MEM) {
78 			if (memcount >= sizeof(mem_reg_property)/4)
79 				continue;
80 			if (!atag->u.mem.size)
81 				continue;
82 			mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start);
83 			mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size);
84 		} else if (atag->hdr.tag == ATAG_INITRD2) {
85 			uint32_t initrd_start, initrd_size;
86 			initrd_start = atag->u.initrd.start;
87 			initrd_size = atag->u.initrd.size;
88 			setprop_cell(fdt, "/chosen", "linux,initrd-start",
89 					initrd_start);
90 			setprop_cell(fdt, "/chosen", "linux,initrd-end",
91 					initrd_start + initrd_size);
92 		}
93 	}
94 
95 	if (memcount)
96 		setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount);
97 
98 	return fdt_pack(fdt);
99 }
100