797f04bedb47e4175ed8cdc707efe12a71ec0693
[linux-2.6.git] / arch / arm / boot / compressed / atags_to_fdt.c
1 #include <asm/setup.h>
2 #include <libfdt.h>
3
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
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
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
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  */
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 }