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