xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/rk_meta.c (revision cfbaa306bdde046e2cfcd3d428f551fdab10dedf)
148201c4cSJason Zhu /* SPDX-License-Identifier:     GPL-2.0+ */
248201c4cSJason Zhu /*
348201c4cSJason Zhu  * (C) Copyright 2022 Rockchip Electronics Co., Ltd
448201c4cSJason Zhu  *
548201c4cSJason Zhu  */
648201c4cSJason Zhu 
748201c4cSJason Zhu #include <common.h>
848201c4cSJason Zhu #include <boot_rkimg.h>
948201c4cSJason Zhu #include <crc.h>
1048201c4cSJason Zhu #include <errno.h>
1148201c4cSJason Zhu #include <fdt_support.h>
1248201c4cSJason Zhu #include <image.h>
1333808c85SJason Zhu #include <misc.h>
1448201c4cSJason Zhu #include <spl.h>
1548201c4cSJason Zhu #include <asm/arch/rk_meta.h>
1648201c4cSJason Zhu 
1748201c4cSJason Zhu static char *cmdline;
1848201c4cSJason Zhu 
19*cfbaa306SXuhui Lin #if defined(CONFIG_ROCKCHIP_RV1106) || \
20*cfbaa306SXuhui Lin     defined(CONFIG_ROCKCHIP_RV1103B) || \
21*cfbaa306SXuhui Lin     defined(CONFIG_ROCKCHIP_RV1126B)
22*cfbaa306SXuhui Lin #define COMPRESS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0xa0000)
2333808c85SJason Zhu #else
2433808c85SJason Zhu #error	"Please Define COMPRESS_LOAD_ADDR !!!"
2533808c85SJason Zhu #endif
2633808c85SJason Zhu 
rk_meta_process(void)273a77b6f5SJason Zhu __weak void rk_meta_process(void) { }
283a77b6f5SJason Zhu 
rk_meta_get_startup_part_info(struct spl_load_info * info,disk_partition_t part_info,uint32_t * per_part_size,struct meta_head * meta_p)29f23e78c3SZhichao Guo static int rk_meta_get_startup_part_info(struct spl_load_info *info, disk_partition_t part_info,
30f23e78c3SZhichao Guo 	                                       uint32_t *per_part_size, struct meta_head *meta_p)
31f23e78c3SZhichao Guo {
32f23e78c3SZhichao Guo 	struct meta_head meta_next;
33f23e78c3SZhichao Guo 	uint32_t total_part_num = 1;
34f23e78c3SZhichao Guo 	uint32_t i = 1;
35f23e78c3SZhichao Guo 	ulong sector = part_info.start;
36f23e78c3SZhichao Guo 
37f23e78c3SZhichao Guo 	if (info->read(info, sector, 1, meta_p) != 1) {
38f23e78c3SZhichao Guo 		printf("%s: Failed to read header\n", __func__);
39f23e78c3SZhichao Guo 		return -EIO;
40f23e78c3SZhichao Guo 	}
41f23e78c3SZhichao Guo 
42f23e78c3SZhichao Guo 	if (meta_p->tag != RK_META) {
43f23e78c3SZhichao Guo 		printf("Invalid meta tag is %x.\n", meta_p->tag);
44f23e78c3SZhichao Guo 		return -EINVAL;
45f23e78c3SZhichao Guo 	}
46f23e78c3SZhichao Guo 
47f23e78c3SZhichao Guo 	total_part_num = meta_p->total_part_num;
48f23e78c3SZhichao Guo 	*per_part_size = meta_p->size + meta_p->part_reserved_size;
49f23e78c3SZhichao Guo 	if (*per_part_size * meta_p->total_part_num > part_info.size * part_info.blksz) {
50f23e78c3SZhichao Guo 		printf("Error: Total part size (0x%08x * %d) is larger than partition size (0x%08lx).\n",
51f23e78c3SZhichao Guo 		       *per_part_size, meta_p->total_part_num, part_info.size * part_info.blksz);
52f23e78c3SZhichao Guo 		return -EINVAL;
53f23e78c3SZhichao Guo 	}
54f23e78c3SZhichao Guo 
55f23e78c3SZhichao Guo 	memset(&meta_next, 0, sizeof(struct meta_head));
56f23e78c3SZhichao Guo 	for (i = 1; i < total_part_num; i++) {
57f23e78c3SZhichao Guo 		if (info->read(info, sector + i * (*per_part_size / info->bl_len),
58f23e78c3SZhichao Guo 			             1, &meta_next) != 1) {
59f23e78c3SZhichao Guo 			printf("%s: Failed to read header\n", __func__);
60f23e78c3SZhichao Guo 			return -EIO;
61f23e78c3SZhichao Guo 		}
62f23e78c3SZhichao Guo 
63f23e78c3SZhichao Guo 		if (meta_next.tag != RK_META) {
64f23e78c3SZhichao Guo 			debug("Not read meta tag from meta part[%d], read from part[%d] by default.\n", i, i - 1);
65f23e78c3SZhichao Guo 			break;
66f23e78c3SZhichao Guo 		}
67f23e78c3SZhichao Guo 
68f23e78c3SZhichao Guo 		debug("Check part[%d]:part_flag=%d  part[%d]:part_flag=%d\n", i - 1, meta_p->part_flag,
69f23e78c3SZhichao Guo 		                                                              i, meta_next.part_flag);
70f23e78c3SZhichao Guo 		if (meta_next.part_flag != meta_p->part_flag)
71f23e78c3SZhichao Guo 			break;
72f23e78c3SZhichao Guo 
73f23e78c3SZhichao Guo 		memcpy(meta_p, &meta_next, sizeof(struct meta_head));
74f23e78c3SZhichao Guo 	}
75f23e78c3SZhichao Guo 
76f23e78c3SZhichao Guo 	if (meta_p->crc32 != crc32(0, (const unsigned char *)meta_p, sizeof(struct meta_head) - 4 - 4)) {
77f23e78c3SZhichao Guo 		printf("Invalid meta crc32.\n");
78f23e78c3SZhichao Guo 		return -EINVAL;
79f23e78c3SZhichao Guo 	}
80f23e78c3SZhichao Guo 
81f23e78c3SZhichao Guo 	return i;
82f23e78c3SZhichao Guo }
83f23e78c3SZhichao Guo 
rk_meta_iq_decom(unsigned long dst,unsigned long src,unsigned long src_len,u64 * len)8433808c85SJason Zhu static int rk_meta_iq_decom(unsigned long dst, unsigned long src,
8533808c85SJason Zhu 			    unsigned long src_len, u64 *len)
8633808c85SJason Zhu {
8733808c85SJason Zhu 	int ret;
8833808c85SJason Zhu #if CONFIG_IS_ENABLED(MISC_DECOMPRESS)
8933808c85SJason Zhu 
9033808c85SJason Zhu 	ret = misc_decompress_process(dst, src, src_len, DECOM_GZIP, true, len, 0);
9133808c85SJason Zhu 	misc_decompress_sync(IH_COMP_GZIP);
9233808c85SJason Zhu #else
9333808c85SJason Zhu 	ret = gunzip((void *)&dst, ALIGN(len, FIT_MAX_SPL_IMAGE_SZ),
9433808c85SJason Zhu 		     (void *)&src, (void *)len);
9533808c85SJason Zhu #endif
9633808c85SJason Zhu 
9733808c85SJason Zhu 	return ret;
9833808c85SJason Zhu }
9933808c85SJason Zhu 
spl_load_meta(struct spl_image_info * spl_image,struct spl_load_info * info)10048201c4cSJason Zhu int spl_load_meta(struct spl_image_info *spl_image, struct spl_load_info *info)
10148201c4cSJason Zhu {
10248201c4cSJason Zhu 	const char *part_name = PART_META;
10348201c4cSJason Zhu 	disk_partition_t part_info;
10448201c4cSJason Zhu 	struct meta_head meta;
1050236dc36SWeiwen Chen 	struct meta_head *meta_p;
10648201c4cSJason Zhu 	struct cmdline_info *cmd;
10748201c4cSJason Zhu 	ulong sector;
10848201c4cSJason Zhu 	char *data;
10933808c85SJason Zhu 	u64 len;
11094e11c15Scww 	int meta_iq_item_size = 0;
111f23e78c3SZhichao Guo 	int meta_startup_part_num = 0;
112f23e78c3SZhichao Guo 	uint32_t meta_per_part_size = 0;
113f23e78c3SZhichao Guo 	uint32_t meta_startup_part_offset = 0;
11448201c4cSJason Zhu 
11548201c4cSJason Zhu 	if (part_get_info_by_name(info->dev, part_name, &part_info) <= 0) {
11648201c4cSJason Zhu 		debug("%s: no partition\n", __func__);
11748201c4cSJason Zhu 		return -EINVAL;
11848201c4cSJason Zhu 	}
11948201c4cSJason Zhu 	sector = part_info.start;
12048201c4cSJason Zhu 
121f23e78c3SZhichao Guo 	printf("\n");
12248201c4cSJason Zhu 	memset(&meta, 0, sizeof(struct meta_head));
12348201c4cSJason Zhu 
124f23e78c3SZhichao Guo 	meta_startup_part_num = rk_meta_get_startup_part_info(info, part_info, &meta_per_part_size, &meta);
125f23e78c3SZhichao Guo 	if (meta_startup_part_num <= 0) {
126f23e78c3SZhichao Guo 		debug("Get startup part number failed.[%d]\n", meta_startup_part_num);
12748201c4cSJason Zhu 		return -EINVAL;
12848201c4cSJason Zhu 	}
129f23e78c3SZhichao Guo 	printf("Meta: Found meta partition. Current part number: %d, total: %d\n",
130f23e78c3SZhichao Guo 	        meta_startup_part_num, meta.total_part_num);
13148201c4cSJason Zhu 
132f23e78c3SZhichao Guo 	/* The first part offset starts at 0x0 offset. */
133f23e78c3SZhichao Guo 	meta_startup_part_offset = (meta_startup_part_num - 1) * (meta_per_part_size / info->bl_len);
13448201c4cSJason Zhu 
135*cfbaa306SXuhui Lin 	data = (char *)(uintptr_t)meta.load;
1360236dc36SWeiwen Chen 	printf("Meta: 0x%08x - 0x%08x\n", meta.load, meta.load + meta.size);
137f23e78c3SZhichao Guo 	if (info->read(info, sector + meta_startup_part_offset,
138f23e78c3SZhichao Guo 		             DIV_ROUND_UP(MAX_META_SEGMENT_SIZE, info->bl_len), data)
13933808c85SJason Zhu 		  != DIV_ROUND_UP(MAX_META_SEGMENT_SIZE, info->bl_len)) {
14048201c4cSJason Zhu 		debug("%s: Failed to read header\n", __func__);
14148201c4cSJason Zhu 		return -EIO;
14248201c4cSJason Zhu 	}
14348201c4cSJason Zhu 
144*cfbaa306SXuhui Lin 	meta_p = (struct meta_head *)(uintptr_t)meta.load;
1450236dc36SWeiwen Chen 
146*cfbaa306SXuhui Lin 	cmd = (struct cmdline_info *)(uintptr_t)(meta_p->load + CMDLINE_OFFSET);
14748201c4cSJason Zhu 	if (cmd->tag == RK_CMDLINE) {
14848201c4cSJason Zhu 		if (cmd->crc32 == crc32(0, (const unsigned char *)cmd, sizeof(struct cmdline_info) - 4))
14948201c4cSJason Zhu 			cmdline = (char *)cmd->data;
15048201c4cSJason Zhu 	}
15148201c4cSJason Zhu 
15233808c85SJason Zhu 	/* load compress data */
15333808c85SJason Zhu 	data = (char *)COMPRESS_LOAD_ADDR;
15494e11c15Scww 	meta_iq_item_size = meta_p->iq_item_size + meta.comp_size;
15533808c85SJason Zhu 	if (meta_p->comp_type == META_COMPRESS_TYPE_GZ) {
156f23e78c3SZhichao Guo 		if (info->read(info,
157f23e78c3SZhichao Guo 			             sector + meta_startup_part_offset + (MAX_META_SEGMENT_SIZE / info->bl_len),
158f23e78c3SZhichao Guo 			             DIV_ROUND_UP(meta_iq_item_size, info->bl_len),
159f23e78c3SZhichao Guo 			             data)
16094e11c15Scww 			  != DIV_ROUND_UP(meta_iq_item_size, info->bl_len)) {
16194e11c15Scww 			printf("%s: Failed to read compress data.\n", __func__);
16233808c85SJason Zhu 			return -EIO;
16333808c85SJason Zhu 		}
16433808c85SJason Zhu 
165*cfbaa306SXuhui Lin 		memcpy((void *)(uintptr_t)(meta_p->load + SENSOR_IQ_BIN_OFFSET), data, meta_p->iq_item_size);
166d3bb9fb9Scww 
16733808c85SJason Zhu 		if (rk_meta_iq_decom((meta_p->load + meta_p->comp_off),
16833808c85SJason Zhu 				     (unsigned long)(data + meta_p->comp_off -
16933808c85SJason Zhu 							MAX_META_SEGMENT_SIZE),
17033808c85SJason Zhu 					 meta.comp_size, &len)) {
171fccae971Scww 			printf("%s: Failed to decompress.\n", __func__);
17233808c85SJason Zhu 			return -EIO;
17333808c85SJason Zhu 		}
174d3bb9fb9Scww 
17533808c85SJason Zhu 	} else {
176f23e78c3SZhichao Guo 		if (info->read(info,
177f23e78c3SZhichao Guo 			             sector + meta_startup_part_offset + (MAX_META_SEGMENT_SIZE / info->bl_len),
17894e11c15Scww 			             DIV_ROUND_UP(meta_iq_item_size, info->bl_len),
179*cfbaa306SXuhui Lin 			             (void *)(uintptr_t)(meta_p->load + MAX_META_SEGMENT_SIZE))
18094e11c15Scww 			  != DIV_ROUND_UP(meta_iq_item_size, info->bl_len)) {
18194e11c15Scww 			printf("%s: Failed to read\n", __func__);
18233808c85SJason Zhu 			return -EIO;
18333808c85SJason Zhu 		}
18433808c85SJason Zhu 	}
18533808c85SJason Zhu 
1860236dc36SWeiwen Chen 	meta_p->meta_flags = META_READ_DONE_FLAG;
1870236dc36SWeiwen Chen 	flush_cache(meta_p->load, meta_p->size);
1883a77b6f5SJason Zhu 	rk_meta_process();
18948201c4cSJason Zhu 
190fccae971Scww 	printf("\nMeta: ok\n");
19148201c4cSJason Zhu 	return 0;
19248201c4cSJason Zhu }
19348201c4cSJason Zhu 
rk_meta_bootargs_append(void * fdt)19448201c4cSJason Zhu void rk_meta_bootargs_append(void *fdt)
19548201c4cSJason Zhu {
196d1efb02aSJason Zhu 	if (!cmdline || (!fdt || fdt_check_header(fdt)))
197d1efb02aSJason Zhu 		return;
198d1efb02aSJason Zhu 
19948201c4cSJason Zhu 	fdt_bootargs_append(fdt, cmdline);
20048201c4cSJason Zhu }
201