Merge drm/drm-next into drm-misc-next
[platform/kernel/linux-starfive.git] / scripts / dtc / fdtoverlay.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2017 Konsulko Group Inc. All rights reserved.
4  *
5  * Author:
6  *       Pantelis Antoniou <pantelis.antoniou@konsulko.com>
7  */
8
9 #include <assert.h>
10 #include <ctype.h>
11 #include <getopt.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <inttypes.h>
16
17 #include <libfdt.h>
18
19 #include "util.h"
20
21 #define BUF_INCREMENT   65536
22
23 /* Usage related data. */
24 static const char usage_synopsis[] =
25         "apply a number of overlays to a base blob\n"
26         "       fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]\n"
27         "\n"
28         USAGE_TYPE_MSG;
29 static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
30 static struct option const usage_long_opts[] = {
31         {"input",            required_argument, NULL, 'i'},
32         {"output",           required_argument, NULL, 'o'},
33         {"verbose",                no_argument, NULL, 'v'},
34         USAGE_COMMON_LONG_OPTS,
35 };
36 static const char * const usage_opts_help[] = {
37         "Input base DT blob",
38         "Output DT blob",
39         "Verbose messages",
40         USAGE_COMMON_OPTS_HELP
41 };
42
43 int verbose = 0;
44
45 static void *apply_one(char *base, const char *overlay, size_t *buf_len,
46                        const char *name)
47 {
48         char *tmp = NULL;
49         char *tmpo;
50         int ret;
51
52         /*
53          * We take a copies first, because a a failed apply can trash
54          * both the base blob and the overlay
55          */
56         tmpo = xmalloc(fdt_totalsize(overlay));
57
58         do {
59                 tmp = xrealloc(tmp, *buf_len);
60                 ret = fdt_open_into(base, tmp, *buf_len);
61                 if (ret) {
62                         fprintf(stderr,
63                                 "\nFailed to make temporary copy: %s\n",
64                                 fdt_strerror(ret));
65                         goto fail;
66                 }
67
68                 memcpy(tmpo, overlay, fdt_totalsize(overlay));
69
70                 ret = fdt_overlay_apply(tmp, tmpo);
71                 if (ret == -FDT_ERR_NOSPACE) {
72                         *buf_len += BUF_INCREMENT;
73                 }
74         } while (ret == -FDT_ERR_NOSPACE);
75
76         if (ret) {
77                 fprintf(stderr, "\nFailed to apply '%s': %s\n",
78                         name, fdt_strerror(ret));
79                 goto fail;
80         }
81
82         free(base);
83         free(tmpo);
84         return tmp;
85
86 fail:
87         free(tmpo);
88         if (tmp)
89                 free(tmp);
90
91         return NULL;
92 }
93 static int do_fdtoverlay(const char *input_filename,
94                          const char *output_filename,
95                          int argc, char *argv[])
96 {
97         char *blob = NULL;
98         char **ovblob = NULL;
99         size_t buf_len;
100         int i, ret = -1;
101
102         blob = utilfdt_read(input_filename, &buf_len);
103         if (!blob) {
104                 fprintf(stderr, "\nFailed to read '%s'\n", input_filename);
105                 goto out_err;
106         }
107         if (fdt_totalsize(blob) > buf_len) {
108                 fprintf(stderr,
109  "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n",
110                         (unsigned long)buf_len, fdt_totalsize(blob));
111                 goto out_err;
112         }
113
114         /* allocate blob pointer array */
115         ovblob = xmalloc(sizeof(*ovblob) * argc);
116         memset(ovblob, 0, sizeof(*ovblob) * argc);
117
118         /* read and keep track of the overlay blobs */
119         for (i = 0; i < argc; i++) {
120                 size_t ov_len;
121                 ovblob[i] = utilfdt_read(argv[i], &ov_len);
122                 if (!ovblob[i]) {
123                         fprintf(stderr, "\nFailed to read '%s'\n", argv[i]);
124                         goto out_err;
125                 }
126                 if (fdt_totalsize(ovblob[i]) > ov_len) {
127                         fprintf(stderr,
128 "\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n",
129                                 argv[i], (unsigned long)ov_len,
130                                 fdt_totalsize(ovblob[i]));
131                         goto out_err;
132                 }
133         }
134
135         buf_len = fdt_totalsize(blob);
136
137         /* apply the overlays in sequence */
138         for (i = 0; i < argc; i++) {
139                 blob = apply_one(blob, ovblob[i], &buf_len, argv[i]);
140                 if (!blob)
141                         goto out_err;
142         }
143
144         fdt_pack(blob);
145         ret = utilfdt_write(output_filename, blob);
146         if (ret)
147                 fprintf(stderr, "\nFailed to write '%s'\n",
148                         output_filename);
149
150 out_err:
151         if (ovblob) {
152                 for (i = 0; i < argc; i++) {
153                         if (ovblob[i])
154                                 free(ovblob[i]);
155                 }
156                 free(ovblob);
157         }
158         free(blob);
159
160         return ret;
161 }
162
163 int main(int argc, char *argv[])
164 {
165         int opt, i;
166         char *input_filename = NULL;
167         char *output_filename = NULL;
168
169         while ((opt = util_getopt_long()) != EOF) {
170                 switch (opt) {
171                 case_USAGE_COMMON_FLAGS
172
173                 case 'i':
174                         input_filename = optarg;
175                         break;
176                 case 'o':
177                         output_filename = optarg;
178                         break;
179                 case 'v':
180                         verbose = 1;
181                         break;
182                 }
183         }
184
185         if (!input_filename)
186                 usage("missing input file");
187
188         if (!output_filename)
189                 usage("missing output file");
190
191         argv += optind;
192         argc -= optind;
193
194         if (argc <= 0)
195                 usage("missing overlay file(s)");
196
197         if (verbose) {
198                 printf("input  = %s\n", input_filename);
199                 printf("output = %s\n", output_filename);
200                 for (i = 0; i < argc; i++)
201                         printf("overlay[%d] = %s\n", i, argv[i]);
202         }
203
204         if (do_fdtoverlay(input_filename, output_filename, argc, argv))
205                 return 1;
206
207         return 0;
208 }