xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/resource_img.c (revision c3e08fa050aa3e8eb31fbd76f4d1e28c00ffe0b4)
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