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