ARM: bcm283x: use OF_CONTROL for bcm283x
[platform/kernel/u-boot.git] / lib / libfdt / fdt_wip.c
1 /*
2  * libfdt - Flat Device Tree manipulation
3  * Copyright (C) 2006 David Gibson, IBM Corporation.
4  * SPDX-License-Identifier:     GPL-2.0+ BSD-2-Clause
5  */
6 #include <libfdt_env.h>
7
8 #ifndef USE_HOSTCC
9 #include <fdt.h>
10 #include <libfdt.h>
11 #else
12 #include "fdt_host.h"
13 #endif
14
15 #include "libfdt_internal.h"
16
17 int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
18                                         const char *name, int namelen,
19                                         uint32_t idx, const void *val,
20                                         int len)
21 {
22         void *propval;
23         int proplen;
24
25         propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen,
26                                         &proplen);
27         if (!propval)
28                 return proplen;
29
30         if (proplen < (len + idx))
31                 return -FDT_ERR_NOSPACE;
32
33         memcpy((char *)propval + idx, val, len);
34         return 0;
35 }
36
37 int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
38                         const void *val, int len)
39 {
40         const void *propval;
41         int proplen;
42
43         propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
44         if (!propval)
45                 return proplen;
46
47         if (proplen != len)
48                 return -FDT_ERR_NOSPACE;
49
50         return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name,
51                                                    strlen(name), 0,
52                                                    val, len);
53 }
54
55 static void _fdt_nop_region(void *start, int len)
56 {
57         fdt32_t *p;
58
59         for (p = start; (char *)p < ((char *)start + len); p++)
60                 *p = cpu_to_fdt32(FDT_NOP);
61 }
62
63 int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
64 {
65         struct fdt_property *prop;
66         int len;
67
68         prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
69         if (!prop)
70                 return len;
71
72         _fdt_nop_region(prop, len + sizeof(*prop));
73
74         return 0;
75 }
76
77 int _fdt_node_end_offset(void *fdt, int offset)
78 {
79         int depth = 0;
80
81         while ((offset >= 0) && (depth >= 0))
82                 offset = fdt_next_node(fdt, offset, &depth);
83
84         return offset;
85 }
86
87 int fdt_nop_node(void *fdt, int nodeoffset)
88 {
89         int endoffset;
90
91         endoffset = _fdt_node_end_offset(fdt, nodeoffset);
92         if (endoffset < 0)
93                 return endoffset;
94
95         _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
96                         endoffset - nodeoffset);
97         return 0;
98 }
99
100 #define FDT_MAX_DEPTH   32
101
102 static int str_in_list(const char *str, char * const list[], int count)
103 {
104         int i;
105
106         for (i = 0; i < count; i++)
107                 if (!strcmp(list[i], str))
108                         return 1;
109
110         return 0;
111 }
112
113 int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
114                      char * const exc_prop[], int exc_prop_count,
115                      struct fdt_region region[], int max_regions,
116                      char *path, int path_len, int add_string_tab)
117 {
118         int stack[FDT_MAX_DEPTH];
119         char *end;
120         int nextoffset = 0;
121         uint32_t tag;
122         int count = 0;
123         int start = -1;
124         int depth = -1;
125         int want = 0;
126         int base = fdt_off_dt_struct(fdt);
127
128         end = path;
129         *end = '\0';
130         do {
131                 const struct fdt_property *prop;
132                 const char *name;
133                 const char *str;
134                 int include = 0;
135                 int stop_at = 0;
136                 int offset;
137                 int len;
138
139                 offset = nextoffset;
140                 tag = fdt_next_tag(fdt, offset, &nextoffset);
141                 stop_at = nextoffset;
142
143                 switch (tag) {
144                 case FDT_PROP:
145                         include = want >= 2;
146                         stop_at = offset;
147                         prop = fdt_get_property_by_offset(fdt, offset, NULL);
148                         str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
149                         if (str_in_list(str, exc_prop, exc_prop_count))
150                                 include = 0;
151                         break;
152
153                 case FDT_NOP:
154                         include = want >= 2;
155                         stop_at = offset;
156                         break;
157
158                 case FDT_BEGIN_NODE:
159                         depth++;
160                         if (depth == FDT_MAX_DEPTH)
161                                 return -FDT_ERR_BADSTRUCTURE;
162                         name = fdt_get_name(fdt, offset, &len);
163                         if (end - path + 2 + len >= path_len)
164                                 return -FDT_ERR_NOSPACE;
165                         if (end != path + 1)
166                                 *end++ = '/';
167                         strcpy(end, name);
168                         end += len;
169                         stack[depth] = want;
170                         if (want == 1)
171                                 stop_at = offset;
172                         if (str_in_list(path, inc, inc_count))
173                                 want = 2;
174                         else if (want)
175                                 want--;
176                         else
177                                 stop_at = offset;
178                         include = want;
179                         break;
180
181                 case FDT_END_NODE:
182                         include = want;
183                         want = stack[depth--];
184                         while (end > path && *--end != '/')
185                                 ;
186                         *end = '\0';
187                         break;
188
189                 case FDT_END:
190                         include = 1;
191                         break;
192                 }
193
194                 if (include && start == -1) {
195                         /* Should we merge with previous? */
196                         if (count && count <= max_regions &&
197                             offset == region[count - 1].offset +
198                                         region[count - 1].size - base)
199                                 start = region[--count].offset - base;
200                         else
201                                 start = offset;
202                 }
203
204                 if (!include && start != -1) {
205                         if (count < max_regions) {
206                                 region[count].offset = base + start;
207                                 region[count].size = stop_at - start;
208                         }
209                         count++;
210                         start = -1;
211                 }
212         } while (tag != FDT_END);
213
214         if (nextoffset != fdt_size_dt_struct(fdt))
215                 return -FDT_ERR_BADLAYOUT;
216
217         /* Add a region for the END tag and the string table */
218         if (count < max_regions) {
219                 region[count].offset = base + start;
220                 region[count].size = nextoffset - start;
221                 if (add_string_tab)
222                         region[count].size += fdt_size_dt_strings(fdt);
223         }
224         count++;
225
226         return count;
227 }