xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/resource_img.c (revision 1490eb89f4697b02cfb8f826d2f5eaf37edcbd47)
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 <bmp_layout.h>
9 #include <asm/io.h>
10 #include <fs.h>
11 #include <malloc.h>
12 #include <sysmem.h>
13 #include <asm/unaligned.h>
14 #include <linux/list.h>
15 #include <asm/arch/resource_img.h>
16 #include <boot_rkimg.h>
17 #include <dm/ofnode.h>
18 #ifdef CONFIG_ANDROID_AB
19 #include <android_avb/libavb_ab.h>
20 #include <android_avb/rk_avb_ops_user.h>
21 #endif
22 #ifdef CONFIG_ANDROID_BOOT_IMAGE
23 #include <android_bootloader.h>
24 #include <android_image.h>
25 #endif
26 
27 DECLARE_GLOBAL_DATA_PTR;
28 
29 #define PART_RESOURCE			"resource"
30 #define RESOURCE_MAGIC			"RSCE"
31 #define RESOURCE_MAGIC_SIZE		4
32 #define RESOURCE_VERSION		0
33 #define CONTENT_VERSION			0
34 #define ENTRY_TAG			"ENTR"
35 #define ENTRY_TAG_SIZE			4
36 #define MAX_FILE_NAME_LEN		256
37 
38 /*
39  *         resource image structure
40  * ----------------------------------------------
41  * |                                            |
42  * |    header  (1 block)                       |
43  * |                                            |
44  * ---------------------------------------------|
45  * |                      |                     |
46  * |    entry0  (1 block) |                     |
47  * |                      |                     |
48  * ------------------------                     |
49  * |                      |                     |
50  * |    entry1  (1 block) | contents (n blocks) |
51  * |                      |                     |
52  * ------------------------                     |
53  * |    ......            |                     |
54  * ------------------------                     |
55  * |                      |                     |
56  * |    entryn  (1 block) |                     |
57  * |                      |                     |
58  * ----------------------------------------------
59  * |                                            |
60  * |    file0  (x blocks)                       |
61  * |                                            |
62  * ----------------------------------------------
63  * |                                            |
64  * |    file1  (y blocks)                       |
65  * |                                            |
66  * ----------------------------------------------
67  * |                   ......                   |
68  * |---------------------------------------------
69  * |                                            |
70  * |    filen  (z blocks)                       |
71  * |                                            |
72  * ----------------------------------------------
73  */
74 
75 /**
76  * struct resource_image_header
77  *
78  * @magic: should be "RSCE"
79  * @version: resource image version, current is 0
80  * @c_version: content version, current is 0
81  * @blks: the size of the header ( 1 block = 512 bytes)
82  * @c_offset: contents offset(by block) in the image
83  * @e_blks: the size(by block) of the entry in the contents
84  * @e_num: numbers of the entrys.
85  */
86 
87 struct resource_img_hdr {
88 	char		magic[4];
89 	uint16_t	version;
90 	uint16_t	c_version;
91 	uint8_t		blks;
92 	uint8_t		c_offset;
93 	uint8_t		e_blks;
94 	uint32_t	e_nums;
95 };
96 
97 struct resource_entry {
98 	char		tag[4];
99 	char		name[MAX_FILE_NAME_LEN];
100 	uint32_t	f_offset;
101 	uint32_t	f_size;
102 };
103 
104 struct resource_file {
105 	char		name[MAX_FILE_NAME_LEN];
106 	uint32_t	f_offset;
107 	uint32_t	f_size;
108 	struct list_head link;
109 	uint32_t 	rsce_base;	/* Base addr of resource */
110 };
111 
112 static LIST_HEAD(entrys_head);
113 
114 static int resource_image_check_header(const struct resource_img_hdr *hdr)
115 {
116 	int ret;
117 
118 	ret = memcmp(RESOURCE_MAGIC, hdr->magic, RESOURCE_MAGIC_SIZE);
119 	if (ret) {
120 		printf("bad resource image magic: %s\n",
121 		       hdr->magic ? hdr->magic : "none");
122 		ret = -EINVAL;
123 	}
124 	debug("resource image header:\n");
125 	debug("magic:%s\n", hdr->magic);
126 	debug("version:%d\n", hdr->version);
127 	debug("c_version:%d\n", hdr->c_version);
128 	debug("blks:%d\n", hdr->blks);
129 	debug("c_offset:%d\n", hdr->c_offset);
130 	debug("e_blks:%d\n", hdr->e_blks);
131 	debug("e_num:%d\n", hdr->e_nums);
132 
133 	return ret;
134 }
135 
136 static int add_file_to_list(struct resource_entry *entry, int rsce_base)
137 {
138 	struct resource_file *file;
139 
140 	if (memcmp(entry->tag, ENTRY_TAG, ENTRY_TAG_SIZE)) {
141 		printf("invalid entry tag\n");
142 		return -ENOENT;
143 	}
144 	file = malloc(sizeof(*file));
145 	if (!file) {
146 		printf("out of memory\n");
147 		return -ENOMEM;
148 	}
149 	strcpy(file->name, entry->name);
150 	file->rsce_base = rsce_base;
151 	file->f_offset = entry->f_offset;
152 	file->f_size = entry->f_size;
153 	list_add_tail(&file->link, &entrys_head);
154 	debug("entry:%p  %s offset:%d size:%d\n",
155 	      entry, file->name, file->f_offset, file->f_size);
156 
157 	return 0;
158 }
159 
160 static int init_resource_list(struct resource_img_hdr *hdr)
161 {
162 	struct resource_entry *entry;
163 	void *content;
164 	int size;
165 	int ret;
166 	int e_num;
167 	int offset = 0;
168 	int resource_found = 0;
169 	struct blk_desc *dev_desc;
170 	struct bmp_header *header;
171 	disk_partition_t part_info;
172 	char *boot_partname = PART_BOOT;
173 
174 /*
175  * Primary detect AOSP format image, try to get resource image from
176  * boot/recovery partition. If not, it's an RK format image and try
177  * to get from resource partition.
178  */
179 #ifdef CONFIG_ANDROID_BOOT_IMAGE
180 	struct andr_img_hdr *andr_hdr;
181 #endif
182 
183 	if (hdr) {
184 		if (resource_image_check_header(hdr))
185 			return -EEXIST;
186 
187 		content = (void *)((char *)hdr
188 				   + (hdr->c_offset) * RK_BLK_SIZE);
189 		for (e_num = 0; e_num < hdr->e_nums; e_num++) {
190 			size = e_num * hdr->e_blks * RK_BLK_SIZE;
191 			entry = (struct resource_entry *)(content + size);
192 			add_file_to_list(entry, offset);
193 		}
194 		return 0;
195 	}
196 
197 	dev_desc = rockchip_get_bootdev();
198 	if (!dev_desc) {
199 		printf("%s: dev_desc is NULL!\n", __func__);
200 		return -ENODEV;
201 	}
202 	hdr = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE);
203 	if (!hdr) {
204 		printf("%s: out of memory!\n", __func__);
205 		return -ENOMEM;
206 	}
207 
208 #ifdef CONFIG_ANDROID_BOOT_IMAGE
209 	/* Get boot mode from misc */
210 #ifndef CONFIG_ANDROID_AB
211 	if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY)
212 		boot_partname = PART_RECOVERY;
213 #endif
214 
215 	/* Read boot/recovery and chenc if this is an AOSP img */
216 #ifdef CONFIG_ANDROID_AB
217 	char slot_suffix[3] = {0};
218 
219 	if (rk_avb_get_current_slot(slot_suffix)) {
220 		ret = -ENODEV;
221 		goto out;
222 	}
223 
224 	boot_partname = android_str_append(boot_partname, slot_suffix);
225 	if (!boot_partname) {
226 		ret = -EINVAL;
227 		goto out;
228 	}
229 #endif
230 	ret = part_get_info_by_name(dev_desc, boot_partname, &part_info);
231 	if (ret < 0) {
232 		printf("%s: failed to get %s part, ret=%d\n",
233 		       __func__, boot_partname, ret);
234 		/* RKIMG can support part table without 'boot' */
235 		goto next;
236 	}
237 
238 	/*
239 	 * Only read header and check magic, is a AOSP format image?
240 	 * If so, get resource image from second part.
241 	 */
242 	andr_hdr = (void *)hdr;
243 	ret = blk_dread(dev_desc, part_info.start, 1, andr_hdr);
244 	if (ret != 1) {
245 		printf("%s: failed to read %s hdr, ret=%d\n",
246 		       __func__, part_info.name, ret);
247 		ret = -EIO;
248 		goto out;
249 	}
250 	ret = android_image_check_header(andr_hdr);
251 	if (!ret) {
252 		u32 os_ver = andr_hdr->os_version >> 11;
253 		u32 os_lvl = andr_hdr->os_version & ((1U << 11) - 1);
254 
255 		if (os_ver)
256 			printf("Android %u.%u, Build %u.%u\n",
257 			       (os_ver >> 14) & 0x7F, (os_ver >> 7) & 0x7F,
258 			       (os_lvl >> 4) + 2000, os_lvl & 0x0F);
259 
260 		debug("%s: Load resource from %s second pos\n",
261 		      __func__, part_info.name);
262 		/* Read resource from second offset */
263 		offset = part_info.start * RK_BLK_SIZE;
264 		offset += andr_hdr->page_size;
265 		offset += ALIGN(andr_hdr->kernel_size, andr_hdr->page_size);
266 		offset += ALIGN(andr_hdr->ramdisk_size, andr_hdr->page_size);
267 		offset = offset / RK_BLK_SIZE;
268 
269 		resource_found = 1;
270 	}
271 next:
272 #endif
273 	/*
274 	 * If not found resource image in AOSP format images(boot/recovery part),
275 	 * try to read RK format images(resource part).
276 	 */
277 	if (!resource_found) {
278 		debug("%s: Load resource from resource part\n", __func__);
279 		/* Read resource from Rockchip Resource partition */
280 		boot_partname = PART_RESOURCE;
281 		ret = part_get_info_by_name(dev_desc, boot_partname, &part_info);
282 		if (ret < 0) {
283 			printf("%s: failed to get resource part, ret=%d\n",
284 			       __func__, ret);
285 			goto out;
286 		}
287 		offset = part_info.start;
288 	}
289 
290 	/* Only read header and check magic */
291 	ret = blk_dread(dev_desc, offset, 1, hdr);
292 	if (ret != 1) {
293 		printf("%s: failed to read resource hdr, ret=%d\n",
294 		       __func__, ret);
295 		ret = -EIO;
296 		goto out;
297 	}
298 
299 	ret = resource_image_check_header(hdr);
300 	if (ret < 0) {
301 		ret = -EINVAL;
302 		goto out;
303 	}
304 
305 	content = memalign(ARCH_DMA_MINALIGN,
306 			   hdr->e_blks * hdr->e_nums * RK_BLK_SIZE);
307 	if (!content) {
308 		printf("%s: failed to alloc memory for content\n", __func__);
309 		ret = -ENOMEM;
310 		goto out;
311 	}
312 
313 	/* Read all entries from resource image */
314 	ret = blk_dread(dev_desc, offset + hdr->c_offset,
315 			hdr->e_blks * hdr->e_nums, content);
316 	if (ret != (hdr->e_blks * hdr->e_nums)) {
317 		printf("%s: failed to read resource entries, ret=%d\n",
318 		       __func__, ret);
319 		ret = -EIO;
320 		goto err;
321 	}
322 
323 	for (e_num = 0; e_num < hdr->e_nums; e_num++) {
324 		size = e_num * hdr->e_blks * RK_BLK_SIZE;
325 		entry = (struct resource_entry *)(content + size);
326 		add_file_to_list(entry, offset);
327 	}
328 
329 	ret = 0;
330 	printf("Load FDT from %s part\n", boot_partname);
331 
332 	/*
333 	 * Add logo.bmp from "logo" parititon
334 	 *
335 	 * We provide a "logo" partition for user to store logo.bmp
336 	 * and update from kernel user space dynamically.
337 	 */
338 	if (part_get_info_by_name(dev_desc, PART_LOGO, &part_info) >= 0) {
339 		struct resource_file *file;
340 		struct list_head *node;
341 
342 		header = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE);
343 		if (!header) {
344 			ret = -ENOMEM;
345 			goto err;
346 		}
347 
348 		ret = blk_dread(dev_desc, part_info.start, 1, header);
349 		if (ret != 1) {
350 			ret = -EIO;
351 			goto err2;
352 		}
353 
354 		if (header->signature[0] != 'B' ||
355 		    header->signature[1] != 'M') {
356 			ret = 0;
357 			goto err2;
358 		}
359 
360 		entry = malloc(sizeof(*entry));
361 		if (!entry) {
362 			ret = -ENOMEM;
363 			goto err2;
364 		}
365 
366 		memcpy(entry->tag, ENTRY_TAG, sizeof(ENTRY_TAG));
367 		memcpy(entry->name, "logo.bmp", sizeof("logo.bmp"));
368 		entry->f_size = get_unaligned_le32(&header->file_size);
369 		entry->f_offset = 0;
370 
371 		/* Delete exist "logo.bmp", then add new */
372 		list_for_each(node, &entrys_head) {
373 			file = list_entry(node,
374 					  struct resource_file, link);
375 			if (!strcmp(file->name, entry->name)) {
376 				list_del(&file->link);
377 				free(file);
378 				break;
379 			}
380 		}
381 
382 		add_file_to_list(entry, part_info.start);
383 		free(entry);
384 		printf("Load \"logo.bmp\" from logo part\n");
385 		ret = 0;
386 err2:
387 		free(header);
388 	}
389 
390 err:
391 	free(content);
392 out:
393 	free(hdr);
394 
395 	return ret;
396 }
397 
398 static struct resource_file *get_file_info(struct resource_img_hdr *hdr,
399 					   const char *name)
400 {
401 	struct resource_file *file;
402 	struct list_head *node;
403 
404 	if (list_empty(&entrys_head)) {
405 		if (init_resource_list(hdr))
406 			return NULL;
407 	}
408 
409 	list_for_each(node, &entrys_head) {
410 		file = list_entry(node, struct resource_file, link);
411 		if (!strcmp(file->name, name))
412 			return file;
413 	}
414 
415 	return NULL;
416 }
417 
418 int rockchip_get_resource_file_offset(void *resc_hdr, const char *name)
419 {
420 	struct resource_file *file;
421 
422 	file = get_file_info(resc_hdr, name);
423 	if (!file)
424 		return -ENFILE;
425 
426 	return file->f_offset;
427 }
428 
429 int rockchip_get_resource_file_size(void *resc_hdr, const char *name)
430 {
431 	struct resource_file *file;
432 
433 	file = get_file_info(resc_hdr, name);
434 	if (!file)
435 		return -ENFILE;
436 
437 	return file->f_size;
438 }
439 
440 /*
441  * read file from resource partition
442  * @buf: destination buf to store file data;
443  * @name: file name
444  * @offset: blocks offset in the file, 1 block = 512 bytes
445  * @len: the size(by bytes) of file to read.
446  */
447 int rockchip_read_resource_file(void *buf, const char *name,
448 				int offset, int len)
449 {
450 	struct resource_file *file;
451 	int ret = 0;
452 	int blks;
453 	struct blk_desc *dev_desc;
454 
455 	file = get_file_info(NULL, name);
456 	if (!file) {
457 		printf("Can't find file:%s\n", name);
458 		return -ENOENT;
459 	}
460 
461 	if (len <= 0 || len > file->f_size)
462 		len = file->f_size;
463 	blks = DIV_ROUND_UP(len, RK_BLK_SIZE);
464 	dev_desc = rockchip_get_bootdev();
465 	if (!dev_desc) {
466 		printf("%s: dev_desc is NULL!\n", __func__);
467 		return -ENODEV;
468 	}
469 	ret = blk_dread(dev_desc, file->rsce_base + file->f_offset + offset,
470 			blks, buf);
471 	if (ret != blks)
472 		ret = -EIO;
473 	else
474 		ret = len;
475 
476 	return ret;
477 }
478 
479 #define is_digit(c)		((c) >= '0' && (c) <= '9')
480 #define is_abcd(c)		((c) >= 'a' && (c) <= 'd')
481 #define is_equal(c)		((c) == '=')
482 
483 #define DTB_FILE		"rk-kernel.dtb"
484 #define KEY_WORDS_ADC_CTRL	"#_"
485 #define KEY_WORDS_ADC_CH	"_ch"
486 #define KEY_WORDS_GPIO		"#gpio"
487 #define GPIO_SWPORT_DDR		0x04
488 #define GPIO_EXT_PORT		0x50
489 #define MAX_ADC_CH_NR		10
490 #define MAX_GPIO_NR		10
491 
492 #ifdef CONFIG_ADC
493 /*
494  * How to make it works ?
495  *
496  * 1. pack dtb into rockchip resource.img, require:
497  *    (1) file name end with ".dtb";
498  *    (2) file name contains key words, like: ...#_[controller]_ch[channel]=[value]...dtb
499  *	  @controller: adc controller name in dts, eg. "saradc", ...;
500  *	  @channel: adc channel;
501  *	  @value: adc value;
502  *    eg: ...#_saradc_ch1=223#_saradc_ch2=650....dtb
503  *
504  * 2. U-Boot dtsi about adc controller node:
505  *    (1) enable "u-boot,dm-pre-reloc;";
506  *    (2) must set status "okay";
507  */
508 static int rockchip_read_dtb_by_adc(const char *file_name)
509 {
510 	static int cached_v[MAX_ADC_CH_NR];
511 	int offset_ctrl = strlen(KEY_WORDS_ADC_CTRL);
512 	int offset_ch = strlen(KEY_WORDS_ADC_CH);
513 	int ret, channel, len = 0, found = 0, margin = 30;
514 	uint32_t raw_adc;
515 	unsigned long dtb_adc;
516 	char *stradc, *strch, *p;
517 	char adc_v_string[10];
518 	char dev_name[32];
519 
520 	debug("%s: %s\n", __func__, file_name);
521 
522 	/* Invalid format ? */
523 	stradc = strstr(file_name, KEY_WORDS_ADC_CTRL);
524 	while (stradc) {
525 		debug("   - substr: %s\n", stradc);
526 
527 		/* Parse controller name */
528 		strch = strstr(stradc, KEY_WORDS_ADC_CH);
529 		len = strch - (stradc + offset_ctrl);
530 		strlcpy(dev_name, stradc + offset_ctrl, len + 1);
531 
532 		/* Parse adc channel */
533 		p = strch + offset_ch;
534 		if (is_digit(*p) && is_equal(*(p + 1))) {
535 			channel = *p - '0';
536 		} else {
537 			debug("   - invalid format: %s\n", stradc);
538 			return -EINVAL;
539 		}
540 
541 		/*
542 		 * Read raw adc value
543 		 *
544 		 * It doesn't need to read adc value every loop, reading once
545 		 * is enough. We use cached_v[] to save what we have read, zero
546 		 * means not read before.
547 		 */
548 		if (cached_v[channel] == 0) {
549 			ret = adc_channel_single_shot(dev_name,
550 						      channel, &raw_adc);
551 			if (ret) {
552 				debug("   - failed to read adc, ret=%d\n", ret);
553 				return ret;
554 			}
555 			cached_v[channel] = raw_adc;
556 		}
557 
558 		/* Parse dtb adc value */
559 		p = strch + offset_ch + 2;	/* 2: channel and '=' */
560 		while (*p && is_digit(*p)) {
561 			len++;
562 			p++;
563 		}
564 		strlcpy(adc_v_string, strch + offset_ch + 2, len + 1);
565 		dtb_adc = simple_strtoul(adc_v_string, NULL, 10);
566 
567 		if (abs(dtb_adc - cached_v[channel]) <= margin) {
568 			found = 1;
569 			stradc = strstr(p, KEY_WORDS_ADC_CTRL);
570 		} else {
571 			found = 0;
572 			break;
573 		}
574 
575 		debug("   - parse: controller=%s, channel=%d, dtb_adc=%ld, read=%d %s\n",
576 		      dev_name, channel, dtb_adc, cached_v[channel], found ? "(Y)" : "");
577 	}
578 
579 	return found ? 0 : -ENOENT;
580 }
581 #else
582 static int rockchip_read_dtb_by_adc(const char *file_name)
583 {
584 	return  -ENOENT;
585 }
586 #endif
587 
588 static int gpio_parse_base_address(fdt_addr_t *gpio_base_addr)
589 {
590 	static int initial;
591 	ofnode parent, node;
592 	const char *name;
593 	int idx, nr = 0;
594 
595 	if (initial)
596 		return 0;
597 
598 	parent = ofnode_path("/pinctrl");
599 	if (!ofnode_valid(parent)) {
600 		debug("   - Can't find pinctrl node\n");
601 		return -EINVAL;
602 	}
603 
604 	ofnode_for_each_subnode(node, parent) {
605 		if (!ofnode_get_property(node, "gpio-controller", NULL)) {
606 			debug("   - Can't find gpio-controller\n");
607 			continue;
608 		}
609 
610 		name = ofnode_get_name(node);
611 		if (!is_digit((char)*(name + 4))) {
612 			debug("   - bad gpio node name: %s\n", name);
613 			continue;
614 		}
615 
616 		nr++;
617 		idx = *(name + 4) - '0';
618 		gpio_base_addr[idx] = ofnode_get_addr(node);
619 		debug("   - gpio%d: 0x%x\n", idx, (uint32_t)gpio_base_addr[idx]);
620 	}
621 
622 	if (nr == 0) {
623 		debug("   - parse gpio address failed\n");
624 		return -EINVAL;
625 	}
626 
627 	initial = 1;
628 
629 	return 0;
630 }
631 
632 /*
633  * How to make it works ?
634  *
635  * 1. pack dtb into rockchip resource.img, require:
636  *    (1) file name end with ".dtb";
637  *    (2) file name contains key words, like: ...#gpio[pin]=[value]...dtb
638  *	  @pin: gpio name, eg. 0a2 means GPIO0A2;
639  *	  @value: gpio level, 0 or 1;
640  *    eg: ...#gpio0a6=1#gpio1c2=0....dtb
641  *
642  * 2. U-Boot dtsi about gpio node:
643  *    (1) enable "u-boot,dm-pre-reloc;" for all gpio node;
644  *    (2) set all gpio status "disabled"(Because we just want their property);
645  */
646 static int rockchip_read_dtb_by_gpio(const char *file_name)
647 {
648 	static uint32_t cached_v[MAX_GPIO_NR];
649 	fdt_addr_t gpio_base_addr[MAX_GPIO_NR];
650 	int ret, found = 0, offset = strlen(KEY_WORDS_GPIO);
651 	uint8_t port, pin, bank, lvl, val;
652 	char *strgpio, *p;
653 	uint32_t bit;
654 
655 	debug("%s\n", file_name);
656 
657 	/* Parse gpio address */
658 	memset(gpio_base_addr, 0, sizeof(gpio_base_addr));
659 	ret = gpio_parse_base_address(gpio_base_addr);
660 	if (ret) {
661 		debug("   - Can't parse gpio base address: %d\n", ret);
662 		return ret;
663 	}
664 
665 	strgpio = strstr(file_name, KEY_WORDS_GPIO);
666 	while (strgpio) {
667 		debug("   - substr: %s\n", strgpio);
668 
669 		p = strgpio + offset;
670 
671 		/* Invalid format ? */
672 		if (!(is_digit(*(p + 0)) && is_abcd(*(p + 1)) &&
673 		      is_digit(*(p + 2)) && is_equal(*(p + 3)) &&
674 		      is_digit(*(p + 4)))) {
675 			debug("   - invalid format: %s\n", strgpio);
676 			return -EINVAL;
677 		}
678 
679 		/* Read gpio value */
680 		port = *(p + 0) - '0';
681 		bank = *(p + 1) - 'a';
682 		pin  = *(p + 2) - '0';
683 		lvl  = *(p + 4) - '0';
684 
685 		/*
686 		 * It doesn't need to read gpio value every loop, reading once
687 		 * is enough. We use cached_v[] to save what we have read, zero
688 		 * means not read before.
689 		 */
690 		if (cached_v[port] == 0) {
691 			if (!gpio_base_addr[port]) {
692 				debug("   - can't find gpio%d base address\n", port);
693 				return 0;
694 			}
695 
696 			/* Input mode */
697 			val = readl(gpio_base_addr[port] + GPIO_SWPORT_DDR);
698 			val &= ~(1 << (bank * 8 + pin));
699 			writel(val, gpio_base_addr[port] + GPIO_SWPORT_DDR);
700 
701 			cached_v[port] =
702 				readl(gpio_base_addr[port] + GPIO_EXT_PORT);
703 		}
704 
705 		/* Verify result */
706 		bit = bank * 8 + pin;
707 		val = cached_v[port] & (1 << bit) ? 1 : 0;
708 
709 		if (val == !!lvl) {
710 			found = 1;
711 			strgpio = strstr(p, KEY_WORDS_GPIO);
712 		} else {
713 			found = 0;
714 			break;
715 		}
716 
717 		debug("   - parse: gpio%d%c%d=%d, read=%d %s\n",
718 		      port, bank + 'a', pin, lvl, val, found ? "(Y)" : "(N)");
719 	}
720 
721 	return found ? 0 : -ENOENT;
722 }
723 
724 #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB
725 static int rockchip_read_distro_dtb_file(char *fdt_addr)
726 {
727 	const char *cmd = "part list ${devtype} ${devnum} -bootable devplist";
728 	char *devnum, *devtype, *devplist;
729 	char devnum_part[12];
730 	char fdt_hex_str[19];
731 	char *fs_argv[5];
732 	int ret;
733 
734 	if (!rockchip_get_bootdev() || !fdt_addr)
735 		return -ENODEV;
736 
737 	ret = run_command_list(cmd, -1, 0);
738 	if (ret)
739 		return ret;
740 
741 	devplist = env_get("devplist");
742 	if (!devplist)
743 		return -ENODEV;
744 
745 	devtype = env_get("devtype");
746 	devnum = env_get("devnum");
747 	sprintf(devnum_part, "%s:%s", devnum, devplist);
748 	sprintf(fdt_hex_str, "0x%lx", (ulong)fdt_addr);
749 
750 #ifdef CONFIG_CMD_FS_GENERIC
751 	fs_argv[0] = "load";
752 	fs_argv[1] = devtype,
753 	fs_argv[2] = devnum_part;
754 	fs_argv[3] = fdt_hex_str;
755 	fs_argv[4] = CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH;
756 
757 	if (do_load(NULL, 0, 5, fs_argv, FS_TYPE_ANY))
758 		return -EIO;
759 #endif
760 	if (fdt_check_header(fdt_addr))
761 		return -EIO;
762 
763 	return fdt_totalsize(fdt_addr);
764 }
765 #endif
766 
767 int rockchip_read_dtb_file(void *fdt_addr)
768 {
769 	struct resource_file *file;
770 	struct list_head *node;
771 	char *dtb_name = DTB_FILE;
772 	int size = -ENODEV;
773 
774 	if (list_empty(&entrys_head)) {
775 		if (init_resource_list(NULL)) {
776 #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB
777 			/* Maybe a distro boot.img with dtb ? */
778 			printf("Distro DTB: %s\n",
779 			       CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH);
780 			size = rockchip_read_distro_dtb_file(fdt_addr);
781 			if (size < 0)
782 				return size;
783 			if (!sysmem_alloc_base(MEMBLK_ID_FDT,
784 				(phys_addr_t)fdt_addr,
785 				ALIGN(size, RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
786 				return -ENOMEM;
787 #endif
788 			return size;
789 		}
790 	}
791 
792 	list_for_each(node, &entrys_head) {
793 		file = list_entry(node, struct resource_file, link);
794 		if (!strstr(file->name, ".dtb"))
795 			continue;
796 
797 		if (strstr(file->name, KEY_WORDS_ADC_CTRL) &&
798 		    strstr(file->name, KEY_WORDS_ADC_CH) &&
799 		    !rockchip_read_dtb_by_adc(file->name)) {
800 			dtb_name = file->name;
801 			break;
802 		} else if (strstr(file->name, KEY_WORDS_GPIO) &&
803 			   !rockchip_read_dtb_by_gpio(file->name)) {
804 			dtb_name = file->name;
805 			break;
806 		}
807 	}
808 
809 	printf("DTB: %s\n", dtb_name);
810 
811 	size = rockchip_get_resource_file_size((void *)fdt_addr, dtb_name);
812 	if (size < 0)
813 		return size;
814 
815 	if (!sysmem_alloc_base(MEMBLK_ID_FDT, (phys_addr_t)fdt_addr,
816 			       ALIGN(size, RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
817 		return -ENOMEM;
818 
819 	size = rockchip_read_resource_file((void *)fdt_addr, dtb_name, 0, 0);
820 	if (size < 0)
821 		return size;
822 
823 #if defined(CONFIG_CMD_DTIMG) && defined(CONFIG_OF_LIBFDT_OVERLAY)
824 	android_fdt_overlay_apply((void *)fdt_addr);
825 #endif
826 
827 	return size;
828 }
829