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