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 <asm/io.h> 9 #include <malloc.h> 10 #include <linux/list.h> 11 #include <asm/arch/resource_img.h> 12 #include <boot_rkimg.h> 13 #include <dm/ofnode.h> 14 #ifdef CONFIG_ANDROID_AB 15 #include <android_avb/libavb_ab.h> 16 #include <android_avb/rk_avb_ops_user.h> 17 #endif 18 #ifdef CONFIG_ANDROID_BOOT_IMAGE 19 #include <android_bootloader.h> 20 #include <android_image.h> 21 #endif 22 23 DECLARE_GLOBAL_DATA_PTR; 24 25 #define PART_RESOURCE "resource" 26 #define RESOURCE_MAGIC "RSCE" 27 #define RESOURCE_MAGIC_SIZE 4 28 #define RESOURCE_VERSION 0 29 #define CONTENT_VERSION 0 30 #define ENTRY_TAG "ENTR" 31 #define ENTRY_TAG_SIZE 4 32 #define MAX_FILE_NAME_LEN 256 33 34 /* 35 * resource image structure 36 * ---------------------------------------------- 37 * | | 38 * | header (1 block) | 39 * | | 40 * ---------------------------------------------| 41 * | | | 42 * | entry0 (1 block) | | 43 * | | | 44 * ------------------------ | 45 * | | | 46 * | entry1 (1 block) | contents (n blocks) | 47 * | | | 48 * ------------------------ | 49 * | ...... | | 50 * ------------------------ | 51 * | | | 52 * | entryn (1 block) | | 53 * | | | 54 * ---------------------------------------------- 55 * | | 56 * | file0 (x blocks) | 57 * | | 58 * ---------------------------------------------- 59 * | | 60 * | file1 (y blocks) | 61 * | | 62 * ---------------------------------------------- 63 * | ...... | 64 * |--------------------------------------------- 65 * | | 66 * | filen (z blocks) | 67 * | | 68 * ---------------------------------------------- 69 */ 70 71 /** 72 * struct resource_image_header 73 * 74 * @magic: should be "RSCE" 75 * @version: resource image version, current is 0 76 * @c_version: content version, current is 0 77 * @blks: the size of the header ( 1 block = 512 bytes) 78 * @c_offset: contents offset(by block) in the image 79 * @e_blks: the size(by block) of the entry in the contents 80 * @e_num: numbers of the entrys. 81 */ 82 83 struct resource_img_hdr { 84 char magic[4]; 85 uint16_t version; 86 uint16_t c_version; 87 uint8_t blks; 88 uint8_t c_offset; 89 uint8_t e_blks; 90 uint32_t e_nums; 91 }; 92 93 struct resource_entry { 94 char tag[4]; 95 char name[MAX_FILE_NAME_LEN]; 96 uint32_t f_offset; 97 uint32_t f_size; 98 }; 99 100 struct resource_file { 101 char name[MAX_FILE_NAME_LEN]; 102 uint32_t f_offset; 103 uint32_t f_size; 104 struct list_head link; 105 uint32_t rsce_base; /* Base addr of resource */ 106 }; 107 108 static LIST_HEAD(entrys_head); 109 110 static int resource_image_check_header(const struct resource_img_hdr *hdr) 111 { 112 int ret; 113 114 ret = memcmp(RESOURCE_MAGIC, hdr->magic, RESOURCE_MAGIC_SIZE); 115 if (ret) { 116 printf("bad resource image magic\n"); 117 ret = -EINVAL; 118 } 119 debug("resource image header:\n"); 120 debug("magic:%s\n", hdr->magic); 121 debug("version:%d\n", hdr->version); 122 debug("c_version:%d\n", hdr->c_version); 123 debug("blks:%d\n", hdr->blks); 124 debug("c_offset:%d\n", hdr->c_offset); 125 debug("e_blks:%d\n", hdr->e_blks); 126 debug("e_num:%d\n", hdr->e_nums); 127 128 return ret; 129 } 130 131 static int add_file_to_list(struct resource_entry *entry, int rsce_base) 132 { 133 struct resource_file *file; 134 135 if (memcmp(entry->tag, ENTRY_TAG, ENTRY_TAG_SIZE)) { 136 printf("invalid entry tag\n"); 137 return -ENOENT; 138 } 139 file = malloc(sizeof(*file)); 140 if (!file) { 141 printf("out of memory\n"); 142 return -ENOMEM; 143 } 144 strcpy(file->name, entry->name); 145 file->rsce_base = rsce_base; 146 file->f_offset = entry->f_offset; 147 file->f_size = entry->f_size; 148 list_add_tail(&file->link, &entrys_head); 149 debug("entry:%p %s offset:%d size:%d\n", 150 entry, file->name, file->f_offset, file->f_size); 151 152 return 0; 153 } 154 155 static int init_resource_list(struct resource_img_hdr *hdr) 156 { 157 struct resource_entry *entry; 158 void *content; 159 int size; 160 int ret; 161 int e_num; 162 int offset = 0; 163 int resource_found = 0; 164 struct blk_desc *dev_desc; 165 disk_partition_t part_info; 166 #ifdef CONFIG_ANDROID_BOOT_IMAGE 167 struct andr_img_hdr *andr_hdr; 168 char *boot_partname = PART_BOOT; 169 #endif 170 171 if (hdr) { 172 content = (void *)((char *)hdr 173 + (hdr->c_offset) * RK_BLK_SIZE); 174 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 175 size = e_num * hdr->e_blks * RK_BLK_SIZE; 176 entry = (struct resource_entry *)(content + size); 177 add_file_to_list(entry, offset); 178 } 179 return 0; 180 } 181 182 dev_desc = rockchip_get_bootdev(); 183 if (!dev_desc) { 184 printf("%s: dev_desc is NULL!\n", __func__); 185 return -ENODEV; 186 } 187 hdr = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE); 188 if (!hdr) { 189 printf("%s out of memory!\n", __func__); 190 return -ENOMEM; 191 } 192 193 #ifdef CONFIG_ANDROID_BOOT_IMAGE 194 /* Get boot mode from misc */ 195 if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) 196 boot_partname = PART_RECOVERY; 197 /* Read boot/recovery and chenc if this is an AOSP img */ 198 #ifdef CONFIG_ANDROID_AB 199 char slot_suffix[3] = {0}; 200 201 if (rk_avb_get_current_slot(slot_suffix)) 202 goto out; 203 boot_partname = android_str_append(boot_partname, slot_suffix); 204 if (boot_partname == NULL) 205 goto out; 206 #endif 207 ret = part_get_info_by_name(dev_desc, boot_partname, 208 &part_info); 209 if (ret < 0) { 210 printf("fail to get %s part\n", boot_partname); 211 /* RKIMG can support part table without 'boot' */ 212 goto next; 213 } 214 andr_hdr = (void *)hdr; 215 ret = blk_dread(dev_desc, part_info.start, 1, andr_hdr); 216 if (ret != 1) { 217 printf("%s read fail\n", __func__); 218 goto out; 219 } 220 ret = android_image_check_header(andr_hdr); 221 if (!ret) { 222 debug("%s Load resource from %s senond pos\n", 223 __func__, part_info.name); 224 /* Read resource from second offset */ 225 offset = part_info.start * RK_BLK_SIZE; 226 offset += andr_hdr->page_size; 227 offset += ALIGN(andr_hdr->kernel_size, andr_hdr->page_size); 228 offset += ALIGN(andr_hdr->ramdisk_size, andr_hdr->page_size); 229 offset = offset / RK_BLK_SIZE; 230 231 resource_found = 1; 232 } 233 next: 234 #endif 235 if (!resource_found) { 236 /* Read resource from Rockchip Resource partition */ 237 ret = part_get_info_by_name(dev_desc, PART_RESOURCE, 238 &part_info); 239 if (ret < 0) { 240 printf("fail to get %s part\n", PART_RESOURCE); 241 goto out; 242 } 243 offset = part_info.start; 244 debug("%s Load resource from %s\n", __func__, part_info.name); 245 } 246 247 ret = blk_dread(dev_desc, offset, 1, hdr); 248 if (ret != 1) 249 goto out; 250 ret = resource_image_check_header(hdr); 251 if (ret < 0) 252 goto out; 253 content = memalign(ARCH_DMA_MINALIGN, 254 hdr->e_blks * hdr->e_nums * RK_BLK_SIZE); 255 if (!content) { 256 printf("alloc memory for content failed\n"); 257 goto out; 258 } 259 ret = blk_dread(dev_desc, offset + hdr->c_offset, 260 hdr->e_blks * hdr->e_nums, content); 261 if (ret != (hdr->e_blks * hdr->e_nums)) 262 goto err; 263 264 for (e_num = 0; e_num < hdr->e_nums; e_num++) { 265 size = e_num * hdr->e_blks * RK_BLK_SIZE; 266 entry = (struct resource_entry *)(content + size); 267 add_file_to_list(entry, offset); 268 } 269 270 err: 271 free(content); 272 out: 273 free(hdr); 274 275 return 0; 276 } 277 278 static struct resource_file *get_file_info(struct resource_img_hdr *hdr, 279 const char *name) 280 { 281 struct resource_file *file; 282 struct list_head *node; 283 284 if (list_empty(&entrys_head)) 285 init_resource_list(hdr); 286 287 list_for_each(node, &entrys_head) { 288 file = list_entry(node, struct resource_file, link); 289 if (!strcmp(file->name, name)) 290 return file; 291 } 292 293 return NULL; 294 } 295 296 int rockchip_get_resource_file(void *buf, const char *name) 297 { 298 struct resource_file *file; 299 300 file = get_file_info(buf, name); 301 302 return file->f_offset; 303 } 304 305 /* 306 * read file from resource partition 307 * @buf: destination buf to store file data; 308 * @name: file name 309 * @offset: blocks offset in the file, 1 block = 512 bytes 310 * @len: the size(by bytes) of file to read. 311 */ 312 int rockchip_read_resource_file(void *buf, const char *name, 313 int offset, int len) 314 { 315 struct resource_file *file; 316 int ret = 0; 317 int blks; 318 struct blk_desc *dev_desc; 319 320 file = get_file_info(NULL, name); 321 if (!file) { 322 printf("Can't find file:%s\n", name); 323 return -ENOENT; 324 } 325 326 if (len <= 0 || len > file->f_size) 327 len = file->f_size; 328 blks = DIV_ROUND_UP(len, RK_BLK_SIZE); 329 dev_desc = rockchip_get_bootdev(); 330 if (!dev_desc) { 331 printf("%s: dev_desc is NULL!\n", __func__); 332 return -ENODEV; 333 } 334 ret = blk_dread(dev_desc, file->rsce_base + file->f_offset + offset, 335 blks, buf); 336 if (ret != blks) 337 ret = -EIO; 338 else 339 ret = len; 340 341 return ret; 342 } 343 344 #define is_digit(c) ((c) >= '0' && (c) <= '9') 345 #define is_abcd(c) ((c) >= 'a' && (c) <= 'd') 346 #define is_equal(c) ((c) == '=') 347 348 #define DTB_FILE "rk-kernel.dtb" 349 #define KEY_WORDS_ADC_CTRL "#_" 350 #define KEY_WORDS_ADC_CH "_ch" 351 #define KEY_WORDS_GPIO "#gpio" 352 #define GPIO_EXT_PORT 0x50 353 #define MAX_ADC_CH_NR 10 354 #define MAX_GPIO_NR 10 355 356 /* 357 * How to make it works ? 358 * 359 * 1. pack dtb into rockchip resource.img, require: 360 * (1) file name end with ".dtb"; 361 * (2) file name contains key words, like: ...#_[controller]_ch[channel]=[value]...dtb 362 * @controller: adc controller name in dts, eg. "saradc", ...; 363 * @channel: adc channel; 364 * @value: adc value; 365 * eg: ...#_saradc_ch1=223#_saradc_ch2=650....dtb 366 * 367 * 2. U-Boot dtsi about adc controller node: 368 * (1) enable "u-boot,dm-pre-reloc;"; 369 * (2) must set status "okay"; 370 */ 371 static int rockchip_read_dtb_by_adc(const char *file_name) 372 { 373 static int cached_v[MAX_ADC_CH_NR]; 374 int offset_ctrl = strlen(KEY_WORDS_ADC_CTRL); 375 int offset_ch = strlen(KEY_WORDS_ADC_CH); 376 int ret, channel, len = 0, found = 0, margin = 30; 377 uint32_t raw_adc; 378 unsigned long dtb_adc; 379 char *stradc, *strch, *p; 380 char adc_v_string[10]; 381 char dev_name[32]; 382 383 debug("%s: %s\n", __func__, file_name); 384 385 /* Invalid format ? */ 386 stradc = strstr(file_name, KEY_WORDS_ADC_CTRL); 387 while (stradc) { 388 debug(" - substr: %s\n", stradc); 389 390 /* Parse controller name */ 391 strch = strstr(stradc, KEY_WORDS_ADC_CH); 392 len = strch - (stradc + offset_ctrl); 393 strlcpy(dev_name, stradc + offset_ctrl, len + 1); 394 395 /* Parse adc channel */ 396 p = strch + offset_ch; 397 if (is_digit(*p) && is_equal(*(p + 1))) { 398 channel = *p - '0'; 399 } else { 400 debug(" - invalid format: %s\n", stradc); 401 return -EINVAL; 402 } 403 404 /* Read raw adc value */ 405 if (cached_v[channel] == 0) { 406 ret = adc_channel_single_shot(dev_name, 407 channel, &raw_adc); 408 if (ret) { 409 debug(" - failed to read adc, ret=%d\n", ret); 410 return ret; 411 } 412 cached_v[channel] = raw_adc; 413 } 414 415 /* Parse dtb adc value */ 416 p = strch + offset_ch + 2; /* 2: channel and '=' */ 417 while (*p && is_digit(*p)) { 418 len++; 419 p++; 420 } 421 strlcpy(adc_v_string, strch + offset_ch + 2, len + 1); 422 dtb_adc = simple_strtoul(adc_v_string, NULL, 10); 423 424 if (abs(dtb_adc - cached_v[channel]) <= margin) { 425 found = 1; 426 stradc = strstr(p, KEY_WORDS_ADC_CTRL); 427 } else { 428 found = 0; 429 break; 430 } 431 432 debug(" - parse: controller=%s, channel=%d, dtb_adc=%ld, read=%d %s\n", 433 dev_name, channel, dtb_adc, cached_v[channel], found ? "(Y)" : ""); 434 } 435 436 return found ? 0 : -ENOENT; 437 } 438 439 static int gpio_parse_base_address(fdt_addr_t *gpio_base_addr) 440 { 441 static int initial; 442 ofnode parent, node; 443 int i = 0; 444 445 if (initial) 446 return 0; 447 448 parent = ofnode_path("/pinctrl"); 449 if (!ofnode_valid(parent)) { 450 debug(" - Can't find pinctrl node\n"); 451 return -EINVAL; 452 } 453 454 ofnode_for_each_subnode(node, parent) { 455 if (!ofnode_get_property(node, "gpio-controller", NULL)) { 456 debug(" - Can't find gpio-controller\n"); 457 continue; 458 } 459 460 gpio_base_addr[i++] = ofnode_get_addr(node); 461 debug(" - gpio%d: 0x%x\n", i - 1, (uint32_t)gpio_base_addr[i - 1]); 462 } 463 464 if (i == 0) { 465 debug(" - parse gpio address failed\n"); 466 return -EINVAL; 467 } 468 469 initial = 1; 470 471 return 0; 472 } 473 474 /* 475 * How to make it works ? 476 * 477 * 1. pack dtb into rockchip resource.img, require: 478 * (1) file name end with ".dtb"; 479 * (2) file name contains key words, like: ...#gpio[pin]=[value]...dtb 480 * @pin: gpio name, eg. 0a2 means GPIO0A2; 481 * @value: gpio level, 0 or 1; 482 * eg: ...#gpio0a6=1#gpio1c2=0....dtb 483 * 484 * 2. U-Boot dtsi about gpio node: 485 * (1) enable "u-boot,dm-pre-reloc;" for all gpio node; 486 * (2) set all gpio status "disabled"(Because we just want their property); 487 */ 488 static int rockchip_read_dtb_by_gpio(const char *file_name) 489 { 490 static uint32_t cached_v[MAX_GPIO_NR]; 491 fdt_addr_t gpio_base_addr[MAX_GPIO_NR]; 492 int ret, found = 0, offset = strlen(KEY_WORDS_GPIO); 493 uint8_t port, pin, bank, lvl, val; 494 char *strgpio, *p; 495 uint32_t bit; 496 497 debug("%s\n", file_name); 498 499 strgpio = strstr(file_name, KEY_WORDS_GPIO); 500 while (strgpio) { 501 debug(" - substr: %s\n", strgpio); 502 503 p = strgpio + offset; 504 505 /* Invalid format ? */ 506 if (!(is_digit(*(p + 0)) && is_abcd(*(p + 1)) && 507 is_digit(*(p + 2)) && is_equal(*(p + 3)) && 508 is_digit(*(p + 4)))) { 509 debug(" - invalid format: %s\n", strgpio); 510 return -EINVAL; 511 } 512 513 /* Parse gpio address */ 514 ret = gpio_parse_base_address(gpio_base_addr); 515 if (ret) { 516 debug(" - Can't parse gpio base address: %d\n", ret); 517 return ret; 518 } 519 520 /* Read gpio value */ 521 port = *(p + 0) - '0'; 522 bank = *(p + 1) - 'a'; 523 pin = *(p + 2) - '0'; 524 lvl = *(p + 4) - '0'; 525 526 if (cached_v[port] == 0) 527 cached_v[port] = 528 readl(gpio_base_addr[port] + GPIO_EXT_PORT); 529 530 /* Verify result */ 531 bit = bank * 32 + pin; 532 val = cached_v[port] & (1 << bit) ? 1 : 0; 533 534 if (val == !!lvl) { 535 found = 1; 536 strgpio = strstr(p, KEY_WORDS_GPIO); 537 } else { 538 found = 0; 539 break; 540 } 541 542 debug(" - parse: gpio%d%c%d=%d, read=%d %s\n", 543 port, bank + 'a', pin, lvl, val, found ? "(Y)" : ""); 544 } 545 546 return found ? 0 : -ENOENT; 547 } 548 549 int rockchip_read_dtb_file(void *fdt_addr) 550 { 551 struct resource_file *file; 552 struct list_head *node; 553 char *dtb_name = DTB_FILE; 554 555 if (list_empty(&entrys_head)) 556 init_resource_list(NULL); 557 558 list_for_each(node, &entrys_head) { 559 file = list_entry(node, struct resource_file, link); 560 if (!strstr(file->name, ".dtb")) 561 continue; 562 563 if (strstr(file->name, KEY_WORDS_ADC_CTRL) && 564 strstr(file->name, KEY_WORDS_ADC_CH) && 565 !rockchip_read_dtb_by_adc(file->name)) { 566 dtb_name = file->name; 567 break; 568 } else if (strstr(file->name, KEY_WORDS_GPIO) && 569 !rockchip_read_dtb_by_gpio(file->name)) { 570 dtb_name = file->name; 571 break; 572 } 573 } 574 575 printf("DTB: %s\n", dtb_name); 576 577 return rockchip_read_resource_file((void *)fdt_addr, dtb_name, 0, 0); 578 } 579