xref: /rk3399_rockchip-uboot/disk/part_rkparm.c (revision b283d2ae7bf9dec650d82c6b10cb92ddd9d9ce5d)
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 
10 #ifdef HAVE_BLOCK_DEVICE
11 #define RK_PARAM_OFFSET			0x2000
12 #define MAX_PARAM_SIZE			(1024 * 64)
13 
14 struct rkparm_param {
15 	u32 tag;
16 	u32 length;
17 	char params[1];
18 	u32 crc;
19 };
20 
21 struct rkparm_part {
22 	char name[PART_NAME_LEN];
23 	unsigned long start;
24 	unsigned long size;
25 	struct list_head node;
26 };
27 
28 
29 static LIST_HEAD(parts_head);
30 
31 static int rkparm_param_parse(char *param, struct list_head *parts_head,
32 			      struct blk_desc *dev_desc)
33 {
34 	struct rkparm_part *part;
35 	const char *cmdline = strstr(param, "CMDLINE:");
36 	char *cmdline_end = strstr(cmdline, "\n"); /* end by '\n' */
37 	const char *blkdev_parts = strstr(cmdline, "mtdparts");
38 	const char *blkdev_def = strchr(blkdev_parts, ':') + 1;
39 	char *next = (char *)blkdev_def;
40 	char *pend;
41 	int len, offset = 0;
42 	unsigned long size, start;
43 	char *initrd;
44 	const char *str;
45 
46 	if (!cmdline) {
47 		printf("invalid parameter\n");
48 		return -EINVAL;
49 	}
50 
51 	*cmdline_end = '\0';
52 
53 	/*
54 	 * Initrd fixup: remove unused "initrd=0x...,0x...", this for
55 	 * compatible with legacy parameter.txt
56 	 */
57 	initrd = strstr(cmdline, "initrd=");
58 	if (initrd) {
59 		str = strstr(initrd, " ");
60 		/* Terminate, so cmdline can be dest for strcat() */
61 		*initrd = '\0';
62 		/* +1 to skip current white space */
63 		strcat((char *)cmdline, (str + 1));
64 	}
65 
66 	/* skip "CMDLINE:" */
67 	env_update("bootargs", cmdline + strlen("CMDLINE:"));
68 
69 	while (*next) {
70 		if (*next == '-') {
71 			size = (~0UL);
72 			next++;
73 		} else {
74 			size = simple_strtoul(next, &next, 16);
75 		}
76 		next++;
77 		start = simple_strtoul(next, &next, 16);
78 		next++;
79 		pend =  strchr(next, ')');
80 		if (!pend)
81 			break;
82 		len = min_t(int, pend - next, PART_NAME_LEN);
83 		part = malloc(sizeof(*part));
84 		if (!part) {
85 			printf("out of memory\n");
86 			break;
87 		}
88 		if (dev_desc->if_type != IF_TYPE_RKNAND)
89 			offset = RK_PARAM_OFFSET;
90 		part->start = start + offset;
91 		part->size = size;
92 		strncpy(part->name, next, len);
93 		part->name[len] = '\0';
94 		next = strchr(next, ',');
95 		next++;
96 		list_add_tail(&part->node, parts_head);
97 	}
98 
99 	return 0;
100 }
101 
102 static int rkparm_init_param(struct blk_desc *dev_desc,
103 				struct list_head *parts_head)
104 {
105 	struct rkparm_param *param;
106 	int offset = 0;
107 	int ret;
108 
109 	param = memalign(ARCH_DMA_MINALIGN, MAX_PARAM_SIZE);
110 	if (!param) {
111 		printf("out of memory\n");
112 		return -ENOMEM;
113 	}
114 
115 	if (dev_desc->if_type != IF_TYPE_RKNAND)
116 		offset = RK_PARAM_OFFSET;
117 
118 	ret = blk_dread(dev_desc, offset, MAX_PARAM_SIZE >> 9, (ulong *)param);
119 	if (ret != (MAX_PARAM_SIZE >> 9)) {
120 		printf("%s param read fail\n", __func__);
121 		return -EINVAL;
122 	}
123 
124 	return rkparm_param_parse(param->params, parts_head, dev_desc);
125 
126 }
127 
128 static void part_print_rkparm(struct blk_desc *dev_desc)
129 {
130 	int ret = 0;
131 	struct list_head *node;
132 	struct rkparm_part *p = NULL;
133 	int i = 0;
134 
135 	if (list_empty(&parts_head))
136 		ret = rkparm_init_param(dev_desc, &parts_head);
137 
138 	if (ret) {
139 		printf("%s Invalid rkparm parameter\n", __func__);
140 		return;
141 	}
142 
143 	printf("Part\tStart LBA\tSize\t\tName\n");
144 	list_for_each(node, &parts_head) {
145 		p = list_entry(node, struct rkparm_part, node);
146 		printf("%3d\t0x%08lx\t0x%08lx\t%s\n", (i++ + 1),
147 		       p->start, p->size, p->name);
148 	}
149 
150 
151 	return;
152 }
153 
154 static int part_get_info_rkparm(struct blk_desc *dev_desc, int idx,
155 		      disk_partition_t *info)
156 {
157 	struct list_head *node;
158 	struct rkparm_part *p = NULL;
159 	int part_num = 1;
160 	int ret = 0;
161 
162 	if (idx < 1) {
163 		printf("%s Invalid partition no.%d\n", __func__, idx);
164 		return -EINVAL;
165 	}
166 
167 	if (list_empty(&parts_head))
168 		ret = rkparm_init_param(dev_desc, &parts_head);
169 
170 	if (ret) {
171 		printf("%s Invalid rkparm partition\n", __func__);
172 		return -1;
173 	}
174 
175 	list_for_each(node, &parts_head) {
176 		p = list_entry(node, struct rkparm_part, node);
177 		if (idx == part_num)
178 			break;
179 		part_num ++;
180 	}
181 
182 	if (part_num > idx) {
183 		printf("%s Invalid partition no.%d\n", __func__, idx);
184 		return -EINVAL;
185 	}
186 
187 	info->start = p->start;
188 	info->size = p->size << 9;
189 	info->blksz = dev_desc->blksz;
190 
191 	sprintf((char *)info->name, "%s", p->name);
192 	strcpy((char *)info->type, "U-Boot");
193 	info->bootable = 0;
194 
195 	return 0;
196 }
197 
198 static int part_test_rkparm(struct blk_desc *dev_desc)
199 {
200 	int ret = 0;
201 
202 	if (list_empty(&parts_head))
203 		ret = rkparm_init_param(dev_desc, &parts_head);
204 	if (ret)
205 		ret = -1;
206 
207 	return ret;
208 }
209 /*
210  * Add an 'b_' prefix so it comes before 'dos' and after 'a_efi' in the linker
211  * list. We need to check EFI first, and then rkparm partition
212  */
213 U_BOOT_PART_TYPE(b_rkparm) = {
214 	.name		= "RKPARM",
215 	.part_type	= PART_TYPE_RKPARM,
216 	.max_entries	= GPT_ENTRY_NUMBERS,
217 	.get_info	= part_get_info_ptr(part_get_info_rkparm),
218 	.print		= part_print_ptr(part_print_rkparm),
219 	.test		= part_test_rkparm,
220 };
221 #endif
222