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