xref: /rk3399_rockchip-uboot/common/fdt_support.c (revision 64dbbd40c58349b64f43fd33dbb5ca0adb67d642)
1 /*
2  * (C) Copyright 2007
3  * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 
24 #include <common.h>
25 #include <linux/ctype.h>
26 #include <linux/types.h>
27 
28 #ifdef CONFIG_OF_LIBFDT
29 
30 #include <asm/global_data.h>
31 #include <fdt.h>
32 #include <libfdt.h>
33 #include <fdt_support.h>
34 
35 /*
36  * Global data (for the gd->bd)
37  */
38 DECLARE_GLOBAL_DATA_PTR;
39 
40 
41 /********************************************************************/
42 
43 int fdt_chosen(void *fdt, ulong initrd_start, ulong initrd_end, int force)
44 {
45 	bd_t *bd = gd->bd;
46 	int   nodeoffset;
47 	int   err;
48 	u32   tmp;			/* used to set 32 bit integer properties */
49 	char  *str;			/* used to set string properties */
50 	ulong clock;
51 
52 	err = fdt_check_header(fdt);
53 	if (err < 0) {
54 		printf("libfdt: %s\n", fdt_strerror(err));
55 		return err;
56 	}
57 
58 #warning "Don't double-add the reserved map"
59 	if (initrd_start && initrd_end) {
60 		err = fdt_add_reservemap_entry(fdt,
61 			initrd_start, initrd_end - initrd_start + 1);
62 		if (err < 0) {
63 			printf("libfdt: %s\n", fdt_strerror(err));
64 			return err;
65 		}
66 	}
67 
68 	/*
69 	 * Find the "chosen" node.
70 	 */
71 	nodeoffset = fdt_path_offset (fdt, "/chosen");
72 
73 	/*
74 	 * If we have a "chosen" node already the "force the writing"
75 	 * is not set, our job is done.
76 	 */
77 	if ((nodeoffset >= 0) && !force)
78 		return 0;
79 
80 	/*
81 	 * No "chosen" node in the blob: create it.
82 	 */
83 	if (nodeoffset < 0) {
84 		/*
85 		 * Create a new node "/chosen" (offset 0 is root level)
86 		 */
87 		nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
88 		if (nodeoffset < 0) {
89 			printf("libfdt: %s\n", fdt_strerror(nodeoffset));
90 			return nodeoffset;
91 		}
92 	}
93 
94 	/*
95 	 * Update pre-existing properties, create them if non-existant.
96 	 */
97 	str = getenv("bootargs");
98 	if (str != NULL) {
99 		err = fdt_setprop(fdt, nodeoffset, "bootargs", str, strlen(str)+1);
100 		if (err < 0)
101 			printf("libfdt: %s\n", fdt_strerror(err));
102 	}
103 	if (initrd_start && initrd_end) {
104 		tmp = __cpu_to_be32(initrd_start);
105 		err = fdt_setprop(fdt, nodeoffset, "linux,initrd-start", &tmp, sizeof(tmp));
106 		if (err < 0)
107 			printf("libfdt: %s\n", fdt_strerror(err));
108 		tmp = __cpu_to_be32(initrd_end);
109 		err = fdt_setprop(fdt, nodeoffset, "linux,initrd-end", &tmp, sizeof(tmp));
110 		if (err < 0)
111 			printf("libfdt: %s\n", fdt_strerror(err));
112 	}
113 #ifdef OF_STDOUT_PATH
114 	err = fdt_setprop(fdt, nodeoffset, "linux,stdout-path", OF_STDOUT_PATH, strlen(OF_STDOUT_PATH)+1);
115 	if (err < 0)
116 		printf("libfdt: %s\n", fdt_strerror(err));
117 #endif
118 
119 	nodeoffset = fdt_path_offset (fdt, "/cpus");
120 	if (nodeoffset >= 0) {
121 		clock = cpu_to_be32(bd->bi_intfreq);
122 		err = fdt_setprop(fdt, nodeoffset, "clock-frequency", &clock, 4);
123 		if (err < 0)
124 			printf("libfdt: %s\n", fdt_strerror(err));
125 	}
126 #ifdef OF_TBCLK
127 	nodeoffset = fdt_path_offset (fdt, "/cpus/" OF_CPU "/timebase-frequency");
128 	if (nodeoffset >= 0) {
129 		clock = cpu_to_be32(OF_TBCLK);
130 		err = fdt_setprop(fdt, nodeoffset, "clock-frequency", &clock, 4);
131 		if (err < 0)
132 			printf("libfdt: %s\n", fdt_strerror(err));
133 	}
134 #endif
135 	return err;
136 }
137 
138 /********************************************************************/
139 
140 #ifdef CONFIG_OF_HAS_UBOOT_ENV
141 
142 /* Function that returns a character from the environment */
143 extern uchar(*env_get_char) (int);
144 
145 
146 int fdt_env(void *fdt)
147 {
148 	int   nodeoffset;
149 	int   err;
150 	int   k, nxt;
151 	int i;
152 	static char tmpenv[256];
153 
154 	err = fdt_check_header(fdt);
155 	if (err < 0) {
156 		printf("libfdt: %s\n", fdt_strerror(err));
157 		return err;
158 	}
159 
160 	/*
161 	 * See if we already have a "u-boot-env" node, delete it if so.
162 	 * Then create a new empty node.
163 	 */
164 	nodeoffset = fdt_path_offset (fdt, "/u-boot-env");
165 	if (nodeoffset >= 0) {
166 		err = fdt_del_node(fdt, nodeoffset);
167 		if (err < 0) {
168 			printf("libfdt: %s\n", fdt_strerror(err));
169 			return err;
170 		}
171 	}
172 	/*
173 	 * Create a new node "/u-boot-env" (offset 0 is root level)
174 	 */
175 	nodeoffset = fdt_add_subnode(fdt, 0, "u-boot-env");
176 	if (nodeoffset < 0) {
177 		printf("libfdt: %s\n", fdt_strerror(nodeoffset));
178 		return nodeoffset;
179 	}
180 
181 	for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
182 		char *s, *lval, *rval;
183 
184 		/*
185 		 * Find the end of the name=definition
186 		 */
187 		for (nxt = i; env_get_char(nxt) != '\0'; ++nxt)
188 			;
189 		s = tmpenv;
190 		for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k)
191 			*s++ = env_get_char(k);
192 		*s++ = '\0';
193 		lval = tmpenv;
194 		/*
195 		 * Find the first '=': it separates the name from the value
196 		 */
197 		s = strchr(tmpenv, '=');
198 		if (s != NULL) {
199 			*s++ = '\0';
200 			rval = s;
201 		} else
202 			continue;
203 		err = fdt_setprop(fdt, nodeoffset, lval, rval, strlen(rval)+1);
204 		if (err < 0) {
205 			printf("libfdt: %s\n", lval, fdt_strerror(err));
206 			return err;
207 		}
208 	}
209 	return 0;
210 }
211 #endif /* CONFIG_OF_HAS_UBOOT_ENV */
212 
213 /********************************************************************/
214 
215 #ifdef CONFIG_OF_HAS_BD_T
216 
217 #define BDM(x)	{	.name = #x, .offset = offsetof(bd_t, bi_ ##x ) }
218 
219 static const struct {
220 	const char *name;
221 	int offset;
222 } bd_map[] = {
223 	BDM(memstart),
224 	BDM(memsize),
225 	BDM(flashstart),
226 	BDM(flashsize),
227 	BDM(flashoffset),
228 	BDM(sramstart),
229 	BDM(sramsize),
230 #if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \
231 	|| defined(CONFIG_E500)
232 	BDM(immr_base),
233 #endif
234 #if defined(CONFIG_MPC5xxx)
235 	BDM(mbar_base),
236 #endif
237 #if defined(CONFIG_MPC83XX)
238 	BDM(immrbar),
239 #endif
240 #if defined(CONFIG_MPC8220)
241 	BDM(mbar_base),
242 	BDM(inpfreq),
243 	BDM(pcifreq),
244 	BDM(pevfreq),
245 	BDM(flbfreq),
246 	BDM(vcofreq),
247 #endif
248 	BDM(bootflags),
249 	BDM(ip_addr),
250 	BDM(intfreq),
251 	BDM(busfreq),
252 #ifdef CONFIG_CPM2
253 	BDM(cpmfreq),
254 	BDM(brgfreq),
255 	BDM(sccfreq),
256 	BDM(vco),
257 #endif
258 #if defined(CONFIG_MPC5xxx)
259 	BDM(ipbfreq),
260 	BDM(pcifreq),
261 #endif
262 	BDM(baudrate),
263 };
264 
265 
266 int fdt_bd_t(void *fdt)
267 {
268 	bd_t *bd = gd->bd;
269 	int   nodeoffset;
270 	int   err;
271 	u32   tmp;			/* used to set 32 bit integer properties */
272 	int i;
273 
274 	err = fdt_check_header(fdt);
275 	if (err < 0) {
276 		printf("libfdt: %s\n", fdt_strerror(err));
277 		return err;
278 	}
279 
280 	/*
281 	 * See if we already have a "bd_t" node, delete it if so.
282 	 * Then create a new empty node.
283 	 */
284 	nodeoffset = fdt_path_offset (fdt, "/bd_t");
285 	if (nodeoffset >= 0) {
286 		err = fdt_del_node(fdt, nodeoffset);
287 		if (err < 0) {
288 			printf("libfdt: %s\n", fdt_strerror(err));
289 			return err;
290 		}
291 	}
292 	/*
293 	 * Create a new node "/bd_t" (offset 0 is root level)
294 	 */
295 	nodeoffset = fdt_add_subnode(fdt, 0, "bd_t");
296 	if (nodeoffset < 0) {
297 		printf("libfdt: %s\n", fdt_strerror(nodeoffset));
298 		return nodeoffset;
299 	}
300 	/*
301 	 * Use the string/pointer structure to create the entries...
302 	 */
303 	for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) {
304 		tmp = cpu_to_be32(getenv("bootargs"));
305 		err = fdt_setprop(fdt, nodeoffset, bd_map[i].name, &tmp, sizeof(tmp));
306 		if (err < 0)
307 			printf("libfdt: %s\n", fdt_strerror(err));
308 	}
309 	/*
310 	 * Add a couple of oddball entries...
311 	 */
312 	err = fdt_setprop(fdt, nodeoffset, "enetaddr", &bd->bi_enetaddr, 6);
313 	if (err < 0)
314 		printf("libfdt: %s\n", fdt_strerror(err));
315 	err = fdt_setprop(fdt, nodeoffset, "ethspeed", &bd->bi_ethspeed, 4);
316 	if (err < 0)
317 		printf("libfdt: %s\n", fdt_strerror(err));
318 
319 	return 0;
320 }
321 #endif /* CONFIG_OF_HAS_BD_T */
322 
323 #endif /* CONFIG_OF_LIBFDT */
324