blob: 20bc01489805e4e7ec589004de528a093d4bbf8c [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) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200779 if ((dp->d_type == DT_REG)) {
780 flen = strlen(dp->d_name);
781 if ((flen > 4) &&
782 (strncmp(&dp->d_name[flen-4], ".dtb", 4) == 0)) {
783 log_info("Found file: %s ... \n", dp->d_name);
David Ng3556e582012-07-27 23:52:11 +0000784
Danny Baumannbd62af82015-08-27 16:08:38 +0200785 flen = strlen(input_dir) + strlen(dp->d_name) + 1;
786 filename = (char *)malloc(flen);
787 if (!filename) {
788 log_err("Out of memory\n");
789 rc = RC_ERROR;
790 break;
791 }
792 strncpy(filename, input_dir, flen);
793 strncat(filename, dp->d_name, flen);
David Ng3556e582012-07-27 23:52:11 +0000794
Danny Baumannbd62af82015-08-27 16:08:38 +0200795 /* To identify the version number */
796 msmversion = GetVersionInfo(filename);
797 if (version < msmversion) {
798 version = msmversion;
799 }
Robin Humble9077ed02014-05-03 16:34:22 +1000800
Danny Baumannbd62af82015-08-27 16:08:38 +0200801 num = 1;
802 chip = getChipInfo(filename, &num, msmversion);
Robin Humble9077ed02014-05-03 16:34:22 +1000803
Danny Baumannbd62af82015-08-27 16:08:38 +0200804 if (msmversion == 1) {
805 if (!chip) {
806 log_err("skip, failed to scan for '%s' tag\n", dt_tag);
807 free(filename);
808 continue;
809 }
810 }
811 if (msmversion == 2) {
812 if (!chip) {
813 log_err("skip, failed to scan for '%s' or '%s' tag\n",
814 dt_tag, QCDT_BOARD_TAG);
815 free(filename);
816 continue;
817 }
818 }
819 if (msmversion == 3) {
820 if (!chip) {
821 log_err("skip, failed to scan for '%s', '%s' or '%s' tag\n",
822 dt_tag, QCDT_BOARD_TAG, QCDT_PMIC_TAG);
823 free(filename);
824 continue;
825 }
826 }
Robin Humble9077ed02014-05-03 16:34:22 +1000827
Danny Baumannbd62af82015-08-27 16:08:38 +0200828 if ((stat(filename, &st) != 0) ||
829 (st.st_size == 0)) {
830 log_err("skip, failed to get DTB size\n");
831 free(filename);
832 continue;
833 }
David Ng3556e582012-07-27 23:52:11 +0000834
Danny Baumannbd62af82015-08-27 16:08:38 +0200835 log_info("chipset: %u, rev: %u, platform: %u, subtype: %u, pmic0: %u, pmic1: %u, pmic2: %u, pmic3: %u\n",
836 chip->chipset, chip->revNum, chip->platform, chip->subtype,
837 chip->pmic_model[0], chip->pmic_model[1], chip->pmic_model[2], chip->pmic_model[3]);
David Ng3556e582012-07-27 23:52:11 +0000838
Danny Baumannbd62af82015-08-27 16:08:38 +0200839 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
840 log_info("additional chipset: %u, rev: %u, platform: %u, subtype: %u, pmic0: %u, pmic1: %u, pmic2: %u, pmic3: %u\n",
841 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype,
842 t_chip->pmic_model[0], t_chip->pmic_model[1], t_chip->pmic_model[2], t_chip->pmic_model[3]);
843 }
844
845 rc = chip_add(chip);
846 if (rc != RC_SUCCESS) {
847 log_err("... duplicate info, skipped\n");
848 free(filename);
849 continue;
850 }
851
852 dtb_count++;
853
854 chip->dtb_size = st.st_size +
855 (page_size - (st.st_size % page_size));
856 chip->dtb_file = filename;
857
858 for (t_chip = chip->t_next; t_chip; t_chip = t_chip->t_next) {
859 rc = chip_add(t_chip);
860 if (rc != RC_SUCCESS) {
861 log_err("... duplicate info, skipped (chipset %u, rev: %u, platform: %u, subtype: %u\n",
862 t_chip->chipset, t_chip->revNum, t_chip->platform, t_chip->subtype);
863 continue;
864 }
865 dtb_count++;
866 }
David Ng3556e582012-07-27 23:52:11 +0000867 }
868 }
David Ng3556e582012-07-27 23:52:11 +0000869 }
870 closedir(dir);
871 log_info("=> Found %d unique DTB(s)\n", dtb_count);
872
873 if (!dtb_count)
874 goto cleanup;
875
876
877 /* Generate the master DTB file:
878
879 Simplify write error handling by just checking for actual vs
880 expected bytes written at the end.
881 */
882
883 log_info("\nGenerating master DTB... ");
884
885 out_fd = open(output_file, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
886 if (!out_fd < 0) {
887 log_err("Cannot create '%s'\n", output_file);
888 rc = RC_ERROR;
889 goto cleanup;
890 }
891
Dan Pasanen5c432712015-11-08 10:16:14 -0600892 if (version_override != 0) {
893 version = version_override;
Danny Baumannbd62af82015-08-27 16:08:38 +0200894 }
895
Dan Pasanen5c432712015-11-08 10:16:14 -0600896 if (version == 1) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200897 entry_size = 20;
Dan Pasanen5c432712015-11-08 10:16:14 -0600898 } else if (version == 2) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200899 entry_size = 24;
900 } else {
901 entry_size = 40;
David Ng3556e582012-07-27 23:52:11 +0000902 }
903
904 /* Write header info */
905 wrote += write(out_fd, QCDT_MAGIC, sizeof(uint8_t) * 4); /* magic */
906 wrote += write(out_fd, &version, sizeof(uint32_t)); /* version */
907 wrote += write(out_fd, (uint32_t *)&dtb_count, sizeof(uint32_t));
908 /* #DTB */
909
910 /* Calculate offset of first DTB block */
Danny Baumannbd62af82015-08-27 16:08:38 +0200911 dtb_offset = 12 + /* header */
912 (entry_size * dtb_count) + /* DTB table entries */
913 4; /* end of table indicator */
914
David Ng3556e582012-07-27 23:52:11 +0000915 /* Round up to page size */
916 padding = page_size - (dtb_offset % page_size);
917 dtb_offset += padding;
918 expected = dtb_offset;
919
920 /* Write index table:
921 chipset
922 platform
Danny Baumannbd62af82015-08-27 16:08:38 +0200923 subtype (v2/v3 only)
David Ng3556e582012-07-27 23:52:11 +0000924 soc rev
Danny Baumannbd62af82015-08-27 16:08:38 +0200925 pmic model0 (v3 only)
926 pmic model1 (v3 only)
927 pmic model2 (v3 only)
928 pmic model3 (v3 only)
David Ng3556e582012-07-27 23:52:11 +0000929 dtb offset
930 dtb size
931 */
932 for (chip = chip_list; chip; chip = chip->next) {
933 wrote += write(out_fd, &chip->chipset, sizeof(uint32_t));
934 wrote += write(out_fd, &chip->platform, sizeof(uint32_t));
Dan Pasanen5c432712015-11-08 10:16:14 -0600935 if (version >= 2) {
David Ng3556e582012-07-27 23:52:11 +0000936 wrote += write(out_fd, &chip->subtype, sizeof(uint32_t));
Danny Baumannbd62af82015-08-27 16:08:38 +0200937 }
David Ng3556e582012-07-27 23:52:11 +0000938 wrote += write(out_fd, &chip->revNum, sizeof(uint32_t));
Dan Pasanen5c432712015-11-08 10:16:14 -0600939 if (version >= 3) {
Danny Baumannbd62af82015-08-27 16:08:38 +0200940 wrote += write(out_fd, &chip->pmic_model[0], sizeof(uint32_t));
941 wrote += write(out_fd, &chip->pmic_model[1], sizeof(uint32_t));
942 wrote += write(out_fd, &chip->pmic_model[2], sizeof(uint32_t));
943 wrote += write(out_fd, &chip->pmic_model[3], sizeof(uint32_t));
944 }
David Ng3556e582012-07-27 23:52:11 +0000945 if (chip->master->master_offset != 0) {
946 wrote += write(out_fd, &chip->master->master_offset, sizeof(uint32_t));
947 } else {
948 wrote += write(out_fd, &expected, sizeof(uint32_t));
949 chip->master->master_offset = expected;
950 expected += chip->master->dtb_size;
951 }
952 wrote += write(out_fd, &chip->master->dtb_size, sizeof(uint32_t));
953 }
954
955 rc = RC_SUCCESS;
956 wrote += write(out_fd, &rc, sizeof(uint32_t)); /* end of table indicator */
957 if (padding > 0)
958 wrote += write(out_fd, filler, padding);
959
960 /* Write DTB's */
961 for (chip = chip_list; chip; chip = chip->next) {
962 if (chip->master->wroteDtb) {
963 continue;
964 }
965
966 chip->master->wroteDtb = 1;
967 filename = chip->master->dtb_file;
968 dtb_size = chip->master->dtb_size;
969
970 log_dbg("\n (writing '%s' - %u bytes) ", filename, dtb_size);
971 pInputFile = fopen(filename, "r");
972 if (pInputFile != NULL) {
973 totBytesRead = 0;
974 while ((numBytesRead = fread(buf, 1, COPY_BLK, pInputFile)) > 0) {
975 wrote += write(out_fd, buf, numBytesRead);
976 totBytesRead += numBytesRead;
977 }
978 fclose(pInputFile);
979 padding = page_size - (totBytesRead % page_size);
980 if ((uint32_t)(totBytesRead + padding) != dtb_size) {
981 log_err("DTB size mismatch, please re-run: expected %d vs actual %d (%s)\n",
982 dtb_size, totBytesRead + padding,
983 filename);
984 rc = RC_ERROR;
985 break;
986 }
987 if (padding > 0)
988 wrote += write(out_fd, filler, padding);
989 } else {
990 log_err("failed to open DTB '%s'\n", filename);
991 rc = RC_ERROR;
992 break;
993 }
994 }
995 close(out_fd);
996
997 if (expected != wrote) {
savoca04489bf2015-10-08 11:52:35 -0700998 log_err("error writing output file, please rerun: size mismatch %zu vs %zu\n",
David Ng3556e582012-07-27 23:52:11 +0000999 expected, wrote);
1000 rc = RC_ERROR;
1001 } else
savoca04489bf2015-10-08 11:52:35 -07001002 log_dbg("Total wrote %zu bytes\n", wrote);
David Ng3556e582012-07-27 23:52:11 +00001003
1004 if (rc != RC_SUCCESS)
1005 unlink(output_file);
1006 else
1007 log_info("completed\n");
1008
1009cleanup:
1010 free(filler);
1011 chip_deleteall();
1012 return rc;
1013}