xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/rk_meta.c (revision a8a4d6c05a2e5f52e75e5096f9470aa3d36fd000)
1 /* SPDX-License-Identifier:     GPL-2.0+ */
2 /*
3  * (C) Copyright 2022 Rockchip Electronics Co., Ltd
4  *
5  */
6 
7 #include <common.h>
8 #include <boot_rkimg.h>
9 #include <crc.h>
10 #include <errno.h>
11 #include <fdt_support.h>
12 #include <image.h>
13 #include <misc.h>
14 #include <spl.h>
15 #include <asm/arch/rk_meta.h>
16 
17 static char *cmdline;
18 
19 #if defined(CONFIG_ROCKCHIP_RV1106) || \
20     defined(CONFIG_ROCKCHIP_RV1103B) || \
21     defined(CONFIG_ROCKCHIP_RV1126B)
22 #define COMPRESS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0xa0000)
23 #else
24 #error	"Please Define COMPRESS_LOAD_ADDR !!!"
25 #endif
26 
27 __weak void rk_meta_process(void) { }
28 
29 static int rk_meta_get_startup_part_info(struct spl_load_info *info, disk_partition_t part_info,
30 	                                       uint32_t *per_part_size, struct meta_head *meta_p)
31 {
32 	struct meta_head meta_next;
33 	uint32_t total_part_num = 1;
34 	uint32_t i = 1;
35 	ulong sector = part_info.start;
36 
37 	if (info->read(info, sector, 1, meta_p) != 1) {
38 		printf("%s: Failed to read header\n", __func__);
39 		return -EIO;
40 	}
41 
42 	if (meta_p->tag != RK_META) {
43 		printf("Invalid meta tag is %x.\n", meta_p->tag);
44 		return -EINVAL;
45 	}
46 
47 	total_part_num = meta_p->total_part_num;
48 	*per_part_size = meta_p->size + meta_p->part_reserved_size;
49 	if (*per_part_size * meta_p->total_part_num > part_info.size * part_info.blksz) {
50 		printf("Error: Total part size (0x%08x * %d) is larger than partition size (0x%08lx).\n",
51 		       *per_part_size, meta_p->total_part_num, part_info.size * part_info.blksz);
52 		return -EINVAL;
53 	}
54 
55 	memset(&meta_next, 0, sizeof(struct meta_head));
56 	for (i = 1; i < total_part_num; i++) {
57 		if (info->read(info, sector + i * (*per_part_size / info->bl_len),
58 			             1, &meta_next) != 1) {
59 			printf("%s: Failed to read header\n", __func__);
60 			return -EIO;
61 		}
62 
63 		if (meta_next.tag != RK_META) {
64 			debug("Not read meta tag from meta part[%d], read from part[%d] by default.\n", i, i - 1);
65 			break;
66 		}
67 
68 		debug("Check part[%d]:part_flag=%d  part[%d]:part_flag=%d\n", i - 1, meta_p->part_flag,
69 		                                                              i, meta_next.part_flag);
70 		if (meta_next.part_flag != meta_p->part_flag)
71 			break;
72 
73 		memcpy(meta_p, &meta_next, sizeof(struct meta_head));
74 	}
75 
76 	if (meta_p->crc32 != crc32(0, (const unsigned char *)meta_p, sizeof(struct meta_head) - 4 - 4)) {
77 		printf("Invalid meta crc32.\n");
78 		return -EINVAL;
79 	}
80 
81 	return i;
82 }
83 
84 static int rk_meta_iq_decom(unsigned long dst, unsigned long src,
85 			    unsigned long src_len, u64 *len)
86 {
87 	int ret;
88 #if CONFIG_IS_ENABLED(MISC_DECOMPRESS)
89 
90 	ret = misc_decompress_process(dst, src, src_len, DECOM_GZIP, true, len, 0);
91 	misc_decompress_sync(IH_COMP_GZIP);
92 #else
93 	ret = gunzip((void *)&dst, ALIGN(len, FIT_MAX_SPL_IMAGE_SZ),
94 		     (void *)&src, (void *)len);
95 #endif
96 
97 	return ret;
98 }
99 
100 int spl_load_meta(struct spl_image_info *spl_image, struct spl_load_info *info)
101 {
102 	const char *part_name = PART_META;
103 	disk_partition_t part_info;
104 	struct meta_head meta;
105 	struct meta_head *meta_p;
106 	struct cmdline_info *cmd;
107 	ulong sector;
108 	char *data;
109 	u64 len;
110 	int meta_iq_item_size = 0;
111 	int meta_startup_part_num = 0;
112 	uint32_t meta_per_part_size = 0;
113 	uint32_t meta_startup_part_offset = 0;
114 
115 	if (part_get_info_by_name(info->dev, part_name, &part_info) <= 0) {
116 		debug("%s: no partition\n", __func__);
117 		return -EINVAL;
118 	}
119 	sector = part_info.start;
120 
121 	printf("\n");
122 	memset(&meta, 0, sizeof(struct meta_head));
123 
124 	meta_startup_part_num = rk_meta_get_startup_part_info(info, part_info, &meta_per_part_size, &meta);
125 	if (meta_startup_part_num <= 0) {
126 		debug("Get startup part number failed.[%d]\n", meta_startup_part_num);
127 		return -EINVAL;
128 	}
129 	printf("Meta: Found meta partition. Current part number: %d, total: %d\n",
130 	        meta_startup_part_num, meta.total_part_num);
131 
132 	/* The first part offset starts at 0x0 offset. */
133 	meta_startup_part_offset = (meta_startup_part_num - 1) * (meta_per_part_size / info->bl_len);
134 
135 	data = (char *)(uintptr_t)meta.load;
136 	printf("Meta: 0x%08x - 0x%08x\n", meta.load, meta.load + meta.size);
137 	if (info->read(info, sector + meta_startup_part_offset,
138 		             DIV_ROUND_UP(MAX_META_SEGMENT_SIZE, info->bl_len), data)
139 		  != DIV_ROUND_UP(MAX_META_SEGMENT_SIZE, info->bl_len)) {
140 		debug("%s: Failed to read header\n", __func__);
141 		return -EIO;
142 	}
143 
144 	meta_p = (struct meta_head *)(uintptr_t)meta.load;
145 
146 	cmd = (struct cmdline_info *)(uintptr_t)(meta_p->load + CMDLINE_OFFSET);
147 	if (cmd->tag == RK_CMDLINE) {
148 		if (cmd->crc32 == crc32(0, (const unsigned char *)cmd, sizeof(struct cmdline_info) - 4))
149 			cmdline = (char *)cmd->data;
150 	}
151 
152 	/* load compress data */
153 	data = (char *)COMPRESS_LOAD_ADDR;
154 	meta_iq_item_size = meta_p->iq_item_size + meta.comp_size;
155 	if (meta_p->comp_type == META_COMPRESS_TYPE_GZ) {
156 		if (info->read(info,
157 			             sector + meta_startup_part_offset + (MAX_META_SEGMENT_SIZE / info->bl_len),
158 			             DIV_ROUND_UP(meta_iq_item_size, info->bl_len),
159 			             data)
160 			  != DIV_ROUND_UP(meta_iq_item_size, info->bl_len)) {
161 			printf("%s: Failed to read compress data.\n", __func__);
162 			return -EIO;
163 		}
164 
165 		memcpy((void *)(uintptr_t)(meta_p->load + SENSOR_IQ_BIN_OFFSET), data, meta_p->iq_item_size);
166 
167 		if (rk_meta_iq_decom((meta_p->load + meta_p->comp_off),
168 				     (unsigned long)(data + meta_p->comp_off -
169 							MAX_META_SEGMENT_SIZE),
170 					 meta.comp_size, &len)) {
171 			printf("%s: Failed to decompress.\n", __func__);
172 			return -EIO;
173 		}
174 
175 	} else {
176 		if (info->read(info,
177 			             sector + meta_startup_part_offset + (MAX_META_SEGMENT_SIZE / info->bl_len),
178 			             DIV_ROUND_UP(meta_iq_item_size, info->bl_len),
179 			             (void *)(uintptr_t)(meta_p->load + MAX_META_SEGMENT_SIZE))
180 			  != DIV_ROUND_UP(meta_iq_item_size, info->bl_len)) {
181 			printf("%s: Failed to read\n", __func__);
182 			return -EIO;
183 		}
184 	}
185 
186 	meta_p->meta_flags = META_READ_DONE_FLAG;
187 	flush_cache(meta_p->load, meta_p->size);
188 	rk_meta_process();
189 
190 	printf("\nMeta: ok\n");
191 	return 0;
192 }
193 
194 void rk_meta_bootargs_append(void *fdt)
195 {
196 	if (!cmdline || (!fdt || fdt_check_header(fdt)))
197 		return;
198 
199 	fdt_bootargs_append(fdt, cmdline);
200 }
201