1 /* 2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 #include <common.h> 7 #include <adc.h> 8 #include <android_bootloader.h> 9 #include <android_image.h> 10 #include <boot_rkimg.h> 11 #include <bmp_layout.h> 12 #include <crypto.h> 13 #include <fs.h> 14 #include <malloc.h> 15 #include <sysmem.h> 16 #include <asm/io.h> 17 #include <asm/unaligned.h> 18 #include <android_avb/libavb_ab.h> 19 #include <android_avb/rk_avb_ops_user.h> 20 #include <dm/ofnode.h> 21 #include <linux/list.h> 22 #include <u-boot/sha1.h> 23 #include <u-boot/sha256.h> 24 #include <asm/arch/resource_img.h> 25 26 DECLARE_GLOBAL_DATA_PTR; 27 28 #define PART_RESOURCE "resource" 29 #define RESOURCE_MAGIC "RSCE" 30 #define RESOURCE_MAGIC_SIZE 4 31 #define RESOURCE_VERSION 0 32 #define CONTENT_VERSION 0 33 #define ENTRY_TAG "ENTR" 34 #define ENTRY_TAG_SIZE 4 35 #define MAX_FILE_NAME_LEN 220 36 #define MAX_HASH_LEN 32 37 38 #define DTB_FILE "rk-kernel.dtb" 39 40 /* 41 * resource image structure 42 * ---------------------------------------------- 43 * | | 44 * | header (1 block) | 45 * | | 46 * ---------------------------------------------| 47 * | | | 48 * | entry0 (1 block) | | 49 * | | | 50 * ------------------------ | 51 * | | | 52 * | entry1 (1 block) | contents (n blocks) | 53 * | | | 54 * ------------------------ | 55 * | ...... | | 56 * ------------------------ | 57 * | | | 58 * | entryn (1 block) | | 59 * | | | 60 * ---------------------------------------------- 61 * | | 62 * | file0 (x blocks) | 63 * | | 64 * ---------------------------------------------- 65 * | | 66 * | file1 (y blocks) | 67 * | | 68 * ---------------------------------------------- 69 * | ...... | 70 * |--------------------------------------------- 71 * | | 72 * | filen (z blocks) | 73 * | | 74 * ---------------------------------------------- 75 */ 76 77 /** 78 * struct resource_image_header 79 * 80 * @magic: should be "RSCE" 81 * @version: resource image version, current is 0 82 * @c_version: content version, current is 0 83 * @blks: the size of the header ( 1 block = 512 bytes) 84 * @c_offset: contents offset(by block) in the image 85 * @e_blks: the size(by block) of the entry in the contents 86 * @e_num: numbers of the entrys. 87 */ 88 89 struct resource_img_hdr { 90 char magic[4]; 91 uint16_t version; 92 uint16_t c_version; 93 uint8_t blks; 94 uint8_t c_offset; 95 uint8_t e_blks; 96 uint32_t e_nums; 97 }; 98 99 struct resource_entry { 100 char tag[4]; 101 char name[MAX_FILE_NAME_LEN]; 102 char hash[MAX_HASH_LEN]; 103 uint32_t hash_size; 104 uint32_t f_offset; 105 uint32_t f_size; 106 }; 107 108 struct resource_file { 109 char name[MAX_FILE_NAME_LEN]; 110 char hash[MAX_HASH_LEN]; 111 uint32_t hash_size; 112 uint32_t f_offset; /* Sector addr */ 113 uint32_t f_size; /* Bytes */ 114 struct list_head link; 115 uint32_t rsce_base; /* Base addr of resource */ 116 }; 117 118 static LIST_HEAD(entrys_head); 119 120 static int resource_image_check_header(const struct resource_img_hdr *hdr) 121 { 122 int ret; 123 124 ret = memcmp(RESOURCE_MAGIC, hdr->magic, RESOURCE_MAGIC_SIZE); 125 if (ret) { 126 debug("bad resource image magic: %s\n", 127 hdr->magic ? hdr->magic : "none"); 128 ret = -EINVAL; 129 } 130 131 debug("resource image header:\n"); 132 debug("magic:%s\n", hdr->magic); 133 debug("version:%d\n", hdr->version); 134 debug("c_version:%d\n", hdr->c_version); 135 debug("blks:%d\n", hdr->blks); 136 debug("c_offset:%d\n", hdr->c_offset); 137 debug("e_blks:%d\n", hdr->e_blks); 138 debug("e_num:%d\n", hdr->e_nums); 139 140 return ret; 141 } 142 143 static int add_file_to_list(struct resource_entry *entry, int rsce_base) 144 { 145 struct resource_file *file; 146 147 if (memcmp(entry->tag, ENTRY_TAG, ENTRY_TAG_SIZE)) { 148 printf("invalid entry tag\n"); 149 return -ENOENT; 150 } 151 152 file = malloc(sizeof(*file)); 153 if (!file) { 154 printf("out of memory\n"); 155 return -ENOMEM; 156 } 157 158 strcpy(file->name, entry->name); 159 file->rsce_base = rsce_base; 160 file->f_offset = entry->f_offset; 161 file->f_size = entry->f_size; 162 file->hash_size = entry->hash_size; 163 memcpy(file->hash, entry->hash, entry->hash_size); 164 list_add_tail(&file->link, &entrys_head); 165 166 debug("entry:%p %s offset:%d size:%d\n", 167 entry, file->name, file->f_offset, file->f_size); 168 169 return 0; 170 } 171 172 static int replace_resource_entry(const char *f_name, uint32_t base, 173 uint32_t f_offset, uint32_t f_size) 174 { 175 struct resource_entry *entry; 176 struct resource_file *file; 177 struct list_head *node; 178 179 if (!f_name || !f_size) 180 return -EINVAL; 181 182 entry = malloc(sizeof(*entry)); 183 if (!entry) 184 return -ENOMEM; 185 186 strcpy(entry->tag, ENTRY_TAG); 187 strcpy(entry->name, f_name); 188 entry->f_offset = f_offset; 189 entry->f_size = f_size; 190 191 /* Delete exist entry, then add this new */ 192 list_for_each(node, &entrys_head) { 193 file = list_entry(node, struct resource_file, link); 194 if (!strcmp(file->name, entry->name)) { 195 list_del(&file->link); 196 free(file); 197 break; 198 } 199 } 200 201 add_file_to_list(entry, base); 202 free(entry); 203 204 return 0; 205 } 206 207 static int read_logo_bmp(const char *name, disk_partition_t *part, 208 uint32_t offset, uint32_t *size) 209 { 210 struct blk_desc *dev_desc; 211 struct bmp_header *header; 212 u32 blk_start, blk_offset, filesz; 213 int ret; 214 215 dev_desc = rockchip_get_bootdev(); 216 if (!dev_desc) 217 return -ENODEV; 218 219 blk_offset = DIV_ROUND_UP(offset, dev_desc->blksz); 220 blk_start = part->start + blk_offset; 221 header = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz); 222 if (!header) { 223 ret = -ENOMEM; 224 goto err; 225 } 226 ret = blk_dread(dev_desc, blk_start, 1, header); 227 if (ret != 1) { 228 ret = -EIO; 229 goto err; 230 } 231 232 if (header->signature[0] != 'B' || 233 header->signature[1] != 'M') { 234 ret = -EINVAL; 235 goto err; 236 } 237 238 filesz = get_unaligned_le32(&header->file_size); 239 ret = replace_resource_entry(name, blk_start, blk_offset, filesz); 240 if (!ret) { 241 printf("LOGO: %s\n", name); 242 if (size) 243 *size = filesz; 244 } 245 err: 246 free(header); 247 248 return ret; 249 } 250 /* 251 * There are: logo/battery pictures and dtb file in the resource image by default. 252 * 253 * This function does: 254 * 255 * 1. Get resource image from part: boot/recovery(AOSP) > resource(RK); 256 * 2. Add all file into resource list(We load them from storage when we need); 257 * 3. Add logo picture from logo partition into resource list(replace the 258 * old one in resource file); 259 * 4. Add dtb file from dtb position into resource list if boot_img_hdr_v2 260 * (replace the old one in resource file); 261 */ 262 static int init_resource_list(struct resource_img_hdr *hdr) 263 { 264 struct resource_entry *entry; 265 struct blk_desc *dev_desc; 266 char *boot_partname = PART_BOOT; 267 disk_partition_t part_info; 268 int resource_found = 0; 269 void *content = NULL; 270 int rsce_base = 0; 271 __maybe_unused int dtb_offset = 0; 272 int dtb_size = 0; 273 int e_num, cnt; 274 int size; 275 int ret; 276 277 dev_desc = rockchip_get_bootdev(); 278 if (!dev_desc) { 279 printf("%s: dev_desc is NULL!\n", __func__); 280 return -ENODEV; 281 } 282 283 /* If hdr is valid from outside, use it */ 284 if (hdr) { 285 if (resource_image_check_header(hdr)) 286 return -EEXIST; 287 288 content = (void *)((char *)hdr + 289 (hdr->c_offset) * dev_desc->blksz); 290 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 291 size = e_num * hdr->e_blks * dev_desc->blksz; 292 entry = (struct resource_entry *)(content + size); 293 add_file_to_list(entry, rsce_base); 294 } 295 return 0; 296 } 297 298 cnt = DIV_ROUND_UP(sizeof(struct andr_img_hdr), dev_desc->blksz); 299 hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz * cnt); 300 if (!hdr) 301 return -ENOMEM; 302 303 /* 304 * Anyway, we must read android hdr firstly from boot partition to get 305 * the 'os_version' for android_bcb_msg_sector_offset() to confirm BCB 306 * message offset of misc partition. 307 */ 308 #ifdef CONFIG_ANDROID_BOOT_IMAGE 309 struct andr_img_hdr *andr_hdr; 310 311 ret = part_get_info_by_name(dev_desc, boot_partname, &part_info); 312 if (ret < 0) { 313 printf("%s: failed to get %s part, ret=%d\n", 314 __func__, boot_partname, ret); 315 goto parse_resource_part; 316 } 317 318 andr_hdr = (void *)hdr; 319 ret = blk_dread(dev_desc, part_info.start, cnt, andr_hdr); 320 if (ret != cnt) { 321 printf("%s: failed to read %s hdr, ret=%d\n", 322 __func__, part_info.name, ret); 323 ret = -EIO; 324 goto out; 325 } 326 327 ret = android_image_check_header(andr_hdr); 328 if (!ret) { 329 u32 os_ver = andr_hdr->os_version >> 11; 330 u32 os_lvl = andr_hdr->os_version & ((1U << 11) - 1); 331 332 if (os_ver) { 333 gd->bd->bi_andr_version = andr_hdr->os_version; 334 printf("Android %u.%u, Build %u.%u\n", 335 (os_ver >> 14) & 0x7F, (os_ver >> 7) & 0x7F, 336 (os_lvl >> 4) + 2000, os_lvl & 0x0F); 337 } 338 } 339 340 /* Get boot mode from misc and read if recovery mode */ 341 #ifndef CONFIG_ANDROID_AB 342 if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) { 343 boot_partname = PART_RECOVERY; 344 345 ret = part_get_info_by_name(dev_desc, boot_partname, &part_info); 346 if (ret < 0) { 347 printf("%s: failed to get %s part, ret=%d\n", 348 __func__, boot_partname, ret); 349 goto parse_resource_part; 350 } 351 352 /* Try to find resource from android second position */ 353 andr_hdr = (void *)hdr; 354 ret = blk_dread(dev_desc, part_info.start, cnt, andr_hdr); 355 if (ret != cnt) { 356 printf("%s: failed to read %s hdr, ret=%d\n", 357 __func__, part_info.name, ret); 358 ret = -EIO; 359 goto out; 360 } 361 } 362 #endif 363 364 ret = android_image_check_header(andr_hdr); 365 if (!ret) { 366 rsce_base = part_info.start * dev_desc->blksz; 367 rsce_base += andr_hdr->page_size; 368 rsce_base += ALIGN(andr_hdr->kernel_size, andr_hdr->page_size); 369 rsce_base += ALIGN(andr_hdr->ramdisk_size, andr_hdr->page_size); 370 371 if (andr_hdr->header_version >= 2) { 372 dtb_offset = rsce_base + 373 ALIGN(andr_hdr->recovery_dtbo_size, 374 andr_hdr->page_size) + 375 ALIGN(andr_hdr->second_size, andr_hdr->page_size); 376 dtb_size = andr_hdr->dtb_size; 377 } 378 379 rsce_base = DIV_ROUND_UP(rsce_base, dev_desc->blksz); 380 dtb_offset = 381 DIV_ROUND_UP(dtb_offset, dev_desc->blksz) - rsce_base; 382 resource_found = 1; 383 } 384 parse_resource_part: 385 #endif /* CONFIG_ANDROID_BOOT_IMAGE*/ 386 387 /* If not find android image, get resource file from resource part */ 388 if (!resource_found) { 389 boot_partname = PART_RESOURCE; 390 ret = part_get_info_by_name(dev_desc, boot_partname, &part_info); 391 if (ret < 0) { 392 printf("%s: failed to get resource part, ret=%d\n", 393 __func__, ret); 394 goto out; 395 } 396 rsce_base = part_info.start; 397 } 398 399 /* 400 * Now, the "rsce_base" points to the resource file sector. 401 */ 402 ret = blk_dread(dev_desc, rsce_base, 1, hdr); 403 if (ret != 1) { 404 printf("%s: failed to read resource hdr, ret=%d\n", 405 __func__, ret); 406 ret = -EIO; 407 goto out; 408 } 409 410 ret = resource_image_check_header(hdr); 411 if (ret < 0) { 412 ret = -EINVAL; 413 goto parse_second_pos_dtb; 414 } 415 416 content = memalign(ARCH_DMA_MINALIGN, 417 hdr->e_blks * hdr->e_nums * dev_desc->blksz); 418 if (!content) { 419 printf("%s: failed to alloc memory for content\n", __func__); 420 ret = -ENOMEM; 421 goto out; 422 } 423 424 ret = blk_dread(dev_desc, rsce_base + hdr->c_offset, 425 hdr->e_blks * hdr->e_nums, content); 426 if (ret != (hdr->e_blks * hdr->e_nums)) { 427 printf("%s: failed to read resource entries, ret=%d\n", 428 __func__, ret); 429 ret = -EIO; 430 goto err; 431 } 432 433 /* 434 * Add all file into resource file list, and load what we want from 435 * storage when we really need it. 436 */ 437 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 438 size = e_num * hdr->e_blks * dev_desc->blksz; 439 entry = (struct resource_entry *)(content + size); 440 add_file_to_list(entry, rsce_base); 441 } 442 443 ret = 0; 444 printf("Found DTB in %s part\n", boot_partname); 445 446 parse_second_pos_dtb: 447 #ifdef CONFIG_ANDROID_BOOT_IMAGE 448 /* 449 * If not find resource file on above, we try to get dtb file from 450 * android second position. 451 */ 452 if (!content && !fdt_check_header((void *)hdr)) { 453 entry = malloc(sizeof(*entry)); 454 if (!entry) { 455 ret = -ENOMEM; 456 goto parse_logo; 457 } 458 459 memcpy(entry->tag, ENTRY_TAG, sizeof(ENTRY_TAG)); 460 memcpy(entry->name, DTB_FILE, sizeof(DTB_FILE)); 461 entry->f_size = fdt_totalsize((void *)hdr); 462 entry->f_offset = 0; 463 464 add_file_to_list(entry, part_info.start); 465 free(entry); 466 ret = 0; 467 printf("Found DTB in %s part(second pos)\n", boot_partname); 468 } 469 470 parse_logo: 471 #endif 472 /* 473 * Add logo.bmp and logo_kernel.bmp from "logo" parititon 474 * 475 * Provide a "logo" partition for user to store logo.bmp and 476 * logo_kernel.bmp, so that the users can update them from 477 * kernel or user-space dynamically. 478 * 479 * "logo" partition layout, not change order: 480 * 481 * |----------------------| 0x00 482 * | raw logo.bmp | 483 * |----------------------| N*512-byte aligned 484 * | raw logo_kernel.bmp | 485 * |----------------------| 486 * 487 * N: the sector count of logo.bmp 488 */ 489 if (part_get_info_by_name(dev_desc, PART_LOGO, &part_info) >= 0) { 490 u32 filesz; 491 492 if (!read_logo_bmp("logo.bmp", &part_info, 0, &filesz)) 493 read_logo_bmp("logo_kernel.bmp", &part_info, 494 filesz, NULL); 495 } 496 497 /* 498 * boot_img_hdr_v2 feature. 499 * 500 * If dtb position is present, replace the old with new one if 501 * we don't need to verify DTB hash from resource.img file entry. 502 */ 503 if (dtb_size) { 504 #ifndef CONFIG_ROCKCHIP_DTB_VERIFY 505 ret = replace_resource_entry(DTB_FILE, rsce_base, 506 dtb_offset, dtb_size); 507 if (ret) 508 printf("Failed to load dtb from dtb position\n"); 509 else 510 #endif 511 env_update("bootargs", "androidboot.dtb_idx=0"); 512 } 513 err: 514 if (content) 515 free(content); 516 out: 517 free(hdr); 518 519 return ret; 520 } 521 522 static struct resource_file *get_file_info(struct resource_img_hdr *hdr, 523 const char *name) 524 { 525 struct resource_file *file; 526 struct list_head *node; 527 528 if (list_empty(&entrys_head)) { 529 if (init_resource_list(hdr)) 530 return NULL; 531 } 532 533 list_for_each(node, &entrys_head) { 534 file = list_entry(node, struct resource_file, link); 535 if (!strcmp(file->name, name)) 536 return file; 537 } 538 539 return NULL; 540 } 541 542 int rockchip_get_resource_file_offset(void *resc_hdr, const char *name) 543 { 544 struct resource_file *file; 545 546 file = get_file_info(resc_hdr, name); 547 if (!file) 548 return -ENFILE; 549 550 return file->f_offset; 551 } 552 553 /* 554 * read file from resource partition 555 * @buf: destination buf to store file data; 556 * @name: file name 557 * @offset: blocks offset in the file, 1 block = 512 bytes 558 * @len: the size(by bytes) of file to read. 559 */ 560 int rockchip_read_resource_file(void *buf, const char *name, 561 int offset, int len) 562 { 563 struct resource_file *file; 564 struct blk_desc *dev_desc; 565 int ret = 0; 566 int blks; 567 568 dev_desc = rockchip_get_bootdev(); 569 if (!dev_desc) { 570 printf("%s: dev_desc is NULL!\n", __func__); 571 return -ENODEV; 572 } 573 574 file = get_file_info(NULL, name); 575 if (!file) { 576 printf("Can't find file:%s\n", name); 577 return -ENOENT; 578 } 579 580 if (len <= 0 || len > file->f_size) 581 len = file->f_size; 582 583 blks = DIV_ROUND_UP(len, dev_desc->blksz); 584 ret = blk_dread(dev_desc, file->rsce_base + file->f_offset + offset, 585 blks, buf); 586 if (ret != blks) 587 ret = -EIO; 588 else 589 ret = len; 590 591 return ret; 592 } 593 594 #ifdef CONFIG_ROCKCHIP_HWID_DTB 595 #define is_digit(c) ((c) >= '0' && (c) <= '9') 596 #define is_abcd(c) ((c) >= 'a' && (c) <= 'd') 597 #define is_equal(c) ((c) == '=') 598 599 #define KEY_WORDS_ADC_CTRL "#_" 600 #define KEY_WORDS_ADC_CH "_ch" 601 #define KEY_WORDS_GPIO "#gpio" 602 #define GPIO_SWPORT_DDR 0x04 603 #define GPIO_EXT_PORT 0x50 604 #define MAX_ADC_CH_NR 10 605 #define MAX_GPIO_NR 10 606 607 /* 608 * How to make it works ? 609 * 610 * 1. pack dtb into rockchip resource.img, require: 611 * (1) file name end with ".dtb"; 612 * (2) file name contains key words, like: ...#_[controller]_ch[channel]=[value]...dtb 613 * @controller: adc controller name in dts, eg. "saradc", ...; 614 * @channel: adc channel; 615 * @value: adc value; 616 * eg: ...#_saradc_ch1=223#_saradc_ch2=650....dtb 617 * 618 * 2. U-Boot dtsi about adc controller node: 619 * (1) enable "u-boot,dm-pre-reloc;"; 620 * (2) must set status "okay"; 621 */ 622 static int rockchip_read_dtb_by_adc(const char *file_name) 623 { 624 static int cached_v[MAX_ADC_CH_NR]; 625 int offset_ctrl = strlen(KEY_WORDS_ADC_CTRL); 626 int offset_ch = strlen(KEY_WORDS_ADC_CH); 627 int ret, channel, len = 0, found = 0, margin = 30; 628 char *stradc, *strch, *p; 629 char adc_v_string[10]; 630 char dev_name[32]; 631 uint32_t raw_adc; 632 ulong dtb_adc; 633 634 debug("%s: %s\n", __func__, file_name); 635 636 /* Invalid format ? */ 637 stradc = strstr(file_name, KEY_WORDS_ADC_CTRL); 638 while (stradc) { 639 debug(" - substr: %s\n", stradc); 640 641 /* Parse controller name */ 642 strch = strstr(stradc, KEY_WORDS_ADC_CH); 643 len = strch - (stradc + offset_ctrl); 644 strlcpy(dev_name, stradc + offset_ctrl, len + 1); 645 646 /* Parse adc channel */ 647 p = strch + offset_ch; 648 if (is_digit(*p) && is_equal(*(p + 1))) { 649 channel = *p - '0'; 650 } else { 651 debug(" - invalid format: %s\n", stradc); 652 return -EINVAL; 653 } 654 655 /* 656 * Read raw adc value 657 * 658 * It doesn't need to read adc value every loop, reading once 659 * is enough. We use cached_v[] to save what we have read, zero 660 * means not read before. 661 */ 662 if (cached_v[channel] == 0) { 663 ret = adc_channel_single_shot(dev_name, 664 channel, &raw_adc); 665 if (ret) { 666 debug(" - failed to read adc, ret=%d\n", ret); 667 return ret; 668 } 669 cached_v[channel] = raw_adc; 670 } 671 672 /* Parse dtb adc value */ 673 p = strch + offset_ch + 2; /* 2: channel and '=' */ 674 while (*p && is_digit(*p)) { 675 len++; 676 p++; 677 } 678 strlcpy(adc_v_string, strch + offset_ch + 2, len + 1); 679 dtb_adc = simple_strtoul(adc_v_string, NULL, 10); 680 681 if (abs(dtb_adc - cached_v[channel]) <= margin) { 682 found = 1; 683 stradc = strstr(p, KEY_WORDS_ADC_CTRL); 684 } else { 685 found = 0; 686 break; 687 } 688 689 debug(" - parse: controller=%s, channel=%d, dtb_adc=%ld, read=%d %s\n", 690 dev_name, channel, dtb_adc, cached_v[channel], found ? "(Y)" : ""); 691 } 692 693 return found ? 0 : -ENOENT; 694 } 695 696 static int gpio_parse_base_address(fdt_addr_t *gpio_base_addr) 697 { 698 static int initialized; 699 ofnode parent, node; 700 const char *name; 701 int idx, nr = 0; 702 703 if (initialized) 704 return 0; 705 706 parent = ofnode_path("/pinctrl"); 707 if (!ofnode_valid(parent)) { 708 debug(" - Can't find pinctrl node\n"); 709 return -EINVAL; 710 } 711 712 ofnode_for_each_subnode(node, parent) { 713 if (!ofnode_get_property(node, "gpio-controller", NULL)) { 714 debug(" - Can't find gpio-controller\n"); 715 continue; 716 } 717 718 name = ofnode_get_name(node); 719 if (!is_digit((char)*(name + 4))) { 720 debug(" - bad gpio node name: %s\n", name); 721 continue; 722 } 723 724 nr++; 725 idx = *(name + 4) - '0'; 726 gpio_base_addr[idx] = ofnode_get_addr(node); 727 debug(" - gpio%d: 0x%x\n", idx, (uint32_t)gpio_base_addr[idx]); 728 } 729 730 if (nr == 0) { 731 debug(" - parse gpio address failed\n"); 732 return -EINVAL; 733 } 734 735 initialized = 1; 736 737 return 0; 738 } 739 740 /* 741 * How to make it works ? 742 * 743 * 1. pack dtb into rockchip resource.img, require: 744 * (1) file name end with ".dtb"; 745 * (2) file name contains key words, like: ...#gpio[pin]=[value]...dtb 746 * @pin: gpio name, eg. 0a2 means GPIO0A2; 747 * @value: gpio level, 0 or 1; 748 * eg: ...#gpio0a6=1#gpio1c2=0....dtb 749 * 750 * 2. U-Boot dtsi about gpio node: 751 * (1) enable "u-boot,dm-pre-reloc;" for all gpio node; 752 * (2) set all gpio status "disabled"(Because we just want their property); 753 */ 754 static int rockchip_read_dtb_by_gpio(const char *file_name) 755 { 756 static uint32_t cached_v[MAX_GPIO_NR]; 757 fdt_addr_t gpio_base_addr[MAX_GPIO_NR]; 758 int ret, found = 0, offset = strlen(KEY_WORDS_GPIO); 759 uint8_t port, pin, bank, lvl, val; 760 char *strgpio, *p; 761 uint32_t bit; 762 763 debug("%s\n", file_name); 764 765 /* Parse gpio address */ 766 memset(gpio_base_addr, 0, sizeof(gpio_base_addr)); 767 ret = gpio_parse_base_address(gpio_base_addr); 768 if (ret) { 769 debug(" - Can't parse gpio base address: %d\n", ret); 770 return ret; 771 } 772 773 strgpio = strstr(file_name, KEY_WORDS_GPIO); 774 while (strgpio) { 775 debug(" - substr: %s\n", strgpio); 776 777 p = strgpio + offset; 778 779 /* Invalid format ? */ 780 if (!(is_digit(*(p + 0)) && is_abcd(*(p + 1)) && 781 is_digit(*(p + 2)) && is_equal(*(p + 3)) && 782 is_digit(*(p + 4)))) { 783 debug(" - invalid format: %s\n", strgpio); 784 return -EINVAL; 785 } 786 787 /* Read gpio value */ 788 port = *(p + 0) - '0'; 789 bank = *(p + 1) - 'a'; 790 pin = *(p + 2) - '0'; 791 lvl = *(p + 4) - '0'; 792 793 /* 794 * It doesn't need to read gpio value every loop, reading once 795 * is enough. We use cached_v[] to save what we have read, zero 796 * means not read before. 797 */ 798 if (cached_v[port] == 0) { 799 if (!gpio_base_addr[port]) { 800 debug(" - can't find gpio%d base address\n", port); 801 return 0; 802 } 803 804 /* Input mode */ 805 val = readl(gpio_base_addr[port] + GPIO_SWPORT_DDR); 806 val &= ~(1 << (bank * 8 + pin)); 807 writel(val, gpio_base_addr[port] + GPIO_SWPORT_DDR); 808 809 cached_v[port] = 810 readl(gpio_base_addr[port] + GPIO_EXT_PORT); 811 } 812 813 /* Verify result */ 814 bit = bank * 8 + pin; 815 val = cached_v[port] & (1 << bit) ? 1 : 0; 816 817 if (val == !!lvl) { 818 found = 1; 819 strgpio = strstr(p, KEY_WORDS_GPIO); 820 } else { 821 found = 0; 822 break; 823 } 824 825 debug(" - parse: gpio%d%c%d=%d, read=%d %s\n", 826 port, bank + 'a', pin, lvl, val, found ? "(Y)" : "(N)"); 827 } 828 829 return found ? 0 : -ENOENT; 830 } 831 832 /* Get according to hardware id(GPIO/ADC) */ 833 static struct resource_file *rockchip_read_hwid_dtb(void) 834 { 835 struct resource_file *file; 836 struct list_head *node; 837 838 /* Find dtb file according to hardware id(GPIO/ADC) */ 839 list_for_each(node, &entrys_head) { 840 file = list_entry(node, struct resource_file, link); 841 if (!strstr(file->name, ".dtb")) 842 continue; 843 844 if (strstr(file->name, KEY_WORDS_ADC_CTRL) && 845 strstr(file->name, KEY_WORDS_ADC_CH) && 846 !rockchip_read_dtb_by_adc(file->name)) { 847 return file; 848 } else if (strstr(file->name, KEY_WORDS_GPIO) && 849 !rockchip_read_dtb_by_gpio(file->name)) { 850 return file; 851 } 852 } 853 854 return NULL; 855 } 856 #endif 857 858 #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB 859 static int rockchip_read_distro_dtb(void *fdt_addr) 860 { 861 const char *cmd = "part list ${devtype} ${devnum} -bootable devplist"; 862 char *devnum, *devtype, *devplist; 863 char devnum_part[12]; 864 char fdt_hex_str[19]; 865 char *fs_argv[5]; 866 int size; 867 int ret; 868 869 if (!rockchip_get_bootdev() || !fdt_addr) 870 return -ENODEV; 871 872 ret = run_command_list(cmd, -1, 0); 873 if (ret) 874 return ret; 875 876 devplist = env_get("devplist"); 877 if (!devplist) 878 return -ENODEV; 879 880 devtype = env_get("devtype"); 881 devnum = env_get("devnum"); 882 sprintf(devnum_part, "%s:%s", devnum, devplist); 883 sprintf(fdt_hex_str, "0x%lx", (ulong)fdt_addr); 884 885 #ifdef CONFIG_CMD_FS_GENERIC 886 fs_argv[0] = "load"; 887 fs_argv[1] = devtype, 888 fs_argv[2] = devnum_part; 889 fs_argv[3] = fdt_hex_str; 890 fs_argv[4] = CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH; 891 892 if (do_load(NULL, 0, 5, fs_argv, FS_TYPE_ANY)) 893 return -EIO; 894 #endif 895 if (fdt_check_header(fdt_addr)) 896 return -EIO; 897 898 size = fdt_totalsize(fdt_addr); 899 if (!sysmem_alloc_base(MEMBLK_ID_FDT, (phys_addr_t)fdt_addr, 900 ALIGN(size, RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD)) 901 return -ENOMEM; 902 903 printf("Distro DTB: %s\n", CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH); 904 905 return size; 906 } 907 #endif 908 909 #ifdef CONFIG_ROCKCHIP_DTB_VERIFY 910 #ifdef CONFIG_DM_CRYPTO 911 static int crypto_csum(u32 cap, char *input, u32 input_len, u8 *output) 912 { 913 sha_context csha_ctx; 914 struct udevice *dev; 915 916 dev = crypto_get_device(cap); 917 if (!dev) { 918 printf("Can't find expected crypto device\n"); 919 return -ENODEV; 920 } 921 922 csha_ctx.algo = cap; 923 csha_ctx.length = input_len; 924 crypto_sha_csum(dev, &csha_ctx, (char *)input, 925 input_len, output); 926 927 return 0; 928 } 929 930 static int fdt_check_hash(void *fdt_addr, struct resource_file *file) 931 { 932 uchar hash[32]; 933 934 if (!file->hash_size) 935 return 0; 936 937 if (file->hash_size == 20) 938 crypto_csum(CRYPTO_SHA1, fdt_addr, file->f_size, hash); 939 else if (file->hash_size == 32) 940 crypto_csum(CRYPTO_SHA256, fdt_addr, file->f_size, hash); 941 else 942 return -EINVAL; 943 944 if (memcmp(hash, file->hash, file->hash_size)) 945 return -EBADF; 946 947 printf("HASH: OK(c)\n"); 948 949 return 0; 950 } 951 952 #else 953 static int fdt_check_hash(void *fdt_addr, struct resource_file *file) 954 { 955 uchar hash[32]; 956 957 if (!file->hash_size) 958 return 0; 959 960 if (file->hash_size == 20) 961 sha1_csum((const uchar *)fdt_addr, file->f_size, hash); 962 else if (file->hash_size == 32) 963 sha256_csum((const uchar *)fdt_addr, file->f_size, hash); 964 else 965 return -EINVAL; 966 967 if (memcmp(hash, file->hash, file->hash_size)) 968 return -EBADF; 969 970 printf("HASH: OK(s)\n"); 971 972 return 0; 973 } 974 #endif 975 #endif /* CONFIG_ROCKCHIP_DTB_VERIFY */ 976 977 int rockchip_read_dtb_file(void *fdt_addr) 978 { 979 struct resource_file *file; 980 char *def_dtb = DTB_FILE; 981 int ret; 982 983 /* search order: "rk-kernel.dtb" -> distro -> hwid */ 984 file = get_file_info(NULL, def_dtb); 985 if (!file) { 986 #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB 987 ret = rockchip_read_distro_dtb(fdt_addr); 988 if (ret > 0) 989 return ret; /* found & load done */ 990 #endif 991 #ifdef CONFIG_ROCKCHIP_HWID_DTB 992 file = rockchip_read_hwid_dtb(); 993 #endif 994 if (!file) 995 return -ENODEV; 996 } 997 998 /* found! */ 999 printf("DTB: %s\n", file->name); 1000 ret = rockchip_read_resource_file(fdt_addr, file->name, 0, 0); 1001 if (ret < 0) 1002 return ret; 1003 1004 if (fdt_check_header(fdt_addr)) { 1005 printf("Get a bad DTB file !\n"); 1006 return -EBADF; 1007 } 1008 1009 /* Note: We only load the DTB from resource.img to verify */ 1010 #ifdef CONFIG_ROCKCHIP_DTB_VERIFY 1011 if (fdt_check_hash(fdt_addr, file)) { 1012 printf("Get a bad hash of DTB !\n"); 1013 return -EBADF; 1014 } 1015 #endif 1016 1017 if (!sysmem_alloc_base(MEMBLK_ID_FDT, (phys_addr_t)fdt_addr, 1018 ALIGN(file->f_size, RK_BLK_SIZE) + 1019 CONFIG_SYS_FDT_PAD)) 1020 return -ENOMEM; 1021 1022 /* Apply DTBO */ 1023 #if defined(CONFIG_CMD_DTIMG) && defined(CONFIG_OF_LIBFDT_OVERLAY) 1024 android_fdt_overlay_apply((void *)fdt_addr); 1025 #endif 1026 1027 return file->f_size; 1028 } 1029