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