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