xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/resource_img.c (revision 2a3fb7bb049d69d96f3bc7dae8caa756fdc8a613)
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 GPIO_SWPORT_DDR		0x04
590 #define GPIO_EXT_PORT		0x50
591 #define MAX_ADC_CH_NR		10
592 #define MAX_GPIO_NR		10
593 
594 /*
595  * How to make it works ?
596  *
597  * 1. pack dtb into rockchip resource.img, require:
598  *    (1) file name end with ".dtb";
599  *    (2) file name contains key words, like: ...#_[controller]_ch[channel]=[value]...dtb
600  *	  @controller: adc controller name in dts, eg. "saradc", ...;
601  *	  @channel: adc channel;
602  *	  @value: adc value;
603  *    eg: ...#_saradc_ch1=223#_saradc_ch2=650....dtb
604  *
605  * 2. U-Boot dtsi about adc controller node:
606  *    (1) enable "u-boot,dm-pre-reloc;";
607  *    (2) must set status "okay";
608  */
609 static int rockchip_read_dtb_by_adc(const char *file_name)
610 {
611 	static int cached_v[MAX_ADC_CH_NR];
612 	int offset_ctrl = strlen(KEY_WORDS_ADC_CTRL);
613 	int offset_ch = strlen(KEY_WORDS_ADC_CH);
614 	int ret, channel, len = 0, found = 0, margin = 30;
615 	char *stradc, *strch, *p;
616 	char adc_v_string[10];
617 	char dev_name[32];
618 	uint32_t raw_adc;
619 	ulong dtb_adc;
620 
621 	debug("%s: %s\n", __func__, file_name);
622 
623 	/* Invalid format ? */
624 	stradc = strstr(file_name, KEY_WORDS_ADC_CTRL);
625 	while (stradc) {
626 		debug("   - substr: %s\n", stradc);
627 
628 		/* Parse controller name */
629 		strch = strstr(stradc, KEY_WORDS_ADC_CH);
630 		len = strch - (stradc + offset_ctrl);
631 		strlcpy(dev_name, stradc + offset_ctrl, len + 1);
632 
633 		/* Parse adc channel */
634 		p = strch + offset_ch;
635 		if (is_digit(*p) && is_equal(*(p + 1))) {
636 			channel = *p - '0';
637 		} else {
638 			debug("   - invalid format: %s\n", stradc);
639 			return -EINVAL;
640 		}
641 
642 		/*
643 		 * Read raw adc value
644 		 *
645 		 * It doesn't need to read adc value every loop, reading once
646 		 * is enough. We use cached_v[] to save what we have read, zero
647 		 * means not read before.
648 		 */
649 		if (cached_v[channel] == 0) {
650 			ret = adc_channel_single_shot(dev_name,
651 						      channel, &raw_adc);
652 			if (ret) {
653 				debug("   - failed to read adc, ret=%d\n", ret);
654 				return ret;
655 			}
656 			cached_v[channel] = raw_adc;
657 		}
658 
659 		/* Parse dtb adc value */
660 		p = strch + offset_ch + 2;	/* 2: channel and '=' */
661 		while (*p && is_digit(*p)) {
662 			len++;
663 			p++;
664 		}
665 		strlcpy(adc_v_string, strch + offset_ch + 2, len + 1);
666 		dtb_adc = simple_strtoul(adc_v_string, NULL, 10);
667 
668 		if (abs(dtb_adc - cached_v[channel]) <= margin) {
669 			found = 1;
670 			stradc = strstr(p, KEY_WORDS_ADC_CTRL);
671 		} else {
672 			found = 0;
673 			break;
674 		}
675 
676 		debug("   - parse: controller=%s, channel=%d, dtb_adc=%ld, read=%d %s\n",
677 		      dev_name, channel, dtb_adc, cached_v[channel], found ? "(Y)" : "");
678 	}
679 
680 	return found ? 0 : -ENOENT;
681 }
682 
683 static int gpio_parse_base_address(fdt_addr_t *gpio_base_addr)
684 {
685 	static int initialized;
686 	ofnode parent, node;
687 	const char *name;
688 	int idx, nr = 0;
689 
690 	if (initialized)
691 		return 0;
692 
693 	parent = ofnode_path("/pinctrl");
694 	if (!ofnode_valid(parent)) {
695 		debug("   - Can't find pinctrl node\n");
696 		return -EINVAL;
697 	}
698 
699 	ofnode_for_each_subnode(node, parent) {
700 		if (!ofnode_get_property(node, "gpio-controller", NULL)) {
701 			debug("   - Can't find gpio-controller\n");
702 			continue;
703 		}
704 
705 		name = ofnode_get_name(node);
706 		if (!is_digit((char)*(name + 4))) {
707 			debug("   - bad gpio node name: %s\n", name);
708 			continue;
709 		}
710 
711 		nr++;
712 		idx = *(name + 4) - '0';
713 		gpio_base_addr[idx] = ofnode_get_addr(node);
714 		debug("   - gpio%d: 0x%x\n", idx, (uint32_t)gpio_base_addr[idx]);
715 	}
716 
717 	if (nr == 0) {
718 		debug("   - parse gpio address failed\n");
719 		return -EINVAL;
720 	}
721 
722 	initialized = 1;
723 
724 	return 0;
725 }
726 
727 /*
728  * How to make it works ?
729  *
730  * 1. pack dtb into rockchip resource.img, require:
731  *    (1) file name end with ".dtb";
732  *    (2) file name contains key words, like: ...#gpio[pin]=[value]...dtb
733  *	  @pin: gpio name, eg. 0a2 means GPIO0A2;
734  *	  @value: gpio level, 0 or 1;
735  *    eg: ...#gpio0a6=1#gpio1c2=0....dtb
736  *
737  * 2. U-Boot dtsi about gpio node:
738  *    (1) enable "u-boot,dm-pre-reloc;" for all gpio node;
739  *    (2) set all gpio status "disabled"(Because we just want their property);
740  */
741 static int rockchip_read_dtb_by_gpio(const char *file_name)
742 {
743 	static uint32_t cached_v[MAX_GPIO_NR];
744 	fdt_addr_t gpio_base_addr[MAX_GPIO_NR];
745 	int ret, found = 0, offset = strlen(KEY_WORDS_GPIO);
746 	uint8_t port, pin, bank, lvl, val;
747 	char *strgpio, *p;
748 	uint32_t bit;
749 
750 	debug("%s\n", file_name);
751 
752 	/* Parse gpio address */
753 	memset(gpio_base_addr, 0, sizeof(gpio_base_addr));
754 	ret = gpio_parse_base_address(gpio_base_addr);
755 	if (ret) {
756 		debug("   - Can't parse gpio base address: %d\n", ret);
757 		return ret;
758 	}
759 
760 	strgpio = strstr(file_name, KEY_WORDS_GPIO);
761 	while (strgpio) {
762 		debug("   - substr: %s\n", strgpio);
763 
764 		p = strgpio + offset;
765 
766 		/* Invalid format ? */
767 		if (!(is_digit(*(p + 0)) && is_abcd(*(p + 1)) &&
768 		      is_digit(*(p + 2)) && is_equal(*(p + 3)) &&
769 		      is_digit(*(p + 4)))) {
770 			debug("   - invalid format: %s\n", strgpio);
771 			return -EINVAL;
772 		}
773 
774 		/* Read gpio value */
775 		port = *(p + 0) - '0';
776 		bank = *(p + 1) - 'a';
777 		pin  = *(p + 2) - '0';
778 		lvl  = *(p + 4) - '0';
779 
780 		/*
781 		 * It doesn't need to read gpio value every loop, reading once
782 		 * is enough. We use cached_v[] to save what we have read, zero
783 		 * means not read before.
784 		 */
785 		if (cached_v[port] == 0) {
786 			if (!gpio_base_addr[port]) {
787 				debug("   - can't find gpio%d base address\n", port);
788 				return 0;
789 			}
790 
791 			/* Input mode */
792 			val = readl(gpio_base_addr[port] + GPIO_SWPORT_DDR);
793 			val &= ~(1 << (bank * 8 + pin));
794 			writel(val, gpio_base_addr[port] + GPIO_SWPORT_DDR);
795 
796 			cached_v[port] =
797 				readl(gpio_base_addr[port] + GPIO_EXT_PORT);
798 		}
799 
800 		/* Verify result */
801 		bit = bank * 8 + pin;
802 		val = cached_v[port] & (1 << bit) ? 1 : 0;
803 
804 		if (val == !!lvl) {
805 			found = 1;
806 			strgpio = strstr(p, KEY_WORDS_GPIO);
807 		} else {
808 			found = 0;
809 			break;
810 		}
811 
812 		debug("   - parse: gpio%d%c%d=%d, read=%d %s\n",
813 		      port, bank + 'a', pin, lvl, val, found ? "(Y)" : "(N)");
814 	}
815 
816 	return found ? 0 : -ENOENT;
817 }
818 
819 /* Get according to hardware id(GPIO/ADC) */
820 static struct resource_file *rockchip_read_hwid_dtb(void)
821 {
822 	struct resource_file *file;
823 	struct list_head *node;
824 
825 	if (list_empty(&entrys_head)) {
826 		if (init_resource_list())
827 			return NULL;
828 	}
829 
830 	/* Find dtb file according to hardware id(GPIO/ADC) */
831 	list_for_each(node, &entrys_head) {
832 		file = list_entry(node, struct resource_file, link);
833 		if (!strstr(file->name, ".dtb"))
834 			continue;
835 
836 		if (strstr(file->name, KEY_WORDS_ADC_CTRL) &&
837 		    strstr(file->name, KEY_WORDS_ADC_CH) &&
838 		    !rockchip_read_dtb_by_adc(file->name)) {
839 			return file;
840 		} else if (strstr(file->name, KEY_WORDS_GPIO) &&
841 			   !rockchip_read_dtb_by_gpio(file->name)) {
842 			return file;
843 		}
844 	}
845 
846 	return NULL;
847 }
848 #endif
849 
850 int rockchip_read_resource_dtb(void *fdt_addr, char **hash, int *hash_size)
851 {
852 	struct resource_file *file;
853 	int ret;
854 
855 #ifdef CONFIG_ROCKCHIP_HWID_DTB
856 	file = rockchip_read_hwid_dtb();
857 	/* If dtbs matched hardware id(GPIO/ADC) not found, try the default */
858 	if (!file)
859 		file = get_file_info(DTB_FILE);
860 #else
861 	file = get_file_info(DTB_FILE);
862 #endif
863 	if (!file)
864 		return -ENODEV;
865 
866 	ret = rockchip_read_resource_file(fdt_addr, file->name, 0, 0);
867 	if (ret < 0)
868 		return ret;
869 
870 	if (fdt_check_header(fdt_addr))
871 		return -EBADF;
872 
873 	*hash = file->hash;
874 	*hash_size = file->hash_size;
875 	printf("DTB: %s\n", file->name);
876 
877 	return 0;
878 }
879