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