xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/resource_img.c (revision 06a213412b027f93b07f8d3fea776fb12b505ea1)
108dcd37cSAndy Yan /*
208dcd37cSAndy Yan  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
308dcd37cSAndy Yan  *
408dcd37cSAndy Yan  * SPDX-License-Identifier:     GPL-2.0+
508dcd37cSAndy Yan  */
608dcd37cSAndy Yan #include <common.h>
709052952SJoseph Chen #include <boot_rkimg.h>
81d30bcc5SJoseph Chen #include <bmp_layout.h>
908dcd37cSAndy Yan #include <malloc.h>
101d30bcc5SJoseph Chen #include <asm/unaligned.h>
116ea28a6cSJoseph Chen #include <linux/libfdt.h>
1209052952SJoseph Chen #include <linux/list.h>
1309052952SJoseph Chen #include <asm/arch/resource_img.h>
14de479f92SXuhui Lin #include <asm/arch/rk_hwid.h>
156ea28a6cSJoseph Chen #include <asm/arch/uimage.h>
166ea28a6cSJoseph Chen #include <asm/arch/fit.h>
1708dcd37cSAndy Yan 
18740107bbSJoseph Chen DECLARE_GLOBAL_DATA_PTR;
19740107bbSJoseph Chen 
2008dcd37cSAndy Yan #define PART_RESOURCE			"resource"
2108dcd37cSAndy Yan #define RESOURCE_MAGIC			"RSCE"
2208dcd37cSAndy Yan #define RESOURCE_MAGIC_SIZE		4
2308dcd37cSAndy Yan #define ENTRY_TAG			"ENTR"
2408dcd37cSAndy Yan #define ENTRY_TAG_SIZE			4
25e0cee412SJoseph Chen #define MAX_FILE_NAME_LEN		220
26e0cee412SJoseph Chen #define MAX_HASH_LEN			32
27dca57e1cSJoseph Chen #define DEFAULT_DTB_FILE		"rk-kernel.dtb"
2809052952SJoseph Chen 
2908dcd37cSAndy Yan /*
3008dcd37cSAndy Yan  *         resource image structure
3108dcd37cSAndy Yan  * ----------------------------------------------
3208dcd37cSAndy Yan  * |                                            |
3308dcd37cSAndy Yan  * |    header  (1 block)                       |
3408dcd37cSAndy Yan  * |                                            |
3508dcd37cSAndy Yan  * ---------------------------------------------|
3608dcd37cSAndy Yan  * |                      |                     |
3708dcd37cSAndy Yan  * |    entry0  (1 block) |                     |
3808dcd37cSAndy Yan  * |                      |                     |
3908dcd37cSAndy Yan  * ------------------------                     |
4008dcd37cSAndy Yan  * |                      |                     |
4108dcd37cSAndy Yan  * |    entry1  (1 block) | contents (n blocks) |
4208dcd37cSAndy Yan  * |                      |                     |
4308dcd37cSAndy Yan  * ------------------------                     |
4408dcd37cSAndy Yan  * |    ......            |                     |
4508dcd37cSAndy Yan  * ------------------------                     |
4608dcd37cSAndy Yan  * |                      |                     |
4708dcd37cSAndy Yan  * |    entryn  (1 block) |                     |
4808dcd37cSAndy Yan  * |                      |                     |
4908dcd37cSAndy Yan  * ----------------------------------------------
5008dcd37cSAndy Yan  * |                                            |
5108dcd37cSAndy Yan  * |    file0  (x blocks)                       |
5208dcd37cSAndy Yan  * |                                            |
5308dcd37cSAndy Yan  * ----------------------------------------------
5408dcd37cSAndy Yan  * |                                            |
5508dcd37cSAndy Yan  * |    file1  (y blocks)                       |
5608dcd37cSAndy Yan  * |                                            |
5708dcd37cSAndy Yan  * ----------------------------------------------
5808dcd37cSAndy Yan  * |                   ......                   |
5908dcd37cSAndy Yan  * |---------------------------------------------
6008dcd37cSAndy Yan  * |                                            |
6108dcd37cSAndy Yan  * |    filen  (z blocks)                       |
6208dcd37cSAndy Yan  * |                                            |
6308dcd37cSAndy Yan  * ----------------------------------------------
6408dcd37cSAndy Yan  */
6508dcd37cSAndy Yan 
6608dcd37cSAndy Yan /**
676ea28a6cSJoseph Chen  * struct resource_img_hdr
6808dcd37cSAndy Yan  *
6908dcd37cSAndy Yan  * @magic: should be "RSCE"
7008dcd37cSAndy Yan  * @version: resource image version, current is 0
7108dcd37cSAndy Yan  * @c_version: content version, current is 0
7208dcd37cSAndy Yan  * @blks: the size of the header ( 1 block = 512 bytes)
7308dcd37cSAndy Yan  * @c_offset: contents offset(by block) in the image
7408dcd37cSAndy Yan  * @e_blks: the size(by block) of the entry in the contents
7508dcd37cSAndy Yan  * @e_num: numbers of the entrys.
7608dcd37cSAndy Yan  */
7708dcd37cSAndy Yan struct resource_img_hdr {
7808dcd37cSAndy Yan 	char		magic[4];
7908dcd37cSAndy Yan 	uint16_t	version;
8008dcd37cSAndy Yan 	uint16_t	c_version;
8108dcd37cSAndy Yan 	uint8_t		blks;
8208dcd37cSAndy Yan 	uint8_t		c_offset;
8308dcd37cSAndy Yan 	uint8_t		e_blks;
8408dcd37cSAndy Yan 	uint32_t	e_nums;
8508dcd37cSAndy Yan };
8608dcd37cSAndy Yan 
8708dcd37cSAndy Yan struct resource_entry {
8808dcd37cSAndy Yan 	char		tag[4];
8908dcd37cSAndy Yan 	char		name[MAX_FILE_NAME_LEN];
90e0cee412SJoseph Chen 	char		hash[MAX_HASH_LEN];
91e0cee412SJoseph Chen 	uint32_t	hash_size;
926ea28a6cSJoseph Chen 	uint32_t	blk_offset;
936ea28a6cSJoseph Chen 	uint32_t	size;		/* in byte */
9408dcd37cSAndy Yan };
9508dcd37cSAndy Yan 
966ea28a6cSJoseph Chen LIST_HEAD(entry_head);
9708dcd37cSAndy Yan 
resource_check_header(struct resource_img_hdr * hdr)986ea28a6cSJoseph Chen static int resource_check_header(struct resource_img_hdr *hdr)
9908dcd37cSAndy Yan {
1006ea28a6cSJoseph Chen 	return memcmp(RESOURCE_MAGIC, hdr->magic, RESOURCE_MAGIC_SIZE);
10108dcd37cSAndy Yan }
10209052952SJoseph Chen 
resource_dump(struct resource_file * f)1036ea28a6cSJoseph Chen static void resource_dump(struct resource_file *f)
10408dcd37cSAndy Yan {
1056ea28a6cSJoseph Chen 	printf("%s\n", f->name);
1061cc374d6SXuhui Lin 	printf("  blk_start:  0x%08lx\n", f->blk_start);
1071cc374d6SXuhui Lin 	printf("  blk_offset: 0x%08lx\n", f->blk_offset);
1086ea28a6cSJoseph Chen 	printf("  size:       0x%08x\n", f->size);
1096ea28a6cSJoseph Chen 	printf("  in_ram:     %d\n", f->in_ram);
1106ea28a6cSJoseph Chen 	printf("  hash_size:  %d\n\n", f->hash_size);
11108dcd37cSAndy Yan }
11209052952SJoseph Chen 
resource_add_file(const char * name,u32 size,ulong blk_start,u32 blk_offset,char * hash,u32 hash_size,bool in_ram)1136ea28a6cSJoseph Chen static int resource_add_file(const char *name, u32 size,
1141cc374d6SXuhui Lin 			     ulong blk_start,  u32 blk_offset,
1156ea28a6cSJoseph Chen 			     char *hash, u32 hash_size,
1166ea28a6cSJoseph Chen 			     bool in_ram)
1174ebf6738SJoseph Chen {
1186ea28a6cSJoseph Chen 	struct resource_file *f;
1194ebf6738SJoseph Chen 	struct list_head *node;
1206ea28a6cSJoseph Chen 	bool _new = true;
1214ebf6738SJoseph Chen 
1226ea28a6cSJoseph Chen 	/* old one ? */
1236ea28a6cSJoseph Chen 	list_for_each(node, &entry_head) {
1246ea28a6cSJoseph Chen 		f = list_entry(node, struct resource_file, link);
1256ea28a6cSJoseph Chen 		if (!strcmp(f->name, name)) {
1266ea28a6cSJoseph Chen 			_new = false;
1274ebf6738SJoseph Chen 			break;
1284ebf6738SJoseph Chen 		}
1294ebf6738SJoseph Chen 	}
1304ebf6738SJoseph Chen 
1316ea28a6cSJoseph Chen 	if (_new) {
1326ea28a6cSJoseph Chen 		f = calloc(1, sizeof(*f));
1336ea28a6cSJoseph Chen 		if (!f)
1346ea28a6cSJoseph Chen 			return -ENOMEM;
1354ebf6738SJoseph Chen 
1366ea28a6cSJoseph Chen 		list_add_tail(&f->link, &entry_head);
1376ea28a6cSJoseph Chen 	}
1386ea28a6cSJoseph Chen 
1396ea28a6cSJoseph Chen 	strcpy(f->name, name);
1406ea28a6cSJoseph Chen 	f->size       = size;
1416ea28a6cSJoseph Chen 	f->in_ram     = in_ram;
1426ea28a6cSJoseph Chen 	f->blk_start  = blk_start;
1436ea28a6cSJoseph Chen 	f->blk_offset = blk_offset;
1446ea28a6cSJoseph Chen 	f->hash_size  = hash_size;
1456ea28a6cSJoseph Chen 	memcpy(f->hash, hash, hash_size);
1466ea28a6cSJoseph Chen #ifdef DEBUG
1476ea28a6cSJoseph Chen 	resource_dump(f);
1486ea28a6cSJoseph Chen #endif
1494ebf6738SJoseph Chen 	return 0;
1504ebf6738SJoseph Chen }
1514ebf6738SJoseph Chen 
resource_destroy(void)152*06a21341SJoseph Chen void resource_destroy(void)
153*06a21341SJoseph Chen {
154*06a21341SJoseph Chen 	INIT_LIST_HEAD(&entry_head);
155*06a21341SJoseph Chen }
156*06a21341SJoseph Chen 
15763f38f9dSJoseph Chen #ifdef CONFIG_ANDROID_BOOT_IMAGE
1586ea28a6cSJoseph Chen /*
1596ea28a6cSJoseph Chen  * Add logo.bmp and logo_kernel.bmp from "logo" parititon
1606ea28a6cSJoseph Chen  *
1616ea28a6cSJoseph Chen  * Provide a "logo" partition for user to store logo.bmp and
1626ea28a6cSJoseph Chen  * logo_kernel.bmp, so that the user can update them from
1636ea28a6cSJoseph Chen  * kernel or user-space dynamically.
1646ea28a6cSJoseph Chen  *
1656ea28a6cSJoseph Chen  * "logo" partition layout, do not change order:
1666ea28a6cSJoseph Chen  *
1676ea28a6cSJoseph Chen  *   |----------------------| 0x00
1686ea28a6cSJoseph Chen  *   | raw logo.bmp	    |
1696ea28a6cSJoseph Chen  *   |----------------------| -> 512-byte aligned
1706ea28a6cSJoseph Chen  *   | raw logo_kernel.bmp  |
1716ea28a6cSJoseph Chen  *   |----------------------|
1726ea28a6cSJoseph Chen  *
1736ea28a6cSJoseph Chen  * N: the sector count of logo.bmp
1746ea28a6cSJoseph Chen  *
1756ea28a6cSJoseph Chen  * How to generate:
1766ea28a6cSJoseph Chen  * 	cat logo.bmp > logo.img && truncate -s %512 logo.img && cat logo_kernel.bmp >> logo.img
1776ea28a6cSJoseph Chen  */
resource_setup_logo_bmp(struct blk_desc * desc)1786ea28a6cSJoseph Chen static int resource_setup_logo_bmp(struct blk_desc *desc)
17945390edfSJoseph Chen {
1806ea28a6cSJoseph Chen 	struct bmp_header *header;
1816ea28a6cSJoseph Chen 	const char *name[] = { "logo.bmp", "logo_kernel.bmp" };
1826ea28a6cSJoseph Chen 	disk_partition_t part;
1836ea28a6cSJoseph Chen 	u32 blk_offset = 0;
1846ea28a6cSJoseph Chen 	u32 filesz;
1856ea28a6cSJoseph Chen 	int ret, i;
18645390edfSJoseph Chen 
1876ea28a6cSJoseph Chen 	if (part_get_info_by_name(desc, PART_LOGO, &part) < 0)
1886ea28a6cSJoseph Chen 		return 0;
1896ea28a6cSJoseph Chen 
1906ea28a6cSJoseph Chen 	header = memalign(ARCH_DMA_MINALIGN, desc->blksz);
1916ea28a6cSJoseph Chen 	if (!header)
1926ea28a6cSJoseph Chen 		return -ENOMEM;
1936ea28a6cSJoseph Chen 
1946ea28a6cSJoseph Chen 	for (i = 0; i < ARRAY_SIZE(name); i++) {
1956ea28a6cSJoseph Chen 		if (blk_dread(desc, part.start + blk_offset, 1, header) != 1) {
1966ea28a6cSJoseph Chen 			ret = -EIO;
1976ea28a6cSJoseph Chen 			break;
1986ea28a6cSJoseph Chen 		}
1996ea28a6cSJoseph Chen 
2006ea28a6cSJoseph Chen 		if (header->signature[0] != 'B' || header->signature[1] != 'M') {
20145390edfSJoseph Chen 			ret = -EINVAL;
2026ea28a6cSJoseph Chen 			break;
20345390edfSJoseph Chen 		}
20445390edfSJoseph Chen 
2056ea28a6cSJoseph Chen 		filesz = get_unaligned_le32(&header->file_size);
2066ea28a6cSJoseph Chen 		ret = resource_add_file(name[i], filesz, part.start, blk_offset,
2076ea28a6cSJoseph Chen 					NULL, 0, false);
2086ea28a6cSJoseph Chen 		if (ret)
2096ea28a6cSJoseph Chen 			break;
2106ea28a6cSJoseph Chen 
2116ea28a6cSJoseph Chen 		/* move to next file */
2126ea28a6cSJoseph Chen 		blk_offset += DIV_ROUND_UP(filesz, desc->blksz);
2136ea28a6cSJoseph Chen 
2146ea28a6cSJoseph Chen 		printf("LOGO: %s\n", name[i]);
2156ea28a6cSJoseph Chen 
21645390edfSJoseph Chen 	}
2176ea28a6cSJoseph Chen 
2186ea28a6cSJoseph Chen 	free(header);
21945390edfSJoseph Chen 
22045390edfSJoseph Chen 	return ret;
22145390edfSJoseph Chen }
22207dca981SXuhui Lin #endif
22345390edfSJoseph Chen 
resource_setup_list(struct blk_desc * desc,ulong blk_start,void * resc_hdr,bool in_ram)2241cc374d6SXuhui Lin static int resource_setup_list(struct blk_desc *desc, ulong blk_start,
22507dca981SXuhui Lin 			       void *resc_hdr, bool in_ram)
22607dca981SXuhui Lin {
22707dca981SXuhui Lin 	struct resource_img_hdr *hdr = resc_hdr;
22807dca981SXuhui Lin 	struct resource_entry *et;
22907dca981SXuhui Lin 	u32 i, stride;
23007dca981SXuhui Lin 	void *pos;
23107dca981SXuhui Lin 
23207dca981SXuhui Lin 	pos = (void *)hdr + hdr->c_offset * desc->blksz;
23307dca981SXuhui Lin 	stride = hdr->e_blks * desc->blksz;
23407dca981SXuhui Lin 
23507dca981SXuhui Lin 	for (i = 0; i < hdr->e_nums; i++) {
23607dca981SXuhui Lin 		et = pos + (i * stride);
23707dca981SXuhui Lin 		if (memcmp(et->tag, ENTRY_TAG, ENTRY_TAG_SIZE))
23807dca981SXuhui Lin 			continue;
23907dca981SXuhui Lin 
24007dca981SXuhui Lin 		resource_add_file(et->name, et->size,
24107dca981SXuhui Lin 				  blk_start, et->blk_offset,
24207dca981SXuhui Lin 				  et->hash, et->hash_size, in_ram);
24307dca981SXuhui Lin 	}
24407dca981SXuhui Lin #ifdef CONFIG_ANDROID_BOOT_IMAGE
24507dca981SXuhui Lin 	resource_setup_logo_bmp(desc);
24607dca981SXuhui Lin #endif
24707dca981SXuhui Lin 	return 0;
24807dca981SXuhui Lin }
24907dca981SXuhui Lin 
resource_setup_ram_list(struct blk_desc * desc,void * hdr)25007dca981SXuhui Lin int resource_setup_ram_list(struct blk_desc *desc, void *hdr)
25107dca981SXuhui Lin {
25207dca981SXuhui Lin 	if (!desc)
25307dca981SXuhui Lin 		return -ENODEV;
25407dca981SXuhui Lin 
25507dca981SXuhui Lin 	if (resource_check_header(hdr)) {
25607dca981SXuhui Lin 		printf("RESC: invalid\n");
25707dca981SXuhui Lin 		return -EINVAL;
25807dca981SXuhui Lin 	}
25907dca981SXuhui Lin 
26007dca981SXuhui Lin 	/* @blk_start: set as 'hdr' point addr, to be used in byte */
2611cc374d6SXuhui Lin 	return resource_setup_list(desc, (ulong)hdr, hdr, true);
26207dca981SXuhui Lin }
26307dca981SXuhui Lin 
26407dca981SXuhui Lin #ifdef CONFIG_ANDROID_BOOT_IMAGE
resource_setup_blk_list(struct blk_desc * desc,ulong blk_start)2651cc374d6SXuhui Lin static int resource_setup_blk_list(struct blk_desc *desc, ulong blk_start)
26645390edfSJoseph Chen {
26745390edfSJoseph Chen 	struct resource_img_hdr *hdr;
2686ea28a6cSJoseph Chen 	int blk_cnt;
26945390edfSJoseph Chen 	int ret = 0;
2706ea28a6cSJoseph Chen 	void *buf;
27145390edfSJoseph Chen 
2726ea28a6cSJoseph Chen 	hdr = memalign(ARCH_DMA_MINALIGN, desc->blksz);
27309052952SJoseph Chen 	if (!hdr)
27409052952SJoseph Chen 		return -ENOMEM;
27509052952SJoseph Chen 
2766ea28a6cSJoseph Chen 	if (blk_dread(desc, blk_start, 1, hdr) != 1) {
277a84f21ebSJoseph Chen 		ret = -EIO;
2786ea28a6cSJoseph Chen 		goto out;
279a84f21ebSJoseph Chen 	}
280a84f21ebSJoseph Chen 
2816ea28a6cSJoseph Chen 	if (resource_check_header(hdr)) {
2826ea28a6cSJoseph Chen 		printf("RESC: invalid\n");
28345390edfSJoseph Chen 		if (fdt_check_header(hdr)) {
28401ff14b0SJoseph Chen 			ret = -EINVAL;
2856ea28a6cSJoseph Chen 			goto out;
28645390edfSJoseph Chen 		} else {
2876ea28a6cSJoseph Chen 			/* this is a dtb file */
2886ea28a6cSJoseph Chen 			printf("RESC: this is dtb\n");
2896ea28a6cSJoseph Chen 			ret = resource_add_file(DEFAULT_DTB_FILE,
2906ea28a6cSJoseph Chen 						fdt_totalsize(hdr),
2916ea28a6cSJoseph Chen 						blk_start, 0, NULL, 0, false);
2926ea28a6cSJoseph Chen 			goto out;
29345390edfSJoseph Chen 		}
29401ff14b0SJoseph Chen 	}
295b498696eSJoseph Chen 
2966ea28a6cSJoseph Chen 	blk_cnt = hdr->e_blks * hdr->e_nums;
2976ea28a6cSJoseph Chen 	hdr = realloc(hdr, (1 + blk_cnt) * desc->blksz);
2986ea28a6cSJoseph Chen 	if (!hdr) {
29901ff14b0SJoseph Chen 		ret = -ENOMEM;
3006ea28a6cSJoseph Chen 		goto out;
30108dcd37cSAndy Yan 	}
302b498696eSJoseph Chen 
3036ea28a6cSJoseph Chen 	buf = (void *)hdr + desc->blksz;
3046ea28a6cSJoseph Chen 	if (blk_dread(desc, blk_start + hdr->c_offset, blk_cnt, buf) != blk_cnt) {
30501ff14b0SJoseph Chen 		ret = -EIO;
3066ea28a6cSJoseph Chen 		goto out;
30710660eccSJoseph Chen 	}
30808dcd37cSAndy Yan 
3096ea28a6cSJoseph Chen 	resource_setup_list(desc, blk_start, hdr, false);
3106ea28a6cSJoseph Chen out:
31108dcd37cSAndy Yan 	free(hdr);
31208dcd37cSAndy Yan 
31301ff14b0SJoseph Chen 	return ret;
31408dcd37cSAndy Yan }
31508dcd37cSAndy Yan 
resource_init(struct blk_desc * desc,disk_partition_t * part,ulong blk_offset)3166ea28a6cSJoseph Chen static int resource_init(struct blk_desc *desc,
3176ea28a6cSJoseph Chen 			 disk_partition_t *part,
3186ea28a6cSJoseph Chen 			 ulong blk_offset)
319745aeb1aSJoseph Chen {
3206ea28a6cSJoseph Chen 	printf("RESC: '%s', blk@0x%08lx\n", part->name, part->start + blk_offset);
321745aeb1aSJoseph Chen 
32277cf005eSJoseph Chen #ifdef CONFIG_ANDROID_AVB
32377cf005eSJoseph Chen 	char hdr[512];
32463f38f9dSJoseph Chen 	ulong resc_buf = 0;
32577cf005eSJoseph Chen 	int ret;
32677cf005eSJoseph Chen 
32777cf005eSJoseph Chen 	if (blk_dread(desc, part->start, 1, hdr) != 1)
32877cf005eSJoseph Chen 		return -EIO;
32977cf005eSJoseph Chen 
33077cf005eSJoseph Chen 	/* only handle android boot/recovery.img and resource.img, ignore fit */
33177cf005eSJoseph Chen 	if (!android_image_check_header((void *)hdr) ||
33277cf005eSJoseph Chen 	    !resource_check_header((void *)hdr)) {
33363f38f9dSJoseph Chen 		ret = android_image_verify_resource((const char *)part->name, &resc_buf);
33477cf005eSJoseph Chen 		if (ret) {
33577cf005eSJoseph Chen 			printf("RESC: '%s', avb verify fail: %d\n", part->name, ret);
33677cf005eSJoseph Chen 			return ret;
33777cf005eSJoseph Chen 		}
33877cf005eSJoseph Chen 
33963f38f9dSJoseph Chen 		/*
34063f38f9dSJoseph Chen 		 * unlock=0: resc_buf is valid and file was already full load in ram.
34163f38f9dSJoseph Chen 		 * unlock=1: resc_buf is 0.
34263f38f9dSJoseph Chen 		 */
34363f38f9dSJoseph Chen 		if (resc_buf && !resource_check_header((void *)resc_buf))
34463f38f9dSJoseph Chen 			return resource_setup_ram_list(desc, (void *)resc_buf);
34577cf005eSJoseph Chen 	}
3469274b15fSXuhui Lin 
34777cf005eSJoseph Chen #endif
34877cf005eSJoseph Chen 
3496ea28a6cSJoseph Chen 	return resource_setup_blk_list(desc, part->start + blk_offset);
350745aeb1aSJoseph Chen }
351745aeb1aSJoseph Chen 
resource_default(struct blk_desc * desc,disk_partition_t * out_part,ulong * out_blk_offset)3526ea28a6cSJoseph Chen static int resource_default(struct blk_desc *desc,
3536ea28a6cSJoseph Chen 			    disk_partition_t *out_part,
3546ea28a6cSJoseph Chen 			    ulong *out_blk_offset)
35545390edfSJoseph Chen {
35645390edfSJoseph Chen 	disk_partition_t part;
35745390edfSJoseph Chen 
3586ea28a6cSJoseph Chen 	if (part_get_info_by_name(desc, PART_RESOURCE, &part) < 0)
35945390edfSJoseph Chen 		return -ENODEV;
3606ea28a6cSJoseph Chen 
3616ea28a6cSJoseph Chen 	*out_part = part;
3626ea28a6cSJoseph Chen 	*out_blk_offset = 0;
3636ea28a6cSJoseph Chen 
3646ea28a6cSJoseph Chen 	return 0;
3656ea28a6cSJoseph Chen }
36663f38f9dSJoseph Chen #endif
3676ea28a6cSJoseph Chen 
resource_scan(void)3686ea28a6cSJoseph Chen static int resource_scan(void)
3696ea28a6cSJoseph Chen {
3706ea28a6cSJoseph Chen 	struct blk_desc *desc = rockchip_get_bootdev();
37163f38f9dSJoseph Chen 	__maybe_unused int ret;
3726ea28a6cSJoseph Chen 
3736ea28a6cSJoseph Chen 	if (!desc) {
3746ea28a6cSJoseph Chen 		printf("RESC: No bootdev\n");
3756ea28a6cSJoseph Chen 		return -ENODEV;
3766ea28a6cSJoseph Chen 	}
3776ea28a6cSJoseph Chen 
3786ea28a6cSJoseph Chen 	if (!list_empty(&entry_head))
3796ea28a6cSJoseph Chen 		return 0;
3806ea28a6cSJoseph Chen 
3816ea28a6cSJoseph Chen #ifdef CONFIG_ROCKCHIP_FIT_IMAGE
38263f38f9dSJoseph Chen 	ret = fit_image_init_resource(desc);
38363f38f9dSJoseph Chen 	if (!ret || ret != -EAGAIN)
38463f38f9dSJoseph Chen 		return ret;
3856ea28a6cSJoseph Chen #endif
3866ea28a6cSJoseph Chen #ifdef CONFIG_ROCKCHIP_UIMAGE
38763f38f9dSJoseph Chen 	ret = uimage_init_resource(desc);
38863f38f9dSJoseph Chen 	if (!ret || ret != -EAGAIN)
38963f38f9dSJoseph Chen 		return ret;
3906ea28a6cSJoseph Chen #endif
39163f38f9dSJoseph Chen #ifdef CONFIG_ANDROID_BOOT_IMAGE
39263f38f9dSJoseph Chen 	disk_partition_t part;
39363f38f9dSJoseph Chen 	ulong blk_offset;
39463f38f9dSJoseph Chen 	char hdr[512];
39563f38f9dSJoseph Chen 	char name[32];
39663f38f9dSJoseph Chen 
39763f38f9dSJoseph Chen 	/* partition priority: boot/recovery > resource */
39863f38f9dSJoseph Chen 	if (!android_image_init_resource(desc, &part, &blk_offset)) {
3996ea28a6cSJoseph Chen 		if (blk_dread(desc, part.start + blk_offset, 1, hdr) != 1)
4006ea28a6cSJoseph Chen 			return -EIO;
4016ea28a6cSJoseph Chen 
4026ea28a6cSJoseph Chen 		if (resource_check_header((void *)hdr)) {
4036ea28a6cSJoseph Chen 			strcpy(name, (char *)part.name);
4046ea28a6cSJoseph Chen 			if (resource_default(desc, &part, &blk_offset))
4056ea28a6cSJoseph Chen 				return -ENOENT;
4066ea28a6cSJoseph Chen 
4076ea28a6cSJoseph Chen 			printf("RESC: '%s' -> '%s'\n", name, part.name);
4086ea28a6cSJoseph Chen 		}
409745aeb1aSJoseph Chen 	} else {
4106ea28a6cSJoseph Chen 		if (resource_default(desc, &part, &blk_offset))
41145390edfSJoseph Chen 			return -ENOENT;
41245390edfSJoseph Chen 	}
41309052952SJoseph Chen 
41463f38f9dSJoseph Chen 	/* now, 'part' can be boot/recovery/resource */
4156ea28a6cSJoseph Chen 	return resource_init(desc, &part, blk_offset);
41663f38f9dSJoseph Chen #endif
41763f38f9dSJoseph Chen 	return -ENOENT;
4186ea28a6cSJoseph Chen }
4196ea28a6cSJoseph Chen 
resource_get_file(const char * name)4206ea28a6cSJoseph Chen static struct resource_file *resource_get_file(const char *name)
4216ea28a6cSJoseph Chen {
4226ea28a6cSJoseph Chen 	struct resource_file *f;
4236ea28a6cSJoseph Chen 	struct list_head *node;
4246ea28a6cSJoseph Chen 
4256ea28a6cSJoseph Chen 	if (resource_scan())
4266ea28a6cSJoseph Chen 		return NULL;
4276ea28a6cSJoseph Chen 
4286ea28a6cSJoseph Chen 	list_for_each(node, &entry_head) {
4296ea28a6cSJoseph Chen 		f = list_entry(node, struct resource_file, link);
4306ea28a6cSJoseph Chen 		if (!strcmp(f->name, name))
4316ea28a6cSJoseph Chen 			return f;
4326ea28a6cSJoseph Chen 	}
4336ea28a6cSJoseph Chen 
4346ea28a6cSJoseph Chen 	return NULL;
4356ea28a6cSJoseph Chen }
4366ea28a6cSJoseph Chen 
rockchip_read_resource_file(void * buf,const char * name,int blk_offset,int len)4376ea28a6cSJoseph Chen int rockchip_read_resource_file(void *buf, const char *name, int blk_offset, int len)
4386ea28a6cSJoseph Chen {
4396ea28a6cSJoseph Chen 	struct blk_desc *desc = rockchip_get_bootdev();
4406ea28a6cSJoseph Chen 	struct resource_file *f;
4416ea28a6cSJoseph Chen 	int blk_cnt;
4421cc374d6SXuhui Lin 	ulong pos;
4436ea28a6cSJoseph Chen 
4446ea28a6cSJoseph Chen 	if (!desc)
44509052952SJoseph Chen 		return -ENODEV;
4466ea28a6cSJoseph Chen 
4476ea28a6cSJoseph Chen 	f = resource_get_file(name);
4486ea28a6cSJoseph Chen 	if (!f) {
4496ea28a6cSJoseph Chen 		printf("No resource file: %s\n", name);
4506ea28a6cSJoseph Chen 		return -ENOENT;
45109052952SJoseph Chen 	}
45208dcd37cSAndy Yan 
4536ea28a6cSJoseph Chen 	if (len <= 0 || len > f->size)
4546ea28a6cSJoseph Chen 		len = f->size;
45509052952SJoseph Chen 
4566ea28a6cSJoseph Chen 	if (f->in_ram) {
4576ea28a6cSJoseph Chen 		pos = f->blk_start + (f->blk_offset + blk_offset) * desc->blksz;
4586ea28a6cSJoseph Chen 		memcpy(buf, (char *)pos, len);
45945390edfSJoseph Chen 	} else {
4606ea28a6cSJoseph Chen 		blk_cnt = DIV_ROUND_UP(len, desc->blksz);
4616ea28a6cSJoseph Chen 		if (blk_dread(desc,
4626ea28a6cSJoseph Chen 			      f->blk_start + f->blk_offset + blk_offset,
4636ea28a6cSJoseph Chen 			      blk_cnt, buf) != blk_cnt)
4646ea28a6cSJoseph Chen 			len = -EIO;
46545390edfSJoseph Chen 	}
46608dcd37cSAndy Yan 
4676ea28a6cSJoseph Chen 	return len;
46808dcd37cSAndy Yan }
469740107bbSJoseph Chen 
470de479f92SXuhui Lin #ifdef CONFIG_ROCKCHIP_HWID_DTB
resource_read_hwid_dtb(void)471de479f92SXuhui Lin static struct resource_file *resource_read_hwid_dtb(void)
472de479f92SXuhui Lin {
473de479f92SXuhui Lin 	struct resource_file *file;
474de479f92SXuhui Lin 	struct list_head *node;
475de479f92SXuhui Lin 
476de479f92SXuhui Lin 	hwid_init_data();
477de479f92SXuhui Lin 
478de479f92SXuhui Lin 	list_for_each(node, &entry_head) {
479de479f92SXuhui Lin 		file = list_entry(node, struct resource_file, link);
480de479f92SXuhui Lin 		if (!strstr(file->name, DTB_SUFFIX))
481de479f92SXuhui Lin 			continue;
482de479f92SXuhui Lin 
483de479f92SXuhui Lin 		if (hwid_dtb_is_available(file->name))
484de479f92SXuhui Lin 			return file;
485de479f92SXuhui Lin 	}
486de479f92SXuhui Lin 
487de479f92SXuhui Lin 	return NULL;
488de479f92SXuhui Lin }
489de479f92SXuhui Lin #endif
4906ea28a6cSJoseph Chen 
rockchip_read_resource_dtb(void * fdt_addr,char ** hash,int * hash_size)491bc4ccd53SJoseph Chen int rockchip_read_resource_dtb(void *fdt_addr, char **hash, int *hash_size)
492740107bbSJoseph Chen {
4936ea28a6cSJoseph Chen 	struct resource_file *f = NULL;
494a6926964SJoseph Chen 	int ret;
495740107bbSJoseph Chen 
496ca6fb291SJoseph Chen #ifdef CONFIG_ROCKCHIP_HWID_DTB
4976ea28a6cSJoseph Chen 	if (resource_scan())
4986ea28a6cSJoseph Chen 		return -ENOENT;
499ea513bf6SJoseph Chen 
5006ea28a6cSJoseph Chen 	f = resource_read_hwid_dtb();
5016ea28a6cSJoseph Chen #endif
5026ea28a6cSJoseph Chen 	/* If no dtb match hardware id(GPIO/ADC), use the default */
5036ea28a6cSJoseph Chen 	if (!f)
5046ea28a6cSJoseph Chen 		f = resource_get_file(DEFAULT_DTB_FILE);
5056ea28a6cSJoseph Chen 
5066ea28a6cSJoseph Chen 	if (!f)
5076069a2ccSJoseph Chen 		return -ENODEV;
508740107bbSJoseph Chen 
5096ea28a6cSJoseph Chen 	ret = rockchip_read_resource_file(fdt_addr, f->name, 0, 0);
510a6926964SJoseph Chen 	if (ret < 0)
511a6926964SJoseph Chen 		return ret;
512b4a94719SJoseph Chen 
513bc4ccd53SJoseph Chen 	if (fdt_check_header(fdt_addr))
5144f74cb30SJoseph Chen 		return -EBADF;
5154f74cb30SJoseph Chen 
5166ea28a6cSJoseph Chen 	*hash = f->hash;
5176ea28a6cSJoseph Chen 	*hash_size = f->hash_size;
518e0cee412SJoseph Chen 
5196ea28a6cSJoseph Chen 	printf("DTB: %s\n", f->name);
520ea513bf6SJoseph Chen 
521ea513bf6SJoseph Chen 	return 0;
522ea513bf6SJoseph Chen }
5235f63fd7aSJoseph Chen 
do_dump_resource(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])5245f63fd7aSJoseph Chen static int do_dump_resource(cmd_tbl_t *cmdtp, int flag,
5255f63fd7aSJoseph Chen 			    int argc, char *const argv[])
5265f63fd7aSJoseph Chen {
5276ea28a6cSJoseph Chen 	struct resource_file *f;
5285f63fd7aSJoseph Chen 	struct list_head *node;
5295f63fd7aSJoseph Chen 
5306ea28a6cSJoseph Chen 	list_for_each(node, &entry_head) {
5316ea28a6cSJoseph Chen 		f = list_entry(node, struct resource_file, link);
5326ea28a6cSJoseph Chen 		resource_dump(f);
5335f63fd7aSJoseph Chen 	}
5345f63fd7aSJoseph Chen 
5355f63fd7aSJoseph Chen 	return 0;
5365f63fd7aSJoseph Chen }
5375f63fd7aSJoseph Chen 
5385f63fd7aSJoseph Chen U_BOOT_CMD(
5395f63fd7aSJoseph Chen 	dump_resource, 1, 1, do_dump_resource,
5406ea28a6cSJoseph Chen 	"dump resource files",
5415f63fd7aSJoseph Chen 	""
5425f63fd7aSJoseph Chen );
5435f63fd7aSJoseph Chen 
544