xref: /rk3399_rockchip-uboot/disk/part_rkparm.c (revision 331c2375688d79920fb06b8f0c4c52a7df56fb29)
1 /*
2  * (C) Copyright 2017 rkparm Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <malloc.h>
9 #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
10 #include <asm/arch/rk_atags.h>
11 #endif
12 
13 #ifdef HAVE_BLOCK_DEVICE
14 #define RK_PARAM_OFFSET			0x2000
15 #define MAX_PARAM_SIZE			(1024 * 64)
16 
17 struct rkparm_param {
18 	u32 tag;
19 	u32 length;
20 	char params[1];
21 	u32 crc;
22 };
23 
24 struct rkparm_part {
25 	char name[PART_NAME_LEN];
26 	unsigned long start;
27 	unsigned long size;
28 	struct list_head node;
29 };
30 
31 
32 static LIST_HEAD(parts_head);
33 
34 /*
35  * What's this?
36  *
37  * There maybe two different storage media need to use this partition driver,
38  * e.g. rkand with SD card. So we need a flag info to recognize it.
39  */
40 static int dev_num = -1;
41 
42 static int rkparm_param_parse(char *param, struct list_head *parts_head,
43 			      struct blk_desc *dev_desc)
44 {
45 	struct rkparm_part *part;
46 	const char *cmdline = strstr(param, "CMDLINE:");
47 	const char *blkdev_parts;
48 	char *cmdline_end, *next, *pend;
49 	int len, offset = 0;
50 	unsigned long size, start;
51 
52 	if (!cmdline) {
53 		debug("RKPARM: Invalid parameter part table from storage\n");
54 		return -EINVAL;
55 	}
56 
57 	blkdev_parts = strstr(cmdline, "mtdparts");
58 	next = strchr(blkdev_parts, ':');
59 	cmdline_end = strstr(cmdline, "\n"); /* end by '\n' */
60 	*cmdline_end = '\0';
61 	/*
62 	 * 1. skip "CMDLINE:"
63 	 * 2. Initrd fixup: remove unused "initrd=0x...,0x...", this for
64 	 *    compatible with legacy parameter.txt
65 	 */
66 	env_update_filter("bootargs", cmdline + strlen("CMDLINE:"), "initrd=");
67 
68 	INIT_LIST_HEAD(parts_head);
69 	while (next) {
70 		/* Skip ':' and ',' */
71 		next++;
72 		if (*next == '-') {
73 			size = (~0UL);
74 			next++;
75 		} else {
76 			size = simple_strtoul(next, &next, 16);
77 		}
78 		/* Skip '@' */
79 		next++;
80 		start = simple_strtoul(next, &next, 16);
81 		next++;
82 		pend =  strchr(next, ')');
83 		if (!pend)
84 			break;
85 		len = min_t(int, pend - next, PART_NAME_LEN);
86 		part = malloc(sizeof(*part));
87 		if (!part) {
88 			printf("out of memory\n");
89 			break;
90 		}
91 		if (dev_desc->if_type != IF_TYPE_RKNAND)
92 			offset = RK_PARAM_OFFSET;
93 		part->start = start + offset;
94 		/* Last partition use all remain space */
95 		if (size == (~0UL))
96 			size = dev_desc->lba - part->start;
97 		part->size = size;
98 		strncpy(part->name, next, len);
99 		part->name[len] = '\0';
100 		list_add_tail(&part->node, parts_head);
101 		next = strchr(next, ',');
102 	}
103 
104 	dev_num = ((dev_desc->if_type << 8) + dev_desc->devnum);
105 
106 	return 0;
107 }
108 
109 static int rkparm_init_param_from_storage(struct blk_desc *dev_desc,
110 					  struct list_head *parts_head)
111 {
112 	struct rkparm_param *param;
113 	int offset = 0;
114 	int ret;
115 
116 	param = memalign(ARCH_DMA_MINALIGN, MAX_PARAM_SIZE);
117 	if (!param) {
118 		printf("out of memory\n");
119 		return -ENOMEM;
120 	}
121 
122 	if (dev_desc->if_type != IF_TYPE_RKNAND)
123 		offset = RK_PARAM_OFFSET;
124 
125 	ret = blk_dread(dev_desc, offset, MAX_PARAM_SIZE >> 9, (ulong *)param);
126 	if (ret != (MAX_PARAM_SIZE >> 9)) {
127 		printf("%s param read fail\n", __func__);
128 		return -EINVAL;
129 	}
130 
131 	return rkparm_param_parse(param->params, parts_head, dev_desc);
132 }
133 
134 #if defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS) && defined(CONFIG_DM_RAMDISK)
135 static int rkparm_init_param_from_atags(struct blk_desc *dev_desc,
136 					struct list_head *parts_head)
137 {
138 	struct rkparm_part *part;
139 	struct tag *t;
140 	u64 start, size;
141 	int i, len;
142 
143 	if (!atags_is_available()) {
144 		debug("%s: can't find ATAGS\n", __func__);
145 		return -ENODATA;
146 	}
147 
148 	t = atags_get_tag(ATAG_RAM_PARTITION);
149 	if (!t) {
150 		debug("%s: can't find ATAGS ramdisk partition\n", __func__);
151 		return -ENODATA;
152 	}
153 
154 	INIT_LIST_HEAD(parts_head);
155 
156 	for (i = 0; i < t->u.ram_part.count; i++) {
157 		part = malloc(sizeof(*part));
158 		if (!part) {
159 			printf("%s: out of memory\n", __func__);
160 			break;
161 		}
162 
163 		len = strlen(t->u.ram_part.part[i].name) + 1;
164 		memcpy((char *)&part->name,
165 		       (char *)&t->u.ram_part.part[i].name, len);
166 
167 		start = t->u.ram_part.part[i].start;
168 		size = t->u.ram_part.part[i].size;
169 
170 		if (!IS_ALIGNED(start, dev_desc->blksz)) {
171 			printf("%s: '%s' addr(0x%llx) is not %ld byte aligned\n",
172 			       __func__, part->name, start, dev_desc->blksz);
173 			return -EINVAL;
174 		} else if (!IS_ALIGNED(size, dev_desc->blksz)) {
175 			printf("%s: '%s' size(0x%llx) is not %ld byte aligned\n",
176 			       __func__, part->name, size, dev_desc->blksz);
177 			return -EINVAL;
178 		}
179 
180 		/* Convert bytes to blksz */
181 		part->start = start / dev_desc->blksz;
182 		part->size = size / dev_desc->blksz;
183 		list_add_tail(&part->node, parts_head);
184 
185 		debug("%s: name=%s, start=0x%lx, size=0x%lx, blksz=0x%lx\n",
186 		      __func__, part->name, part->start,
187 		      part->size, dev_desc->blksz);
188 	}
189 
190 	dev_num = ((dev_desc->if_type << 8) + dev_desc->devnum);
191 
192 	return 0;
193 }
194 #endif
195 
196 static int rkparm_init_param(struct blk_desc *dev_desc,
197 			     struct list_head *parts_head)
198 {
199 	int ret;
200 
201 	ret = rkparm_init_param_from_storage(dev_desc, parts_head);
202 	if (ret) {
203 		debug("%s: failed to init param from storage\n", __func__);
204 #if defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS) && defined(CONFIG_DM_RAMDISK)
205 		ret = rkparm_init_param_from_atags(dev_desc, parts_head);
206 		if (ret) {
207 			debug("%s: failed to init param from ram\n", __func__);
208 			return ret;
209 		}
210 #endif
211 	}
212 
213 	if (ret)
214 		printf("RKPARM: Invalid parameter part table\n");
215 
216 	return ret;
217 }
218 
219 static void part_print_rkparm(struct blk_desc *dev_desc)
220 {
221 	int ret = 0;
222 	struct list_head *node;
223 	struct rkparm_part *p = NULL;
224 	int i = 0;
225 
226 	if (list_empty(&parts_head) ||
227 	    (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum)))
228 		ret = rkparm_init_param(dev_desc, &parts_head);
229 
230 	if (ret) {
231 		printf("%s Invalid rkparm parameter\n", __func__);
232 		return;
233 	}
234 
235 	printf("Part\tStart LBA\tSize\t\tName\n");
236 	list_for_each(node, &parts_head) {
237 		p = list_entry(node, struct rkparm_part, node);
238 		printf("%3d\t0x%08lx\t0x%08lx\t%s\n", (i++ + 1),
239 		       p->start, p->size, p->name);
240 	}
241 
242 	return;
243 }
244 
245 static int part_get_info_rkparm(struct blk_desc *dev_desc, int idx,
246 		      disk_partition_t *info)
247 {
248 	struct list_head *node;
249 	struct rkparm_part *p = NULL;
250 	int part_num = 1;
251 	int ret = 0;
252 
253 	if (idx < 1) {
254 		printf("%s Invalid partition no.%d\n", __func__, idx);
255 		return -EINVAL;
256 	}
257 
258 	if (list_empty(&parts_head) ||
259 	    (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) {
260 		ret = rkparm_init_param(dev_desc, &parts_head);
261 		if (ret) {
262 			printf("%s Invalid rkparm partition\n", __func__);
263 			return -1;
264 		}
265 	}
266 
267 	list_for_each(node, &parts_head) {
268 		p = list_entry(node, struct rkparm_part, node);
269 		if (idx == part_num)
270 			break;
271 		part_num ++;
272 	}
273 
274 	if (part_num < idx) {
275 		debug("%s Invalid partition no.%d\n", __func__, idx);
276 		return -EINVAL;
277 	}
278 
279 	info->start = p->start;
280 	info->size = p->size;
281 	info->blksz = dev_desc->blksz;
282 
283 	sprintf((char *)info->name, "%s", p->name);
284 	strcpy((char *)info->type, "U-Boot");
285 	info->bootable = 0;
286 
287 	return 0;
288 }
289 
290 static int part_test_rkparm(struct blk_desc *dev_desc)
291 {
292 	int ret = 0;
293 
294 	if (list_empty(&parts_head) ||
295 	    (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum)))
296 		ret = rkparm_init_param(dev_desc, &parts_head);
297 	if (ret)
298 		ret = -1;
299 
300 	return ret;
301 }
302 /*
303  * Add an 'b_' prefix so it comes before 'dos' and after 'a_efi' in the linker
304  * list. We need to check EFI first, and then rkparm partition
305  */
306 U_BOOT_PART_TYPE(b_rkparm) = {
307 	.name		= "RKPARM",
308 	.part_type	= PART_TYPE_RKPARM,
309 	.max_entries	= RKPARM_ENTRY_NUMBERS,
310 	.get_info	= part_get_info_ptr(part_get_info_rkparm),
311 	.print		= part_print_ptr(part_print_rkparm),
312 	.test		= part_test_rkparm,
313 };
314 #endif
315