xref: /openbmc/linux/scripts/dtc/dtc.c (revision a77725a9)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29fffb55fSDavid Gibson /*
39fffb55fSDavid Gibson  * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
49fffb55fSDavid Gibson  */
59fffb55fSDavid Gibson 
691feabc2SRob Herring #include <sys/stat.h>
791feabc2SRob Herring 
89fffb55fSDavid Gibson #include "dtc.h"
99fffb55fSDavid Gibson #include "srcpos.h"
109fffb55fSDavid Gibson 
119fffb55fSDavid Gibson /*
129fffb55fSDavid Gibson  * Command line options
139fffb55fSDavid Gibson  */
149fffb55fSDavid Gibson int quiet;		/* Level of quietness */
15*a77725a9SRob Herring unsigned int reservenum;/* Number of memory reservation slots */
169fffb55fSDavid Gibson int minsize;		/* Minimum blob size */
179fffb55fSDavid Gibson int padsize;		/* Additional padding to blob */
186f05afcbSRob Herring int alignsize;		/* Additional padding to blob accroding to the alignsize */
194201d057SRob Herring int phandle_format = PHANDLE_EPAPR;	/* Use linux,phandle or phandle properties */
206f05afcbSRob Herring int generate_symbols;	/* enable symbols & fixup support */
216f05afcbSRob Herring int generate_fixups;		/* suppress generation of fixups on symbol support */
226f05afcbSRob Herring int auto_label_aliases;		/* auto generate labels -> aliases */
23c2e7075cSRob Herring int annotate;		/* Level of annotation: 1 for input source location
24c2e7075cSRob Herring 			   >1 for full input source location. */
256f05afcbSRob Herring 
is_power_of_2(int x)266f05afcbSRob Herring static int is_power_of_2(int x)
276f05afcbSRob Herring {
286f05afcbSRob Herring 	return (x > 0) && ((x & (x - 1)) == 0);
296f05afcbSRob Herring }
309fffb55fSDavid Gibson 
fill_fullpaths(struct node * tree,const char * prefix)319fffb55fSDavid Gibson static void fill_fullpaths(struct node *tree, const char *prefix)
329fffb55fSDavid Gibson {
339fffb55fSDavid Gibson 	struct node *child;
349fffb55fSDavid Gibson 	const char *unit;
359fffb55fSDavid Gibson 
369fffb55fSDavid Gibson 	tree->fullpath = join_path(prefix, tree->name);
379fffb55fSDavid Gibson 
389fffb55fSDavid Gibson 	unit = strchr(tree->name, '@');
399fffb55fSDavid Gibson 	if (unit)
409fffb55fSDavid Gibson 		tree->basenamelen = unit - tree->name;
419fffb55fSDavid Gibson 	else
429fffb55fSDavid Gibson 		tree->basenamelen = strlen(tree->name);
439fffb55fSDavid Gibson 
449fffb55fSDavid Gibson 	for_each_child(tree, child)
459fffb55fSDavid Gibson 		fill_fullpaths(child, tree->fullpath);
469fffb55fSDavid Gibson }
479fffb55fSDavid Gibson 
4873ab39b1SGrant Likely /* Usage related data. */
4973ab39b1SGrant Likely static const char usage_synopsis[] = "dtc [options] <input file>";
50c2e7075cSRob Herring static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AThv";
5173ab39b1SGrant Likely static struct option const usage_long_opts[] = {
5273ab39b1SGrant Likely 	{"quiet",            no_argument, NULL, 'q'},
5373ab39b1SGrant Likely 	{"in-format",         a_argument, NULL, 'I'},
5473ab39b1SGrant Likely 	{"out",               a_argument, NULL, 'o'},
5573ab39b1SGrant Likely 	{"out-format",        a_argument, NULL, 'O'},
5673ab39b1SGrant Likely 	{"out-version",       a_argument, NULL, 'V'},
5773ab39b1SGrant Likely 	{"out-dependency",    a_argument, NULL, 'd'},
5873ab39b1SGrant Likely 	{"reserve",           a_argument, NULL, 'R'},
5973ab39b1SGrant Likely 	{"space",             a_argument, NULL, 'S'},
6073ab39b1SGrant Likely 	{"pad",               a_argument, NULL, 'p'},
616f05afcbSRob Herring 	{"align",             a_argument, NULL, 'a'},
6273ab39b1SGrant Likely 	{"boot-cpu",          a_argument, NULL, 'b'},
6373ab39b1SGrant Likely 	{"force",            no_argument, NULL, 'f'},
6473ab39b1SGrant Likely 	{"include",           a_argument, NULL, 'i'},
6573ab39b1SGrant Likely 	{"sort",             no_argument, NULL, 's'},
6673ab39b1SGrant Likely 	{"phandle",           a_argument, NULL, 'H'},
6773ab39b1SGrant Likely 	{"warning",           a_argument, NULL, 'W'},
6873ab39b1SGrant Likely 	{"error",             a_argument, NULL, 'E'},
696f05afcbSRob Herring 	{"symbols",	     no_argument, NULL, '@'},
706f05afcbSRob Herring 	{"auto-alias",       no_argument, NULL, 'A'},
71c2e7075cSRob Herring 	{"annotate",         no_argument, NULL, 'T'},
7273ab39b1SGrant Likely 	{"help",             no_argument, NULL, 'h'},
7373ab39b1SGrant Likely 	{"version",          no_argument, NULL, 'v'},
7473ab39b1SGrant Likely 	{NULL,               no_argument, NULL, 0x0},
7573ab39b1SGrant Likely };
7673ab39b1SGrant Likely static const char * const usage_opts_help[] = {
7773ab39b1SGrant Likely 	"\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
7873ab39b1SGrant Likely 	"\n\tInput formats are:\n"
7973ab39b1SGrant Likely 	 "\t\tdts - device tree source text\n"
8073ab39b1SGrant Likely 	 "\t\tdtb - device tree blob\n"
8173ab39b1SGrant Likely 	 "\t\tfs  - /proc/device-tree style directory",
8273ab39b1SGrant Likely 	"\n\tOutput file",
8373ab39b1SGrant Likely 	"\n\tOutput formats are:\n"
8473ab39b1SGrant Likely 	 "\t\tdts - device tree source text\n"
8573ab39b1SGrant Likely 	 "\t\tdtb - device tree blob\n"
86f858927fSRob Herring #ifndef NO_YAML
87f858927fSRob Herring 	 "\t\tyaml - device tree encoded as YAML\n"
88f858927fSRob Herring #endif
8973ab39b1SGrant Likely 	 "\t\tasm - assembler source",
909130ba88SRob Herring 	"\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
9173ab39b1SGrant Likely 	"\n\tOutput dependency file",
9247605971SRob Herring 	"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
9373ab39b1SGrant Likely 	"\n\tMake the blob at least <bytes> long (extra space)",
9473ab39b1SGrant Likely 	"\n\tAdd padding to the blob of <bytes> long (extra space)",
956f05afcbSRob Herring 	"\n\tMake the blob align to the <bytes> (extra space)",
9673ab39b1SGrant Likely 	"\n\tSet the physical boot cpu",
9773ab39b1SGrant Likely 	"\n\tTry to produce output even if the input tree has errors",
9873ab39b1SGrant Likely 	"\n\tAdd a path to search for include files",
9973ab39b1SGrant Likely 	"\n\tSort nodes and properties before outputting (useful for comparing trees)",
10073ab39b1SGrant Likely 	"\n\tValid phandle formats are:\n"
10173ab39b1SGrant Likely 	 "\t\tlegacy - \"linux,phandle\" properties only\n"
10273ab39b1SGrant Likely 	 "\t\tepapr  - \"phandle\" properties only\n"
10373ab39b1SGrant Likely 	 "\t\tboth   - Both \"linux,phandle\" and \"phandle\" properties",
10473ab39b1SGrant Likely 	"\n\tEnable/disable warnings (prefix with \"no-\")",
10573ab39b1SGrant Likely 	"\n\tEnable/disable errors (prefix with \"no-\")",
1066f05afcbSRob Herring 	"\n\tEnable generation of symbols",
1076f05afcbSRob Herring 	"\n\tEnable auto-alias of labels",
108c2e7075cSRob Herring 	"\n\tAnnotate output .dts with input source file and line (-T -T for more details)",
10973ab39b1SGrant Likely 	"\n\tPrint this help and exit",
11073ab39b1SGrant Likely 	"\n\tPrint version and exit",
11173ab39b1SGrant Likely 	NULL,
11273ab39b1SGrant Likely };
1139fffb55fSDavid Gibson 
guess_type_by_name(const char * fname,const char * fallback)11491feabc2SRob Herring static const char *guess_type_by_name(const char *fname, const char *fallback)
11591feabc2SRob Herring {
11691feabc2SRob Herring 	const char *s;
11791feabc2SRob Herring 
11891feabc2SRob Herring 	s = strrchr(fname, '.');
11991feabc2SRob Herring 	if (s == NULL)
12091feabc2SRob Herring 		return fallback;
12191feabc2SRob Herring 	if (!strcasecmp(s, ".dts"))
12291feabc2SRob Herring 		return "dts";
123f858927fSRob Herring 	if (!strcasecmp(s, ".yaml"))
124f858927fSRob Herring 		return "yaml";
12579edff12SRob Herring 	if (!strcasecmp(s, ".dtbo"))
12679edff12SRob Herring 		return "dtb";
12791feabc2SRob Herring 	if (!strcasecmp(s, ".dtb"))
12891feabc2SRob Herring 		return "dtb";
12991feabc2SRob Herring 	return fallback;
13091feabc2SRob Herring }
13191feabc2SRob Herring 
guess_input_format(const char * fname,const char * fallback)13291feabc2SRob Herring static const char *guess_input_format(const char *fname, const char *fallback)
13391feabc2SRob Herring {
13491feabc2SRob Herring 	struct stat statbuf;
13589d12310SRob Herring 	fdt32_t magic;
13691feabc2SRob Herring 	FILE *f;
13791feabc2SRob Herring 
13891feabc2SRob Herring 	if (stat(fname, &statbuf) != 0)
13991feabc2SRob Herring 		return fallback;
14091feabc2SRob Herring 
14191feabc2SRob Herring 	if (S_ISDIR(statbuf.st_mode))
14291feabc2SRob Herring 		return "fs";
14391feabc2SRob Herring 
14491feabc2SRob Herring 	if (!S_ISREG(statbuf.st_mode))
14591feabc2SRob Herring 		return fallback;
14691feabc2SRob Herring 
14791feabc2SRob Herring 	f = fopen(fname, "r");
14891feabc2SRob Herring 	if (f == NULL)
14991feabc2SRob Herring 		return fallback;
15091feabc2SRob Herring 	if (fread(&magic, 4, 1, f) != 1) {
15191feabc2SRob Herring 		fclose(f);
15291feabc2SRob Herring 		return fallback;
15391feabc2SRob Herring 	}
15491feabc2SRob Herring 	fclose(f);
15591feabc2SRob Herring 
15689d12310SRob Herring 	if (fdt32_to_cpu(magic) == FDT_MAGIC)
15791feabc2SRob Herring 		return "dtb";
15891feabc2SRob Herring 
15991feabc2SRob Herring 	return guess_type_by_name(fname, fallback);
16091feabc2SRob Herring }
16191feabc2SRob Herring 
main(int argc,char * argv[])1629fffb55fSDavid Gibson int main(int argc, char *argv[])
1639fffb55fSDavid Gibson {
1646f05afcbSRob Herring 	struct dt_info *dti;
16591feabc2SRob Herring 	const char *inform = NULL;
16691feabc2SRob Herring 	const char *outform = NULL;
1679fffb55fSDavid Gibson 	const char *outname = "-";
168136ec204SStephen Warren 	const char *depname = NULL;
16947605971SRob Herring 	bool force = false, sort = false;
1709fffb55fSDavid Gibson 	const char *arg;
1719fffb55fSDavid Gibson 	int opt;
1729fffb55fSDavid Gibson 	FILE *outf = NULL;
1739fffb55fSDavid Gibson 	int outversion = DEFAULT_FDT_VERSION;
1749fffb55fSDavid Gibson 	long long cmdline_boot_cpuid = -1;
1759fffb55fSDavid Gibson 
1769fffb55fSDavid Gibson 	quiet      = 0;
1779fffb55fSDavid Gibson 	reservenum = 0;
1789fffb55fSDavid Gibson 	minsize    = 0;
1799fffb55fSDavid Gibson 	padsize    = 0;
1806f05afcbSRob Herring 	alignsize  = 0;
1819fffb55fSDavid Gibson 
18273ab39b1SGrant Likely 	while ((opt = util_getopt_long()) != EOF) {
1839fffb55fSDavid Gibson 		switch (opt) {
1849fffb55fSDavid Gibson 		case 'I':
1859fffb55fSDavid Gibson 			inform = optarg;
1869fffb55fSDavid Gibson 			break;
1879fffb55fSDavid Gibson 		case 'O':
1889fffb55fSDavid Gibson 			outform = optarg;
1899fffb55fSDavid Gibson 			break;
1909fffb55fSDavid Gibson 		case 'o':
1919fffb55fSDavid Gibson 			outname = optarg;
1929fffb55fSDavid Gibson 			break;
1939fffb55fSDavid Gibson 		case 'V':
1949fffb55fSDavid Gibson 			outversion = strtol(optarg, NULL, 0);
1959fffb55fSDavid Gibson 			break;
196136ec204SStephen Warren 		case 'd':
197136ec204SStephen Warren 			depname = optarg;
198136ec204SStephen Warren 			break;
1999fffb55fSDavid Gibson 		case 'R':
200*a77725a9SRob Herring 			reservenum = strtoul(optarg, NULL, 0);
2019fffb55fSDavid Gibson 			break;
2029fffb55fSDavid Gibson 		case 'S':
2039fffb55fSDavid Gibson 			minsize = strtol(optarg, NULL, 0);
2049fffb55fSDavid Gibson 			break;
2059fffb55fSDavid Gibson 		case 'p':
2069fffb55fSDavid Gibson 			padsize = strtol(optarg, NULL, 0);
2079fffb55fSDavid Gibson 			break;
2086f05afcbSRob Herring 		case 'a':
2096f05afcbSRob Herring 			alignsize = strtol(optarg, NULL, 0);
2106f05afcbSRob Herring 			if (!is_power_of_2(alignsize))
2116f05afcbSRob Herring 				die("Invalid argument \"%d\" to -a option\n",
21289d12310SRob Herring 				    alignsize);
2136f05afcbSRob Herring 			break;
2149fffb55fSDavid Gibson 		case 'f':
21547605971SRob Herring 			force = true;
2169fffb55fSDavid Gibson 			break;
2179fffb55fSDavid Gibson 		case 'q':
2189fffb55fSDavid Gibson 			quiet++;
2199fffb55fSDavid Gibson 			break;
2209fffb55fSDavid Gibson 		case 'b':
2219fffb55fSDavid Gibson 			cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
2229fffb55fSDavid Gibson 			break;
223cd296721SStephen Warren 		case 'i':
224cd296721SStephen Warren 			srcfile_add_search_path(optarg);
225cd296721SStephen Warren 			break;
2269fffb55fSDavid Gibson 		case 'v':
22773ab39b1SGrant Likely 			util_version();
228658f29a5SJohn Bonesio 		case 'H':
229658f29a5SJohn Bonesio 			if (streq(optarg, "legacy"))
230658f29a5SJohn Bonesio 				phandle_format = PHANDLE_LEGACY;
231658f29a5SJohn Bonesio 			else if (streq(optarg, "epapr"))
232658f29a5SJohn Bonesio 				phandle_format = PHANDLE_EPAPR;
233658f29a5SJohn Bonesio 			else if (streq(optarg, "both"))
234658f29a5SJohn Bonesio 				phandle_format = PHANDLE_BOTH;
235658f29a5SJohn Bonesio 			else
236658f29a5SJohn Bonesio 				die("Invalid argument \"%s\" to -H option\n",
237658f29a5SJohn Bonesio 				    optarg);
238658f29a5SJohn Bonesio 			break;
239658f29a5SJohn Bonesio 
240658f29a5SJohn Bonesio 		case 's':
24147605971SRob Herring 			sort = true;
242658f29a5SJohn Bonesio 			break;
243658f29a5SJohn Bonesio 
244cd296721SStephen Warren 		case 'W':
245cd296721SStephen Warren 			parse_checks_option(true, false, optarg);
246cd296721SStephen Warren 			break;
247cd296721SStephen Warren 
248cd296721SStephen Warren 		case 'E':
249cd296721SStephen Warren 			parse_checks_option(false, true, optarg);
250cd296721SStephen Warren 			break;
251cd296721SStephen Warren 
2526f05afcbSRob Herring 		case '@':
2536f05afcbSRob Herring 			generate_symbols = 1;
2546f05afcbSRob Herring 			break;
2556f05afcbSRob Herring 		case 'A':
2566f05afcbSRob Herring 			auto_label_aliases = 1;
2576f05afcbSRob Herring 			break;
258c2e7075cSRob Herring 		case 'T':
259c2e7075cSRob Herring 			annotate++;
260c2e7075cSRob Herring 			break;
2616f05afcbSRob Herring 
2629fffb55fSDavid Gibson 		case 'h':
26373ab39b1SGrant Likely 			usage(NULL);
2649fffb55fSDavid Gibson 		default:
26573ab39b1SGrant Likely 			usage("unknown option");
2669fffb55fSDavid Gibson 		}
2679fffb55fSDavid Gibson 	}
2689fffb55fSDavid Gibson 
2699fffb55fSDavid Gibson 	if (argc > (optind+1))
27073ab39b1SGrant Likely 		usage("missing files");
2719fffb55fSDavid Gibson 	else if (argc < (optind+1))
2729fffb55fSDavid Gibson 		arg = "-";
2739fffb55fSDavid Gibson 	else
2749fffb55fSDavid Gibson 		arg = argv[optind];
2759fffb55fSDavid Gibson 
2769fffb55fSDavid Gibson 	/* minsize and padsize are mutually exclusive */
2779fffb55fSDavid Gibson 	if (minsize && padsize)
2789fffb55fSDavid Gibson 		die("Can't set both -p and -S\n");
2799fffb55fSDavid Gibson 
280136ec204SStephen Warren 	if (depname) {
281136ec204SStephen Warren 		depfile = fopen(depname, "w");
282136ec204SStephen Warren 		if (!depfile)
283136ec204SStephen Warren 			die("Couldn't open dependency file %s: %s\n", depname,
284136ec204SStephen Warren 			    strerror(errno));
285136ec204SStephen Warren 		fprintf(depfile, "%s:", outname);
286136ec204SStephen Warren 	}
287136ec204SStephen Warren 
28891feabc2SRob Herring 	if (inform == NULL)
28991feabc2SRob Herring 		inform = guess_input_format(arg, "dts");
29091feabc2SRob Herring 	if (outform == NULL) {
29191feabc2SRob Herring 		outform = guess_type_by_name(outname, NULL);
29291feabc2SRob Herring 		if (outform == NULL) {
29391feabc2SRob Herring 			if (streq(inform, "dts"))
29491feabc2SRob Herring 				outform = "dtb";
29591feabc2SRob Herring 			else
29691feabc2SRob Herring 				outform = "dts";
29791feabc2SRob Herring 		}
29891feabc2SRob Herring 	}
299c2e7075cSRob Herring 	if (annotate && (!streq(inform, "dts") || !streq(outform, "dts")))
300c2e7075cSRob Herring 		die("--annotate requires -I dts -O dts\n");
3019fffb55fSDavid Gibson 	if (streq(inform, "dts"))
3026f05afcbSRob Herring 		dti = dt_from_source(arg);
3039fffb55fSDavid Gibson 	else if (streq(inform, "fs"))
3046f05afcbSRob Herring 		dti = dt_from_fs(arg);
3059fffb55fSDavid Gibson 	else if(streq(inform, "dtb"))
3066f05afcbSRob Herring 		dti = dt_from_blob(arg);
3079fffb55fSDavid Gibson 	else
3089fffb55fSDavid Gibson 		die("Unknown input format \"%s\"\n", inform);
3099fffb55fSDavid Gibson 
31089d12310SRob Herring 	dti->outname = outname;
31189d12310SRob Herring 
312136ec204SStephen Warren 	if (depfile) {
313136ec204SStephen Warren 		fputc('\n', depfile);
314136ec204SStephen Warren 		fclose(depfile);
315136ec204SStephen Warren 	}
316136ec204SStephen Warren 
3179fffb55fSDavid Gibson 	if (cmdline_boot_cpuid != -1)
3186f05afcbSRob Herring 		dti->boot_cpuid_phys = cmdline_boot_cpuid;
3199fffb55fSDavid Gibson 
3206f05afcbSRob Herring 	fill_fullpaths(dti->dt, "");
3216f05afcbSRob Herring 
3226f05afcbSRob Herring 	/* on a plugin, generate by default */
3236f05afcbSRob Herring 	if (dti->dtsflags & DTSF_PLUGIN) {
3246f05afcbSRob Herring 		generate_fixups = 1;
3256f05afcbSRob Herring 	}
3266f05afcbSRob Herring 
3279130ba88SRob Herring 	process_checks(force, dti);
3289130ba88SRob Herring 
3296f05afcbSRob Herring 	if (auto_label_aliases)
3306f05afcbSRob Herring 		generate_label_tree(dti, "aliases", false);
3316f05afcbSRob Herring 
3326f05afcbSRob Herring 	if (generate_symbols)
3336f05afcbSRob Herring 		generate_label_tree(dti, "__symbols__", true);
3346f05afcbSRob Herring 
3356f05afcbSRob Herring 	if (generate_fixups) {
3366f05afcbSRob Herring 		generate_fixups_tree(dti, "__fixups__");
3376f05afcbSRob Herring 		generate_local_fixups_tree(dti, "__local_fixups__");
3386f05afcbSRob Herring 	}
3399fffb55fSDavid Gibson 
340658f29a5SJohn Bonesio 	if (sort)
3416f05afcbSRob Herring 		sort_tree(dti);
3429fffb55fSDavid Gibson 
3439fffb55fSDavid Gibson 	if (streq(outname, "-")) {
3449fffb55fSDavid Gibson 		outf = stdout;
3459fffb55fSDavid Gibson 	} else {
34647605971SRob Herring 		outf = fopen(outname, "wb");
3479fffb55fSDavid Gibson 		if (! outf)
3489fffb55fSDavid Gibson 			die("Couldn't open output file %s: %s\n",
3499fffb55fSDavid Gibson 			    outname, strerror(errno));
3509fffb55fSDavid Gibson 	}
3519fffb55fSDavid Gibson 
3529fffb55fSDavid Gibson 	if (streq(outform, "dts")) {
3536f05afcbSRob Herring 		dt_to_source(outf, dti);
354f858927fSRob Herring #ifndef NO_YAML
355f858927fSRob Herring 	} else if (streq(outform, "yaml")) {
356f858927fSRob Herring 		if (!streq(inform, "dts"))
357f858927fSRob Herring 			die("YAML output format requires dts input format\n");
358f858927fSRob Herring 		dt_to_yaml(outf, dti);
359f858927fSRob Herring #endif
3609fffb55fSDavid Gibson 	} else if (streq(outform, "dtb")) {
3616f05afcbSRob Herring 		dt_to_blob(outf, dti, outversion);
3629fffb55fSDavid Gibson 	} else if (streq(outform, "asm")) {
3636f05afcbSRob Herring 		dt_to_asm(outf, dti, outversion);
3649fffb55fSDavid Gibson 	} else if (streq(outform, "null")) {
3659fffb55fSDavid Gibson 		/* do nothing */
3669fffb55fSDavid Gibson 	} else {
3679fffb55fSDavid Gibson 		die("Unknown output format \"%s\"\n", outform);
3689fffb55fSDavid Gibson 	}
3699fffb55fSDavid Gibson 
3709fffb55fSDavid Gibson 	exit(0);
3719fffb55fSDavid Gibson }
372