blob: 797f04bedb47e4175ed8cdc707efe12a71ec0693 [file] [log] [blame]
Nicolas Pitreb90b9a32011-09-13 22:37:07 -04001#include <asm/setup.h>
2#include <libfdt.h>
3
4static 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
12static 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
21static 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
30static 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 */
47int 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;
Marc Zyngiera106b212012-04-11 14:52:56 +010080 if (!atag->u.mem.size)
81 continue;
Nicolas Pitreb90b9a32011-09-13 22:37:07 -040082 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}