xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/resource_img.c (revision fec9980f93fa667caac9706bb08d2001a63ea3e1)
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 <dm/ofnode.h>
19 #include <linux/list.h>
20 #include <u-boot/sha1.h>
21 #include <u-boot/sha256.h>
22 #include <asm/arch/resource_img.h>
23 
24 DECLARE_GLOBAL_DATA_PTR;
25 
26 #define PART_RESOURCE			"resource"
27 #define RESOURCE_MAGIC			"RSCE"
28 #define RESOURCE_MAGIC_SIZE		4
29 #define RESOURCE_VERSION		0
30 #define CONTENT_VERSION			0
31 #define ENTRY_TAG			"ENTR"
32 #define ENTRY_TAG_SIZE			4
33 #define MAX_FILE_NAME_LEN		220
34 #define MAX_HASH_LEN			32
35 
36 #define DTB_FILE			"rk-kernel.dtb"
37 
38 /*
39  *         resource image structure
40  * ----------------------------------------------
41  * |                                            |
42  * |    header  (1 block)                       |
43  * |                                            |
44  * ---------------------------------------------|
45  * |                      |                     |
46  * |    entry0  (1 block) |                     |
47  * |                      |                     |
48  * ------------------------                     |
49  * |                      |                     |
50  * |    entry1  (1 block) | contents (n blocks) |
51  * |                      |                     |
52  * ------------------------                     |
53  * |    ......            |                     |
54  * ------------------------                     |
55  * |                      |                     |
56  * |    entryn  (1 block) |                     |
57  * |                      |                     |
58  * ----------------------------------------------
59  * |                                            |
60  * |    file0  (x blocks)                       |
61  * |                                            |
62  * ----------------------------------------------
63  * |                                            |
64  * |    file1  (y blocks)                       |
65  * |                                            |
66  * ----------------------------------------------
67  * |                   ......                   |
68  * |---------------------------------------------
69  * |                                            |
70  * |    filen  (z blocks)                       |
71  * |                                            |
72  * ----------------------------------------------
73  */
74 
75 /**
76  * struct resource_image_header
77  *
78  * @magic: should be "RSCE"
79  * @version: resource image version, current is 0
80  * @c_version: content version, current is 0
81  * @blks: the size of the header ( 1 block = 512 bytes)
82  * @c_offset: contents offset(by block) in the image
83  * @e_blks: the size(by block) of the entry in the contents
84  * @e_num: numbers of the entrys.
85  */
86 
87 struct resource_img_hdr {
88 	char		magic[4];
89 	uint16_t	version;
90 	uint16_t	c_version;
91 	uint8_t		blks;
92 	uint8_t		c_offset;
93 	uint8_t		e_blks;
94 	uint32_t	e_nums;
95 };
96 
97 struct resource_entry {
98 	char		tag[4];
99 	char		name[MAX_FILE_NAME_LEN];
100 	char		hash[MAX_HASH_LEN];
101 	uint32_t	hash_size;
102 	uint32_t	f_offset;
103 	uint32_t	f_size;
104 };
105 
106 struct resource_file {
107 	char		name[MAX_FILE_NAME_LEN];
108 	char		hash[MAX_HASH_LEN];
109 	uint32_t	hash_size;
110 	uint32_t	f_offset;	/* Sector addr */
111 	uint32_t	f_size;		/* Bytes */
112 	struct list_head link;
113 	uint32_t	rsce_base;	/* Base addr of resource */
114 };
115 
116 static LIST_HEAD(entrys_head);
117 
118 static int resource_image_check_header(const struct resource_img_hdr *hdr)
119 {
120 	int ret;
121 
122 	ret = memcmp(RESOURCE_MAGIC, hdr->magic, RESOURCE_MAGIC_SIZE);
123 	if (ret) {
124 		debug("bad resource image magic: %s\n",
125 		      hdr->magic ? hdr->magic : "none");
126 		ret = -EINVAL;
127 	}
128 
129 	debug("resource image header:\n");
130 	debug("magic:%s\n", hdr->magic);
131 	debug("version:%d\n", hdr->version);
132 	debug("c_version:%d\n", hdr->c_version);
133 	debug("blks:%d\n", hdr->blks);
134 	debug("c_offset:%d\n", hdr->c_offset);
135 	debug("e_blks:%d\n", hdr->e_blks);
136 	debug("e_num:%d\n", hdr->e_nums);
137 
138 	return ret;
139 }
140 
141 static int add_file_to_list(struct resource_entry *entry, int rsce_base)
142 {
143 	struct resource_file *file;
144 
145 	if (memcmp(entry->tag, ENTRY_TAG, ENTRY_TAG_SIZE)) {
146 		printf("invalid entry tag\n");
147 		return -ENOENT;
148 	}
149 
150 	file = malloc(sizeof(*file));
151 	if (!file) {
152 		printf("out of memory\n");
153 		return -ENOMEM;
154 	}
155 
156 	strcpy(file->name, entry->name);
157 	file->rsce_base = rsce_base;
158 	file->f_offset = entry->f_offset;
159 	file->f_size = entry->f_size;
160 	file->hash_size = entry->hash_size;
161 	memcpy(file->hash, entry->hash, entry->hash_size);
162 	list_add_tail(&file->link, &entrys_head);
163 
164 	debug("entry:%p  %s offset:%d size:%d\n",
165 	      entry, file->name, file->f_offset, file->f_size);
166 
167 	return 0;
168 }
169 
170 static int replace_resource_entry(const char *f_name, uint32_t base,
171 				  uint32_t f_offset, uint32_t f_size)
172 {
173 	struct resource_entry *entry;
174 	struct resource_file *file;
175 	struct list_head *node;
176 
177 	if (!f_name || !f_size)
178 		return -EINVAL;
179 
180 	entry = malloc(sizeof(*entry));
181 	if (!entry)
182 		return -ENOMEM;
183 
184 	strcpy(entry->tag, ENTRY_TAG);
185 	strcpy(entry->name, f_name);
186 	entry->f_offset = f_offset;
187 	entry->f_size = f_size;
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);
200 	free(entry);
201 
202 	return 0;
203 }
204 
205 static int read_logo_bmp(const char *name, disk_partition_t *part,
206 			 uint32_t offset, uint32_t *size)
207 {
208 	struct blk_desc *dev_desc;
209 	struct bmp_header *header;
210 	u32 blk_start, blk_offset, filesz;
211 	int ret;
212 
213 	dev_desc = rockchip_get_bootdev();
214 	if (!dev_desc)
215 		return -ENODEV;
216 
217 	blk_offset = DIV_ROUND_UP(offset, dev_desc->blksz);
218 	blk_start = part->start + blk_offset;
219 	header = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz);
220 	if (!header) {
221 		ret = -ENOMEM;
222 		goto err;
223 	}
224 	ret = blk_dread(dev_desc, blk_start, 1, header);
225 	if (ret != 1) {
226 		ret = -EIO;
227 		goto err;
228 	}
229 
230 	if (header->signature[0] != 'B' ||
231 	    header->signature[1] != 'M') {
232 		ret = -EINVAL;
233 		goto err;
234 	}
235 
236 	filesz = get_unaligned_le32(&header->file_size);
237 	ret = replace_resource_entry(name, blk_start, blk_offset, filesz);
238 	if (!ret) {
239 		printf("LOGO: %s\n", name);
240 		if (size)
241 			*size = filesz;
242 	}
243 err:
244 	free(header);
245 
246 	return ret;
247 }
248 /*
249  * There are: logo/battery pictures and dtb file in the resource image by default.
250  *
251  * This function does:
252  *
253  * 1. Get resource image from part: boot/recovery(AOSP) > resource(RK);
254  * 2. Add all file into resource list(We load them from storage when we need);
255  * 3. Add logo picture from logo partition into resource list(replace the
256  *    old one in resource file);
257  * 4. Add dtb file from dtb position into resource list if boot_img_hdr_v2
258  *    (replace the old one in resource file);
259  */
260 static int init_resource_list(struct resource_img_hdr *hdr)
261 {
262 	struct resource_entry *entry;
263 	struct blk_desc *dev_desc;
264 	char *boot_partname = PART_BOOT;
265 	disk_partition_t part_info;
266 	int resource_found = 0;
267 	void *content = NULL;
268 	int rsce_base = 0;
269 	__maybe_unused int dtb_offset = 0;
270 	int dtb_size = 0;
271 	int e_num, cnt;
272 	int size;
273 	int ret;
274 
275 	dev_desc = rockchip_get_bootdev();
276 	if (!dev_desc) {
277 		printf("%s: dev_desc is NULL!\n", __func__);
278 		return -ENODEV;
279 	}
280 
281 	/* If hdr is valid from outside, use it */
282 	if (hdr) {
283 		if (resource_image_check_header(hdr))
284 			return -EEXIST;
285 
286 		content = (void *)((char *)hdr +
287 				(hdr->c_offset) * dev_desc->blksz);
288 		for (e_num = 0; e_num < hdr->e_nums; e_num++) {
289 			size = e_num * hdr->e_blks * dev_desc->blksz;
290 			entry = (struct resource_entry *)(content + size);
291 			add_file_to_list(entry, rsce_base);
292 		}
293 		return 0;
294 	}
295 
296 	cnt = DIV_ROUND_UP(sizeof(struct andr_img_hdr), dev_desc->blksz);
297 	hdr = memalign(ARCH_DMA_MINALIGN, dev_desc->blksz * cnt);
298 	if (!hdr)
299 		return -ENOMEM;
300 
301 	/*
302 	 * Anyway, we must read android hdr firstly from boot partition to get
303 	 * the 'os_version' for android_bcb_msg_sector_offset() to confirm BCB
304 	 * message offset of misc partition.
305 	 */
306 #ifdef CONFIG_ANDROID_BOOT_IMAGE
307 	struct andr_img_hdr *andr_hdr;
308 
309 	ret = part_get_info_by_name(dev_desc, boot_partname, &part_info);
310 	if (ret < 0) {
311 		printf("%s: failed to get %s part, ret=%d\n",
312 		       __func__, boot_partname, ret);
313 		goto parse_resource_part;
314 	}
315 
316 	andr_hdr = (void *)hdr;
317 	ret = blk_dread(dev_desc, part_info.start, cnt, andr_hdr);
318 	if (ret != cnt) {
319 		printf("%s: failed to read %s hdr, ret=%d\n",
320 		       __func__, part_info.name, ret);
321 		ret = -EIO;
322 		goto out;
323 	}
324 
325 	ret = android_image_check_header(andr_hdr);
326 	if (!ret) {
327 		u32 os_ver = andr_hdr->os_version >> 11;
328 		u32 os_lvl = andr_hdr->os_version & ((1U << 11) - 1);
329 
330 		if (os_ver) {
331 			gd->bd->bi_andr_version = andr_hdr->os_version;
332 			printf("Android %u.%u, Build %u.%u\n",
333 			       (os_ver >> 14) & 0x7F, (os_ver >> 7) & 0x7F,
334 			       (os_lvl >> 4) + 2000, os_lvl & 0x0F);
335 		}
336 	}
337 
338 	/* Get boot mode from misc and read if recovery mode */
339 #ifndef CONFIG_ANDROID_AB
340 	if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) {
341 		boot_partname = PART_RECOVERY;
342 
343 		ret = part_get_info_by_name(dev_desc, boot_partname, &part_info);
344 		if (ret < 0) {
345 			printf("%s: failed to get %s part, ret=%d\n",
346 			       __func__, boot_partname, ret);
347 			goto parse_resource_part;
348 		}
349 
350 		/* Try to find resource from android second position */
351 		andr_hdr = (void *)hdr;
352 		ret = blk_dread(dev_desc, part_info.start, cnt, andr_hdr);
353 		if (ret != cnt) {
354 			printf("%s: failed to read %s hdr, ret=%d\n",
355 			       __func__, part_info.name, ret);
356 			ret = -EIO;
357 			goto out;
358 		}
359 	}
360 #endif
361 
362 	ret = android_image_check_header(andr_hdr);
363 	if (!ret) {
364 		rsce_base = part_info.start * dev_desc->blksz;
365 		rsce_base += andr_hdr->page_size;
366 		rsce_base += ALIGN(andr_hdr->kernel_size, andr_hdr->page_size);
367 		rsce_base += ALIGN(andr_hdr->ramdisk_size, andr_hdr->page_size);
368 
369 		if (andr_hdr->header_version >= 2) {
370 			dtb_offset = rsce_base +
371 			     ALIGN(andr_hdr->recovery_dtbo_size,
372 				   andr_hdr->page_size) +
373 			     ALIGN(andr_hdr->second_size, andr_hdr->page_size);
374 			dtb_size = andr_hdr->dtb_size;
375 		}
376 
377 		rsce_base = DIV_ROUND_UP(rsce_base, dev_desc->blksz);
378 		dtb_offset =
379 			DIV_ROUND_UP(dtb_offset, dev_desc->blksz) - rsce_base;
380 		resource_found = 1;
381 	}
382 parse_resource_part:
383 #endif  /* CONFIG_ANDROID_BOOT_IMAGE*/
384 
385 	/* If not find android image, get resource file from resource part */
386 	if (!resource_found) {
387 		boot_partname = PART_RESOURCE;
388 		ret = part_get_info_by_name(dev_desc, boot_partname, &part_info);
389 		if (ret < 0) {
390 			printf("%s: failed to get resource part, ret=%d\n",
391 			       __func__, ret);
392 			goto out;
393 		}
394 		rsce_base = part_info.start;
395 	}
396 
397 	/*
398 	 * Now, the "rsce_base" points to the resource file sector.
399 	 */
400 	ret = blk_dread(dev_desc, rsce_base, 1, hdr);
401 	if (ret != 1) {
402 		printf("%s: failed to read resource hdr, ret=%d\n",
403 		       __func__, ret);
404 		ret = -EIO;
405 		goto out;
406 	}
407 
408 	ret = resource_image_check_header(hdr);
409 	if (ret < 0) {
410 		ret = -EINVAL;
411 		goto parse_second_pos_dtb;
412 	}
413 
414 	content = memalign(ARCH_DMA_MINALIGN,
415 			   hdr->e_blks * hdr->e_nums * dev_desc->blksz);
416 	if (!content) {
417 		printf("%s: failed to alloc memory for content\n", __func__);
418 		ret = -ENOMEM;
419 		goto out;
420 	}
421 
422 	ret = blk_dread(dev_desc, rsce_base + hdr->c_offset,
423 			hdr->e_blks * hdr->e_nums, content);
424 	if (ret != (hdr->e_blks * hdr->e_nums)) {
425 		printf("%s: failed to read resource entries, ret=%d\n",
426 		       __func__, ret);
427 		ret = -EIO;
428 		goto err;
429 	}
430 
431 	/*
432 	 * Add all file into resource file list, and load what we want from
433 	 * storage when we really need it.
434 	 */
435 	for (e_num = 0; e_num < hdr->e_nums; e_num++) {
436 		size = e_num * hdr->e_blks * dev_desc->blksz;
437 		entry = (struct resource_entry *)(content + size);
438 		add_file_to_list(entry, rsce_base);
439 	}
440 
441 	ret = 0;
442 	printf("Found DTB in %s part\n", boot_partname);
443 
444 parse_second_pos_dtb:
445 #ifdef CONFIG_ANDROID_BOOT_IMAGE
446 	/*
447 	 * If not find resource file on above, we try to get dtb file from
448 	 * android second position.
449 	 */
450 	if (!content && !fdt_check_header((void *)hdr)) {
451 		entry = malloc(sizeof(*entry));
452 		if (!entry) {
453 			ret = -ENOMEM;
454 			goto parse_logo;
455 		}
456 
457 		memcpy(entry->tag, ENTRY_TAG, sizeof(ENTRY_TAG));
458 		memcpy(entry->name, DTB_FILE, sizeof(DTB_FILE));
459 		entry->f_size = fdt_totalsize((void *)hdr);
460 		entry->f_offset = 0;
461 
462 		add_file_to_list(entry, part_info.start);
463 		free(entry);
464 		ret = 0;
465 		printf("Found DTB in %s part(second pos)\n", boot_partname);
466 	}
467 
468 parse_logo:
469 #endif
470 	/*
471 	 * Add logo.bmp and logo_kernel.bmp from "logo" parititon
472 	 *
473 	 * Provide a "logo" partition for user to store logo.bmp and
474 	 * logo_kernel.bmp, so that the users can update them from
475 	 * kernel or user-space dynamically.
476 	 *
477 	 * "logo" partition layout, not change order:
478 	 *
479 	 *   |----------------------| 0x00
480 	 *   | raw logo.bmp         |
481 	 *   |----------------------| N*512-byte aligned
482 	 *   | raw logo_kernel.bmp  |
483 	 *   |----------------------|
484 	 *
485 	 * N: the sector count of logo.bmp
486 	 */
487 	if (part_get_info_by_name(dev_desc, PART_LOGO, &part_info) >= 0) {
488 		u32 filesz;
489 
490 		if (!read_logo_bmp("logo.bmp", &part_info, 0, &filesz))
491 			read_logo_bmp("logo_kernel.bmp", &part_info,
492 				      filesz, NULL);
493 	}
494 
495 	/*
496 	 * boot_img_hdr_v2 feature.
497 	 *
498 	 * If dtb position is present, replace the old with new one if
499 	 * we don't need to verify DTB hash from resource.img file entry.
500 	 */
501 	if (dtb_size) {
502 #ifndef CONFIG_ROCKCHIP_DTB_VERIFY
503 		ret = replace_resource_entry(DTB_FILE, rsce_base,
504 					     dtb_offset, dtb_size);
505 		if (ret)
506 			printf("Failed to load dtb from dtb position\n");
507 		else
508 #endif
509 			env_update("bootargs", "androidboot.dtb_idx=0");
510 	}
511 err:
512 	if (content)
513 		free(content);
514 out:
515 	free(hdr);
516 
517 	return ret;
518 }
519 
520 static struct resource_file *get_file_info(struct resource_img_hdr *hdr,
521 					   const char *name)
522 {
523 	struct resource_file *file;
524 	struct list_head *node;
525 
526 	if (list_empty(&entrys_head)) {
527 		if (init_resource_list(hdr))
528 			return NULL;
529 	}
530 
531 	list_for_each(node, &entrys_head) {
532 		file = list_entry(node, struct resource_file, link);
533 		if (!strcmp(file->name, name))
534 			return file;
535 	}
536 
537 	return NULL;
538 }
539 
540 /*
541  * read file from resource partition
542  * @buf: destination buf to store file data;
543  * @name: file name
544  * @offset: blocks offset in the file, 1 block = 512 bytes
545  * @len: the size(by bytes) of file to read.
546  */
547 int rockchip_read_resource_file(void *buf, const char *name,
548 				int offset, int len)
549 {
550 	struct resource_file *file;
551 	struct blk_desc *dev_desc;
552 	int ret = 0;
553 	int blks;
554 
555 	dev_desc = rockchip_get_bootdev();
556 	if (!dev_desc) {
557 		printf("%s: dev_desc is NULL!\n", __func__);
558 		return -ENODEV;
559 	}
560 
561 	file = get_file_info(NULL, name);
562 	if (!file) {
563 		printf("Can't find file:%s\n", name);
564 		return -ENOENT;
565 	}
566 
567 	if (len <= 0 || len > file->f_size)
568 		len = file->f_size;
569 
570 	blks = DIV_ROUND_UP(len, dev_desc->blksz);
571 	ret = blk_dread(dev_desc, file->rsce_base + file->f_offset + offset,
572 			blks, buf);
573 	if (ret != blks)
574 		ret = -EIO;
575 	else
576 		ret = len;
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 	/* Find dtb file according to hardware id(GPIO/ADC) */
826 	list_for_each(node, &entrys_head) {
827 		file = list_entry(node, struct resource_file, link);
828 		if (!strstr(file->name, ".dtb"))
829 			continue;
830 
831 		if (strstr(file->name, KEY_WORDS_ADC_CTRL) &&
832 		    strstr(file->name, KEY_WORDS_ADC_CH) &&
833 		    !rockchip_read_dtb_by_adc(file->name)) {
834 			return file;
835 		} else if (strstr(file->name, KEY_WORDS_GPIO) &&
836 			   !rockchip_read_dtb_by_gpio(file->name)) {
837 			return file;
838 		}
839 	}
840 
841 	return NULL;
842 }
843 #endif
844 
845 #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB
846 static int rockchip_read_distro_dtb(void *fdt_addr)
847 {
848 	const char *cmd = "part list ${devtype} ${devnum} -bootable devplist";
849 	char *devnum, *devtype, *devplist;
850 	char devnum_part[12];
851 	char fdt_hex_str[19];
852 	char *fs_argv[5];
853 	int size;
854 	int ret;
855 
856 	if (!rockchip_get_bootdev() || !fdt_addr)
857 		return -ENODEV;
858 
859 	ret = run_command_list(cmd, -1, 0);
860 	if (ret)
861 		return ret;
862 
863 	devplist = env_get("devplist");
864 	if (!devplist)
865 		return -ENODEV;
866 
867 	devtype = env_get("devtype");
868 	devnum = env_get("devnum");
869 	sprintf(devnum_part, "%s:%s", devnum, devplist);
870 	sprintf(fdt_hex_str, "0x%lx", (ulong)fdt_addr);
871 
872 #ifdef CONFIG_CMD_FS_GENERIC
873 	fs_argv[0] = "load";
874 	fs_argv[1] = devtype,
875 	fs_argv[2] = devnum_part;
876 	fs_argv[3] = fdt_hex_str;
877 	fs_argv[4] = CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH;
878 
879 	if (do_load(NULL, 0, 5, fs_argv, FS_TYPE_ANY))
880 		return -EIO;
881 #endif
882 	if (fdt_check_header(fdt_addr))
883 		return -EIO;
884 
885 	size = fdt_totalsize(fdt_addr);
886 	if (!sysmem_alloc_base(MEMBLK_ID_FDT, (phys_addr_t)fdt_addr,
887 			       ALIGN(size, RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
888 		return -ENOMEM;
889 
890 	printf("Distro DTB: %s\n", CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH);
891 
892 	return size;
893 }
894 #endif
895 
896 #ifdef CONFIG_ROCKCHIP_DTB_VERIFY
897 #ifdef CONFIG_DM_CRYPTO
898 static int crypto_csum(u32 cap, char *input, u32 input_len, u8 *output)
899 {
900 	sha_context csha_ctx;
901 	struct udevice *dev;
902 
903 	dev = crypto_get_device(cap);
904 	if (!dev) {
905 		printf("Can't find expected crypto device\n");
906 		return -ENODEV;
907 	}
908 
909 	csha_ctx.algo = cap;
910 	csha_ctx.length = input_len;
911 	crypto_sha_csum(dev, &csha_ctx, (char *)input,
912 			input_len, output);
913 
914 	return 0;
915 }
916 
917 static int fdt_check_hash(void *fdt_addr, struct resource_file *file)
918 {
919 	uchar hash[32];
920 
921 	if (!file->hash_size)
922 		return 0;
923 
924 	if (file->hash_size == 20)
925 		crypto_csum(CRYPTO_SHA1, fdt_addr, file->f_size, hash);
926 	else if (file->hash_size == 32)
927 		crypto_csum(CRYPTO_SHA256, fdt_addr, file->f_size, hash);
928 	else
929 		return -EINVAL;
930 
931 	if (memcmp(hash, file->hash, file->hash_size))
932 		return -EBADF;
933 
934 	printf("HASH: OK(c)\n");
935 
936 	return 0;
937 }
938 
939 #else
940 static int fdt_check_hash(void *fdt_addr, struct resource_file *file)
941 {
942 	uchar hash[32];
943 
944 	if (!file->hash_size)
945 		return 0;
946 
947 	if (file->hash_size == 20)
948 		sha1_csum((const uchar *)fdt_addr, file->f_size, hash);
949 	else if (file->hash_size == 32)
950 		sha256_csum((const uchar *)fdt_addr, file->f_size, hash);
951 	else
952 		return -EINVAL;
953 
954 	if (memcmp(hash, file->hash, file->hash_size))
955 		return -EBADF;
956 
957 	printf("HASH: OK(s)\n");
958 
959 	return 0;
960 }
961 #endif
962 #endif	/* CONFIG_ROCKCHIP_DTB_VERIFY */
963 
964 int rockchip_read_dtb_file(void *fdt_addr)
965 {
966 	struct resource_file *file;
967 	char *def_dtb = DTB_FILE;
968 	int ret;
969 
970 	/* search order: "rk-kernel.dtb" -> distro -> hwid */
971 	file = get_file_info(NULL, def_dtb);
972 	if (!file) {
973 #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB
974 		ret = rockchip_read_distro_dtb(fdt_addr);
975 		if (ret > 0)
976 			return ret; /* found & load done */
977 #endif
978 #ifdef CONFIG_ROCKCHIP_HWID_DTB
979 		file = rockchip_read_hwid_dtb();
980 #endif
981 		if (!file)
982 			return -ENODEV;
983 	}
984 
985 	/* found! */
986 	printf("DTB: %s\n", file->name);
987 	ret = rockchip_read_resource_file(fdt_addr, file->name, 0, 0);
988 	if (ret < 0)
989 		return ret;
990 
991 	if (fdt_check_header(fdt_addr)) {
992 		printf("Get a bad DTB file !\n");
993 		return -EBADF;
994 	}
995 
996 	/* Note: We only load the DTB from resource.img to verify */
997 #ifdef CONFIG_ROCKCHIP_DTB_VERIFY
998 	if (fdt_check_hash(fdt_addr, file)) {
999 		printf("Get a bad hash of DTB !\n");
1000 		return -EBADF;
1001 	}
1002 #endif
1003 
1004 	if (!sysmem_alloc_base(MEMBLK_ID_FDT, (phys_addr_t)fdt_addr,
1005 			       ALIGN(file->f_size, RK_BLK_SIZE) +
1006 			       CONFIG_SYS_FDT_PAD))
1007 		return -ENOMEM;
1008 
1009 	/* Apply DTBO */
1010 #if defined(CONFIG_CMD_DTIMG) && defined(CONFIG_OF_LIBFDT_OVERLAY)
1011 	android_fdt_overlay_apply((void *)fdt_addr);
1012 #endif
1013 
1014 	return file->f_size;
1015 }
1016