blob: 08a1b8ac219a88cb107c6ce3a0a61e550f85b63c [file] [log] [blame]
David Ng3556e582012-07-27 23:52:11 +00001/*
2 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#define _GNU_SOURCE
31#include <stdint.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <dirent.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <getopt.h>
40#include <errno.h>
41#include <unistd.h>
Keith Mok15d0e092015-11-09 10:10:09 -080042#include <limits.h>
David Ng3556e582012-07-27 23:52:11 +000043
44#define QCDT_MAGIC "QCDT" /* Master DTB magic */
Danny Baumannbd62af82015-08-27 16:08:38 +020045#define QCDT_VERSION 3 /* QCDT version */
David Ng3556e582012-07-27 23:52:11 +000046
47#define QCDT_DT_TAG "qcom,msm-id = <"
48#define QCDT_BOARD_TAG "qcom,board-id = <"
Danny Baumannbd62af82015-08-27 16:08:38 +020049#define QCDT_PMIC_TAG "qcom,pmic-id = <"
50
David Ng3556e582012-07-27 23:52:11 +000051
52#define PAGE_SIZE_DEF 2048
53#define PAGE_SIZE_MAX (1024*1024)
54
55#define log_err(x...) printf(x)
56#define log_info(x...) printf(x)
57#define log_dbg(x...) { if (verbose) printf(x); }
58
59#define COPY_BLK 1024 /* File copy block size */
60
61#define RC_SUCCESS 0
62#define RC_ERROR -1
63
64struct chipInfo_t {
65 uint32_t chipset;
66 uint32_t platform;
67 uint32_t subtype;
68 uint32_t revNum;
Danny Baumannbd62af82015-08-27 16:08:38 +020069 uint32_t pmic_model[4];
David Ng3556e582012-07-27 23:52:11 +000070 uint32_t dtb_size;
71 char *dtb_file;
72 struct chipInfo_t *prev;
73 struct chipInfo_t *next;
74 struct chipInfo_t *master;
75 int wroteDtb;
76 uint32_t master_offset;
77 struct chipInfo_t *t_next;
78};
79
80struct chipInfo_t *chip_list;
81
82struct chipId_t {
83 uint32_t chipset;
84 uint32_t revNum;
85 struct chipId_t *next;
86 struct chipId_t *t_next;
87};
88
89struct chipSt_t {
90 uint32_t platform;
91 uint32_t subtype;
92 struct chipSt_t *next;
93 struct chipSt_t *t_next;
94};
95
Danny Baumannbd62af82015-08-27 16:08:38 +020096struct chipPt_t {
97 uint32_t pmic0;
98 uint32_t pmic1;
99 uint32_t pmic2;
100 uint32_t pmic3;
101 struct chipPt_t *next;
102 struct chipPt_t *t_next;
103};
104
David Ng3556e582012-07-27 23:52:11 +0000105char *input_dir;
106char *output_file;
107char *dtc_path;
h8rift09db8b22014-04-07 22:10:33 -0400108char *dt_tag = QCDT_DT_TAG;
David Ng3556e582012-07-27 23:52:11 +0000109int verbose;
110int page_size = PAGE_SIZE_DEF;
Dan Pasanen5c432712015-11-08 10:16:14 -0600111int version_override = 0;
David Ng3556e582012-07-27 23:52:11 +0000112
113void print_help()
114{
115 log_info("dtbTool version %d (kinda :) )\n", QCDT_VERSION);
116 log_info("dtbTool [options] -o <output file> <input DTB path>\n");
117 log_info(" options:\n");
118 log_info(" --output-file/-o output file\n");
119 log_info(" --dtc-path/-p path to dtc\n");
120 log_info(" --page-size/-s page size in bytes\n");
h8rift09db8b22014-04-07 22:10:33 -0400121 log_info(" --dt-tag/-d alternate QCDT_DT_TAG\n");
David Ng3556e582012-07-27 23:52:11 +0000122 log_info(" --verbose/-v verbose\n");
Danny Baumannbd62af82015-08-27 16:08:38 +0200123 log_info(" --force-v2/-2 output dtb v2 format\n");
124 log_info(" --force-v3/-3 output dtb v3 format\n");
David Ng3556e582012-07-27 23:52:11 +0000125 log_info(" --help/-h this help screen\n");
126}
127
128int parse_commandline(int argc, char *const argv[])
129{
130 int c;
131
132 struct option long_options[] = {
133 {"output-file", 1, 0, 'o'},
134 {"dtc-path", 1, 0, 'p'},
135 {"page-size", 1, 0, 's'},
h8rift09db8b22014-04-07 22:10:33 -0400136 {"dt-tag", 1, 0, 'd'},
Danny Baumannbd62af82015-08-27 16:08:38 +0200137 {"force-v2", 0, 0, '2'},
138 {"force-v3", 0, 0, '3'},
David Ng3556e582012-07-27 23:52:11 +0000139 {"verbose", 0, 0, 'v'},
140 {"help", 0, 0, 'h'},
David Ng3556e582012-07-27 23:52:11 +0000141 {0, 0, 0, 0}
142 };
143
Danny Baumannbd62af82015-08-27 16:08:38 +0200144 while ((c = getopt_long(argc, argv, "-o:p:s:d:23vh", long_options, NULL))
David Ng3556e582012-07-27 23:52:11 +0000145 != -1) {
146 switch (c) {
147 case 1:
148 if (!input_dir)
149 input_dir = optarg;
150 break;
151 case 'o':
152 output_file = optarg;
153 break;
154 case 'p':
155 dtc_path = optarg;
156 break;
157 case 's':
158 page_size = atoi(optarg);
159 if ((page_size <= 0) || (page_size > (PAGE_SIZE_MAX))) {
160 log_err("Invalid page size (> 0 and <=1MB\n");
161 return RC_ERROR;
162 }
163 break;
h8rift09db8b22014-04-07 22:10:33 -0400164 case 'd':
165 dt_tag = optarg;
166 break;
Danny Baumannbd62af82015-08-27 16:08:38 +0200167 case '2':
168 case '3':
Dan Pasanen5c432712015-11-08 10:16:14 -0600169 if (version_override != 0) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200170 log_err("A version output argument may only be passed once\n");
171 return RC_ERROR;
172 }
Dan Pasanen5c432712015-11-08 10:16:14 -0600173 version_override = c - '0';
Danny Baumannbd62af82015-08-27 16:08:38 +0200174 break;
David Ng3556e582012-07-27 23:52:11 +0000175 case 'v':
176 verbose = 1;
177 break;
David Ng3556e582012-07-27 23:52:11 +0000178 case 'h':
179 default:
180 return RC_ERROR;
181 }
182 }
183
184 if (!output_file) {
185 log_err("Output file must be specified\n");
186 return RC_ERROR;
187 }
188
189 if (!input_dir)
190 input_dir = "./";
191
192 if (!dtc_path)
193 dtc_path = "";
194
195 return RC_SUCCESS;
196}
197
198/* Unique entry sorted list add (by chipset->platform->rev) */
199int chip_add(struct chipInfo_t *c)
200{
201 struct chipInfo_t *x = chip_list;
202
203 if (!chip_list) {
204 chip_list = c;
205 c->next = NULL;
206 c->prev = NULL;
207 return RC_SUCCESS;
208 }
209
210 while (1) {
211 if ((c->chipset < x->chipset) ||
212 ((c->chipset == x->chipset) &&
213 ((c->platform < x->platform) ||
214 ((c->platform == x->platform) &&
215 ((c->subtype < x->subtype) ||
216 ((c->subtype == x->subtype) &&
217 (c->revNum < x->revNum))))))) {
218 if (!x->prev) {
219 c->next = x;
220 c->prev = NULL;
221 x->prev = c;
222 chip_list = c;
223 break;
224 } else {
225 c->next = x;
226 c->prev = x->prev;
227 x->prev->next = c;
228 x->prev = c;
229 break;
230 }
231 }
232 if ((c->chipset == x->chipset) &&
233 (c->platform == x->platform) &&
234 (c->subtype == x->subtype) &&
Danny Baumannbd62af82015-08-27 16:08:38 +0200235 (c->revNum == x->revNum) &&
236 (c->pmic_model[0] == x->pmic_model[0]) &&
237 (c->pmic_model[1] == x->pmic_model[1]) &&
238 (c->pmic_model[2] == x->pmic_model[2]) &&
239 (c->pmic_model[3] == x->pmic_model[3])) {
David Ng3556e582012-07-27 23:52:11 +0000240 return RC_ERROR; /* duplicate */
241 }
242 if (!x->next) {
243 c->prev = x;
244 c->next = NULL;
245 x->next = c;
246 break;
247 }
248 x = x->next;
249 }
250 return RC_SUCCESS;
251}
252
253void chip_deleteall()
254{
255 struct chipInfo_t *c = chip_list, *t;
256
257 while (c) {
258 t = c;
259 c = c->next;
260 if (t->dtb_file)
261 free(t->dtb_file);
262 free(t);
263 }
264}
265
266/*
267 For v1 Extract 'qcom,msm-id' parameter triplet from DTB
268 qcom,msm-id = <x y z>;
269
270 For v2 Extract 'qcom,msm-id', 'qcom,board-id' parameter double from DTB
271 qcom,msm-id = <x z> i.e chipset, revision number;
272 qcom,board-id = <y y'> i.e platform and sub-type;
273 */
274
275struct chipInfo_t *getChipInfo(const char *filename, int *num, uint32_t msmversion)
276{
277
278 const char str1[] = "dtc -I dtb -O dts \"";
279 const char str2[] = "\" 2>&1";
280 char *buf, *pos;
281 char *line = NULL;
282 size_t line_size;
283 FILE *pfile;
284 int llen;
Danny Baumannbd62af82015-08-27 16:08:38 +0200285 struct chipInfo_t *chip = NULL, *tmp, *chip_t;
David Ng3556e582012-07-27 23:52:11 +0000286 uint32_t data[3] = {0, 0, 0};
287 uint32_t data_st[2] = {0, 0};
Danny Baumannbd62af82015-08-27 16:08:38 +0200288 uint32_t data_pt[4] = {0, 0, 0, 0};
David Ng3556e582012-07-27 23:52:11 +0000289 char *tok, *sptr = NULL;
290 int i, entryValid, entryEnded;
Danny Baumannbd62af82015-08-27 16:08:38 +0200291 int count = 0, count1 = 0, count2 = 0, count3 = 0;
292 int entryValidST, entryEndedST, entryValidDT, entryEndedDT, entryValidPT, entryEndedPT;
David Ng3556e582012-07-27 23:52:11 +0000293 struct chipId_t *chipId = NULL, *cId = NULL, *tmp_id = NULL;
294 struct chipSt_t *chipSt = NULL, *cSt = NULL, *tmp_st = NULL;
Danny Baumannbd62af82015-08-27 16:08:38 +0200295 struct chipPt_t *chipPt = NULL, *cPt = NULL, *tmp_pt = NULL;
296 struct chipId_t *chipId_tmp = NULL;
297 struct chipSt_t *chipSt_tmp = NULL;
298 struct chipPt_t *chipPt_tmp = NULL;
David Ng3556e582012-07-27 23:52:11 +0000299
300 line_size = 1024;
301 line = (char *)malloc(line_size);
302 if (!line) {
303 log_err("Out of memory\n");
304 return NULL;
305 }
306
307 llen = sizeof(char) * (strlen(dtc_path) +
308 strlen(str1) +
309 strlen(str2) +
310 strlen(filename) + 1);
311 buf = (char *)malloc(llen);
312 if (!buf) {
313 log_err("Out of memory\n");
314 free(line);
315 return NULL;
316 }
317
318 strncpy(buf, dtc_path, llen);
319 strncat(buf, str1, llen);
320 strncat(buf, filename, llen);
321 strncat(buf, str2, llen);
322
323 pfile = popen(buf, "r");
324 free(buf);
325
326 if (pfile == NULL) {
327 log_err("... skip, fail to decompile dtb\n");
328 } else {
329 /* Find "qcom,msm-id" */
330 while ((llen = getline(&line, &line_size, pfile)) != -1) {
331 if (msmversion == 1) {
h8rift09db8b22014-04-07 22:10:33 -0400332 if ((pos = strstr(line, dt_tag)) != NULL) {
333 pos += strlen(dt_tag);
David Ng3556e582012-07-27 23:52:11 +0000334
Ethan Chenebe5c222014-03-09 10:08:22 -0700335 entryEnded = 0;
336 while (1) {
337 entryValid = 1;
338 for (i = 0; i < 3; i++) {
339 tok = strtok_r(pos, " \t", &sptr);
340 pos = NULL;
341 if (tok != NULL) {
342 if (*tok == '>') {
343 entryEnded = 1;
344 entryValid = 0;
345 break;
346 }
347 data[i] = strtoul(tok, NULL, 0);
348 } else {
349 data[i] = 0;
David Ng3556e582012-07-27 23:52:11 +0000350 entryValid = 0;
Ethan Chenebe5c222014-03-09 10:08:22 -0700351 entryEnded = 1;
352 }
353 }
354 if (entryEnded) {
355 free(line);
356 pclose(pfile);
357 *num = count;
358 return chip;
359 }
360 if (entryValid) {
361 tmp = (struct chipInfo_t *)
362 malloc(sizeof(struct chipInfo_t));
363 if (!tmp) {
364 log_err("Out of memory\n");
David Ng3556e582012-07-27 23:52:11 +0000365 break;
366 }
Ethan Chenebe5c222014-03-09 10:08:22 -0700367 if (!chip) {
368 chip = tmp;
369 chip->t_next = NULL;
370 } else {
371 tmp->t_next = chip->t_next;
372 chip->t_next = tmp;
373 }
374 tmp->chipset = data[0];
375 tmp->platform = data[1];
David Ng3556e582012-07-27 23:52:11 +0000376 tmp->subtype = 0;
Ethan Chenebe5c222014-03-09 10:08:22 -0700377 tmp->revNum = data[2];
Danny Baumannbd62af82015-08-27 16:08:38 +0200378 tmp->pmic_model[0] = 0;
379 tmp->pmic_model[1] = 0;
380 tmp->pmic_model[2] = 0;
381 tmp->pmic_model[3] = 0;
Ethan Chenebe5c222014-03-09 10:08:22 -0700382 tmp->dtb_size = 0;
383 tmp->dtb_file = NULL;
384 tmp->master = chip;
385 tmp->wroteDtb = 0;
386 tmp->master_offset = 0;
387 count++;
388 }
David Ng3556e582012-07-27 23:52:11 +0000389 }
David Ng3556e582012-07-27 23:52:11 +0000390
h8rift09db8b22014-04-07 22:10:33 -0400391 log_err("... skip, incorrect '%s' format\n", dt_tag);
Ethan Chenebe5c222014-03-09 10:08:22 -0700392 break;
393 }
Danny Baumannbd62af82015-08-27 16:08:38 +0200394 } else if (msmversion == 2 || msmversion == 3) {
h8rift09db8b22014-04-07 22:10:33 -0400395 if ((pos = strstr(line, dt_tag)) != NULL) {
396 pos += strlen(dt_tag);
David Ng3556e582012-07-27 23:52:11 +0000397
398 entryEndedDT = 0;
399 for (;entryEndedDT < 1;) {
400 entryValidDT = 1;
401 for (i = 0; i < 2; i++) {
402 tok = strtok_r(pos, " \t", &sptr);
403 pos = NULL;
404 if (tok != NULL) {
405 if (*tok == '>') {
406 entryEndedDT = 1;
407 entryValidDT = 0;
408 break;
409 }
410 data_st[i] = strtoul(tok, NULL, 0);
411 } else {
412 data_st[i] = 0;
413 entryValidDT = 0;
414 entryEndedDT = 1;
415 }
416 }
417
418 if (entryValidDT) {
419 tmp_id = (struct chipId_t *)
420 malloc(sizeof(struct chipId_t));
421 if (!tmp_id) {
422 log_err("Out of memory\n");
423 break;
424 }
425 if (!chipId) {
426 chipId = tmp_id;
427 cId = tmp_id;
428 chipId->t_next = NULL;
429 } else {
430 tmp_id->t_next = chipId->t_next;
431 chipId->t_next = tmp_id;
432 }
433 tmp_id->chipset = data_st[0];
434 tmp_id->revNum= data_st[1];
435 count1++;
436 }
Ethan Chenebe5c222014-03-09 10:08:22 -0700437 }
David Ng3556e582012-07-27 23:52:11 +0000438 }
439
440 if ((pos = strstr(line,QCDT_BOARD_TAG)) != NULL) {
441 pos += strlen(QCDT_BOARD_TAG);
442 entryEndedST = 0;
443 for (;entryEndedST < 1;) {
444 entryValidST = 1;
445 for (i = 0; i < 2; i++) {
446 tok = strtok_r(pos, " \t", &sptr);
447 pos = NULL;
448 if (tok != NULL) {
449 if (*tok == '>') {
450 entryEndedST = 1;
451 entryValidST = 0;
452 break;
453 }
454 data_st[i] = strtoul(tok, NULL, 0);
455 } else {
456 data_st[i] = 0;
457 entryValidST = 0;
458 entryEndedST = 1;
459 }
460 }
461 if (entryValidST) {
462 tmp_st = (struct chipSt_t *)
463 malloc(sizeof(struct chipSt_t));
464 if (!tmp_st) {
465 log_err("Out of memory\n");
466 break;
467 }
468
469 if (!chipSt) {
470 chipSt = tmp_st;
471 cSt = tmp_st;
472 chipSt->t_next = NULL;
473 } else {
474 tmp_st->t_next = chipSt->t_next;
475 chipSt->t_next = tmp_st;
476 }
477
478 tmp_st->platform = data_st[0];
479 tmp_st->subtype= data_st[1];
480 count2++;
481 }
482 }
483 }
Danny Baumannbd62af82015-08-27 16:08:38 +0200484
485 if ((pos = strstr(line,QCDT_PMIC_TAG)) != NULL) {
486 pos += strlen(QCDT_PMIC_TAG);
487 entryEndedPT = 0;
488 for (;entryEndedPT < 1;) {
489 entryValidPT = 1;
490 for (i = 0; i < 4; i++) {
491 tok = strtok_r(pos, " \t", &sptr);
492 pos = NULL;
493 if (tok != NULL) {
494 if (*tok == '>') {
495 entryEndedPT = 1;
496 entryValidPT = 0;
497 break;
498 }
499 data_pt[i] = strtoul(tok, NULL, 0);
500 } else {
501 data_pt[i] = 0;
502 entryValidPT = 0;
503 entryEndedPT = 1;
504 }
505 }
506 if (entryValidPT) {
507 tmp_pt = (struct chipPt_t *)
508 malloc(sizeof(struct chipPt_t));
509 if (!tmp_pt) {
510 log_err("Out of memory\n");
511 break;
512 }
513
514 if (!chipPt) {
515 chipPt = tmp_pt;
516 cPt = tmp_pt;
517 chipPt->t_next = NULL;
518 } else {
519 tmp_pt->t_next = chipPt->t_next;
520 chipPt->t_next = tmp_pt;
521 }
522
523 tmp_pt->pmic0 = data_pt[0];
524 tmp_pt->pmic1 = data_pt[1];
525 tmp_pt->pmic2 = data_pt[2];
526 tmp_pt->pmic3 = data_pt[3];
527 count3++;
528 }
529 }
530 }
David Ng3556e582012-07-27 23:52:11 +0000531 }
532 }
533 }
534
Ethan Chenebe5c222014-03-09 10:08:22 -0700535 if (line)
536 free(line);
David Ng3556e582012-07-27 23:52:11 +0000537
David Ng3556e582012-07-27 23:52:11 +0000538 if (count1 == 0) {
h8rift09db8b22014-04-07 22:10:33 -0400539 log_err("... skip, incorrect '%s' format\n", dt_tag);
David Ng3556e582012-07-27 23:52:11 +0000540 return NULL;
541 }
542 if (count2 == 0) {
543 log_err("... skip, incorrect '%s' format\n", QCDT_BOARD_TAG);
544 return NULL;
545 }
Danny Baumannbd62af82015-08-27 16:08:38 +0200546 if (count3 == 0 && msmversion == 3) {
547 log_err("... skip, incorrect '%s' format\n", QCDT_PMIC_TAG);
548 return NULL;
549 }
David Ng3556e582012-07-27 23:52:11 +0000550
551 tmp_st = cSt;
Danny Baumannbd62af82015-08-27 16:08:38 +0200552 tmp_pt = cPt;
David Ng3556e582012-07-27 23:52:11 +0000553 while (cId != NULL) {
554 while (cSt != NULL) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200555 if (msmversion == 3) {
556 while (cPt != NULL) {
557 tmp = (struct chipInfo_t *)
558 malloc(sizeof(struct chipInfo_t));
559 if (!tmp) {
560 log_err("Out of memory\n");
561 break;
562 }
563 if (!chip) {
564 chip = tmp;
565 chip->t_next = NULL;
566 } else {
567 tmp->t_next = chip->t_next;
568 chip->t_next = tmp;
569 }
570
571 tmp->chipset = cId->chipset;
572 tmp->platform = cSt->platform;
573 tmp->revNum = cId->revNum;
574 tmp->subtype = cSt->subtype;
575 tmp->pmic_model[0] = cPt->pmic0;
576 tmp->pmic_model[1] = cPt->pmic1;
577 tmp->pmic_model[2] = cPt->pmic2;
578 tmp->pmic_model[3] = cPt->pmic3;
579 tmp->dtb_size = 0;
580 tmp->dtb_file = NULL;
581 tmp->master = chip;
582 tmp->wroteDtb = 0;
583 tmp->master_offset = 0;
584 cPt = cPt->t_next;
585 }
586 cPt = tmp_pt;
David Ng3556e582012-07-27 23:52:11 +0000587 } else {
Danny Baumannbd62af82015-08-27 16:08:38 +0200588 tmp = (struct chipInfo_t *)
589 malloc(sizeof(struct chipInfo_t));
590 if (!tmp) {
591 log_err("Out of memory\n");
592 break;
593 }
594 if (!chip) {
595 chip = tmp;
596 chip->t_next = NULL;
597 } else {
598 tmp->t_next = chip->t_next;
599 chip->t_next = tmp;
600 }
601 tmp->chipset = cId->chipset;
602 tmp->platform = cSt->platform;
603 tmp->revNum = cId->revNum;
604 tmp->subtype = cSt->subtype;
605 tmp->pmic_model[0] = 0;
606 tmp->pmic_model[1] = 0;
607 tmp->pmic_model[2] = 0;
608 tmp->pmic_model[3] = 0;
609 tmp->dtb_size = 0;
610 tmp->dtb_file = NULL;
611 tmp->master = chip;
612 tmp->wroteDtb = 0;
613 tmp->master_offset = 0;
David Ng3556e582012-07-27 23:52:11 +0000614 }
David Ng3556e582012-07-27 23:52:11 +0000615 cSt = cSt->t_next;
David Ng3556e582012-07-27 23:52:11 +0000616 }
617 cSt = tmp_st;
618 cId = cId->t_next;
619 }
620
Danny Baumannbd62af82015-08-27 16:08:38 +0200621 if (msmversion == 2)
622 entryEndedPT = 1;
623
624 /* clear memory*/
625 pclose(pfile);
626 while (chipId) {
627 chipId_tmp = chipId;
628 chipId = chipId->t_next;
629 free(chipId_tmp);
630 }
631 while (chipSt) {
632 chipSt_tmp= chipSt;
633 chipSt = chipSt->t_next;
634 free(chipSt_tmp);
635 }
636
637 while (chipPt) {
638 chipPt_tmp= chipPt;
639 chipPt = chipPt->t_next;
640 free(chipPt_tmp);
641 }
642
643 if (entryEndedST == 1 && entryEndedDT == 1 && entryEndedPT == 1) {
David Ng3556e582012-07-27 23:52:11 +0000644 *num = count1;
David Ng3556e582012-07-27 23:52:11 +0000645 return chip;
646 }
Ethan Chenebe5c222014-03-09 10:08:22 -0700647
Danny Baumannbd62af82015-08-27 16:08:38 +0200648 /* clear memory*/
649 while (chip) {
650 chip_t = chip;
651 chip = chip->next;
652 if (chip_t->dtb_file)
653 free(chip_t->dtb_file);
654 free(chip_t);
David Ng3556e582012-07-27 23:52:11 +0000655 }
David Ng3556e582012-07-27 23:52:11 +0000656 return NULL;
657}
658
659/* Get the version-id based on dtb files */
Scott Mertzc64d2972015-12-08 16:12:55 -0800660uint32_t GetVersionInfo(const char *filename)
David Ng3556e582012-07-27 23:52:11 +0000661{
662 const char str1[] = "dtc -I dtb -O dts \"";
663 const char str2[] = "\" 2>&1";
664 char *buf, *pos;
665 char *line = NULL;
666 size_t line_size;
667 FILE *pfile;
668 int llen;
Scott Mertzc64d2972015-12-08 16:12:55 -0800669 uint32_t v = 1;
David Ng3556e582012-07-27 23:52:11 +0000670
671 line_size = 1024;
672 line = (char *)malloc(line_size);
673 if (!line) {
674 log_err("Out of memory\n");
675 return 0;
676 }
677
678 llen = sizeof(char) * (strlen(dtc_path) +
679 strlen(str1) +
680 strlen(str2) +
681 strlen(filename) + 1);
682 buf = (char *)malloc(llen);
683 if (!buf) {
684 log_err("Out of memory\n");
685 free(line);
686 return 0;
687 }
688
689 strncpy(buf, dtc_path, llen);
690 strncat(buf, str1, llen);
691 strncat(buf, filename, llen);
692 strncat(buf, str2, llen);
693
694 pfile = popen(buf, "r");
695 free(buf);
696
697 if (pfile == NULL) {
698 log_err("... skip, fail to decompile dtb\n");
699 } else {
700 /* Find the type of version */
701 while ((llen = getline(&line, &line_size, pfile)) != -1) {
702 if ((pos = strstr(line,QCDT_BOARD_TAG)) != NULL) {
703 v = 2;
Danny Baumannbd62af82015-08-27 16:08:38 +0200704 }
705 if ((pos = strstr(line,QCDT_PMIC_TAG)) != NULL) {
706 v = 3;
David Ng3556e582012-07-27 23:52:11 +0000707 break;
708 }
709 }
710 }
Danny Baumannbd62af82015-08-27 16:08:38 +0200711
David Ng3556e582012-07-27 23:52:11 +0000712 free(line);
Danny Baumannbd62af82015-08-27 16:08:38 +0200713 log_info("Version:%d\n", v);
David Ng3556e582012-07-27 23:52:11 +0000714
715 return v;
716}
717
Scott Mertzc64d2972015-12-08 16:12:55 -0800718static int find_dtb(const char *path, uint32_t *version)
David Ng3556e582012-07-27 23:52:11 +0000719{
David Ng3556e582012-07-27 23:52:11 +0000720 struct dirent *dp;
David Ng3556e582012-07-27 23:52:11 +0000721 int flen;
Scott Mertzc64d2972015-12-08 16:12:55 -0800722 char *filename;
723 struct chipInfo_t *chip, *t_chip;
David Ng3556e582012-07-27 23:52:11 +0000724 struct stat st;
David Ng3556e582012-07-27 23:52:11 +0000725 int num;
Scott Mertzc64d2972015-12-08 16:12:55 -0800726 int rc = RC_SUCCESS;
727 uint32_t msmversion = 0;
728 int dtb_count = 0;
David Ng3556e582012-07-27 23:52:11 +0000729
Scott Mertzc64d2972015-12-08 16:12:55 -0800730 DIR *dir = opendir(path);
David Ng3556e582012-07-27 23:52:11 +0000731 if (!dir) {
Scott Mertzc64d2972015-12-08 16:12:55 -0800732 log_err("Failed to open input directory '%s'\n", path);
David Ng3556e582012-07-27 23:52:11 +0000733 return RC_ERROR;
734 }
735
David Ng3556e582012-07-27 23:52:11 +0000736 /* Open the .dtb files in the specified path, decompile and
737 extract "qcom,msm-id" parameter
738 */
739 while ((dp = readdir(dir)) != NULL) {
Dan Pasanenb2b1bbc2015-11-08 09:56:04 -0600740 if (dp->d_type == DT_UNKNOWN) {
741 struct stat statbuf;
742 char name[PATH_MAX];
743 snprintf(name, sizeof(name), "%s%s%s",
Scott Mertzc64d2972015-12-08 16:12:55 -0800744 path,
745 (path[strlen(path) - 1] == '/' ? "" : "/"),
Dan Pasanenb2b1bbc2015-11-08 09:56:04 -0600746 dp->d_name);
Scott Mertzc64d2972015-12-08 16:12:55 -0800747 if (!stat(name, &statbuf)) {
748 if (S_ISREG(statbuf.st_mode)) {
749 dp->d_type = DT_REG;
750 } else if (S_ISDIR(statbuf.st_mode)) {
751 dp->d_type = DT_DIR;
752 }
Dan Pasanenb2b1bbc2015-11-08 09:56:04 -0600753 }
754 }
755
Scott Mertzc64d2972015-12-08 16:12:55 -0800756 if (dp->d_type == DT_DIR) {
757 char name[PATH_MAX];
758 if (dp->d_name[0] == '.') {
759 continue;
760 }
761 snprintf(name, sizeof(name), "%s%s%s%s",
762 path,
763 (path[strlen(path) - 1] == '/' ? "" : "/"),
764 dp->d_name,
765 "/");
766 log_info("Searching subdir: %s ... \n", name);
767 dtb_count += find_dtb(name, version);
768 } else if (dp->d_type == DT_REG) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200769 flen = strlen(dp->d_name);
770 if ((flen > 4) &&
771 (strncmp(&dp->d_name[flen-4], ".dtb", 4) == 0)) {
772 log_info("Found file: %s ... \n", dp->d_name);
David Ng3556e582012-07-27 23:52:11 +0000773
Scott Mertzc64d2972015-12-08 16:12:55 -0800774 flen = strlen(path) + strlen(dp->d_name) + 1;
Danny Baumannbd62af82015-08-27 16:08:38 +0200775 filename = (char *)malloc(flen);
776 if (!filename) {
777 log_err("Out of memory\n");
778 rc = RC_ERROR;
779 break;
780 }
Scott Mertzc64d2972015-12-08 16:12:55 -0800781 strncpy(filename, path, flen);
Danny Baumannbd62af82015-08-27 16:08:38 +0200782 strncat(filename, dp->d_name, flen);
David Ng3556e582012-07-27 23:52:11 +0000783
Danny Baumannbd62af82015-08-27 16:08:38 +0200784 /* To identify the version number */
785 msmversion = GetVersionInfo(filename);
Scott Mertzc64d2972015-12-08 16:12:55 -0800786 if (*version < msmversion) {
787 *version = msmversion;
Danny Baumannbd62af82015-08-27 16:08:38 +0200788 }
Robin Humble9077ed02014-05-03 16:34:22 +1000789
Danny Baumannbd62af82015-08-27 16:08:38 +0200790 num = 1;
791 chip = getChipInfo(filename, &num, msmversion);
Robin Humble9077ed02014-05-03 16:34:22 +1000792
Danny Baumannbd62af82015-08-27 16:08:38 +0200793 if (msmversion == 1) {
794 if (!chip) {
795 log_err("skip, failed to scan for '%s' tag\n", dt_tag);
796 free(filename);
797 continue;
798 }
799 }
800 if (msmversion == 2) {
801 if (!chip) {
802 log_err("skip, failed to scan for '%s' or '%s' tag\n",
803 dt_tag, QCDT_BOARD_TAG);
804 free(filename);
805 continue;
806 }
807 }
808 if (msmversion == 3) {
809 if (!chip) {
810 log_err("skip, failed to scan for '%s', '%s' or '%s' tag\n",
811 dt_tag, QCDT_BOARD_TAG, QCDT_PMIC_TAG);
812 free(filename);
813 continue;
814 }
815 }
Robin Humble9077ed02014-05-03 16:34:22 +1000816
Danny Baumannbd62af82015-08-27 16:08:38 +0200817 if ((stat(filename, &st) != 0) ||
818 (st.st_size == 0)) {
819 log_err("skip, failed to get DTB size\n");
820 free(filename);
821 continue;
822 }
David Ng3556e582012-07-27 23:52:11 +0000823
Danny Baumannbd62af82015-08-27 16:08:38 +0200824 log_info("chipset: %u, rev: %u, platform: %u, subtype: %u, pmic0: %u, pmic1: %u, pmic2: %u, pmic3: %u\n",
825 chip->chipset, chip->revNum, chip->platform, chip->subtype,
826 chip->pmic_model[0], chip->pmic_model[1], chip->pmic_model[2], chip->pmic_model[3]);
David Ng3556e582012-07-27 23:52:11 +0000827
Danny Baumannbd62af82015-08-27 16:08:38 +0200828 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
829 log_info("additional chipset: %u, rev: %u, platform: %u, subtype: %u, pmic0: %u, pmic1: %u, pmic2: %u, pmic3: %u\n",
830 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype,
831 t_chip->pmic_model[0], t_chip->pmic_model[1], t_chip->pmic_model[2], t_chip->pmic_model[3]);
832 }
833
834 rc = chip_add(chip);
835 if (rc != RC_SUCCESS) {
836 log_err("... duplicate info, skipped\n");
837 free(filename);
838 continue;
839 }
840
841 dtb_count++;
842
843 chip->dtb_size = st.st_size +
844 (page_size - (st.st_size % page_size));
845 chip->dtb_file = filename;
846
847 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
848 rc = chip_add(t_chip);
849 if (rc != RC_SUCCESS) {
850 log_err("... duplicate info, skipped (chipset %u, rev: %u, platform: %u, subtype: %u\n",
851 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype);
852 continue;
853 }
854 dtb_count++;
855 }
David Ng3556e582012-07-27 23:52:11 +0000856 }
857 }
David Ng3556e582012-07-27 23:52:11 +0000858 }
859 closedir(dir);
Scott Mertzc64d2972015-12-08 16:12:55 -0800860 return dtb_count;
861}
862
863/* Extract 'qcom,msm-id' 'qcom,board-id' parameter from DTB
864 v1 format:
865 qcom,msm-id = <x y z> [, <x2 y2 z2> ...];
866 v2 format:
867 qcom,msm-id = <x z> [, <x2 z2> ...;
868 qcom,board-id = <y y'> [, <y2 y2'> ...;
869 Fields:
870 x = chipset
871 y = platform
872 y' = subtype
873 z = soc rev
874 */
875int main(int argc, char **argv)
876{
877 char buf[COPY_BLK];
878 struct chipInfo_t *chip;
879 FILE *pInputFile;
880 int padding;
881 uint8_t *filler = NULL;
882 int numBytesRead = 0;
883 int totBytesRead = 0;
884 int out_fd;
885 int rc = RC_SUCCESS;
886 int dtb_count = 0, dtb_offset = 0, entry_size;
887 size_t wrote = 0, expected = 0;
888 uint32_t dtb_size;
889 uint32_t version = 0;
890 char *filename;
891
892 log_info("DTB combiner:\n");
893
894 if (parse_commandline(argc, argv) != RC_SUCCESS) {
895 print_help();
896 return RC_ERROR;
897 }
898
899 log_info(" Input directory: '%s'\n", input_dir);
900 log_info(" Output file: '%s'\n", output_file);
901
902
903 filler = (uint8_t *)malloc(page_size);
904 if (!filler) {
905 log_err("Out of memory\n");
906 return RC_ERROR;
907 }
908 memset(filler, 0, page_size);
909
910 dtb_count = find_dtb(input_dir, &version);
911
David Ng3556e582012-07-27 23:52:11 +0000912 log_info("=> Found %d unique DTB(s)\n", dtb_count);
913
914 if (!dtb_count)
915 goto cleanup;
916
917
918 /* Generate the master DTB file:
919
920 Simplify write error handling by just checking for actual vs
921 expected bytes written at the end.
922 */
923
924 log_info("\nGenerating master DTB... ");
925
M1cha67ac39c2016-07-16 09:49:42 +0200926 out_fd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
Keith Mok8f9d7d82015-11-09 10:12:06 -0800927 if (out_fd == -1) {
David Ng3556e582012-07-27 23:52:11 +0000928 log_err("Cannot create '%s'\n", output_file);
929 rc = RC_ERROR;
930 goto cleanup;
931 }
932
Dan Pasanen5c432712015-11-08 10:16:14 -0600933 if (version_override != 0) {
934 version = version_override;
Danny Baumannbd62af82015-08-27 16:08:38 +0200935 }
936
Dan Pasanen5c432712015-11-08 10:16:14 -0600937 if (version == 1) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200938 entry_size = 20;
Dan Pasanen5c432712015-11-08 10:16:14 -0600939 } else if (version == 2) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200940 entry_size = 24;
941 } else {
942 entry_size = 40;
David Ng3556e582012-07-27 23:52:11 +0000943 }
944
945 /* Write header info */
946 wrote += write(out_fd, QCDT_MAGIC, sizeof(uint8_t) * 4); /* magic */
947 wrote += write(out_fd, &version, sizeof(uint32_t)); /* version */
948 wrote += write(out_fd, (uint32_t *)&dtb_count, sizeof(uint32_t));
949 /* #DTB */
950
951 /* Calculate offset of first DTB block */
Danny Baumannbd62af82015-08-27 16:08:38 +0200952 dtb_offset = 12 + /* header */
953 (entry_size * dtb_count) + /* DTB table entries */
954 4; /* end of table indicator */
955
David Ng3556e582012-07-27 23:52:11 +0000956 /* Round up to page size */
957 padding = page_size - (dtb_offset % page_size);
958 dtb_offset += padding;
959 expected = dtb_offset;
960
961 /* Write index table:
962 chipset
963 platform
Danny Baumannbd62af82015-08-27 16:08:38 +0200964 subtype (v2/v3 only)
David Ng3556e582012-07-27 23:52:11 +0000965 soc rev
Danny Baumannbd62af82015-08-27 16:08:38 +0200966 pmic model0 (v3 only)
967 pmic model1 (v3 only)
968 pmic model2 (v3 only)
969 pmic model3 (v3 only)
David Ng3556e582012-07-27 23:52:11 +0000970 dtb offset
971 dtb size
972 */
973 for (chip = chip_list; chip; chip = chip->next) {
974 wrote += write(out_fd, &chip->chipset, sizeof(uint32_t));
975 wrote += write(out_fd, &chip->platform, sizeof(uint32_t));
Dan Pasanen5c432712015-11-08 10:16:14 -0600976 if (version >= 2) {
David Ng3556e582012-07-27 23:52:11 +0000977 wrote += write(out_fd, &chip->subtype, sizeof(uint32_t));
Danny Baumannbd62af82015-08-27 16:08:38 +0200978 }
David Ng3556e582012-07-27 23:52:11 +0000979 wrote += write(out_fd, &chip->revNum, sizeof(uint32_t));
Dan Pasanen5c432712015-11-08 10:16:14 -0600980 if (version >= 3) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200981 wrote += write(out_fd, &chip->pmic_model[0], sizeof(uint32_t));
982 wrote += write(out_fd, &chip->pmic_model[1], sizeof(uint32_t));
983 wrote += write(out_fd, &chip->pmic_model[2], sizeof(uint32_t));
984 wrote += write(out_fd, &chip->pmic_model[3], sizeof(uint32_t));
985 }
David Ng3556e582012-07-27 23:52:11 +0000986 if (chip->master->master_offset != 0) {
987 wrote += write(out_fd, &chip->master->master_offset, sizeof(uint32_t));
988 } else {
989 wrote += write(out_fd, &expected, sizeof(uint32_t));
990 chip->master->master_offset = expected;
991 expected += chip->master->dtb_size;
992 }
993 wrote += write(out_fd, &chip->master->dtb_size, sizeof(uint32_t));
994 }
995
996 rc = RC_SUCCESS;
997 wrote += write(out_fd, &rc, sizeof(uint32_t)); /* end of table indicator */
998 if (padding > 0)
999 wrote += write(out_fd, filler, padding);
1000
1001 /* Write DTB's */
1002 for (chip = chip_list; chip; chip = chip->next) {
1003 if (chip->master->wroteDtb) {
1004 continue;
1005 }
1006
1007 chip->master->wroteDtb = 1;
1008 filename = chip->master->dtb_file;
1009 dtb_size = chip->master->dtb_size;
1010
1011 log_dbg("\n (writing '%s' - %u bytes) ", filename, dtb_size);
1012 pInputFile = fopen(filename, "r");
1013 if (pInputFile != NULL) {
1014 totBytesRead = 0;
1015 while ((numBytesRead = fread(buf, 1, COPY_BLK, pInputFile)) > 0) {
1016 wrote += write(out_fd, buf, numBytesRead);
1017 totBytesRead += numBytesRead;
1018 }
1019 fclose(pInputFile);
1020 padding = page_size - (totBytesRead % page_size);
1021 if ((uint32_t)(totBytesRead + padding) != dtb_size) {
1022 log_err("DTB size mismatch, please re-run: expected %d vs actual %d (%s)\n",
1023 dtb_size, totBytesRead + padding,
1024 filename);
1025 rc = RC_ERROR;
1026 break;
1027 }
1028 if (padding > 0)
1029 wrote += write(out_fd, filler, padding);
1030 } else {
1031 log_err("failed to open DTB '%s'\n", filename);
1032 rc = RC_ERROR;
1033 break;
1034 }
1035 }
1036 close(out_fd);
1037
1038 if (expected != wrote) {
savoca04489bf2015-10-08 11:52:35 -07001039 log_err("error writing output file, please rerun: size mismatch %zu vs %zu\n",
David Ng3556e582012-07-27 23:52:11 +00001040 expected, wrote);
1041 rc = RC_ERROR;
1042 } else
savoca04489bf2015-10-08 11:52:35 -07001043 log_dbg("Total wrote %zu bytes\n", wrote);
David Ng3556e582012-07-27 23:52:11 +00001044
1045 if (rc != RC_SUCCESS)
1046 unlink(output_file);
1047 else
1048 log_info("completed\n");
1049
1050cleanup:
1051 free(filler);
1052 chip_deleteall();
1053 return rc;
1054}