Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
atags_to_fdt.c
Go to the documentation of this file.
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 
10 static 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 
18 static 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 
27 static 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 
36 static 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 
45 static 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 
56 static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
57 {
59  const char *fdt_bootargs;
60  char *ptr = cmdline;
61  int len = 0;
62 
63  /* copy the fdt command line into the buffer */
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  /* len is the length of the string
69  * including the NULL terminator */
70  ptr += len - 1;
71  }
72 
73  /* and append the ATAG_CMDLINE */
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  * Convert and fold provided ATAGs into the provided FDT.
89  *
90  * REturn values:
91  * = 0 -> pretend success
92  * = 1 -> bad ATAG (may retry with another possible ATAG pointer)
93  * < 0 -> error from libfdt
94  */
95 int 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  /* make sure we've got an aligned pointer */
103  if ((u32)atag_list & 0x3)
104  return 1;
105 
106  /* if we get a DTB here we're done already */
107  if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC))
108  return 0;
109 
110  /* validate the ATAG */
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  /* let's give it all the room it could need */
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  /* Append the ATAGS command line to the device tree
124  * command line.
125  * NB: This means that if the same parameter is set in
126  * the device tree and in the tags, the one from the
127  * tags will be chosen.
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 }