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; 97 uint32_t f_size; 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 188 /* Delete exist entry, then add this new */ 189 list_for_each(node, &entrys_head) { 190 file = list_entry(node, struct resource_file, link); 191 if (!strcmp(file->name, entry->name)) { 192 list_del(&file->link); 193 free(file); 194 break; 195 } 196 } 197 198 add_file_to_list(entry, base, false); 199 free(entry); 200 201 return 0; 202 } 203 204 static int read_bmp(struct blk_desc *dev_desc, const char *name, 205 disk_partition_t *part, uint32_t offset, 206 uint32_t *size) 207 { 208 struct bmp_header *header; 209 u32 blk_start, blk_offset; 210 u32 filesz; 211 int ret; 212 213 blk_offset = DIV_ROUND_UP(offset, dev_desc->blksz); 214 blk_start = part->start + blk_offset; 215 header = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz); 216 if (!header) { 217 ret = -ENOMEM; 218 goto out; 219 } 220 221 if (blk_dread(dev_desc, blk_start, 1, header) != 1) { 222 ret = -EIO; 223 goto out; 224 } 225 226 if (header->signature[0] != 'B' || header->signature[1] != 'M') { 227 ret = -EINVAL; 228 goto out; 229 } 230 231 filesz = get_unaligned_le32(&header->file_size); 232 ret = replace_resource_entry(name, blk_start, blk_offset, filesz); 233 if (!ret) { 234 printf("LOGO: %s\n", name); 235 if (size) 236 *size = filesz; 237 } 238 out: 239 free(header); 240 241 return ret; 242 } 243 244 /* 245 * Add logo.bmp and logo_kernel.bmp from "logo" parititon 246 * 247 * Provide a "logo" partition for user to store logo.bmp and 248 * logo_kernel.bmp, so that the user can update them from 249 * kernel or user-space dynamically. 250 * 251 * "logo" partition layout, do not change order: 252 * 253 * |----------------------| 0x00 254 * | raw logo.bmp | 255 * |----------------------| N*512-byte aligned 256 * | raw logo_kernel.bmp | 257 * |----------------------| 258 * 259 * N: the sector count of logo.bmp 260 */ 261 static int read_logo_bmps(struct blk_desc *dev_desc) 262 { 263 disk_partition_t part; 264 u32 filesz; 265 266 if (part_get_info_by_name(dev_desc, PART_LOGO, &part) < 0) 267 return -ENODEV; 268 269 if (!read_bmp(dev_desc, "logo.bmp", &part, 0, &filesz)) 270 read_bmp(dev_desc, "logo_kernel.bmp", &part, filesz, NULL); 271 272 return 0; 273 } 274 275 static int read_dtb_from_android_v2(int rsce_base, int dtb_offset, int dtb_size) 276 { 277 if (!dtb_size) 278 return 0; 279 280 /* 281 * boot_img_hdr_v2 feature. 282 * 283 * If dtb position is present, replace the old with new one if 284 * we don't need to verify DTB hash from resource.img file entry. 285 */ 286 #ifndef CONFIG_ROCKCHIP_DTB_VERIFY 287 if (replace_resource_entry(DTB_FILE, rsce_base, dtb_offset, dtb_size)) 288 printf("Failed to load dtb from v2 dtb position\n"); 289 else 290 #endif 291 env_update("bootargs", "androidboot.dtb_idx=0"); 292 293 return 0; 294 } 295 296 int resource_create_ram_list(struct blk_desc *dev_desc, void *rsce_hdr) 297 { 298 struct resource_img_hdr *hdr = rsce_hdr; 299 struct resource_entry *entry; 300 int e_num, size; 301 void *data; 302 int ret = 0; 303 304 if (resource_image_check_header(hdr)) { 305 ret = -EINVAL; 306 goto out; 307 } 308 309 data = (void *)((ulong)hdr + hdr->c_offset * dev_desc->blksz); 310 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 311 size = e_num * hdr->e_blks * dev_desc->blksz; 312 entry = (struct resource_entry *)(data + size); 313 add_file_to_list(entry, (ulong)hdr, true); 314 } 315 out: 316 read_logo_bmps(dev_desc); 317 318 return ret; 319 } 320 321 static int resource_create_list(struct blk_desc *dev_desc, int rsce_base) 322 { 323 struct resource_img_hdr *hdr; 324 struct resource_entry *entry; 325 int blknum, e_num; 326 void *data = NULL; 327 int ret = 0; 328 int size; 329 330 hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz); 331 if (!hdr) 332 return -ENOMEM; 333 334 if (blk_dread(dev_desc, rsce_base, 1, hdr) != 1) { 335 printf("Failed to read resource hdr\n"); 336 ret = -EIO; 337 goto err; 338 } 339 340 if (resource_image_check_header(hdr)) { 341 if (fdt_check_header(hdr)) { 342 printf("No valid resource or dtb file\n"); 343 ret = -EINVAL; 344 goto err; 345 } else { 346 free(hdr); 347 return replace_resource_entry(DTB_FILE, rsce_base, 348 0, fdt_totalsize(hdr)); 349 } 350 } 351 352 blknum = hdr->e_blks * hdr->e_nums; 353 data = memalign(ARCH_DMA_MINALIGN, blknum * dev_desc->blksz); 354 if (!data) { 355 ret = -ENOMEM; 356 goto err; 357 } 358 359 if (blk_dread(dev_desc, rsce_base + hdr->c_offset, 360 blknum, data) != blknum) { 361 printf("Failed to read resource entries\n"); 362 ret = -EIO; 363 goto err; 364 } 365 366 /* 367 * Add all file into resource file list, and load what we want from 368 * storage when we really need it. 369 */ 370 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 371 size = e_num * hdr->e_blks * dev_desc->blksz; 372 entry = (struct resource_entry *)(data + size); 373 add_file_to_list(entry, rsce_base, false); 374 } 375 376 err: 377 if (data) 378 free(data); 379 if (hdr) 380 free(hdr); 381 382 read_logo_bmps(dev_desc); 383 384 return ret; 385 } 386 387 static int get_resource_base_sector(struct blk_desc *dev_desc, 388 disk_partition_t *from_part, 389 int *dtb_off, int *dtb_size) 390 { 391 disk_partition_t part; 392 int rsce_base; 393 #ifdef CONFIG_ANDROID_BOOT_IMAGE 394 struct andr_img_hdr *hdr; 395 int blknum; 396 397 /* 398 * Anyway, we must read android hdr firstly from boot partition to get 399 * the 'os_version' for android_bcb_msg_sector_offset(), in order to 400 * confirm BCB message offset of misc partition. 401 */ 402 if (part_get_info_by_name(dev_desc, PART_BOOT, &part) < 0) 403 goto resource_part; 404 405 blknum = DIV_ROUND_UP(sizeof(*hdr), dev_desc->blksz); 406 hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz * blknum); 407 if (!hdr) 408 return -ENOMEM; 409 410 if (blk_dread(dev_desc, part.start, blknum, hdr) != blknum) { 411 printf("Failed to read %s hdr\n", part.name); 412 free(hdr); 413 return -EIO; 414 } 415 416 if (!android_image_check_header(hdr)) { 417 u32 os_ver, os_lvl; 418 419 os_ver = hdr->os_version >> 11; 420 os_lvl = hdr->os_version & ((1U << 11) - 1); 421 if (os_ver) { 422 gd->bd->bi_andr_version = hdr->os_version; 423 printf("Android %u.%u, Build %u.%u\n", 424 (os_ver >> 14) & 0x7F, (os_ver >> 7) & 0x7F, 425 (os_lvl >> 4) + 2000, os_lvl & 0x0F); 426 } 427 } 428 429 #ifndef CONFIG_ANDROID_AB 430 /* Get boot mode from misc and read if recovery mode */ 431 if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) { 432 if (part_get_info_by_name(dev_desc, PART_RECOVERY, &part) < 0) 433 goto resource_part; 434 435 if (blk_dread(dev_desc, part.start, blknum, hdr) != blknum) { 436 printf("Failed to read %s hdr\n", part.name); 437 free(hdr); 438 return -EIO; 439 } 440 } 441 #endif 442 /* get ! */ 443 if (!android_image_check_header(hdr)) { 444 rsce_base = part.start * dev_desc->blksz; 445 rsce_base += hdr->page_size; 446 rsce_base += ALIGN(hdr->kernel_size, hdr->page_size); 447 rsce_base += ALIGN(hdr->ramdisk_size, hdr->page_size); 448 449 if (hdr->header_version >= 2) { 450 *dtb_size = hdr->dtb_size; 451 *dtb_off = 452 rsce_base + 453 ALIGN(hdr->recovery_dtbo_size, hdr->page_size) + 454 ALIGN(hdr->second_size, hdr->page_size); 455 } 456 457 rsce_base = DIV_ROUND_UP(rsce_base, dev_desc->blksz); 458 *dtb_off = DIV_ROUND_UP(*dtb_off, dev_desc->blksz) - rsce_base; 459 *from_part = part; 460 free(hdr); 461 goto finish; 462 } 463 resource_part: 464 #endif 465 /* resource partition */ 466 if (part_get_info_by_name(dev_desc, PART_RESOURCE, &part) < 0) { 467 printf("No resource partition\n"); 468 return -ENODEV; 469 } 470 471 *from_part = part; 472 rsce_base = part.start; 473 #ifdef CONFIG_ANDROID_BOOT_IMAGE 474 finish: 475 #endif 476 printf("Found DTB in %s part\n", part.name); 477 478 return rsce_base; 479 } 480 481 /* 482 * There are: logo/battery pictures and dtb file in the resource image by default. 483 * 484 * This function does: 485 * 486 * 1. Get resource image base sector from: boot/recovery(AOSP) > resource(RK) 487 * 2. Create resource files list(addition: add logo bmps) 488 * 3. Add dtb from android v2 dtb pos, override the old one from resource file 489 */ 490 static int init_resource_list(void) 491 { 492 struct blk_desc *dev_desc; 493 disk_partition_t part; 494 int rsce_base; 495 int dtb_offset; 496 int dtb_size = 0; 497 498 dev_desc = rockchip_get_bootdev(); 499 if (!dev_desc) { 500 printf("No dev_desc!\n"); 501 return -ENODEV; 502 } 503 504 rsce_base = get_resource_base_sector(dev_desc, &part, 505 &dtb_offset, &dtb_size); 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 old one if dtb_size != 0 */ 512 read_dtb_from_android_v2(rsce_base, dtb_offset, dtb_size); 513 514 return 0; 515 } 516 517 static struct resource_file *get_file_info(const char *name) 518 { 519 struct resource_file *file; 520 struct list_head *node; 521 522 if (list_empty(&entrys_head)) { 523 if (init_resource_list()) 524 return NULL; 525 } 526 527 list_for_each(node, &entrys_head) { 528 file = list_entry(node, struct resource_file, link); 529 if (!strcmp(file->name, name)) 530 return file; 531 } 532 533 return NULL; 534 } 535 536 /* 537 * read file from resource partition 538 * @buf: destination buf to store file data; 539 * @name: file name 540 * @offset: blocks offset in the file, 1 block = 512 bytes 541 * @len: the size(by bytes) of file to read. 542 */ 543 int rockchip_read_resource_file(void *buf, const char *name, 544 int offset, int len) 545 { 546 struct resource_file *file; 547 struct blk_desc *dev_desc; 548 int ret = 0; 549 int blks; 550 ulong src; 551 552 file = get_file_info(name); 553 if (!file) { 554 printf("No file: %s\n", name); 555 return -ENOENT; 556 } 557 558 dev_desc = rockchip_get_bootdev(); 559 if (!dev_desc) { 560 printf("No dev_desc!\n"); 561 return -ENODEV; 562 } 563 564 if (len <= 0 || len > file->f_size) 565 len = file->f_size; 566 567 if (file->ram) { 568 src = file->rsce_base + 569 (file->f_offset + offset) * dev_desc->blksz; 570 memcpy(buf, (char *)src, len); 571 ret = len; 572 } else { 573 blks = DIV_ROUND_UP(len, dev_desc->blksz); 574 ret = blk_dread(dev_desc, 575 file->rsce_base + file->f_offset + offset, 576 blks, buf); 577 ret = (ret != blks) ? -EIO : len; 578 } 579 580 return ret; 581 } 582 583 #ifdef CONFIG_ROCKCHIP_HWID_DTB 584 #define is_digit(c) ((c) >= '0' && (c) <= '9') 585 #define is_abcd(c) ((c) >= 'a' && (c) <= 'd') 586 #define is_equal(c) ((c) == '=') 587 588 #define KEY_WORDS_ADC_CTRL "#_" 589 #define KEY_WORDS_ADC_CH "_ch" 590 #define KEY_WORDS_GPIO "#gpio" 591 #define GPIO_SWPORT_DDR 0x04 592 #define GPIO_EXT_PORT 0x50 593 #define MAX_ADC_CH_NR 10 594 #define MAX_GPIO_NR 10 595 596 /* 597 * How to make it works ? 598 * 599 * 1. pack dtb into rockchip resource.img, require: 600 * (1) file name end with ".dtb"; 601 * (2) file name contains key words, like: ...#_[controller]_ch[channel]=[value]...dtb 602 * @controller: adc controller name in dts, eg. "saradc", ...; 603 * @channel: adc channel; 604 * @value: adc value; 605 * eg: ...#_saradc_ch1=223#_saradc_ch2=650....dtb 606 * 607 * 2. U-Boot dtsi about adc controller node: 608 * (1) enable "u-boot,dm-pre-reloc;"; 609 * (2) must set status "okay"; 610 */ 611 static int rockchip_read_dtb_by_adc(const char *file_name) 612 { 613 static int cached_v[MAX_ADC_CH_NR]; 614 int offset_ctrl = strlen(KEY_WORDS_ADC_CTRL); 615 int offset_ch = strlen(KEY_WORDS_ADC_CH); 616 int ret, channel, len = 0, found = 0, margin = 30; 617 char *stradc, *strch, *p; 618 char adc_v_string[10]; 619 char dev_name[32]; 620 uint32_t raw_adc; 621 ulong dtb_adc; 622 623 debug("%s: %s\n", __func__, file_name); 624 625 /* Invalid format ? */ 626 stradc = strstr(file_name, KEY_WORDS_ADC_CTRL); 627 while (stradc) { 628 debug(" - substr: %s\n", stradc); 629 630 /* Parse controller name */ 631 strch = strstr(stradc, KEY_WORDS_ADC_CH); 632 len = strch - (stradc + offset_ctrl); 633 strlcpy(dev_name, stradc + offset_ctrl, len + 1); 634 635 /* Parse adc channel */ 636 p = strch + offset_ch; 637 if (is_digit(*p) && is_equal(*(p + 1))) { 638 channel = *p - '0'; 639 } else { 640 debug(" - invalid format: %s\n", stradc); 641 return -EINVAL; 642 } 643 644 /* 645 * Read raw adc value 646 * 647 * It doesn't need to read adc value every loop, reading once 648 * is enough. We use cached_v[] to save what we have read, zero 649 * means not read before. 650 */ 651 if (cached_v[channel] == 0) { 652 ret = adc_channel_single_shot(dev_name, 653 channel, &raw_adc); 654 if (ret) { 655 debug(" - failed to read adc, ret=%d\n", ret); 656 return ret; 657 } 658 cached_v[channel] = raw_adc; 659 } 660 661 /* Parse dtb adc value */ 662 p = strch + offset_ch + 2; /* 2: channel and '=' */ 663 while (*p && is_digit(*p)) { 664 len++; 665 p++; 666 } 667 strlcpy(adc_v_string, strch + offset_ch + 2, len + 1); 668 dtb_adc = simple_strtoul(adc_v_string, NULL, 10); 669 670 if (abs(dtb_adc - cached_v[channel]) <= margin) { 671 found = 1; 672 stradc = strstr(p, KEY_WORDS_ADC_CTRL); 673 } else { 674 found = 0; 675 break; 676 } 677 678 debug(" - parse: controller=%s, channel=%d, dtb_adc=%ld, read=%d %s\n", 679 dev_name, channel, dtb_adc, cached_v[channel], found ? "(Y)" : ""); 680 } 681 682 return found ? 0 : -ENOENT; 683 } 684 685 static int gpio_parse_base_address(fdt_addr_t *gpio_base_addr) 686 { 687 static int initialized; 688 ofnode parent, node; 689 const char *name; 690 int idx, nr = 0; 691 692 if (initialized) 693 return 0; 694 695 parent = ofnode_path("/pinctrl"); 696 if (!ofnode_valid(parent)) { 697 debug(" - Can't find pinctrl node\n"); 698 return -EINVAL; 699 } 700 701 ofnode_for_each_subnode(node, parent) { 702 if (!ofnode_get_property(node, "gpio-controller", NULL)) { 703 debug(" - Can't find gpio-controller\n"); 704 continue; 705 } 706 707 name = ofnode_get_name(node); 708 if (!is_digit((char)*(name + 4))) { 709 debug(" - bad gpio node name: %s\n", name); 710 continue; 711 } 712 713 nr++; 714 idx = *(name + 4) - '0'; 715 gpio_base_addr[idx] = ofnode_get_addr(node); 716 debug(" - gpio%d: 0x%x\n", idx, (uint32_t)gpio_base_addr[idx]); 717 } 718 719 if (nr == 0) { 720 debug(" - parse gpio address failed\n"); 721 return -EINVAL; 722 } 723 724 initialized = 1; 725 726 return 0; 727 } 728 729 /* 730 * How to make it works ? 731 * 732 * 1. pack dtb into rockchip resource.img, require: 733 * (1) file name end with ".dtb"; 734 * (2) file name contains key words, like: ...#gpio[pin]=[value]...dtb 735 * @pin: gpio name, eg. 0a2 means GPIO0A2; 736 * @value: gpio level, 0 or 1; 737 * eg: ...#gpio0a6=1#gpio1c2=0....dtb 738 * 739 * 2. U-Boot dtsi about gpio node: 740 * (1) enable "u-boot,dm-pre-reloc;" for all gpio node; 741 * (2) set all gpio status "disabled"(Because we just want their property); 742 */ 743 static int rockchip_read_dtb_by_gpio(const char *file_name) 744 { 745 static uint32_t cached_v[MAX_GPIO_NR]; 746 fdt_addr_t gpio_base_addr[MAX_GPIO_NR]; 747 int ret, found = 0, offset = strlen(KEY_WORDS_GPIO); 748 uint8_t port, pin, bank, lvl, val; 749 char *strgpio, *p; 750 uint32_t bit; 751 752 debug("%s\n", file_name); 753 754 /* Parse gpio address */ 755 memset(gpio_base_addr, 0, sizeof(gpio_base_addr)); 756 ret = gpio_parse_base_address(gpio_base_addr); 757 if (ret) { 758 debug(" - Can't parse gpio base address: %d\n", ret); 759 return ret; 760 } 761 762 strgpio = strstr(file_name, KEY_WORDS_GPIO); 763 while (strgpio) { 764 debug(" - substr: %s\n", strgpio); 765 766 p = strgpio + offset; 767 768 /* Invalid format ? */ 769 if (!(is_digit(*(p + 0)) && is_abcd(*(p + 1)) && 770 is_digit(*(p + 2)) && is_equal(*(p + 3)) && 771 is_digit(*(p + 4)))) { 772 debug(" - invalid format: %s\n", strgpio); 773 return -EINVAL; 774 } 775 776 /* Read gpio value */ 777 port = *(p + 0) - '0'; 778 bank = *(p + 1) - 'a'; 779 pin = *(p + 2) - '0'; 780 lvl = *(p + 4) - '0'; 781 782 /* 783 * It doesn't need to read gpio value every loop, reading once 784 * is enough. We use cached_v[] to save what we have read, zero 785 * means not read before. 786 */ 787 if (cached_v[port] == 0) { 788 if (!gpio_base_addr[port]) { 789 debug(" - can't find gpio%d base address\n", port); 790 return 0; 791 } 792 793 /* Input mode */ 794 val = readl(gpio_base_addr[port] + GPIO_SWPORT_DDR); 795 val &= ~(1 << (bank * 8 + pin)); 796 writel(val, gpio_base_addr[port] + GPIO_SWPORT_DDR); 797 798 cached_v[port] = 799 readl(gpio_base_addr[port] + GPIO_EXT_PORT); 800 } 801 802 /* Verify result */ 803 bit = bank * 8 + pin; 804 val = cached_v[port] & (1 << bit) ? 1 : 0; 805 806 if (val == !!lvl) { 807 found = 1; 808 strgpio = strstr(p, KEY_WORDS_GPIO); 809 } else { 810 found = 0; 811 break; 812 } 813 814 debug(" - parse: gpio%d%c%d=%d, read=%d %s\n", 815 port, bank + 'a', pin, lvl, val, found ? "(Y)" : "(N)"); 816 } 817 818 return found ? 0 : -ENOENT; 819 } 820 821 /* Get according to hardware id(GPIO/ADC) */ 822 static struct resource_file *rockchip_read_hwid_dtb(void) 823 { 824 struct resource_file *file; 825 struct list_head *node; 826 827 if (list_empty(&entrys_head)) { 828 if (init_resource_list()) 829 return NULL; 830 } 831 832 /* Find dtb file according to hardware id(GPIO/ADC) */ 833 list_for_each(node, &entrys_head) { 834 file = list_entry(node, struct resource_file, link); 835 if (!strstr(file->name, ".dtb")) 836 continue; 837 838 if (strstr(file->name, KEY_WORDS_ADC_CTRL) && 839 strstr(file->name, KEY_WORDS_ADC_CH) && 840 !rockchip_read_dtb_by_adc(file->name)) { 841 return file; 842 } else if (strstr(file->name, KEY_WORDS_GPIO) && 843 !rockchip_read_dtb_by_gpio(file->name)) { 844 return file; 845 } 846 } 847 848 return NULL; 849 } 850 #endif 851 852 int rockchip_read_resource_dtb(void *fdt_addr, char **hash, int *hash_size) 853 { 854 struct resource_file *file; 855 int ret; 856 857 #ifdef CONFIG_ROCKCHIP_HWID_DTB 858 file = rockchip_read_hwid_dtb(); 859 /* If dtbs matched hardware id(GPIO/ADC) not found, try the default */ 860 if (!file) 861 file = get_file_info(DTB_FILE); 862 #else 863 file = get_file_info(DTB_FILE); 864 #endif 865 if (!file) 866 return -ENODEV; 867 868 ret = rockchip_read_resource_file(fdt_addr, file->name, 0, 0); 869 if (ret < 0) 870 return ret; 871 872 if (fdt_check_header(fdt_addr)) 873 return -EBADF; 874 875 *hash = file->hash; 876 *hash_size = file->hash_size; 877 printf("DTB: %s\n", file->name); 878 879 return 0; 880 } 881