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