blob: 9df62a91c4162f1a25107834f70b96b185ddb42e [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>
42
43#define QCDT_MAGIC "QCDT" /* Master DTB magic */
Danny Baumannbd62af82015-08-27 16:08:38 +020044#define QCDT_VERSION 3 /* QCDT version */
David Ng3556e582012-07-27 23:52:11 +000045
46#define QCDT_DT_TAG "qcom,msm-id = <"
47#define QCDT_BOARD_TAG "qcom,board-id = <"
Danny Baumannbd62af82015-08-27 16:08:38 +020048#define QCDT_PMIC_TAG "qcom,pmic-id = <"
49
David Ng3556e582012-07-27 23:52:11 +000050
51#define PAGE_SIZE_DEF 2048
52#define PAGE_SIZE_MAX (1024*1024)
53
54#define log_err(x...) printf(x)
55#define log_info(x...) printf(x)
56#define log_dbg(x...) { if (verbose) printf(x); }
57
58#define COPY_BLK 1024 /* File copy block size */
59
60#define RC_SUCCESS 0
61#define RC_ERROR -1
62
63struct chipInfo_t {
64 uint32_t chipset;
65 uint32_t platform;
66 uint32_t subtype;
67 uint32_t revNum;
Danny Baumannbd62af82015-08-27 16:08:38 +020068 uint32_t pmic_model[4];
David Ng3556e582012-07-27 23:52:11 +000069 uint32_t dtb_size;
70 char *dtb_file;
71 struct chipInfo_t *prev;
72 struct chipInfo_t *next;
73 struct chipInfo_t *master;
74 int wroteDtb;
75 uint32_t master_offset;
76 struct chipInfo_t *t_next;
77};
78
79struct chipInfo_t *chip_list;
80
81struct chipId_t {
82 uint32_t chipset;
83 uint32_t revNum;
84 struct chipId_t *next;
85 struct chipId_t *t_next;
86};
87
88struct chipSt_t {
89 uint32_t platform;
90 uint32_t subtype;
91 struct chipSt_t *next;
92 struct chipSt_t *t_next;
93};
94
Danny Baumannbd62af82015-08-27 16:08:38 +020095struct chipPt_t {
96 uint32_t pmic0;
97 uint32_t pmic1;
98 uint32_t pmic2;
99 uint32_t pmic3;
100 struct chipPt_t *next;
101 struct chipPt_t *t_next;
102};
103
David Ng3556e582012-07-27 23:52:11 +0000104char *input_dir;
105char *output_file;
106char *dtc_path;
h8rift09db8b22014-04-07 22:10:33 -0400107char *dt_tag = QCDT_DT_TAG;
David Ng3556e582012-07-27 23:52:11 +0000108int verbose;
109int page_size = PAGE_SIZE_DEF;
Dan Pasanen5c432712015-11-08 10:16:14 -0600110int version_override = 0;
David Ng3556e582012-07-27 23:52:11 +0000111
112void print_help()
113{
114 log_info("dtbTool version %d (kinda :) )\n", QCDT_VERSION);
115 log_info("dtbTool [options] -o <output file> <input DTB path>\n");
116 log_info(" options:\n");
117 log_info(" --output-file/-o output file\n");
118 log_info(" --dtc-path/-p path to dtc\n");
119 log_info(" --page-size/-s page size in bytes\n");
h8rift09db8b22014-04-07 22:10:33 -0400120 log_info(" --dt-tag/-d alternate QCDT_DT_TAG\n");
David Ng3556e582012-07-27 23:52:11 +0000121 log_info(" --verbose/-v verbose\n");
Danny Baumannbd62af82015-08-27 16:08:38 +0200122 log_info(" --force-v2/-2 output dtb v2 format\n");
123 log_info(" --force-v3/-3 output dtb v3 format\n");
David Ng3556e582012-07-27 23:52:11 +0000124 log_info(" --help/-h this help screen\n");
125}
126
127int parse_commandline(int argc, char *const argv[])
128{
129 int c;
130
131 struct option long_options[] = {
132 {"output-file", 1, 0, 'o'},
133 {"dtc-path", 1, 0, 'p'},
134 {"page-size", 1, 0, 's'},
h8rift09db8b22014-04-07 22:10:33 -0400135 {"dt-tag", 1, 0, 'd'},
Danny Baumannbd62af82015-08-27 16:08:38 +0200136 {"force-v2", 0, 0, '2'},
137 {"force-v3", 0, 0, '3'},
David Ng3556e582012-07-27 23:52:11 +0000138 {"verbose", 0, 0, 'v'},
139 {"help", 0, 0, 'h'},
David Ng3556e582012-07-27 23:52:11 +0000140 {0, 0, 0, 0}
141 };
142
Danny Baumannbd62af82015-08-27 16:08:38 +0200143 while ((c = getopt_long(argc, argv, "-o:p:s:d:23vh", long_options, NULL))
David Ng3556e582012-07-27 23:52:11 +0000144 != -1) {
145 switch (c) {
146 case 1:
147 if (!input_dir)
148 input_dir = optarg;
149 break;
150 case 'o':
151 output_file = optarg;
152 break;
153 case 'p':
154 dtc_path = optarg;
155 break;
156 case 's':
157 page_size = atoi(optarg);
158 if ((page_size <= 0) || (page_size > (PAGE_SIZE_MAX))) {
159 log_err("Invalid page size (> 0 and <=1MB\n");
160 return RC_ERROR;
161 }
162 break;
h8rift09db8b22014-04-07 22:10:33 -0400163 case 'd':
164 dt_tag = optarg;
165 break;
Danny Baumannbd62af82015-08-27 16:08:38 +0200166 case '2':
167 case '3':
Dan Pasanen5c432712015-11-08 10:16:14 -0600168 if (version_override != 0) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200169 log_err("A version output argument may only be passed once\n");
170 return RC_ERROR;
171 }
Dan Pasanen5c432712015-11-08 10:16:14 -0600172 version_override = c - '0';
Danny Baumannbd62af82015-08-27 16:08:38 +0200173 break;
David Ng3556e582012-07-27 23:52:11 +0000174 case 'v':
175 verbose = 1;
176 break;
David Ng3556e582012-07-27 23:52:11 +0000177 case 'h':
178 default:
179 return RC_ERROR;
180 }
181 }
182
183 if (!output_file) {
184 log_err("Output file must be specified\n");
185 return RC_ERROR;
186 }
187
188 if (!input_dir)
189 input_dir = "./";
190
191 if (!dtc_path)
192 dtc_path = "";
193
194 return RC_SUCCESS;
195}
196
197/* Unique entry sorted list add (by chipset->platform->rev) */
198int chip_add(struct chipInfo_t *c)
199{
200 struct chipInfo_t *x = chip_list;
201
202 if (!chip_list) {
203 chip_list = c;
204 c->next = NULL;
205 c->prev = NULL;
206 return RC_SUCCESS;
207 }
208
209 while (1) {
210 if ((c->chipset < x->chipset) ||
211 ((c->chipset == x->chipset) &&
212 ((c->platform < x->platform) ||
213 ((c->platform == x->platform) &&
214 ((c->subtype < x->subtype) ||
215 ((c->subtype == x->subtype) &&
216 (c->revNum < x->revNum))))))) {
217 if (!x->prev) {
218 c->next = x;
219 c->prev = NULL;
220 x->prev = c;
221 chip_list = c;
222 break;
223 } else {
224 c->next = x;
225 c->prev = x->prev;
226 x->prev->next = c;
227 x->prev = c;
228 break;
229 }
230 }
231 if ((c->chipset == x->chipset) &&
232 (c->platform == x->platform) &&
233 (c->subtype == x->subtype) &&
Danny Baumannbd62af82015-08-27 16:08:38 +0200234 (c->revNum == x->revNum) &&
235 (c->pmic_model[0] == x->pmic_model[0]) &&
236 (c->pmic_model[1] == x->pmic_model[1]) &&
237 (c->pmic_model[2] == x->pmic_model[2]) &&
238 (c->pmic_model[3] == x->pmic_model[3])) {
David Ng3556e582012-07-27 23:52:11 +0000239 return RC_ERROR; /* duplicate */
240 }
241 if (!x->next) {
242 c->prev = x;
243 c->next = NULL;
244 x->next = c;
245 break;
246 }
247 x = x->next;
248 }
249 return RC_SUCCESS;
250}
251
252void chip_deleteall()
253{
254 struct chipInfo_t *c = chip_list, *t;
255
256 while (c) {
257 t = c;
258 c = c->next;
259 if (t->dtb_file)
260 free(t->dtb_file);
261 free(t);
262 }
263}
264
265/*
266 For v1 Extract 'qcom,msm-id' parameter triplet from DTB
267 qcom,msm-id = <x y z>;
268
269 For v2 Extract 'qcom,msm-id', 'qcom,board-id' parameter double from DTB
270 qcom,msm-id = <x z> i.e chipset, revision number;
271 qcom,board-id = <y y'> i.e platform and sub-type;
272 */
273
274struct chipInfo_t *getChipInfo(const char *filename, int *num, uint32_t msmversion)
275{
276
277 const char str1[] = "dtc -I dtb -O dts \"";
278 const char str2[] = "\" 2>&1";
279 char *buf, *pos;
280 char *line = NULL;
281 size_t line_size;
282 FILE *pfile;
283 int llen;
Danny Baumannbd62af82015-08-27 16:08:38 +0200284 struct chipInfo_t *chip = NULL, *tmp, *chip_t;
David Ng3556e582012-07-27 23:52:11 +0000285 uint32_t data[3] = {0, 0, 0};
286 uint32_t data_st[2] = {0, 0};
Danny Baumannbd62af82015-08-27 16:08:38 +0200287 uint32_t data_pt[4] = {0, 0, 0, 0};
David Ng3556e582012-07-27 23:52:11 +0000288 char *tok, *sptr = NULL;
289 int i, entryValid, entryEnded;
Danny Baumannbd62af82015-08-27 16:08:38 +0200290 int count = 0, count1 = 0, count2 = 0, count3 = 0;
291 int entryValidST, entryEndedST, entryValidDT, entryEndedDT, entryValidPT, entryEndedPT;
David Ng3556e582012-07-27 23:52:11 +0000292 struct chipId_t *chipId = NULL, *cId = NULL, *tmp_id = NULL;
293 struct chipSt_t *chipSt = NULL, *cSt = NULL, *tmp_st = NULL;
Danny Baumannbd62af82015-08-27 16:08:38 +0200294 struct chipPt_t *chipPt = NULL, *cPt = NULL, *tmp_pt = NULL;
295 struct chipId_t *chipId_tmp = NULL;
296 struct chipSt_t *chipSt_tmp = NULL;
297 struct chipPt_t *chipPt_tmp = NULL;
David Ng3556e582012-07-27 23:52:11 +0000298
299 line_size = 1024;
300 line = (char *)malloc(line_size);
301 if (!line) {
302 log_err("Out of memory\n");
303 return NULL;
304 }
305
306 llen = sizeof(char) * (strlen(dtc_path) +
307 strlen(str1) +
308 strlen(str2) +
309 strlen(filename) + 1);
310 buf = (char *)malloc(llen);
311 if (!buf) {
312 log_err("Out of memory\n");
313 free(line);
314 return NULL;
315 }
316
317 strncpy(buf, dtc_path, llen);
318 strncat(buf, str1, llen);
319 strncat(buf, filename, llen);
320 strncat(buf, str2, llen);
321
322 pfile = popen(buf, "r");
323 free(buf);
324
325 if (pfile == NULL) {
326 log_err("... skip, fail to decompile dtb\n");
327 } else {
328 /* Find "qcom,msm-id" */
329 while ((llen = getline(&line, &line_size, pfile)) != -1) {
330 if (msmversion == 1) {
h8rift09db8b22014-04-07 22:10:33 -0400331 if ((pos = strstr(line, dt_tag)) != NULL) {
332 pos += strlen(dt_tag);
David Ng3556e582012-07-27 23:52:11 +0000333
Ethan Chenebe5c222014-03-09 10:08:22 -0700334 entryEnded = 0;
335 while (1) {
336 entryValid = 1;
337 for (i = 0; i < 3; i++) {
338 tok = strtok_r(pos, " \t", &sptr);
339 pos = NULL;
340 if (tok != NULL) {
341 if (*tok == '>') {
342 entryEnded = 1;
343 entryValid = 0;
344 break;
345 }
346 data[i] = strtoul(tok, NULL, 0);
347 } else {
348 data[i] = 0;
David Ng3556e582012-07-27 23:52:11 +0000349 entryValid = 0;
Ethan Chenebe5c222014-03-09 10:08:22 -0700350 entryEnded = 1;
351 }
352 }
353 if (entryEnded) {
354 free(line);
355 pclose(pfile);
356 *num = count;
357 return chip;
358 }
359 if (entryValid) {
360 tmp = (struct chipInfo_t *)
361 malloc(sizeof(struct chipInfo_t));
362 if (!tmp) {
363 log_err("Out of memory\n");
David Ng3556e582012-07-27 23:52:11 +0000364 break;
365 }
Ethan Chenebe5c222014-03-09 10:08:22 -0700366 if (!chip) {
367 chip = tmp;
368 chip->t_next = NULL;
369 } else {
370 tmp->t_next = chip->t_next;
371 chip->t_next = tmp;
372 }
373 tmp->chipset = data[0];
374 tmp->platform = data[1];
David Ng3556e582012-07-27 23:52:11 +0000375 tmp->subtype = 0;
Ethan Chenebe5c222014-03-09 10:08:22 -0700376 tmp->revNum = data[2];
Danny Baumannbd62af82015-08-27 16:08:38 +0200377 tmp->pmic_model[0] = 0;
378 tmp->pmic_model[1] = 0;
379 tmp->pmic_model[2] = 0;
380 tmp->pmic_model[3] = 0;
Ethan Chenebe5c222014-03-09 10:08:22 -0700381 tmp->dtb_size = 0;
382 tmp->dtb_file = NULL;
383 tmp->master = chip;
384 tmp->wroteDtb = 0;
385 tmp->master_offset = 0;
386 count++;
387 }
David Ng3556e582012-07-27 23:52:11 +0000388 }
David Ng3556e582012-07-27 23:52:11 +0000389
h8rift09db8b22014-04-07 22:10:33 -0400390 log_err("... skip, incorrect '%s' format\n", dt_tag);
Ethan Chenebe5c222014-03-09 10:08:22 -0700391 break;
392 }
Danny Baumannbd62af82015-08-27 16:08:38 +0200393 } else if (msmversion == 2 || msmversion == 3) {
h8rift09db8b22014-04-07 22:10:33 -0400394 if ((pos = strstr(line, dt_tag)) != NULL) {
395 pos += strlen(dt_tag);
David Ng3556e582012-07-27 23:52:11 +0000396
397 entryEndedDT = 0;
398 for (;entryEndedDT < 1;) {
399 entryValidDT = 1;
400 for (i = 0; i < 2; i++) {
401 tok = strtok_r(pos, " \t", &sptr);
402 pos = NULL;
403 if (tok != NULL) {
404 if (*tok == '>') {
405 entryEndedDT = 1;
406 entryValidDT = 0;
407 break;
408 }
409 data_st[i] = strtoul(tok, NULL, 0);
410 } else {
411 data_st[i] = 0;
412 entryValidDT = 0;
413 entryEndedDT = 1;
414 }
415 }
416
417 if (entryValidDT) {
418 tmp_id = (struct chipId_t *)
419 malloc(sizeof(struct chipId_t));
420 if (!tmp_id) {
421 log_err("Out of memory\n");
422 break;
423 }
424 if (!chipId) {
425 chipId = tmp_id;
426 cId = tmp_id;
427 chipId->t_next = NULL;
428 } else {
429 tmp_id->t_next = chipId->t_next;
430 chipId->t_next = tmp_id;
431 }
432 tmp_id->chipset = data_st[0];
433 tmp_id->revNum= data_st[1];
434 count1++;
435 }
Ethan Chenebe5c222014-03-09 10:08:22 -0700436 }
David Ng3556e582012-07-27 23:52:11 +0000437 }
438
439 if ((pos = strstr(line,QCDT_BOARD_TAG)) != NULL) {
440 pos += strlen(QCDT_BOARD_TAG);
441 entryEndedST = 0;
442 for (;entryEndedST < 1;) {
443 entryValidST = 1;
444 for (i = 0; i < 2; i++) {
445 tok = strtok_r(pos, " \t", &sptr);
446 pos = NULL;
447 if (tok != NULL) {
448 if (*tok == '>') {
449 entryEndedST = 1;
450 entryValidST = 0;
451 break;
452 }
453 data_st[i] = strtoul(tok, NULL, 0);
454 } else {
455 data_st[i] = 0;
456 entryValidST = 0;
457 entryEndedST = 1;
458 }
459 }
460 if (entryValidST) {
461 tmp_st = (struct chipSt_t *)
462 malloc(sizeof(struct chipSt_t));
463 if (!tmp_st) {
464 log_err("Out of memory\n");
465 break;
466 }
467
468 if (!chipSt) {
469 chipSt = tmp_st;
470 cSt = tmp_st;
471 chipSt->t_next = NULL;
472 } else {
473 tmp_st->t_next = chipSt->t_next;
474 chipSt->t_next = tmp_st;
475 }
476
477 tmp_st->platform = data_st[0];
478 tmp_st->subtype= data_st[1];
479 count2++;
480 }
481 }
482 }
Danny Baumannbd62af82015-08-27 16:08:38 +0200483
484 if ((pos = strstr(line,QCDT_PMIC_TAG)) != NULL) {
485 pos += strlen(QCDT_PMIC_TAG);
486 entryEndedPT = 0;
487 for (;entryEndedPT < 1;) {
488 entryValidPT = 1;
489 for (i = 0; i < 4; i++) {
490 tok = strtok_r(pos, " \t", &sptr);
491 pos = NULL;
492 if (tok != NULL) {
493 if (*tok == '>') {
494 entryEndedPT = 1;
495 entryValidPT = 0;
496 break;
497 }
498 data_pt[i] = strtoul(tok, NULL, 0);
499 } else {
500 data_pt[i] = 0;
501 entryValidPT = 0;
502 entryEndedPT = 1;
503 }
504 }
505 if (entryValidPT) {
506 tmp_pt = (struct chipPt_t *)
507 malloc(sizeof(struct chipPt_t));
508 if (!tmp_pt) {
509 log_err("Out of memory\n");
510 break;
511 }
512
513 if (!chipPt) {
514 chipPt = tmp_pt;
515 cPt = tmp_pt;
516 chipPt->t_next = NULL;
517 } else {
518 tmp_pt->t_next = chipPt->t_next;
519 chipPt->t_next = tmp_pt;
520 }
521
522 tmp_pt->pmic0 = data_pt[0];
523 tmp_pt->pmic1 = data_pt[1];
524 tmp_pt->pmic2 = data_pt[2];
525 tmp_pt->pmic3 = data_pt[3];
526 count3++;
527 }
528 }
529 }
David Ng3556e582012-07-27 23:52:11 +0000530 }
531 }
532 }
533
Ethan Chenebe5c222014-03-09 10:08:22 -0700534 if (line)
535 free(line);
David Ng3556e582012-07-27 23:52:11 +0000536
David Ng3556e582012-07-27 23:52:11 +0000537 if (count1 == 0) {
h8rift09db8b22014-04-07 22:10:33 -0400538 log_err("... skip, incorrect '%s' format\n", dt_tag);
David Ng3556e582012-07-27 23:52:11 +0000539 return NULL;
540 }
541 if (count2 == 0) {
542 log_err("... skip, incorrect '%s' format\n", QCDT_BOARD_TAG);
543 return NULL;
544 }
Danny Baumannbd62af82015-08-27 16:08:38 +0200545 if (count3 == 0 && msmversion == 3) {
546 log_err("... skip, incorrect '%s' format\n", QCDT_PMIC_TAG);
547 return NULL;
548 }
David Ng3556e582012-07-27 23:52:11 +0000549
550 tmp_st = cSt;
Danny Baumannbd62af82015-08-27 16:08:38 +0200551 tmp_pt = cPt;
David Ng3556e582012-07-27 23:52:11 +0000552 while (cId != NULL) {
553 while (cSt != NULL) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200554 if (msmversion == 3) {
555 while (cPt != NULL) {
556 tmp = (struct chipInfo_t *)
557 malloc(sizeof(struct chipInfo_t));
558 if (!tmp) {
559 log_err("Out of memory\n");
560 break;
561 }
562 if (!chip) {
563 chip = tmp;
564 chip->t_next = NULL;
565 } else {
566 tmp->t_next = chip->t_next;
567 chip->t_next = tmp;
568 }
569
570 tmp->chipset = cId->chipset;
571 tmp->platform = cSt->platform;
572 tmp->revNum = cId->revNum;
573 tmp->subtype = cSt->subtype;
574 tmp->pmic_model[0] = cPt->pmic0;
575 tmp->pmic_model[1] = cPt->pmic1;
576 tmp->pmic_model[2] = cPt->pmic2;
577 tmp->pmic_model[3] = cPt->pmic3;
578 tmp->dtb_size = 0;
579 tmp->dtb_file = NULL;
580 tmp->master = chip;
581 tmp->wroteDtb = 0;
582 tmp->master_offset = 0;
583 cPt = cPt->t_next;
584 }
585 cPt = tmp_pt;
David Ng3556e582012-07-27 23:52:11 +0000586 } else {
Danny Baumannbd62af82015-08-27 16:08:38 +0200587 tmp = (struct chipInfo_t *)
588 malloc(sizeof(struct chipInfo_t));
589 if (!tmp) {
590 log_err("Out of memory\n");
591 break;
592 }
593 if (!chip) {
594 chip = tmp;
595 chip->t_next = NULL;
596 } else {
597 tmp->t_next = chip->t_next;
598 chip->t_next = tmp;
599 }
600 tmp->chipset = cId->chipset;
601 tmp->platform = cSt->platform;
602 tmp->revNum = cId->revNum;
603 tmp->subtype = cSt->subtype;
604 tmp->pmic_model[0] = 0;
605 tmp->pmic_model[1] = 0;
606 tmp->pmic_model[2] = 0;
607 tmp->pmic_model[3] = 0;
608 tmp->dtb_size = 0;
609 tmp->dtb_file = NULL;
610 tmp->master = chip;
611 tmp->wroteDtb = 0;
612 tmp->master_offset = 0;
David Ng3556e582012-07-27 23:52:11 +0000613 }
David Ng3556e582012-07-27 23:52:11 +0000614 cSt = cSt->t_next;
David Ng3556e582012-07-27 23:52:11 +0000615 }
616 cSt = tmp_st;
617 cId = cId->t_next;
618 }
619
Danny Baumannbd62af82015-08-27 16:08:38 +0200620 if (msmversion == 2)
621 entryEndedPT = 1;
622
623 /* clear memory*/
624 pclose(pfile);
625 while (chipId) {
626 chipId_tmp = chipId;
627 chipId = chipId->t_next;
628 free(chipId_tmp);
629 }
630 while (chipSt) {
631 chipSt_tmp= chipSt;
632 chipSt = chipSt->t_next;
633 free(chipSt_tmp);
634 }
635
636 while (chipPt) {
637 chipPt_tmp= chipPt;
638 chipPt = chipPt->t_next;
639 free(chipPt_tmp);
640 }
641
642 if (entryEndedST == 1 && entryEndedDT == 1 && entryEndedPT == 1) {
David Ng3556e582012-07-27 23:52:11 +0000643 *num = count1;
David Ng3556e582012-07-27 23:52:11 +0000644 return chip;
645 }
Ethan Chenebe5c222014-03-09 10:08:22 -0700646
Danny Baumannbd62af82015-08-27 16:08:38 +0200647 /* clear memory*/
648 while (chip) {
649 chip_t = chip;
650 chip = chip->next;
651 if (chip_t->dtb_file)
652 free(chip_t->dtb_file);
653 free(chip_t);
David Ng3556e582012-07-27 23:52:11 +0000654 }
David Ng3556e582012-07-27 23:52:11 +0000655 return NULL;
656}
657
658/* Get the version-id based on dtb files */
659int GetVersionInfo(const char *filename)
660{
661 const char str1[] = "dtc -I dtb -O dts \"";
662 const char str2[] = "\" 2>&1";
663 char *buf, *pos;
664 char *line = NULL;
665 size_t line_size;
666 FILE *pfile;
667 int llen;
668 int v = 1;
669
670 line_size = 1024;
671 line = (char *)malloc(line_size);
672 if (!line) {
673 log_err("Out of memory\n");
674 return 0;
675 }
676
677 llen = sizeof(char) * (strlen(dtc_path) +
678 strlen(str1) +
679 strlen(str2) +
680 strlen(filename) + 1);
681 buf = (char *)malloc(llen);
682 if (!buf) {
683 log_err("Out of memory\n");
684 free(line);
685 return 0;
686 }
687
688 strncpy(buf, dtc_path, llen);
689 strncat(buf, str1, llen);
690 strncat(buf, filename, llen);
691 strncat(buf, str2, llen);
692
693 pfile = popen(buf, "r");
694 free(buf);
695
696 if (pfile == NULL) {
697 log_err("... skip, fail to decompile dtb\n");
698 } else {
699 /* Find the type of version */
700 while ((llen = getline(&line, &line_size, pfile)) != -1) {
701 if ((pos = strstr(line,QCDT_BOARD_TAG)) != NULL) {
702 v = 2;
Danny Baumannbd62af82015-08-27 16:08:38 +0200703 }
704 if ((pos = strstr(line,QCDT_PMIC_TAG)) != NULL) {
705 v = 3;
David Ng3556e582012-07-27 23:52:11 +0000706 break;
707 }
708 }
709 }
Danny Baumannbd62af82015-08-27 16:08:38 +0200710
David Ng3556e582012-07-27 23:52:11 +0000711 free(line);
Danny Baumannbd62af82015-08-27 16:08:38 +0200712 log_info("Version:%d\n", v);
David Ng3556e582012-07-27 23:52:11 +0000713
714 return v;
715}
716
717/* Extract 'qcom,msm-id' 'qcom,board-id' parameter from DTB
718 v1 format:
719 qcom,msm-id = <x y z> [, <x2 y2 z2> ...];
720 v2 format:
721 qcom,msm-id = <x z> [, <x2 z2> ...;
722 qcom,board-id = <y y'> [, <y2 y2'> ...;
723 Fields:
724 x = chipset
725 y = platform
726 y' = subtype
727 z = soc rev
728 */
729int main(int argc, char **argv)
730{
731 char buf[COPY_BLK];
732 struct chipInfo_t *chip, *t_chip;
733 struct dirent *dp;
734 FILE *pInputFile;
735 char *filename;
736 int padding;
737 uint8_t *filler = NULL;
738 int numBytesRead = 0;
739 int totBytesRead = 0;
740 int out_fd;
741 int flen;
742 int rc = RC_SUCCESS;
Danny Baumannbd62af82015-08-27 16:08:38 +0200743 int dtb_count = 0, dtb_offset = 0, entry_size;
David Ng3556e582012-07-27 23:52:11 +0000744 size_t wrote = 0, expected = 0;
745 struct stat st;
Danny Baumannbd62af82015-08-27 16:08:38 +0200746 uint32_t version = 0;
David Ng3556e582012-07-27 23:52:11 +0000747 int num;
748 uint32_t dtb_size;
749 int msmversion = 0;
750
751 log_info("DTB combiner:\n");
752
753 if (parse_commandline(argc, argv) != RC_SUCCESS) {
754 print_help();
755 return RC_ERROR;
756 }
757
758 log_info(" Input directory: '%s'\n", input_dir);
759 log_info(" Output file: '%s'\n", output_file);
760
761 DIR *dir = opendir(input_dir);
762 if (!dir) {
763 log_err("Failed to open input directory '%s'\n", input_dir);
764 return RC_ERROR;
765 }
766
767 filler = (uint8_t *)malloc(page_size);
768 if (!filler) {
769 log_err("Out of memory\n");
770 closedir(dir);
771 return RC_ERROR;
772 }
773 memset(filler, 0, page_size);
774
775 /* Open the .dtb files in the specified path, decompile and
776 extract "qcom,msm-id" parameter
777 */
778 while ((dp = readdir(dir)) != NULL) {
Dan Pasanenb2b1bbc2015-11-08 09:56:04 -0600779 if (dp->d_type == DT_UNKNOWN) {
780 struct stat statbuf;
781 char name[PATH_MAX];
782 snprintf(name, sizeof(name), "%s%s%s",
783 input_dir,
784 (input_dir[strlen(input_dir) - 1] == '/' ? "" : "/"),
785 dp->d_name);
786 if (!stat(name, &statbuf) && S_ISREG(statbuf.st_mode)) {
787 dp->d_type = DT_REG;
788 }
789 }
790
791 if (dp->d_type == DT_REG) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200792 flen = strlen(dp->d_name);
793 if ((flen > 4) &&
794 (strncmp(&dp->d_name[flen-4], ".dtb", 4) == 0)) {
795 log_info("Found file: %s ... \n", dp->d_name);
David Ng3556e582012-07-27 23:52:11 +0000796
Danny Baumannbd62af82015-08-27 16:08:38 +0200797 flen = strlen(input_dir) + strlen(dp->d_name) + 1;
798 filename = (char *)malloc(flen);
799 if (!filename) {
800 log_err("Out of memory\n");
801 rc = RC_ERROR;
802 break;
803 }
804 strncpy(filename, input_dir, flen);
805 strncat(filename, dp->d_name, flen);
David Ng3556e582012-07-27 23:52:11 +0000806
Danny Baumannbd62af82015-08-27 16:08:38 +0200807 /* To identify the version number */
808 msmversion = GetVersionInfo(filename);
809 if (version < msmversion) {
810 version = msmversion;
811 }
Robin Humble9077ed02014-05-03 16:34:22 +1000812
Danny Baumannbd62af82015-08-27 16:08:38 +0200813 num = 1;
814 chip = getChipInfo(filename, &num, msmversion);
Robin Humble9077ed02014-05-03 16:34:22 +1000815
Danny Baumannbd62af82015-08-27 16:08:38 +0200816 if (msmversion == 1) {
817 if (!chip) {
818 log_err("skip, failed to scan for '%s' tag\n", dt_tag);
819 free(filename);
820 continue;
821 }
822 }
823 if (msmversion == 2) {
824 if (!chip) {
825 log_err("skip, failed to scan for '%s' or '%s' tag\n",
826 dt_tag, QCDT_BOARD_TAG);
827 free(filename);
828 continue;
829 }
830 }
831 if (msmversion == 3) {
832 if (!chip) {
833 log_err("skip, failed to scan for '%s', '%s' or '%s' tag\n",
834 dt_tag, QCDT_BOARD_TAG, QCDT_PMIC_TAG);
835 free(filename);
836 continue;
837 }
838 }
Robin Humble9077ed02014-05-03 16:34:22 +1000839
Danny Baumannbd62af82015-08-27 16:08:38 +0200840 if ((stat(filename, &st) != 0) ||
841 (st.st_size == 0)) {
842 log_err("skip, failed to get DTB size\n");
843 free(filename);
844 continue;
845 }
David Ng3556e582012-07-27 23:52:11 +0000846
Danny Baumannbd62af82015-08-27 16:08:38 +0200847 log_info("chipset: %u, rev: %u, platform: %u, subtype: %u, pmic0: %u, pmic1: %u, pmic2: %u, pmic3: %u\n",
848 chip->chipset, chip->revNum, chip->platform, chip->subtype,
849 chip->pmic_model[0], chip->pmic_model[1], chip->pmic_model[2], chip->pmic_model[3]);
David Ng3556e582012-07-27 23:52:11 +0000850
Danny Baumannbd62af82015-08-27 16:08:38 +0200851 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
852 log_info("additional chipset: %u, rev: %u, platform: %u, subtype: %u, pmic0: %u, pmic1: %u, pmic2: %u, pmic3: %u\n",
853 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype,
854 t_chip->pmic_model[0], t_chip->pmic_model[1], t_chip->pmic_model[2], t_chip->pmic_model[3]);
855 }
856
857 rc = chip_add(chip);
858 if (rc != RC_SUCCESS) {
859 log_err("... duplicate info, skipped\n");
860 free(filename);
861 continue;
862 }
863
864 dtb_count++;
865
866 chip->dtb_size = st.st_size +
867 (page_size - (st.st_size % page_size));
868 chip->dtb_file = filename;
869
870 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
871 rc = chip_add(t_chip);
872 if (rc != RC_SUCCESS) {
873 log_err("... duplicate info, skipped (chipset %u, rev: %u, platform: %u, subtype: %u\n",
874 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype);
875 continue;
876 }
877 dtb_count++;
878 }
David Ng3556e582012-07-27 23:52:11 +0000879 }
880 }
David Ng3556e582012-07-27 23:52:11 +0000881 }
882 closedir(dir);
883 log_info("=> Found %d unique DTB(s)\n", dtb_count);
884
885 if (!dtb_count)
886 goto cleanup;
887
888
889 /* Generate the master DTB file:
890
891 Simplify write error handling by just checking for actual vs
892 expected bytes written at the end.
893 */
894
895 log_info("\nGenerating master DTB... ");
896
897 out_fd = open(output_file, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
Keith Mok8f9d7d82015-11-09 10:12:06 -0800898 if (out_fd == -1) {
David Ng3556e582012-07-27 23:52:11 +0000899 log_err("Cannot create '%s'\n", output_file);
900 rc = RC_ERROR;
901 goto cleanup;
902 }
903
Dan Pasanen5c432712015-11-08 10:16:14 -0600904 if (version_override != 0) {
905 version = version_override;
Danny Baumannbd62af82015-08-27 16:08:38 +0200906 }
907
Dan Pasanen5c432712015-11-08 10:16:14 -0600908 if (version == 1) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200909 entry_size = 20;
Dan Pasanen5c432712015-11-08 10:16:14 -0600910 } else if (version == 2) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200911 entry_size = 24;
912 } else {
913 entry_size = 40;
David Ng3556e582012-07-27 23:52:11 +0000914 }
915
916 /* Write header info */
917 wrote += write(out_fd, QCDT_MAGIC, sizeof(uint8_t) * 4); /* magic */
918 wrote += write(out_fd, &version, sizeof(uint32_t)); /* version */
919 wrote += write(out_fd, (uint32_t *)&dtb_count, sizeof(uint32_t));
920 /* #DTB */
921
922 /* Calculate offset of first DTB block */
Danny Baumannbd62af82015-08-27 16:08:38 +0200923 dtb_offset = 12 + /* header */
924 (entry_size * dtb_count) + /* DTB table entries */
925 4; /* end of table indicator */
926
David Ng3556e582012-07-27 23:52:11 +0000927 /* Round up to page size */
928 padding = page_size - (dtb_offset % page_size);
929 dtb_offset += padding;
930 expected = dtb_offset;
931
932 /* Write index table:
933 chipset
934 platform
Danny Baumannbd62af82015-08-27 16:08:38 +0200935 subtype (v2/v3 only)
David Ng3556e582012-07-27 23:52:11 +0000936 soc rev
Danny Baumannbd62af82015-08-27 16:08:38 +0200937 pmic model0 (v3 only)
938 pmic model1 (v3 only)
939 pmic model2 (v3 only)
940 pmic model3 (v3 only)
David Ng3556e582012-07-27 23:52:11 +0000941 dtb offset
942 dtb size
943 */
944 for (chip = chip_list; chip; chip = chip->next) {
945 wrote += write(out_fd, &chip->chipset, sizeof(uint32_t));
946 wrote += write(out_fd, &chip->platform, sizeof(uint32_t));
Dan Pasanen5c432712015-11-08 10:16:14 -0600947 if (version >= 2) {
David Ng3556e582012-07-27 23:52:11 +0000948 wrote += write(out_fd, &chip->subtype, sizeof(uint32_t));
Danny Baumannbd62af82015-08-27 16:08:38 +0200949 }
David Ng3556e582012-07-27 23:52:11 +0000950 wrote += write(out_fd, &chip->revNum, sizeof(uint32_t));
Dan Pasanen5c432712015-11-08 10:16:14 -0600951 if (version >= 3) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200952 wrote += write(out_fd, &chip->pmic_model[0], sizeof(uint32_t));
953 wrote += write(out_fd, &chip->pmic_model[1], sizeof(uint32_t));
954 wrote += write(out_fd, &chip->pmic_model[2], sizeof(uint32_t));
955 wrote += write(out_fd, &chip->pmic_model[3], sizeof(uint32_t));
956 }
David Ng3556e582012-07-27 23:52:11 +0000957 if (chip->master->master_offset != 0) {
958 wrote += write(out_fd, &chip->master->master_offset, sizeof(uint32_t));
959 } else {
960 wrote += write(out_fd, &expected, sizeof(uint32_t));
961 chip->master->master_offset = expected;
962 expected += chip->master->dtb_size;
963 }
964 wrote += write(out_fd, &chip->master->dtb_size, sizeof(uint32_t));
965 }
966
967 rc = RC_SUCCESS;
968 wrote += write(out_fd, &rc, sizeof(uint32_t)); /* end of table indicator */
969 if (padding > 0)
970 wrote += write(out_fd, filler, padding);
971
972 /* Write DTB's */
973 for (chip = chip_list; chip; chip = chip->next) {
974 if (chip->master->wroteDtb) {
975 continue;
976 }
977
978 chip->master->wroteDtb = 1;
979 filename = chip->master->dtb_file;
980 dtb_size = chip->master->dtb_size;
981
982 log_dbg("\n (writing '%s' - %u bytes) ", filename, dtb_size);
983 pInputFile = fopen(filename, "r");
984 if (pInputFile != NULL) {
985 totBytesRead = 0;
986 while ((numBytesRead = fread(buf, 1, COPY_BLK, pInputFile)) > 0) {
987 wrote += write(out_fd, buf, numBytesRead);
988 totBytesRead += numBytesRead;
989 }
990 fclose(pInputFile);
991 padding = page_size - (totBytesRead % page_size);
992 if ((uint32_t)(totBytesRead + padding) != dtb_size) {
993 log_err("DTB size mismatch, please re-run: expected %d vs actual %d (%s)\n",
994 dtb_size, totBytesRead + padding,
995 filename);
996 rc = RC_ERROR;
997 break;
998 }
999 if (padding > 0)
1000 wrote += write(out_fd, filler, padding);
1001 } else {
1002 log_err("failed to open DTB '%s'\n", filename);
1003 rc = RC_ERROR;
1004 break;
1005 }
1006 }
1007 close(out_fd);
1008
1009 if (expected != wrote) {
savoca04489bf2015-10-08 11:52:35 -07001010 log_err("error writing output file, please rerun: size mismatch %zu vs %zu\n",
David Ng3556e582012-07-27 23:52:11 +00001011 expected, wrote);
1012 rc = RC_ERROR;
1013 } else
savoca04489bf2015-10-08 11:52:35 -07001014 log_dbg("Total wrote %zu bytes\n", wrote);
David Ng3556e582012-07-27 23:52:11 +00001015
1016 if (rc != RC_SUCCESS)
1017 unlink(output_file);
1018 else
1019 log_info("completed\n");
1020
1021cleanup:
1022 free(filler);
1023 chip_deleteall();
1024 return rc;
1025}