xref: /rk3399_rockchip-uboot/scripts/dtc/dtc.c (revision d7857e40f2de4c570bb962d517058aeb5fc87ad4)
1d18719a4STom Rini /*
2d18719a4STom Rini  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3d18719a4STom Rini  *
4d18719a4STom Rini  *
5d18719a4STom Rini  * This program is free software; you can redistribute it and/or
6d18719a4STom Rini  * modify it under the terms of the GNU General Public License as
7d18719a4STom Rini  * published by the Free Software Foundation; either version 2 of the
8d18719a4STom Rini  * License, or (at your option) any later version.
9d18719a4STom Rini  *
10d18719a4STom Rini  *  This program is distributed in the hope that it will be useful,
11d18719a4STom Rini  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12d18719a4STom Rini  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13d18719a4STom Rini  *  General Public License for more details.
14d18719a4STom Rini  *
15d18719a4STom Rini  *  You should have received a copy of the GNU General Public License
16d18719a4STom Rini  *  along with this program; if not, write to the Free Software
17d18719a4STom Rini  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18d18719a4STom Rini  *                                                                   USA
19d18719a4STom Rini  */
20d18719a4STom Rini 
21d18719a4STom Rini #include <sys/stat.h>
22d18719a4STom Rini 
23d18719a4STom Rini #include "dtc.h"
24d18719a4STom Rini #include "srcpos.h"
25d18719a4STom Rini 
26d18719a4STom Rini /*
27d18719a4STom Rini  * Command line options
28d18719a4STom Rini  */
29d18719a4STom Rini int quiet;		/* Level of quietness */
30d18719a4STom Rini int reservenum;		/* Number of memory reservation slots */
31d18719a4STom Rini int minsize;		/* Minimum blob size */
32d18719a4STom Rini int padsize;		/* Additional padding to blob */
33d18719a4STom Rini int alignsize;		/* Additional padding to blob accroding to the alignsize */
34*d7857e40STom Rini int phandle_format = PHANDLE_EPAPR;	/* Use linux,phandle or phandle properties */
35d18719a4STom Rini int generate_symbols;	/* enable symbols & fixup support */
36d18719a4STom Rini int generate_fixups;		/* suppress generation of fixups on symbol support */
37d18719a4STom Rini int auto_label_aliases;		/* auto generate labels -> aliases */
38d18719a4STom Rini 
is_power_of_2(int x)39d18719a4STom Rini static int is_power_of_2(int x)
40d18719a4STom Rini {
41d18719a4STom Rini 	return (x > 0) && ((x & (x - 1)) == 0);
42d18719a4STom Rini }
43d18719a4STom Rini 
fill_fullpaths(struct node * tree,const char * prefix)44d18719a4STom Rini static void fill_fullpaths(struct node *tree, const char *prefix)
45d18719a4STom Rini {
46d18719a4STom Rini 	struct node *child;
47d18719a4STom Rini 	const char *unit;
48d18719a4STom Rini 
49d18719a4STom Rini 	tree->fullpath = join_path(prefix, tree->name);
50d18719a4STom Rini 
51d18719a4STom Rini 	unit = strchr(tree->name, '@');
52d18719a4STom Rini 	if (unit)
53d18719a4STom Rini 		tree->basenamelen = unit - tree->name;
54d18719a4STom Rini 	else
55d18719a4STom Rini 		tree->basenamelen = strlen(tree->name);
56d18719a4STom Rini 
57d18719a4STom Rini 	for_each_child(tree, child)
58d18719a4STom Rini 		fill_fullpaths(child, tree->fullpath);
59d18719a4STom Rini }
60d18719a4STom Rini 
61d18719a4STom Rini /* Usage related data. */
62d18719a4STom Rini #define FDT_VERSION(version)	_FDT_VERSION(version)
63d18719a4STom Rini #define _FDT_VERSION(version)	#version
64d18719a4STom Rini static const char usage_synopsis[] = "dtc [options] <input file>";
65d18719a4STom Rini static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
66d18719a4STom Rini static struct option const usage_long_opts[] = {
67d18719a4STom Rini 	{"quiet",            no_argument, NULL, 'q'},
68d18719a4STom Rini 	{"in-format",         a_argument, NULL, 'I'},
69d18719a4STom Rini 	{"out",               a_argument, NULL, 'o'},
70d18719a4STom Rini 	{"out-format",        a_argument, NULL, 'O'},
71d18719a4STom Rini 	{"out-version",       a_argument, NULL, 'V'},
72d18719a4STom Rini 	{"out-dependency",    a_argument, NULL, 'd'},
73d18719a4STom Rini 	{"reserve",           a_argument, NULL, 'R'},
74d18719a4STom Rini 	{"space",             a_argument, NULL, 'S'},
75d18719a4STom Rini 	{"pad",               a_argument, NULL, 'p'},
76d18719a4STom Rini 	{"align",             a_argument, NULL, 'a'},
77d18719a4STom Rini 	{"boot-cpu",          a_argument, NULL, 'b'},
78d18719a4STom Rini 	{"force",            no_argument, NULL, 'f'},
79d18719a4STom Rini 	{"include",           a_argument, NULL, 'i'},
80d18719a4STom Rini 	{"sort",             no_argument, NULL, 's'},
81d18719a4STom Rini 	{"phandle",           a_argument, NULL, 'H'},
82d18719a4STom Rini 	{"warning",           a_argument, NULL, 'W'},
83d18719a4STom Rini 	{"error",             a_argument, NULL, 'E'},
84d18719a4STom Rini 	{"symbols",	     no_argument, NULL, '@'},
85d18719a4STom Rini 	{"auto-alias",       no_argument, NULL, 'A'},
86d18719a4STom Rini 	{"help",             no_argument, NULL, 'h'},
87d18719a4STom Rini 	{"version",          no_argument, NULL, 'v'},
88d18719a4STom Rini 	{NULL,               no_argument, NULL, 0x0},
89d18719a4STom Rini };
90d18719a4STom Rini static const char * const usage_opts_help[] = {
91d18719a4STom Rini 	"\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
92d18719a4STom Rini 	"\n\tInput formats are:\n"
93d18719a4STom Rini 	 "\t\tdts - device tree source text\n"
94d18719a4STom Rini 	 "\t\tdtb - device tree blob\n"
95d18719a4STom Rini 	 "\t\tfs  - /proc/device-tree style directory",
96d18719a4STom Rini 	"\n\tOutput file",
97d18719a4STom Rini 	"\n\tOutput formats are:\n"
98d18719a4STom Rini 	 "\t\tdts - device tree source text\n"
99d18719a4STom Rini 	 "\t\tdtb - device tree blob\n"
100d18719a4STom Rini 	 "\t\tasm - assembler source",
101d18719a4STom Rini 	"\n\tBlob version to produce, defaults to "FDT_VERSION(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
102d18719a4STom Rini 	"\n\tOutput dependency file",
103d18719a4STom Rini 	"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
104d18719a4STom Rini 	"\n\tMake the blob at least <bytes> long (extra space)",
105d18719a4STom Rini 	"\n\tAdd padding to the blob of <bytes> long (extra space)",
106d18719a4STom Rini 	"\n\tMake the blob align to the <bytes> (extra space)",
107d18719a4STom Rini 	"\n\tSet the physical boot cpu",
108d18719a4STom Rini 	"\n\tTry to produce output even if the input tree has errors",
109d18719a4STom Rini 	"\n\tAdd a path to search for include files",
110d18719a4STom Rini 	"\n\tSort nodes and properties before outputting (useful for comparing trees)",
111d18719a4STom Rini 	"\n\tValid phandle formats are:\n"
112d18719a4STom Rini 	 "\t\tlegacy - \"linux,phandle\" properties only\n"
113d18719a4STom Rini 	 "\t\tepapr  - \"phandle\" properties only\n"
114d18719a4STom Rini 	 "\t\tboth   - Both \"linux,phandle\" and \"phandle\" properties",
115d18719a4STom Rini 	"\n\tEnable/disable warnings (prefix with \"no-\")",
116d18719a4STom Rini 	"\n\tEnable/disable errors (prefix with \"no-\")",
117d18719a4STom Rini 	"\n\tEnable generation of symbols",
118d18719a4STom Rini 	"\n\tEnable auto-alias of labels",
119d18719a4STom Rini 	"\n\tPrint this help and exit",
120d18719a4STom Rini 	"\n\tPrint version and exit",
121d18719a4STom Rini 	NULL,
122d18719a4STom Rini };
123d18719a4STom Rini 
guess_type_by_name(const char * fname,const char * fallback)124d18719a4STom Rini static const char *guess_type_by_name(const char *fname, const char *fallback)
125d18719a4STom Rini {
126d18719a4STom Rini 	const char *s;
127d18719a4STom Rini 
128d18719a4STom Rini 	s = strrchr(fname, '.');
129d18719a4STom Rini 	if (s == NULL)
130d18719a4STom Rini 		return fallback;
131d18719a4STom Rini 	if (!strcasecmp(s, ".dts"))
132d18719a4STom Rini 		return "dts";
133d18719a4STom Rini 	if (!strcasecmp(s, ".dtb"))
134d18719a4STom Rini 		return "dtb";
135d18719a4STom Rini 	return fallback;
136d18719a4STom Rini }
137d18719a4STom Rini 
guess_input_format(const char * fname,const char * fallback)138d18719a4STom Rini static const char *guess_input_format(const char *fname, const char *fallback)
139d18719a4STom Rini {
140d18719a4STom Rini 	struct stat statbuf;
141e23ffda2STom Rini 	fdt32_t magic;
142d18719a4STom Rini 	FILE *f;
143d18719a4STom Rini 
144d18719a4STom Rini 	if (stat(fname, &statbuf) != 0)
145d18719a4STom Rini 		return fallback;
146d18719a4STom Rini 
147d18719a4STom Rini 	if (S_ISDIR(statbuf.st_mode))
148d18719a4STom Rini 		return "fs";
149d18719a4STom Rini 
150d18719a4STom Rini 	if (!S_ISREG(statbuf.st_mode))
151d18719a4STom Rini 		return fallback;
152d18719a4STom Rini 
153d18719a4STom Rini 	f = fopen(fname, "r");
154d18719a4STom Rini 	if (f == NULL)
155d18719a4STom Rini 		return fallback;
156d18719a4STom Rini 	if (fread(&magic, 4, 1, f) != 1) {
157d18719a4STom Rini 		fclose(f);
158d18719a4STom Rini 		return fallback;
159d18719a4STom Rini 	}
160d18719a4STom Rini 	fclose(f);
161d18719a4STom Rini 
162e23ffda2STom Rini 	if (fdt32_to_cpu(magic) == FDT_MAGIC)
163d18719a4STom Rini 		return "dtb";
164d18719a4STom Rini 
165d18719a4STom Rini 	return guess_type_by_name(fname, fallback);
166d18719a4STom Rini }
167d18719a4STom Rini 
main(int argc,char * argv[])168d18719a4STom Rini int main(int argc, char *argv[])
169d18719a4STom Rini {
170d18719a4STom Rini 	struct dt_info *dti;
171d18719a4STom Rini 	const char *inform = NULL;
172d18719a4STom Rini 	const char *outform = NULL;
173d18719a4STom Rini 	const char *outname = "-";
174d18719a4STom Rini 	const char *depname = NULL;
175d18719a4STom Rini 	bool force = false, sort = false;
176d18719a4STom Rini 	const char *arg;
177d18719a4STom Rini 	int opt;
178d18719a4STom Rini 	FILE *outf = NULL;
179d18719a4STom Rini 	int outversion = DEFAULT_FDT_VERSION;
180d18719a4STom Rini 	long long cmdline_boot_cpuid = -1;
181d18719a4STom Rini 
182d18719a4STom Rini 	quiet      = 0;
183d18719a4STom Rini 	reservenum = 0;
184d18719a4STom Rini 	minsize    = 0;
185d18719a4STom Rini 	padsize    = 0;
186d18719a4STom Rini 	alignsize  = 0;
187d18719a4STom Rini 
188d18719a4STom Rini 	while ((opt = util_getopt_long()) != EOF) {
189d18719a4STom Rini 		switch (opt) {
190d18719a4STom Rini 		case 'I':
191d18719a4STom Rini 			inform = optarg;
192d18719a4STom Rini 			break;
193d18719a4STom Rini 		case 'O':
194d18719a4STom Rini 			outform = optarg;
195d18719a4STom Rini 			break;
196d18719a4STom Rini 		case 'o':
197d18719a4STom Rini 			outname = optarg;
198d18719a4STom Rini 			break;
199d18719a4STom Rini 		case 'V':
200d18719a4STom Rini 			outversion = strtol(optarg, NULL, 0);
201d18719a4STom Rini 			break;
202d18719a4STom Rini 		case 'd':
203d18719a4STom Rini 			depname = optarg;
204d18719a4STom Rini 			break;
205d18719a4STom Rini 		case 'R':
206d18719a4STom Rini 			reservenum = strtol(optarg, NULL, 0);
207d18719a4STom Rini 			break;
208d18719a4STom Rini 		case 'S':
209d18719a4STom Rini 			minsize = strtol(optarg, NULL, 0);
210d18719a4STom Rini 			break;
211d18719a4STom Rini 		case 'p':
212d18719a4STom Rini 			padsize = strtol(optarg, NULL, 0);
213d18719a4STom Rini 			break;
214d18719a4STom Rini 		case 'a':
215d18719a4STom Rini 			alignsize = strtol(optarg, NULL, 0);
216d18719a4STom Rini 			if (!is_power_of_2(alignsize))
217d18719a4STom Rini 				die("Invalid argument \"%d\" to -a option\n",
218d18719a4STom Rini 				    alignsize);
219d18719a4STom Rini 			break;
220d18719a4STom Rini 		case 'f':
221d18719a4STom Rini 			force = true;
222d18719a4STom Rini 			break;
223d18719a4STom Rini 		case 'q':
224d18719a4STom Rini 			quiet++;
225d18719a4STom Rini 			break;
226d18719a4STom Rini 		case 'b':
227d18719a4STom Rini 			cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
228d18719a4STom Rini 			break;
229d18719a4STom Rini 		case 'i':
230d18719a4STom Rini 			srcfile_add_search_path(optarg);
231d18719a4STom Rini 			break;
232d18719a4STom Rini 		case 'v':
233d18719a4STom Rini 			util_version();
234d18719a4STom Rini 		case 'H':
235d18719a4STom Rini 			if (streq(optarg, "legacy"))
236d18719a4STom Rini 				phandle_format = PHANDLE_LEGACY;
237d18719a4STom Rini 			else if (streq(optarg, "epapr"))
238d18719a4STom Rini 				phandle_format = PHANDLE_EPAPR;
239d18719a4STom Rini 			else if (streq(optarg, "both"))
240d18719a4STom Rini 				phandle_format = PHANDLE_BOTH;
241d18719a4STom Rini 			else
242d18719a4STom Rini 				die("Invalid argument \"%s\" to -H option\n",
243d18719a4STom Rini 				    optarg);
244d18719a4STom Rini 			break;
245d18719a4STom Rini 
246d18719a4STom Rini 		case 's':
247d18719a4STom Rini 			sort = true;
248d18719a4STom Rini 			break;
249d18719a4STom Rini 
250d18719a4STom Rini 		case 'W':
251d18719a4STom Rini 			parse_checks_option(true, false, optarg);
252d18719a4STom Rini 			break;
253d18719a4STom Rini 
254d18719a4STom Rini 		case 'E':
255d18719a4STom Rini 			parse_checks_option(false, true, optarg);
256d18719a4STom Rini 			break;
257d18719a4STom Rini 
258d18719a4STom Rini 		case '@':
259d18719a4STom Rini 			generate_symbols = 1;
260d18719a4STom Rini 			break;
261d18719a4STom Rini 		case 'A':
262d18719a4STom Rini 			auto_label_aliases = 1;
263d18719a4STom Rini 			break;
264d18719a4STom Rini 
265d18719a4STom Rini 		case 'h':
266d18719a4STom Rini 			usage(NULL);
267d18719a4STom Rini 		default:
268d18719a4STom Rini 			usage("unknown option");
269d18719a4STom Rini 		}
270d18719a4STom Rini 	}
271d18719a4STom Rini 
272d18719a4STom Rini 	if (argc > (optind+1))
273d18719a4STom Rini 		usage("missing files");
274d18719a4STom Rini 	else if (argc < (optind+1))
275d18719a4STom Rini 		arg = "-";
276d18719a4STom Rini 	else
277d18719a4STom Rini 		arg = argv[optind];
278d18719a4STom Rini 
279d18719a4STom Rini 	/* minsize and padsize are mutually exclusive */
280d18719a4STom Rini 	if (minsize && padsize)
281d18719a4STom Rini 		die("Can't set both -p and -S\n");
282d18719a4STom Rini 
283d18719a4STom Rini 	if (depname) {
284d18719a4STom Rini 		depfile = fopen(depname, "w");
285d18719a4STom Rini 		if (!depfile)
286d18719a4STom Rini 			die("Couldn't open dependency file %s: %s\n", depname,
287d18719a4STom Rini 			    strerror(errno));
288d18719a4STom Rini 		fprintf(depfile, "%s:", outname);
289d18719a4STom Rini 	}
290d18719a4STom Rini 
291d18719a4STom Rini 	if (inform == NULL)
292d18719a4STom Rini 		inform = guess_input_format(arg, "dts");
293d18719a4STom Rini 	if (outform == NULL) {
294d18719a4STom Rini 		outform = guess_type_by_name(outname, NULL);
295d18719a4STom Rini 		if (outform == NULL) {
296d18719a4STom Rini 			if (streq(inform, "dts"))
297d18719a4STom Rini 				outform = "dtb";
298d18719a4STom Rini 			else
299d18719a4STom Rini 				outform = "dts";
300d18719a4STom Rini 		}
301d18719a4STom Rini 	}
302d18719a4STom Rini 	if (streq(inform, "dts"))
303d18719a4STom Rini 		dti = dt_from_source(arg);
304d18719a4STom Rini 	else if (streq(inform, "fs"))
305d18719a4STom Rini 		dti = dt_from_fs(arg);
306d18719a4STom Rini 	else if(streq(inform, "dtb"))
307d18719a4STom Rini 		dti = dt_from_blob(arg);
308d18719a4STom Rini 	else
309d18719a4STom Rini 		die("Unknown input format \"%s\"\n", inform);
310d18719a4STom Rini 
311d18719a4STom Rini 	dti->outname = outname;
312d18719a4STom Rini 
313d18719a4STom Rini 	if (depfile) {
314d18719a4STom Rini 		fputc('\n', depfile);
315d18719a4STom Rini 		fclose(depfile);
316d18719a4STom Rini 	}
317d18719a4STom Rini 
318d18719a4STom Rini 	if (cmdline_boot_cpuid != -1)
319d18719a4STom Rini 		dti->boot_cpuid_phys = cmdline_boot_cpuid;
320d18719a4STom Rini 
321d18719a4STom Rini 	fill_fullpaths(dti->dt, "");
322d18719a4STom Rini 	process_checks(force, dti);
323d18719a4STom Rini 
324d18719a4STom Rini 	/* on a plugin, generate by default */
325d18719a4STom Rini 	if (dti->dtsflags & DTSF_PLUGIN) {
326d18719a4STom Rini 		generate_fixups = 1;
327d18719a4STom Rini 	}
328d18719a4STom Rini 
329d18719a4STom Rini 	if (auto_label_aliases)
330d18719a4STom Rini 		generate_label_tree(dti, "aliases", false);
331d18719a4STom Rini 
332d18719a4STom Rini 	if (generate_symbols)
333d18719a4STom Rini 		generate_label_tree(dti, "__symbols__", true);
334d18719a4STom Rini 
335d18719a4STom Rini 	if (generate_fixups) {
336d18719a4STom Rini 		generate_fixups_tree(dti, "__fixups__");
337d18719a4STom Rini 		generate_local_fixups_tree(dti, "__local_fixups__");
338d18719a4STom Rini 	}
339d18719a4STom Rini 
340d18719a4STom Rini 	if (sort)
341d18719a4STom Rini 		sort_tree(dti);
342d18719a4STom Rini 
343d18719a4STom Rini 	if (streq(outname, "-")) {
344d18719a4STom Rini 		outf = stdout;
345d18719a4STom Rini 	} else {
346d18719a4STom Rini 		outf = fopen(outname, "wb");
347d18719a4STom Rini 		if (! outf)
348d18719a4STom Rini 			die("Couldn't open output file %s: %s\n",
349d18719a4STom Rini 			    outname, strerror(errno));
350d18719a4STom Rini 	}
351d18719a4STom Rini 
352d18719a4STom Rini 	if (streq(outform, "dts")) {
353d18719a4STom Rini 		dt_to_source(outf, dti);
354d18719a4STom Rini 	} else if (streq(outform, "dtb")) {
355d18719a4STom Rini 		dt_to_blob(outf, dti, outversion);
356d18719a4STom Rini 	} else if (streq(outform, "asm")) {
357d18719a4STom Rini 		dt_to_asm(outf, dti, outversion);
358d18719a4STom Rini 	} else if (streq(outform, "null")) {
359d18719a4STom Rini 		/* do nothing */
360d18719a4STom Rini 	} else {
361d18719a4STom Rini 		die("Unknown output format \"%s\"\n", outform);
362d18719a4STom Rini 	}
363d18719a4STom Rini 
364d18719a4STom Rini 	exit(0);
365d18719a4STom Rini }
366