xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/resource_img.c (revision 33f8d8a65e85191a1fdeeae37fda3fa465daa7e5)
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;
97 	uint32_t	f_size;
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 
188 	/* Delete exist entry, then add this new */
189 	list_for_each(node, &entrys_head) {
190 		file = list_entry(node, struct resource_file, link);
191 		if (!strcmp(file->name, entry->name)) {
192 			list_del(&file->link);
193 			free(file);
194 			break;
195 		}
196 	}
197 
198 	add_file_to_list(entry, base, false);
199 	free(entry);
200 
201 	return 0;
202 }
203 
204 static int read_bmp(struct blk_desc *dev_desc, const char *name,
205 		    disk_partition_t *part, uint32_t offset,
206 		    uint32_t *size)
207 {
208 	struct bmp_header *header;
209 	u32 blk_start, blk_offset;
210 	u32 filesz;
211 	int ret;
212 
213 	blk_offset = DIV_ROUND_UP(offset, dev_desc->blksz);
214 	blk_start = part->start + blk_offset;
215 	header = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz);
216 	if (!header) {
217 		ret = -ENOMEM;
218 		goto out;
219 	}
220 
221 	if (blk_dread(dev_desc, blk_start, 1, header) != 1) {
222 		ret = -EIO;
223 		goto out;
224 	}
225 
226 	if (header->signature[0] != 'B' || header->signature[1] != 'M') {
227 		ret = -EINVAL;
228 		goto out;
229 	}
230 
231 	filesz = get_unaligned_le32(&header->file_size);
232 	ret = replace_resource_entry(name, blk_start, blk_offset, filesz);
233 	if (!ret) {
234 		printf("LOGO: %s\n", name);
235 		if (size)
236 			*size = filesz;
237 	}
238 out:
239 	free(header);
240 
241 	return ret;
242 }
243 
244 /*
245  * Add logo.bmp and logo_kernel.bmp from "logo" parititon
246  *
247  * Provide a "logo" partition for user to store logo.bmp and
248  * logo_kernel.bmp, so that the user can update them from
249  * kernel or user-space dynamically.
250  *
251  * "logo" partition layout, do not change order:
252  *
253  *   |----------------------| 0x00
254  *   | raw logo.bmp	    |
255  *   |----------------------| N*512-byte aligned
256  *   | raw logo_kernel.bmp  |
257  *   |----------------------|
258  *
259  * N: the sector count of logo.bmp
260  */
261 static int read_logo_bmps(struct blk_desc *dev_desc)
262 {
263 	disk_partition_t part;
264 	u32 filesz;
265 
266 	if (part_get_info_by_name(dev_desc, PART_LOGO, &part) < 0)
267 		return -ENODEV;
268 
269 	if (!read_bmp(dev_desc, "logo.bmp", &part, 0, &filesz))
270 		read_bmp(dev_desc, "logo_kernel.bmp", &part, filesz, NULL);
271 
272 	return 0;
273 }
274 
275 static int read_dtb_from_android_v2(int rsce_base, int dtb_offset, int dtb_size)
276 {
277 	if (!dtb_size)
278 		return 0;
279 
280 	/*
281 	 * boot_img_hdr_v2 feature.
282 	 *
283 	 * If dtb position is present, replace the old with new one if
284 	 * we don't need to verify DTB hash from resource.img file entry.
285 	 */
286 #ifndef CONFIG_ROCKCHIP_DTB_VERIFY
287 	if (replace_resource_entry(DTB_FILE, rsce_base, dtb_offset, dtb_size))
288 		printf("Failed to load dtb from v2 dtb position\n");
289 	else
290 #endif
291 		env_update("bootargs", "androidboot.dtb_idx=0");
292 
293 	return 0;
294 }
295 
296 int resource_create_ram_list(struct blk_desc *dev_desc, void *rsce_hdr)
297 {
298 	struct resource_img_hdr *hdr = rsce_hdr;
299 	struct resource_entry *entry;
300 	int e_num, size;
301 	void *data;
302 	int ret = 0;
303 
304 	if (resource_image_check_header(hdr)) {
305 		ret = -EINVAL;
306 		goto out;
307 	}
308 
309 	data = (void *)((ulong)hdr + hdr->c_offset * dev_desc->blksz);
310 	for (e_num = 0; e_num < hdr->e_nums; e_num++) {
311 		size = e_num * hdr->e_blks * dev_desc->blksz;
312 		entry = (struct resource_entry *)(data + size);
313 		add_file_to_list(entry, (ulong)hdr, true);
314 	}
315 out:
316 	read_logo_bmps(dev_desc);
317 
318 	return ret;
319 }
320 
321 static int resource_create_list(struct blk_desc *dev_desc, int rsce_base)
322 {
323 	struct resource_img_hdr *hdr;
324 	struct resource_entry *entry;
325 	int blknum, e_num;
326 	void *data = NULL;
327 	int ret = 0;
328 	int size;
329 
330 	hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz);
331 	if (!hdr)
332 		return -ENOMEM;
333 
334 	if (blk_dread(dev_desc, rsce_base, 1, hdr) != 1) {
335 		printf("Failed to read resource hdr\n");
336 		ret = -EIO;
337 		goto err;
338 	}
339 
340 	if (resource_image_check_header(hdr)) {
341 		if (fdt_check_header(hdr)) {
342 			printf("No valid resource or dtb file\n");
343 			ret = -EINVAL;
344 			goto err;
345 		} else {
346 			free(hdr);
347 			return replace_resource_entry(DTB_FILE, rsce_base,
348 						      0, fdt_totalsize(hdr));
349 		}
350 	}
351 
352 	blknum = hdr->e_blks * hdr->e_nums;
353 	data = memalign(ARCH_DMA_MINALIGN, blknum * dev_desc->blksz);
354 	if (!data) {
355 		ret = -ENOMEM;
356 		goto err;
357 	}
358 
359 	if (blk_dread(dev_desc, rsce_base + hdr->c_offset,
360 		      blknum, data) != blknum) {
361 		printf("Failed to read resource entries\n");
362 		ret = -EIO;
363 		goto err;
364 	}
365 
366 	/*
367 	 * Add all file into resource file list, and load what we want from
368 	 * storage when we really need it.
369 	 */
370 	for (e_num = 0; e_num < hdr->e_nums; e_num++) {
371 		size = e_num * hdr->e_blks * dev_desc->blksz;
372 		entry = (struct resource_entry *)(data + size);
373 		add_file_to_list(entry, rsce_base, false);
374 	}
375 
376 err:
377 	if (data)
378 		free(data);
379 	if (hdr)
380 		free(hdr);
381 
382 	read_logo_bmps(dev_desc);
383 
384 	return ret;
385 }
386 
387 static int get_resource_base_sector(struct blk_desc *dev_desc,
388 				    disk_partition_t *from_part,
389 				    int *dtb_off, int *dtb_size)
390 {
391 	disk_partition_t part;
392 	int rsce_base;
393 #ifdef CONFIG_ANDROID_BOOT_IMAGE
394 	struct andr_img_hdr *hdr;
395 	int blknum;
396 
397 	/*
398 	 * Anyway, we must read android hdr firstly from boot partition to get
399 	 * the 'os_version' for android_bcb_msg_sector_offset(), in order to
400 	 * confirm BCB message offset of misc partition.
401 	 */
402 	if (part_get_info_by_name(dev_desc, PART_BOOT, &part) < 0)
403 		goto resource_part;
404 
405 	blknum = DIV_ROUND_UP(sizeof(*hdr), dev_desc->blksz);
406 	hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz * blknum);
407 	if (!hdr)
408 		return -ENOMEM;
409 
410 	if (blk_dread(dev_desc, part.start, blknum, hdr) != blknum) {
411 		printf("Failed to read %s hdr\n", part.name);
412 		free(hdr);
413 		return -EIO;
414 	}
415 
416 	if (!android_image_check_header(hdr)) {
417 		u32 os_ver, os_lvl;
418 
419 		os_ver = hdr->os_version >> 11;
420 		os_lvl = hdr->os_version & ((1U << 11) - 1);
421 		if (os_ver) {
422 			gd->bd->bi_andr_version = hdr->os_version;
423 			printf("Android %u.%u, Build %u.%u\n",
424 			       (os_ver >> 14) & 0x7F, (os_ver >> 7) & 0x7F,
425 			       (os_lvl >> 4) + 2000, os_lvl & 0x0F);
426 		}
427 	}
428 
429 #ifndef CONFIG_ANDROID_AB
430 	/* Get boot mode from misc and read if recovery mode */
431 	if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) {
432 		if (part_get_info_by_name(dev_desc, PART_RECOVERY, &part) < 0)
433 			goto resource_part;
434 
435 		if (blk_dread(dev_desc, part.start, blknum, hdr) != blknum) {
436 			printf("Failed to read %s hdr\n", part.name);
437 			free(hdr);
438 			return -EIO;
439 		}
440 	}
441 #endif
442 	/* get ! */
443 	if (!android_image_check_header(hdr)) {
444 		rsce_base = part.start * dev_desc->blksz;
445 		rsce_base += hdr->page_size;
446 		rsce_base += ALIGN(hdr->kernel_size, hdr->page_size);
447 		rsce_base += ALIGN(hdr->ramdisk_size, hdr->page_size);
448 
449 		if (hdr->header_version >= 2) {
450 			*dtb_size = hdr->dtb_size;
451 			*dtb_off =
452 				rsce_base +
453 				ALIGN(hdr->recovery_dtbo_size, hdr->page_size) +
454 				ALIGN(hdr->second_size, hdr->page_size);
455 		}
456 
457 		rsce_base = DIV_ROUND_UP(rsce_base, dev_desc->blksz);
458 		*dtb_off = DIV_ROUND_UP(*dtb_off, dev_desc->blksz) - rsce_base;
459 		*from_part = part;
460 		free(hdr);
461 		goto finish;
462 	}
463 resource_part:
464 #endif
465 	/* resource partition */
466 	if (part_get_info_by_name(dev_desc, PART_RESOURCE, &part) < 0) {
467 		printf("No resource partition\n");
468 		return -ENODEV;
469 	}
470 
471 	*from_part = part;
472 	rsce_base = part.start;
473 #ifdef CONFIG_ANDROID_BOOT_IMAGE
474 finish:
475 #endif
476 	printf("Found DTB in %s part\n", part.name);
477 
478 	return rsce_base;
479 }
480 
481 /*
482  * There are: logo/battery pictures and dtb file in the resource image by default.
483  *
484  * This function does:
485  *
486  * 1. Get resource image base sector from: boot/recovery(AOSP) > resource(RK)
487  * 2. Create resource files list(addition: add logo bmps)
488  * 3. Add dtb from android v2 dtb pos, override the old one from resource file
489  */
490 static int init_resource_list(void)
491 {
492 	struct blk_desc *dev_desc;
493 	disk_partition_t part;
494 	int rsce_base;
495 	int dtb_offset;
496 	int dtb_size = 0;
497 
498 	dev_desc = rockchip_get_bootdev();
499 	if (!dev_desc) {
500 		printf("No dev_desc!\n");
501 		return -ENODEV;
502 	}
503 
504 	rsce_base = get_resource_base_sector(dev_desc, &part,
505 					     &dtb_offset, &dtb_size);
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 old one if dtb_size != 0 */
512 	read_dtb_from_android_v2(rsce_base, dtb_offset, dtb_size);
513 
514 	return 0;
515 }
516 
517 static struct resource_file *get_file_info(const char *name)
518 {
519 	struct resource_file *file;
520 	struct list_head *node;
521 
522 	if (list_empty(&entrys_head)) {
523 		if (init_resource_list())
524 			return NULL;
525 	}
526 
527 	list_for_each(node, &entrys_head) {
528 		file = list_entry(node, struct resource_file, link);
529 		if (!strcmp(file->name, name))
530 			return file;
531 	}
532 
533 	return NULL;
534 }
535 
536 /*
537  * read file from resource partition
538  * @buf: destination buf to store file data;
539  * @name: file name
540  * @offset: blocks offset in the file, 1 block = 512 bytes
541  * @len: the size(by bytes) of file to read.
542  */
543 int rockchip_read_resource_file(void *buf, const char *name,
544 				int offset, int len)
545 {
546 	struct resource_file *file;
547 	struct blk_desc *dev_desc;
548 	int ret = 0;
549 	int blks;
550 	ulong src;
551 
552 	file = get_file_info(name);
553 	if (!file) {
554 		printf("No file: %s\n", name);
555 		return -ENOENT;
556 	}
557 
558 	dev_desc = rockchip_get_bootdev();
559 	if (!dev_desc) {
560 		printf("No dev_desc!\n");
561 		return -ENODEV;
562 	}
563 
564 	if (len <= 0 || len > file->f_size)
565 		len = file->f_size;
566 
567 	if (file->ram) {
568 		src = file->rsce_base +
569 			(file->f_offset + offset) * dev_desc->blksz;
570 		memcpy(buf, (char *)src, len);
571 		ret = len;
572 	} else {
573 		blks = DIV_ROUND_UP(len, dev_desc->blksz);
574 		ret = blk_dread(dev_desc,
575 				file->rsce_base + file->f_offset + offset,
576 				blks, buf);
577 		ret = (ret != blks) ? -EIO : len;
578 	}
579 
580 	return ret;
581 }
582 
583 #ifdef CONFIG_ROCKCHIP_HWID_DTB
584 #define is_digit(c)		((c) >= '0' && (c) <= '9')
585 #define is_abcd(c)		((c) >= 'a' && (c) <= 'd')
586 #define is_equal(c)		((c) == '=')
587 
588 #define KEY_WORDS_ADC_CTRL	"#_"
589 #define KEY_WORDS_ADC_CH	"_ch"
590 #define KEY_WORDS_GPIO		"#gpio"
591 #define GPIO_SWPORT_DDR		0x04
592 #define GPIO_EXT_PORT		0x50
593 #define MAX_ADC_CH_NR		10
594 #define MAX_GPIO_NR		10
595 
596 /*
597  * How to make it works ?
598  *
599  * 1. pack dtb into rockchip resource.img, require:
600  *    (1) file name end with ".dtb";
601  *    (2) file name contains key words, like: ...#_[controller]_ch[channel]=[value]...dtb
602  *	  @controller: adc controller name in dts, eg. "saradc", ...;
603  *	  @channel: adc channel;
604  *	  @value: adc value;
605  *    eg: ...#_saradc_ch1=223#_saradc_ch2=650....dtb
606  *
607  * 2. U-Boot dtsi about adc controller node:
608  *    (1) enable "u-boot,dm-pre-reloc;";
609  *    (2) must set status "okay";
610  */
611 static int rockchip_read_dtb_by_adc(const char *file_name)
612 {
613 	static int cached_v[MAX_ADC_CH_NR];
614 	int offset_ctrl = strlen(KEY_WORDS_ADC_CTRL);
615 	int offset_ch = strlen(KEY_WORDS_ADC_CH);
616 	int ret, channel, len = 0, found = 0, margin = 30;
617 	char *stradc, *strch, *p;
618 	char adc_v_string[10];
619 	char dev_name[32];
620 	uint32_t raw_adc;
621 	ulong dtb_adc;
622 
623 	debug("%s: %s\n", __func__, file_name);
624 
625 	/* Invalid format ? */
626 	stradc = strstr(file_name, KEY_WORDS_ADC_CTRL);
627 	while (stradc) {
628 		debug("   - substr: %s\n", stradc);
629 
630 		/* Parse controller name */
631 		strch = strstr(stradc, KEY_WORDS_ADC_CH);
632 		len = strch - (stradc + offset_ctrl);
633 		strlcpy(dev_name, stradc + offset_ctrl, len + 1);
634 
635 		/* Parse adc channel */
636 		p = strch + offset_ch;
637 		if (is_digit(*p) && is_equal(*(p + 1))) {
638 			channel = *p - '0';
639 		} else {
640 			debug("   - invalid format: %s\n", stradc);
641 			return -EINVAL;
642 		}
643 
644 		/*
645 		 * Read raw adc value
646 		 *
647 		 * It doesn't need to read adc value every loop, reading once
648 		 * is enough. We use cached_v[] to save what we have read, zero
649 		 * means not read before.
650 		 */
651 		if (cached_v[channel] == 0) {
652 			ret = adc_channel_single_shot(dev_name,
653 						      channel, &raw_adc);
654 			if (ret) {
655 				debug("   - failed to read adc, ret=%d\n", ret);
656 				return ret;
657 			}
658 			cached_v[channel] = raw_adc;
659 		}
660 
661 		/* Parse dtb adc value */
662 		p = strch + offset_ch + 2;	/* 2: channel and '=' */
663 		while (*p && is_digit(*p)) {
664 			len++;
665 			p++;
666 		}
667 		strlcpy(adc_v_string, strch + offset_ch + 2, len + 1);
668 		dtb_adc = simple_strtoul(adc_v_string, NULL, 10);
669 
670 		if (abs(dtb_adc - cached_v[channel]) <= margin) {
671 			found = 1;
672 			stradc = strstr(p, KEY_WORDS_ADC_CTRL);
673 		} else {
674 			found = 0;
675 			break;
676 		}
677 
678 		debug("   - parse: controller=%s, channel=%d, dtb_adc=%ld, read=%d %s\n",
679 		      dev_name, channel, dtb_adc, cached_v[channel], found ? "(Y)" : "");
680 	}
681 
682 	return found ? 0 : -ENOENT;
683 }
684 
685 static int gpio_parse_base_address(fdt_addr_t *gpio_base_addr)
686 {
687 	static int initialized;
688 	ofnode parent, node;
689 	const char *name;
690 	int idx, nr = 0;
691 
692 	if (initialized)
693 		return 0;
694 
695 	parent = ofnode_path("/pinctrl");
696 	if (!ofnode_valid(parent)) {
697 		debug("   - Can't find pinctrl node\n");
698 		return -EINVAL;
699 	}
700 
701 	ofnode_for_each_subnode(node, parent) {
702 		if (!ofnode_get_property(node, "gpio-controller", NULL)) {
703 			debug("   - Can't find gpio-controller\n");
704 			continue;
705 		}
706 
707 		name = ofnode_get_name(node);
708 		if (!is_digit((char)*(name + 4))) {
709 			debug("   - bad gpio node name: %s\n", name);
710 			continue;
711 		}
712 
713 		nr++;
714 		idx = *(name + 4) - '0';
715 		gpio_base_addr[idx] = ofnode_get_addr(node);
716 		debug("   - gpio%d: 0x%x\n", idx, (uint32_t)gpio_base_addr[idx]);
717 	}
718 
719 	if (nr == 0) {
720 		debug("   - parse gpio address failed\n");
721 		return -EINVAL;
722 	}
723 
724 	initialized = 1;
725 
726 	return 0;
727 }
728 
729 /*
730  * How to make it works ?
731  *
732  * 1. pack dtb into rockchip resource.img, require:
733  *    (1) file name end with ".dtb";
734  *    (2) file name contains key words, like: ...#gpio[pin]=[value]...dtb
735  *	  @pin: gpio name, eg. 0a2 means GPIO0A2;
736  *	  @value: gpio level, 0 or 1;
737  *    eg: ...#gpio0a6=1#gpio1c2=0....dtb
738  *
739  * 2. U-Boot dtsi about gpio node:
740  *    (1) enable "u-boot,dm-pre-reloc;" for all gpio node;
741  *    (2) set all gpio status "disabled"(Because we just want their property);
742  */
743 static int rockchip_read_dtb_by_gpio(const char *file_name)
744 {
745 	static uint32_t cached_v[MAX_GPIO_NR];
746 	fdt_addr_t gpio_base_addr[MAX_GPIO_NR];
747 	int ret, found = 0, offset = strlen(KEY_WORDS_GPIO);
748 	uint8_t port, pin, bank, lvl, val;
749 	char *strgpio, *p;
750 	uint32_t bit;
751 
752 	debug("%s\n", file_name);
753 
754 	/* Parse gpio address */
755 	memset(gpio_base_addr, 0, sizeof(gpio_base_addr));
756 	ret = gpio_parse_base_address(gpio_base_addr);
757 	if (ret) {
758 		debug("   - Can't parse gpio base address: %d\n", ret);
759 		return ret;
760 	}
761 
762 	strgpio = strstr(file_name, KEY_WORDS_GPIO);
763 	while (strgpio) {
764 		debug("   - substr: %s\n", strgpio);
765 
766 		p = strgpio + offset;
767 
768 		/* Invalid format ? */
769 		if (!(is_digit(*(p + 0)) && is_abcd(*(p + 1)) &&
770 		      is_digit(*(p + 2)) && is_equal(*(p + 3)) &&
771 		      is_digit(*(p + 4)))) {
772 			debug("   - invalid format: %s\n", strgpio);
773 			return -EINVAL;
774 		}
775 
776 		/* Read gpio value */
777 		port = *(p + 0) - '0';
778 		bank = *(p + 1) - 'a';
779 		pin  = *(p + 2) - '0';
780 		lvl  = *(p + 4) - '0';
781 
782 		/*
783 		 * It doesn't need to read gpio value every loop, reading once
784 		 * is enough. We use cached_v[] to save what we have read, zero
785 		 * means not read before.
786 		 */
787 		if (cached_v[port] == 0) {
788 			if (!gpio_base_addr[port]) {
789 				debug("   - can't find gpio%d base address\n", port);
790 				return 0;
791 			}
792 
793 			/* Input mode */
794 			val = readl(gpio_base_addr[port] + GPIO_SWPORT_DDR);
795 			val &= ~(1 << (bank * 8 + pin));
796 			writel(val, gpio_base_addr[port] + GPIO_SWPORT_DDR);
797 
798 			cached_v[port] =
799 				readl(gpio_base_addr[port] + GPIO_EXT_PORT);
800 		}
801 
802 		/* Verify result */
803 		bit = bank * 8 + pin;
804 		val = cached_v[port] & (1 << bit) ? 1 : 0;
805 
806 		if (val == !!lvl) {
807 			found = 1;
808 			strgpio = strstr(p, KEY_WORDS_GPIO);
809 		} else {
810 			found = 0;
811 			break;
812 		}
813 
814 		debug("   - parse: gpio%d%c%d=%d, read=%d %s\n",
815 		      port, bank + 'a', pin, lvl, val, found ? "(Y)" : "(N)");
816 	}
817 
818 	return found ? 0 : -ENOENT;
819 }
820 
821 /* Get according to hardware id(GPIO/ADC) */
822 static struct resource_file *rockchip_read_hwid_dtb(void)
823 {
824 	struct resource_file *file;
825 	struct list_head *node;
826 
827 	if (list_empty(&entrys_head)) {
828 		if (init_resource_list())
829 			return NULL;
830 	}
831 
832 	/* Find dtb file according to hardware id(GPIO/ADC) */
833 	list_for_each(node, &entrys_head) {
834 		file = list_entry(node, struct resource_file, link);
835 		if (!strstr(file->name, ".dtb"))
836 			continue;
837 
838 		if (strstr(file->name, KEY_WORDS_ADC_CTRL) &&
839 		    strstr(file->name, KEY_WORDS_ADC_CH) &&
840 		    !rockchip_read_dtb_by_adc(file->name)) {
841 			return file;
842 		} else if (strstr(file->name, KEY_WORDS_GPIO) &&
843 			   !rockchip_read_dtb_by_gpio(file->name)) {
844 			return file;
845 		}
846 	}
847 
848 	return NULL;
849 }
850 #endif
851 
852 int rockchip_read_resource_dtb(void *fdt_addr, char **hash, int *hash_size)
853 {
854 	struct resource_file *file;
855 	int ret;
856 
857 #ifdef CONFIG_ROCKCHIP_HWID_DTB
858 	file = rockchip_read_hwid_dtb();
859 	/* If dtbs matched hardware id(GPIO/ADC) not found, try the default */
860 	if (!file)
861 		file = get_file_info(DTB_FILE);
862 #else
863 	file = get_file_info(DTB_FILE);
864 #endif
865 	if (!file)
866 		return -ENODEV;
867 
868 	ret = rockchip_read_resource_file(fdt_addr, file->name, 0, 0);
869 	if (ret < 0)
870 		return ret;
871 
872 	if (fdt_check_header(fdt_addr))
873 		return -EBADF;
874 
875 	*hash = file->hash;
876 	*hash_size = file->hash_size;
877 	printf("DTB: %s\n", file->name);
878 
879 	return 0;
880 }
881