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 <malloc.h> 13 #include <asm/io.h> 14 #include <asm/unaligned.h> 15 #include <dm/ofnode.h> 16 #include <linux/list.h> 17 #include <asm/arch/resource_img.h> 18 19 DECLARE_GLOBAL_DATA_PTR; 20 21 #define PART_RESOURCE "resource" 22 #define RESOURCE_MAGIC "RSCE" 23 #define RESOURCE_MAGIC_SIZE 4 24 #define RESOURCE_VERSION 0 25 #define CONTENT_VERSION 0 26 #define ENTRY_TAG "ENTR" 27 #define ENTRY_TAG_SIZE 4 28 #define MAX_FILE_NAME_LEN 220 29 #define MAX_HASH_LEN 32 30 #define DTB_FILE "rk-kernel.dtb" 31 32 /* 33 * resource image structure 34 * ---------------------------------------------- 35 * | | 36 * | header (1 block) | 37 * | | 38 * ---------------------------------------------| 39 * | | | 40 * | entry0 (1 block) | | 41 * | | | 42 * ------------------------ | 43 * | | | 44 * | entry1 (1 block) | contents (n blocks) | 45 * | | | 46 * ------------------------ | 47 * | ...... | | 48 * ------------------------ | 49 * | | | 50 * | entryn (1 block) | | 51 * | | | 52 * ---------------------------------------------- 53 * | | 54 * | file0 (x blocks) | 55 * | | 56 * ---------------------------------------------- 57 * | | 58 * | file1 (y blocks) | 59 * | | 60 * ---------------------------------------------- 61 * | ...... | 62 * |--------------------------------------------- 63 * | | 64 * | filen (z blocks) | 65 * | | 66 * ---------------------------------------------- 67 */ 68 69 /** 70 * struct resource_image_header 71 * 72 * @magic: should be "RSCE" 73 * @version: resource image version, current is 0 74 * @c_version: content version, current is 0 75 * @blks: the size of the header ( 1 block = 512 bytes) 76 * @c_offset: contents offset(by block) in the image 77 * @e_blks: the size(by block) of the entry in the contents 78 * @e_num: numbers of the entrys. 79 */ 80 81 struct resource_img_hdr { 82 char magic[4]; 83 uint16_t version; 84 uint16_t c_version; 85 uint8_t blks; 86 uint8_t c_offset; 87 uint8_t e_blks; 88 uint32_t e_nums; 89 }; 90 91 struct resource_entry { 92 char tag[4]; 93 char name[MAX_FILE_NAME_LEN]; 94 char hash[MAX_HASH_LEN]; 95 uint32_t hash_size; 96 uint32_t f_offset; /* Sector offset */ 97 uint32_t f_size; /* Bytes */ 98 }; 99 100 struct resource_file { 101 char name[MAX_FILE_NAME_LEN]; 102 char hash[MAX_HASH_LEN]; 103 uint32_t hash_size; 104 uint32_t f_offset; /* Sector offset */ 105 uint32_t f_size; /* Bytes */ 106 struct list_head link; 107 /* Sector base of resource when ram=false, byte base when ram=true */ 108 uint32_t rsce_base; 109 bool ram; 110 }; 111 112 static LIST_HEAD(entrys_head); 113 114 int resource_image_check_header(void *rsce_hdr) 115 { 116 struct resource_img_hdr *hdr = rsce_hdr; 117 int ret; 118 119 ret = memcmp(RESOURCE_MAGIC, hdr->magic, RESOURCE_MAGIC_SIZE); 120 if (ret) { 121 debug("bad resource image magic: %s\n", 122 hdr->magic ? hdr->magic : "none"); 123 ret = -EINVAL; 124 } 125 126 debug("resource image header:\n"); 127 debug("magic:%s\n", hdr->magic); 128 debug("version:%d\n", hdr->version); 129 debug("c_version:%d\n", hdr->c_version); 130 debug("blks:%d\n", hdr->blks); 131 debug("c_offset:%d\n", hdr->c_offset); 132 debug("e_blks:%d\n", hdr->e_blks); 133 debug("e_num:%d\n", hdr->e_nums); 134 135 return ret; 136 } 137 138 static int add_file_to_list(struct resource_entry *entry, 139 int rsce_base, bool ram) 140 { 141 struct resource_file *file; 142 143 if (memcmp(entry->tag, ENTRY_TAG, ENTRY_TAG_SIZE)) { 144 printf("invalid entry tag\n"); 145 return -ENOENT; 146 } 147 148 file = malloc(sizeof(*file)); 149 if (!file) { 150 printf("out of memory\n"); 151 return -ENOMEM; 152 } 153 154 strcpy(file->name, entry->name); 155 file->rsce_base = rsce_base; 156 file->f_offset = entry->f_offset; 157 file->f_size = entry->f_size; 158 file->hash_size = entry->hash_size; 159 file->ram = ram; 160 memcpy(file->hash, entry->hash, entry->hash_size); 161 list_add_tail(&file->link, &entrys_head); 162 163 debug("entry: %p, %18s, base: 0x%08x, offset: 0x%08x, size: 0x%08x\n", 164 entry, file->name, file->rsce_base, file->f_offset, file->f_size); 165 166 return 0; 167 } 168 169 static int replace_resource_entry(const char *f_name, uint32_t base, 170 uint32_t f_offset, uint32_t f_size) 171 { 172 struct resource_entry *entry; 173 struct resource_file *file; 174 struct list_head *node; 175 176 if (!f_name || !f_size) 177 return -EINVAL; 178 179 entry = calloc(1, sizeof(*entry)); 180 if (!entry) 181 return -ENOMEM; 182 183 strcpy(entry->tag, ENTRY_TAG); 184 strcpy(entry->name, f_name); 185 entry->f_offset = f_offset; 186 entry->f_size = f_size; 187 entry->hash_size = 0; 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, false); 200 free(entry); 201 202 return 0; 203 } 204 205 static int read_bmp(struct blk_desc *dev_desc, const char *name, 206 disk_partition_t *part, uint32_t offset, 207 uint32_t *size) 208 { 209 struct bmp_header *header; 210 u32 blk_start, blk_offset; 211 u32 filesz; 212 int ret; 213 214 blk_offset = DIV_ROUND_UP(offset, dev_desc->blksz); 215 blk_start = part->start + blk_offset; 216 header = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz); 217 if (!header) { 218 ret = -ENOMEM; 219 goto out; 220 } 221 222 if (blk_dread(dev_desc, blk_start, 1, header) != 1) { 223 ret = -EIO; 224 goto out; 225 } 226 227 if (header->signature[0] != 'B' || header->signature[1] != 'M') { 228 ret = -EINVAL; 229 goto out; 230 } 231 232 filesz = get_unaligned_le32(&header->file_size); 233 ret = replace_resource_entry(name, blk_start, blk_offset, filesz); 234 if (!ret) { 235 printf("LOGO: %s\n", name); 236 if (size) 237 *size = filesz; 238 } 239 out: 240 free(header); 241 242 return ret; 243 } 244 245 /* 246 * Add logo.bmp and logo_kernel.bmp from "logo" parititon 247 * 248 * Provide a "logo" partition for user to store logo.bmp and 249 * logo_kernel.bmp, so that the user can update them from 250 * kernel or user-space dynamically. 251 * 252 * "logo" partition layout, do not change order: 253 * 254 * |----------------------| 0x00 255 * | raw logo.bmp | 256 * |----------------------| N*512-byte aligned 257 * | raw logo_kernel.bmp | 258 * |----------------------| 259 * 260 * N: the sector count of logo.bmp 261 */ 262 static int read_logo_bmps(struct blk_desc *dev_desc) 263 { 264 disk_partition_t part; 265 u32 filesz; 266 267 if (part_get_info_by_name(dev_desc, PART_LOGO, &part) < 0) 268 return -ENODEV; 269 270 if (!read_bmp(dev_desc, "logo.bmp", &part, 0, &filesz)) 271 read_bmp(dev_desc, "logo_kernel.bmp", &part, filesz, NULL); 272 273 return 0; 274 } 275 276 int resource_create_ram_list(struct blk_desc *dev_desc, void *rsce_hdr) 277 { 278 struct resource_img_hdr *hdr = rsce_hdr; 279 struct resource_entry *entry; 280 int e_num, size; 281 void *data; 282 int ret = 0; 283 284 if (resource_image_check_header(hdr)) { 285 ret = -EINVAL; 286 goto out; 287 } 288 289 data = (void *)((ulong)hdr + 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 *)(data + size); 293 add_file_to_list(entry, (ulong)hdr, true); 294 } 295 out: 296 read_logo_bmps(dev_desc); 297 298 return ret; 299 } 300 301 static int resource_create_list(struct blk_desc *dev_desc, int rsce_base) 302 { 303 struct resource_img_hdr *hdr; 304 struct resource_entry *entry; 305 int blknum, e_num; 306 void *data = NULL; 307 int ret = 0; 308 int size; 309 310 hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz); 311 if (!hdr) 312 return -ENOMEM; 313 314 if (blk_dread(dev_desc, rsce_base, 1, hdr) != 1) { 315 printf("Failed to read resource hdr\n"); 316 ret = -EIO; 317 goto err; 318 } 319 320 if (resource_image_check_header(hdr)) { 321 if (fdt_check_header(hdr)) { 322 printf("No valid resource or dtb file\n"); 323 ret = -EINVAL; 324 goto err; 325 } else { 326 free(hdr); 327 return replace_resource_entry(DTB_FILE, rsce_base, 328 0, fdt_totalsize(hdr)); 329 } 330 } 331 332 blknum = hdr->e_blks * hdr->e_nums; 333 data = memalign(ARCH_DMA_MINALIGN, blknum * dev_desc->blksz); 334 if (!data) { 335 ret = -ENOMEM; 336 goto err; 337 } 338 339 if (blk_dread(dev_desc, rsce_base + hdr->c_offset, 340 blknum, data) != blknum) { 341 printf("Failed to read resource entries\n"); 342 ret = -EIO; 343 goto err; 344 } 345 346 /* 347 * Add all file into resource file list, and load what we want from 348 * storage when we really need it. 349 */ 350 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 351 size = e_num * hdr->e_blks * dev_desc->blksz; 352 entry = (struct resource_entry *)(data + size); 353 add_file_to_list(entry, rsce_base, false); 354 } 355 356 err: 357 if (data) 358 free(data); 359 if (hdr) 360 free(hdr); 361 362 read_logo_bmps(dev_desc); 363 364 return ret; 365 } 366 367 static int read_dtb_from_android(struct blk_desc *dev_desc, 368 struct andr_img_hdr *hdr, 369 ulong rsce_base) 370 { 371 ulong dtb_offset = 0; 372 ulong dtb_size = 0; 373 374 if (!hdr || hdr->header_version <= 1) { 375 return 0; 376 } else if (hdr->header_version == 2) { 377 dtb_offset += hdr->page_size; 378 dtb_offset += ALIGN(hdr->kernel_size, hdr->page_size); 379 dtb_offset += ALIGN(hdr->ramdisk_size, hdr->page_size); 380 dtb_offset += ALIGN(hdr->recovery_dtbo_size, hdr->page_size) + 381 ALIGN(hdr->second_size, hdr->page_size); 382 dtb_size = hdr->dtb_size; 383 } else if (hdr->header_version == 3) { 384 dtb_offset += ALIGN(VENDOR_BOOT_HDR_SIZE, 385 hdr->vendor_page_size) + 386 ALIGN(hdr->vendor_ramdisk_size, 387 hdr->vendor_page_size); 388 dtb_size = hdr->dtb_size; 389 } 390 391 if (!dtb_size) 392 return 0; 393 394 /* 395 * boot_img_hdr_v2,3 feature. 396 * 397 * If dtb position is present, replace the old with new one if 398 * we don't need to verify DTB hash from resource.img file entry. 399 */ 400 dtb_offset = DIV_ROUND_UP(dtb_offset, dev_desc->blksz); 401 #ifndef CONFIG_ROCKCHIP_DTB_VERIFY 402 if (replace_resource_entry(DTB_FILE, rsce_base, dtb_offset, dtb_size)) 403 printf("Failed to load dtb from v2 dtb position\n"); 404 else 405 #endif 406 env_update("bootargs", "androidboot.dtb_idx=0"); 407 408 return 0; 409 } 410 411 static int get_resource_base_sector(struct blk_desc *dev_desc, 412 struct andr_img_hdr **ret_hdr) 413 { 414 disk_partition_t part; 415 int rsce_base = 0; 416 #ifdef CONFIG_ANDROID_BOOT_IMAGE 417 struct andr_img_hdr *hdr; 418 u32 os_ver = 0, os_lvl; 419 420 /* 421 * Anyway, we must read android hdr firstly from boot partition to get 422 * the 'os_version' for android_bcb_msg_sector_offset(), in order to 423 * confirm BCB message offset of *MISC* partition. 424 */ 425 if (part_get_info_by_name(dev_desc, PART_BOOT, &part) < 0) 426 goto resource_part; 427 428 hdr = populate_andr_img_hdr(dev_desc, &part); 429 if (hdr) { 430 os_ver = hdr->os_version >> 11; 431 os_lvl = hdr->os_version & ((1U << 11) - 1); 432 if (os_ver) 433 gd->bd->bi_andr_version = hdr->os_version; 434 } 435 436 #ifndef CONFIG_ANDROID_AB 437 /* Get boot mode from misc and read if recovery mode */ 438 if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) { 439 if (hdr) 440 free(hdr); 441 442 if (part_get_info_by_name(dev_desc, PART_RECOVERY, &part) < 0) 443 goto resource_part; 444 445 hdr = populate_andr_img_hdr(dev_desc, &part); 446 if (!hdr) 447 goto resource_part; 448 } 449 #endif 450 /* If Android v012, getting resource from second position ! */ 451 if (hdr) { 452 if (os_ver) 453 printf("Android %u.%u, Build %u.%u, v%d\n", 454 (os_ver >> 14) & 0x7F, (os_ver >> 7) & 0x7F, 455 (os_lvl >> 4) + 2000, os_lvl & 0x0F, 456 hdr->header_version); 457 *ret_hdr = hdr; 458 if (hdr->header_version < 3) { 459 rsce_base = part.start * dev_desc->blksz; 460 rsce_base += hdr->page_size; 461 rsce_base += ALIGN(hdr->kernel_size, hdr->page_size); 462 rsce_base += ALIGN(hdr->ramdisk_size, hdr->page_size); 463 rsce_base = DIV_ROUND_UP(rsce_base, dev_desc->blksz); 464 goto finish; 465 } 466 } 467 resource_part: 468 #endif 469 /* resource partition */ 470 if (part_get_info_by_name(dev_desc, PART_RESOURCE, &part) < 0) { 471 printf("No resource partition\n"); 472 return -ENODEV; 473 } else { 474 rsce_base = part.start; 475 } 476 #ifdef CONFIG_ANDROID_BOOT_IMAGE 477 finish: 478 #endif 479 printf("Found DTB in %s part\n", part.name); 480 481 return rsce_base; 482 } 483 484 /* 485 * There are: logo/battery pictures and dtb file in the resource image by default. 486 * 487 * This function does: 488 * 489 * 1. Get resource image base sector from: boot/recovery(AOSP) > resource(RK) 490 * 2. Create resource files list(addition: add logo bmps) 491 * 3. Add dtb from android v2 dtb pos, override the old one from resource file 492 */ 493 static int init_resource_list(void) 494 { 495 struct andr_img_hdr *hdr = NULL; 496 struct blk_desc *dev_desc; 497 int rsce_base; 498 499 dev_desc = rockchip_get_bootdev(); 500 if (!dev_desc) { 501 printf("No dev_desc!\n"); 502 return -ENODEV; 503 } 504 505 rsce_base = get_resource_base_sector(dev_desc, &hdr); 506 if (rsce_base > 0) { 507 if (resource_create_list(dev_desc, rsce_base)) 508 printf("Failed to create resource list\n"); 509 } 510 511 /* override the resource dtb with android dtb if need */ 512 return read_dtb_from_android(dev_desc, hdr, rsce_base); 513 } 514 515 static struct resource_file *get_file_info(const char *name) 516 { 517 struct resource_file *file; 518 struct list_head *node; 519 520 if (list_empty(&entrys_head)) { 521 if (init_resource_list()) 522 return NULL; 523 } 524 525 list_for_each(node, &entrys_head) { 526 file = list_entry(node, struct resource_file, link); 527 if (!strcmp(file->name, name)) 528 return file; 529 } 530 531 return NULL; 532 } 533 534 /* 535 * read file from resource partition 536 * @buf: destination buf to store file data; 537 * @name: file name 538 * @offset: blocks offset in the file, 1 block = 512 bytes 539 * @len: the size(by bytes) of file to read. 540 */ 541 int rockchip_read_resource_file(void *buf, const char *name, 542 int offset, int len) 543 { 544 struct resource_file *file; 545 struct blk_desc *dev_desc; 546 int ret = 0; 547 int blks; 548 ulong src; 549 550 file = get_file_info(name); 551 if (!file) { 552 printf("No file: %s\n", name); 553 return -ENOENT; 554 } 555 556 dev_desc = rockchip_get_bootdev(); 557 if (!dev_desc) { 558 printf("No dev_desc!\n"); 559 return -ENODEV; 560 } 561 562 if (len <= 0 || len > file->f_size) 563 len = file->f_size; 564 565 if (file->ram) { 566 src = file->rsce_base + 567 (file->f_offset + offset) * dev_desc->blksz; 568 memcpy(buf, (char *)src, len); 569 ret = len; 570 } else { 571 blks = DIV_ROUND_UP(len, dev_desc->blksz); 572 ret = blk_dread(dev_desc, 573 file->rsce_base + file->f_offset + offset, 574 blks, buf); 575 ret = (ret != blks) ? -EIO : len; 576 } 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 if (list_empty(&entrys_head)) { 826 if (init_resource_list()) 827 return NULL; 828 } 829 830 /* Find dtb file according to hardware id(GPIO/ADC) */ 831 list_for_each(node, &entrys_head) { 832 file = list_entry(node, struct resource_file, link); 833 if (!strstr(file->name, ".dtb")) 834 continue; 835 836 if (strstr(file->name, KEY_WORDS_ADC_CTRL) && 837 strstr(file->name, KEY_WORDS_ADC_CH) && 838 !rockchip_read_dtb_by_adc(file->name)) { 839 return file; 840 } else if (strstr(file->name, KEY_WORDS_GPIO) && 841 !rockchip_read_dtb_by_gpio(file->name)) { 842 return file; 843 } 844 } 845 846 return NULL; 847 } 848 #endif 849 850 int rockchip_read_resource_dtb(void *fdt_addr, char **hash, int *hash_size) 851 { 852 struct resource_file *file; 853 int ret; 854 855 #ifdef CONFIG_ROCKCHIP_HWID_DTB 856 file = rockchip_read_hwid_dtb(); 857 /* If dtbs matched hardware id(GPIO/ADC) not found, try the default */ 858 if (!file) 859 file = get_file_info(DTB_FILE); 860 #else 861 file = get_file_info(DTB_FILE); 862 #endif 863 if (!file) 864 return -ENODEV; 865 866 ret = rockchip_read_resource_file(fdt_addr, file->name, 0, 0); 867 if (ret < 0) 868 return ret; 869 870 if (fdt_check_header(fdt_addr)) 871 return -EBADF; 872 873 *hash = file->hash; 874 *hash_size = file->hash_size; 875 printf("DTB: %s\n", file->name); 876 877 return 0; 878 } 879