xref: /OK3568_Linux_fs/u-boot/disk/part_rkparm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 
rkparm_param_parse(char * param,struct list_head * parts_head,struct blk_desc * dev_desc)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 #ifndef PARTS_RKPARM
92 		if (dev_desc->if_type != IF_TYPE_RKNAND)
93 			offset = RK_PARAM_OFFSET;
94 #endif
95 		part->start = start + offset;
96 		/* Last partition use all remain space */
97 		if (size == (~0UL))
98 			size = dev_desc->lba - part->start;
99 		part->size = size;
100 		strncpy(part->name, next, len);
101 		part->name[len] = '\0';
102 		list_add_tail(&part->node, parts_head);
103 		next = strchr(next, ',');
104 	}
105 
106 	dev_num = ((dev_desc->if_type << 8) + dev_desc->devnum);
107 
108 	return 0;
109 }
110 
rkparm_init_param(struct blk_desc * dev_desc,struct list_head * parts_head)111 static int rkparm_init_param(struct blk_desc *dev_desc,
112 					  struct list_head *parts_head)
113 {
114 	char *parts_list;
115 
116 	/*
117 	 * There are ways to get partition tables:
118 	 *
119 	 * 1. macro 'PARTS_RKPARM' string list (No RK_PARAM_OFFSET for every partition),
120 	 * 2. Legacy rk parameter in flash @RK_PARAM_OFFSET sectors offset
121 	 */
122 #ifdef PARTS_RKPARM
123 	parts_list = PARTS_RKPARM;
124 #else
125 	struct rkparm_param *param;
126 	int offset = 0;
127 	int ret;
128 
129 	param = memalign(ARCH_DMA_MINALIGN, MAX_PARAM_SIZE);
130 	if (!param) {
131 		printf("out of memory\n");
132 		return -ENOMEM;
133 	}
134 
135 	if (dev_desc->if_type != IF_TYPE_RKNAND)
136 		offset = RK_PARAM_OFFSET;
137 
138 	ret = blk_dread(dev_desc, offset, MAX_PARAM_SIZE >> 9, (ulong *)param);
139 	if (ret != (MAX_PARAM_SIZE >> 9)) {
140 		printf("%s param read fail\n", __func__);
141 		return -EINVAL;
142 	}
143 	parts_list = param->params;
144 #endif
145 	return rkparm_param_parse(parts_list, parts_head, dev_desc);
146 }
147 
part_print_rkparm(struct blk_desc * dev_desc)148 static void part_print_rkparm(struct blk_desc *dev_desc)
149 {
150 	int ret = 0;
151 	struct list_head *node;
152 	struct rkparm_part *p = NULL;
153 	int i = 0;
154 
155 	if (list_empty(&parts_head) ||
156 	    (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum)))
157 		ret = rkparm_init_param(dev_desc, &parts_head);
158 
159 	if (ret) {
160 		printf("%s Invalid rkparm parameter\n", __func__);
161 		return;
162 	}
163 
164 	printf("Part\tStart LBA\tSize\t\tName\n");
165 	list_for_each(node, &parts_head) {
166 		p = list_entry(node, struct rkparm_part, node);
167 		printf("%3d\t0x%08lx\t0x%08lx\t%s\n", (i++ + 1),
168 		       p->start, p->size, p->name);
169 	}
170 
171 	return;
172 }
173 
part_get_info_rkparm(struct blk_desc * dev_desc,int idx,disk_partition_t * info)174 static int part_get_info_rkparm(struct blk_desc *dev_desc, int idx,
175 		      disk_partition_t *info)
176 {
177 	struct list_head *node;
178 	struct rkparm_part *p = NULL;
179 	int part_num = 1;
180 	int ret = 0;
181 
182 	if (idx < 1) {
183 		printf("%s Invalid partition no.%d\n", __func__, idx);
184 		return -EINVAL;
185 	}
186 
187 	if (list_empty(&parts_head) ||
188 	    (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum))) {
189 		ret = rkparm_init_param(dev_desc, &parts_head);
190 		if (ret) {
191 			printf("%s Invalid rkparm partition\n", __func__);
192 			return -1;
193 		}
194 	}
195 
196 	list_for_each(node, &parts_head) {
197 		p = list_entry(node, struct rkparm_part, node);
198 		if (idx == part_num)
199 			break;
200 		part_num ++;
201 	}
202 
203 	if (part_num < idx) {
204 		debug("%s Invalid partition no.%d\n", __func__, idx);
205 		return -EINVAL;
206 	}
207 
208 	info->start = p->start;
209 	info->size = p->size;
210 	info->blksz = dev_desc->blksz;
211 
212 	sprintf((char *)info->name, "%s", p->name);
213 	strcpy((char *)info->type, "U-Boot");
214 	info->bootable = 0;
215 
216 	return 0;
217 }
218 
part_test_rkparm(struct blk_desc * dev_desc)219 static int part_test_rkparm(struct blk_desc *dev_desc)
220 {
221 	int ret = 0;
222 
223 	if (list_empty(&parts_head) ||
224 	    (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum)))
225 		ret = rkparm_init_param(dev_desc, &parts_head);
226 	if (ret)
227 		ret = -1;
228 
229 	return ret;
230 }
231 /*
232  * Add an 'b_' prefix so it comes before 'dos' and after 'a_efi' in the linker
233  * list. We need to check EFI first, and then rkparm partition
234  */
235 U_BOOT_PART_TYPE(b_rkparm) = {
236 #ifdef PARTS_RKPARM
237 	.name		= "RKPARM(FIXED)",
238 #else
239 	.name		= "RKPARM",
240 #endif
241 	.part_type	= PART_TYPE_RKPARM,
242 	.max_entries	= RKPARM_ENTRY_NUMBERS,
243 	.get_info	= part_get_info_ptr(part_get_info_rkparm),
244 	.print		= part_print_ptr(part_print_rkparm),
245 	.test		= part_test_rkparm,
246 };
247 #endif
248