1#include <asm/setup.h>
2#include <libfdt.h>
3
4#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND)
5#define do_extend_cmdline 1
6#else
7#define do_extend_cmdline 0
8#endif
9
10static int node_offset(void *fdt, const char *node_path)
11{
12 int offset = fdt_path_offset(fdt, node_path);
13 if (offset == -FDT_ERR_NOTFOUND)
14 offset = fdt_add_subnode(fdt, 0, node_path);
15 return offset;
16}
17
18static int setprop(void *fdt, const char *node_path, const char *property,
19 uint32_t *val_array, int size)
20{
21 int offset = node_offset(fdt, node_path);
22 if (offset < 0)
23 return offset;
24 return fdt_setprop(fdt, offset, property, val_array, size);
25}
26
27static int setprop_string(void *fdt, const char *node_path,
28 const char *property, const char *string)
29{
30 int offset = node_offset(fdt, node_path);
31 if (offset < 0)
32 return offset;
33 return fdt_setprop_string(fdt, offset, property, string);
34}
35
36static int setprop_cell(void *fdt, const char *node_path,
37 const char *property, uint32_t val)
38{
39 int offset = node_offset(fdt, node_path);
40 if (offset < 0)
41 return offset;
42 return fdt_setprop_cell(fdt, offset, property, val);
43}
44
45static const void *getprop(const void *fdt, const char *node_path,
46 const char *property, int *len)
47{
48 int offset = fdt_path_offset(fdt, node_path);
49
50 if (offset == -FDT_ERR_NOTFOUND)
51 return NULL;
52
53 return fdt_getprop(fdt, offset, property, len);
54}
55
56static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
57{
58 char cmdline[COMMAND_LINE_SIZE];
59 const char *fdt_bootargs;
60 char *ptr = cmdline;
61 int len = 0;
62
63
64 fdt_bootargs = getprop(fdt, "/chosen", "bootargs", &len);
65 if (fdt_bootargs)
66 if (len < COMMAND_LINE_SIZE) {
67 memcpy(ptr, fdt_bootargs, len);
68
69
70 ptr += len - 1;
71 }
72
73
74 if (fdt_cmdline) {
75 len = strlen(fdt_cmdline);
76 if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) {
77 *ptr++ = ' ';
78 memcpy(ptr, fdt_cmdline, len);
79 ptr += len;
80 }
81 }
82 *ptr = '\0';
83
84 setprop_string(fdt, "/chosen", "bootargs", cmdline);
85}
86
87
88
89
90
91
92
93
94
95int atags_to_fdt(void *atag_list, void *fdt, int total_space)
96{
97 struct tag *atag = atag_list;
98 uint32_t mem_reg_property[2 * NR_BANKS];
99 int memcount = 0;
100 int ret;
101
102
103 if ((u32)atag_list & 0x3)
104 return 1;
105
106
107 if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC))
108 return 0;
109
110
111 if (atag->hdr.tag != ATAG_CORE ||
112 (atag->hdr.size != tag_size(tag_core) &&
113 atag->hdr.size != 2))
114 return 1;
115
116
117 ret = fdt_open_into(fdt, fdt, total_space);
118 if (ret < 0)
119 return ret;
120
121 for_each_tag(atag, atag_list) {
122 if (atag->hdr.tag == ATAG_CMDLINE) {
123
124
125
126
127
128
129 if (do_extend_cmdline)
130 merge_fdt_bootargs(fdt,
131 atag->u.cmdline.cmdline);
132 else
133 setprop_string(fdt, "/chosen", "bootargs",
134 atag->u.cmdline.cmdline);
135 } else if (atag->hdr.tag == ATAG_MEM) {
136 if (memcount >= sizeof(mem_reg_property)/4)
137 continue;
138 if (!atag->u.mem.size)
139 continue;
140 mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start);
141 mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size);
142 } else if (atag->hdr.tag == ATAG_INITRD2) {
143 uint32_t initrd_start, initrd_size;
144 initrd_start = atag->u.initrd.start;
145 initrd_size = atag->u.initrd.size;
146 setprop_cell(fdt, "/chosen", "linux,initrd-start",
147 initrd_start);
148 setprop_cell(fdt, "/chosen", "linux,initrd-end",
149 initrd_start + initrd_size);
150 }
151 }
152
153 if (memcount)
154 setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount);
155
156 return fdt_pack(fdt);
157}
158