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 MAX_ADC_CH_NR 10 590 #define MAX_GPIO_NR 10 591 592 #ifdef CONFIG_ROCKCHIP_GPIO_V2 593 #define GPIO_SWPORT_DDR 0x08 594 #define GPIO_EXT_PORT 0x70 595 #define WMSK_SETBIT(n) (n << 16 | n) 596 #define WMSK_CLRBIT(n) (n << 16) 597 #define REG_PLUS4(off, n) (off + (n >= BIT(16) ? 4 : 0)) 598 #define BIT_SUB16(n) (n >= BIT(16) ? (n >> 16) : n) 599 600 static int gpio_read(fdt_addr_t gpio_addr, 601 int gpio_bank, int gpio_pin) 602 { 603 uint32_t offset, bit; 604 605 bit = gpio_bank * 8 + gpio_pin; 606 607 offset = REG_PLUS4(GPIO_SWPORT_DDR, bit); 608 bit = BIT_SUB16(bit); 609 writel(WMSK_CLRBIT(bit), gpio_addr + offset); 610 611 return readl(gpio_addr + GPIO_EXT_PORT); 612 } 613 614 #else 615 #define GPIO_SWPORT_DDR 0x04 616 #define GPIO_EXT_PORT 0x50 617 618 static int gpio_read(fdt_addr_t gpio_addr, 619 int gpio_bank, int gpio_pin) 620 { 621 uint32_t val; 622 623 val = readl(gpio_addr + GPIO_SWPORT_DDR); 624 val &= ~(1 << (gpio_bank * 8 + gpio_pin)); 625 writel(val, gpio_addr + GPIO_SWPORT_DDR); 626 627 return readl(gpio_addr + GPIO_EXT_PORT); 628 } 629 #endif 630 631 /* 632 * How to make it works ? 633 * 634 * 1. pack dtb into rockchip resource.img, require: 635 * (1) file name end with ".dtb"; 636 * (2) file name contains key words, like: ...#_[controller]_ch[channel]=[value]...dtb 637 * @controller: adc controller name in dts, eg. "saradc", ...; 638 * @channel: adc channel; 639 * @value: adc value; 640 * eg: ...#_saradc_ch1=223#_saradc_ch2=650....dtb 641 * 642 * 2. U-Boot dtsi about adc controller node: 643 * (1) enable "u-boot,dm-pre-reloc;"; 644 * (2) must set status "okay"; 645 */ 646 static int rockchip_read_dtb_by_adc(const char *file_name) 647 { 648 static int cached_v[MAX_ADC_CH_NR]; 649 int offset_ctrl = strlen(KEY_WORDS_ADC_CTRL); 650 int offset_ch = strlen(KEY_WORDS_ADC_CH); 651 int ret, channel, len = 0, found = 0, margin = 30; 652 char *stradc, *strch, *p; 653 char adc_v_string[10]; 654 char dev_name[32]; 655 uint32_t raw_adc; 656 ulong dtb_adc; 657 658 debug("%s: %s\n", __func__, file_name); 659 660 /* Invalid format ? */ 661 stradc = strstr(file_name, KEY_WORDS_ADC_CTRL); 662 while (stradc) { 663 debug(" - substr: %s\n", stradc); 664 665 /* Parse controller name */ 666 strch = strstr(stradc, KEY_WORDS_ADC_CH); 667 len = strch - (stradc + offset_ctrl); 668 strlcpy(dev_name, stradc + offset_ctrl, len + 1); 669 670 /* Parse adc channel */ 671 p = strch + offset_ch; 672 if (is_digit(*p) && is_equal(*(p + 1))) { 673 channel = *p - '0'; 674 } else { 675 debug(" - invalid format: %s\n", stradc); 676 return -EINVAL; 677 } 678 679 /* 680 * Read raw adc value 681 * 682 * It doesn't need to read adc value every loop, reading once 683 * is enough. We use cached_v[] to save what we have read, zero 684 * means not read before. 685 */ 686 if (cached_v[channel] == 0) { 687 ret = adc_channel_single_shot(dev_name, 688 channel, &raw_adc); 689 if (ret) { 690 debug(" - failed to read adc, ret=%d\n", ret); 691 return ret; 692 } 693 cached_v[channel] = raw_adc; 694 } 695 696 /* Parse dtb adc value */ 697 p = strch + offset_ch + 2; /* 2: channel and '=' */ 698 while (*p && is_digit(*p)) { 699 len++; 700 p++; 701 } 702 strlcpy(adc_v_string, strch + offset_ch + 2, len + 1); 703 dtb_adc = simple_strtoul(adc_v_string, NULL, 10); 704 705 if (abs(dtb_adc - cached_v[channel]) <= margin) { 706 found = 1; 707 stradc = strstr(p, KEY_WORDS_ADC_CTRL); 708 } else { 709 found = 0; 710 break; 711 } 712 713 debug(" - parse: controller=%s, channel=%d, dtb_adc=%ld, read=%d %s\n", 714 dev_name, channel, dtb_adc, cached_v[channel], found ? "(Y)" : ""); 715 } 716 717 return found ? 0 : -ENOENT; 718 } 719 720 static int gpio_parse_base_address(fdt_addr_t *gpio_base_addr) 721 { 722 static int initialized; 723 ofnode parent, node; 724 int idx = 0; 725 726 if (initialized) 727 return 0; 728 729 parent = ofnode_path("/pinctrl"); 730 if (!ofnode_valid(parent)) { 731 debug(" - Can't find pinctrl node\n"); 732 return -EINVAL; 733 } 734 735 ofnode_for_each_subnode(node, parent) { 736 if (!ofnode_get_property(node, "gpio-controller", NULL)) { 737 debug(" - Not gpio controller node\n"); 738 continue; 739 } 740 gpio_base_addr[idx] = ofnode_get_addr(node); 741 debug(" - gpio%d: 0x%x\n", idx, (uint32_t)gpio_base_addr[idx]); 742 idx++; 743 } 744 745 if (idx == 0) { 746 debug(" - parse gpio address failed\n"); 747 return -EINVAL; 748 } 749 750 initialized = 1; 751 752 return 0; 753 } 754 755 /* 756 * How to make it works ? 757 * 758 * 1. pack dtb into rockchip resource.img, require: 759 * (1) file name end with ".dtb"; 760 * (2) file name contains key words, like: ...#gpio[pin]=[value]...dtb 761 * @pin: gpio name, eg. 0a2 means GPIO0A2; 762 * @value: gpio level, 0 or 1; 763 * eg: ...#gpio0a6=1#gpio1c2=0....dtb 764 * 765 * 2. U-Boot dtsi about gpio node: 766 * (1) enable "u-boot,dm-pre-reloc;" for [all] gpio node; 767 * (2) set all gpio status "disabled"(Because we just want their property); 768 */ 769 static int rockchip_read_dtb_by_gpio(const char *file_name) 770 { 771 static uint32_t cached_v[MAX_GPIO_NR]; 772 static fdt_addr_t gpio_base_addr[MAX_GPIO_NR]; 773 int ret, found = 0, offset = strlen(KEY_WORDS_GPIO); 774 uint8_t port, pin, bank, lvl, val; 775 char *strgpio, *p; 776 uint32_t bit; 777 778 debug("[*] %s\n", file_name); 779 780 /* Parse gpio address */ 781 memset(gpio_base_addr, 0, sizeof(gpio_base_addr)); 782 ret = gpio_parse_base_address(gpio_base_addr); 783 if (ret) { 784 debug(" - Can't parse gpio base address: %d\n", ret); 785 return ret; 786 } 787 788 strgpio = strstr(file_name, KEY_WORDS_GPIO); 789 while (strgpio) { 790 debug(" - substr: %s\n", strgpio); 791 792 p = strgpio + offset; 793 794 /* Invalid format ? */ 795 if (!(is_digit(*(p + 0)) && is_abcd(*(p + 1)) && 796 is_digit(*(p + 2)) && is_equal(*(p + 3)) && 797 is_digit(*(p + 4)))) { 798 debug(" - invalid format: %s\n", strgpio); 799 return -EINVAL; 800 } 801 802 /* Read gpio value */ 803 port = *(p + 0) - '0'; 804 bank = *(p + 1) - 'a'; 805 pin = *(p + 2) - '0'; 806 lvl = *(p + 4) - '0'; 807 808 /* 809 * It doesn't need to read gpio value every loop, reading once 810 * is enough. We use cached_v[] to save what we have read, zero 811 * means not read before. 812 */ 813 if (cached_v[port] == 0) { 814 if (!gpio_base_addr[port]) { 815 debug(" - can't find gpio%d base address\n", port); 816 return 0; 817 } 818 cached_v[port] = gpio_read(gpio_base_addr[port], bank, pin); 819 debug(" - gpio-val[%d]: 0x%08x\n", port, cached_v[port]); 820 } 821 822 /* Verify result */ 823 bit = bank * 8 + pin; 824 val = cached_v[port] & (1 << bit) ? 1 : 0; 825 if (val == !!lvl) { 826 found = 1; 827 strgpio = strstr(p, KEY_WORDS_GPIO); 828 } else { 829 found = 0; 830 debug(" - parse: gpio%d%c%d=%d, read=%d %s\n", 831 port, bank + 'a', pin, lvl, val, found ? "(Y)" : "(N)"); 832 break; 833 } 834 835 debug(" - parse: gpio%d%c%d=%d, read=%d %s\n", 836 port, bank + 'a', pin, lvl, val, found ? "(Y)" : "(N)"); 837 } 838 839 debug(" # result: %s\n", found ? "OK" : "Try next one .."); 840 841 return found ? 0 : -ENOENT; 842 } 843 844 /* Get according to hardware id(GPIO/ADC) */ 845 static struct resource_file *rockchip_read_hwid_dtb(void) 846 { 847 struct resource_file *file; 848 struct list_head *node; 849 850 if (list_empty(&entrys_head)) { 851 if (init_resource_list()) 852 return NULL; 853 } 854 855 /* Find dtb file according to hardware id(GPIO/ADC) */ 856 list_for_each(node, &entrys_head) { 857 file = list_entry(node, struct resource_file, link); 858 if (!strstr(file->name, ".dtb")) 859 continue; 860 861 if (strstr(file->name, KEY_WORDS_ADC_CTRL) && 862 strstr(file->name, KEY_WORDS_ADC_CH) && 863 !rockchip_read_dtb_by_adc(file->name)) { 864 return file; 865 } else if (strstr(file->name, KEY_WORDS_GPIO) && 866 !rockchip_read_dtb_by_gpio(file->name)) { 867 return file; 868 } 869 } 870 871 return NULL; 872 } 873 #endif 874 875 int rockchip_read_resource_dtb(void *fdt_addr, char **hash, int *hash_size) 876 { 877 struct resource_file *file; 878 int ret; 879 880 #ifdef CONFIG_ROCKCHIP_HWID_DTB 881 file = rockchip_read_hwid_dtb(); 882 /* If dtbs matched hardware id(GPIO/ADC) not found, try the default */ 883 if (!file) 884 file = get_file_info(DTB_FILE); 885 #else 886 file = get_file_info(DTB_FILE); 887 #endif 888 if (!file) 889 return -ENODEV; 890 891 ret = rockchip_read_resource_file(fdt_addr, file->name, 0, 0); 892 if (ret < 0) 893 return ret; 894 895 if (fdt_check_header(fdt_addr)) 896 return -EBADF; 897 898 *hash = file->hash; 899 *hash_size = file->hash_size; 900 printf("DTB: %s\n", file->name); 901 902 return 0; 903 } 904