xref: /rk3399_rockchip-uboot/disk/part_rkparm.c (revision 7c1937d6d1c7daf8e59b4760f8adc7ee42bd7bea)
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 static int dev_num = -1;
31 
32 static int rkparm_param_parse(char *param, struct list_head *parts_head,
33 			      struct blk_desc *dev_desc)
34 {
35 	struct rkparm_part *part;
36 	const char *cmdline = strstr(param, "CMDLINE:");
37 	const char *blkdev_parts;
38 	char *cmdline_end, *next, *pend;
39 	int len, offset = 0;
40 	unsigned long size, start;
41 
42 	if (!cmdline) {
43 		printf("invalid parameter\n");
44 		return -EINVAL;
45 	}
46 
47 	blkdev_parts = strstr(cmdline, "mtdparts");
48 	next = strchr(blkdev_parts, ':');
49 	cmdline_end = strstr(cmdline, "\n"); /* end by '\n' */
50 	*cmdline_end = '\0';
51 	/*
52 	 * 1. skip "CMDLINE:"
53 	 * 2. Initrd fixup: remove unused "initrd=0x...,0x...", this for
54 	 *    compatible with legacy parameter.txt
55 	 */
56 	env_update_filter("bootargs", cmdline + strlen("CMDLINE:"), "initrd=");
57 
58 	INIT_LIST_HEAD(parts_head);
59 	while (next) {
60 		/* Skip ':' and ',' */
61 		next++;
62 		if (*next == '-') {
63 			size = (~0UL);
64 			next++;
65 		} else {
66 			size = simple_strtoul(next, &next, 16);
67 		}
68 		/* Skip '@' */
69 		next++;
70 		start = simple_strtoul(next, &next, 16);
71 		next++;
72 		pend =  strchr(next, ')');
73 		if (!pend)
74 			break;
75 		len = min_t(int, pend - next, PART_NAME_LEN);
76 		part = malloc(sizeof(*part));
77 		if (!part) {
78 			printf("out of memory\n");
79 			break;
80 		}
81 		if (dev_desc->if_type != IF_TYPE_RKNAND)
82 			offset = RK_PARAM_OFFSET;
83 		part->start = start + offset;
84 		/* Last partition use all remain space */
85 		if (size == (~0UL))
86 			size = dev_desc->lba - part->start;
87 		part->size = size;
88 		strncpy(part->name, next, len);
89 		part->name[len] = '\0';
90 		list_add_tail(&part->node, parts_head);
91 		next = strchr(next, ',');
92 	}
93 
94 	dev_num = ((dev_desc->if_type << 8) + dev_desc->devnum);
95 
96 	return 0;
97 }
98 
99 static int rkparm_init_param(struct blk_desc *dev_desc,
100 				struct list_head *parts_head)
101 {
102 	struct rkparm_param *param;
103 	int offset = 0;
104 	int ret;
105 
106 	param = memalign(ARCH_DMA_MINALIGN, MAX_PARAM_SIZE);
107 	if (!param) {
108 		printf("out of memory\n");
109 		return -ENOMEM;
110 	}
111 
112 	if (dev_desc->if_type != IF_TYPE_RKNAND)
113 		offset = RK_PARAM_OFFSET;
114 
115 	ret = blk_dread(dev_desc, offset, MAX_PARAM_SIZE >> 9, (ulong *)param);
116 	if (ret != (MAX_PARAM_SIZE >> 9)) {
117 		printf("%s param read fail\n", __func__);
118 		return -EINVAL;
119 	}
120 
121 	return rkparm_param_parse(param->params, parts_head, dev_desc);
122 
123 }
124 
125 static void part_print_rkparm(struct blk_desc *dev_desc)
126 {
127 	int ret = 0;
128 	struct list_head *node;
129 	struct rkparm_part *p = NULL;
130 	int i = 0;
131 
132 	if (list_empty(&parts_head) ||
133 	    (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum)))
134 		ret = rkparm_init_param(dev_desc, &parts_head);
135 
136 	if (ret) {
137 		printf("%s Invalid rkparm parameter\n", __func__);
138 		return;
139 	}
140 
141 	printf("Part\tStart LBA\tSize\t\tName\n");
142 	list_for_each(node, &parts_head) {
143 		p = list_entry(node, struct rkparm_part, node);
144 		printf("%3d\t0x%08lx\t0x%08lx\t%s\n", (i++ + 1),
145 		       p->start, p->size, p->name);
146 	}
147 
148 
149 	return;
150 }
151 
152 static int part_get_info_rkparm(struct blk_desc *dev_desc, int idx,
153 		      disk_partition_t *info)
154 {
155 	struct list_head *node;
156 	struct rkparm_part *p = NULL;
157 	int part_num = 1;
158 	int ret = 0;
159 
160 	if (idx < 1) {
161 		printf("%s Invalid partition no.%d\n", __func__, idx);
162 		return -EINVAL;
163 	}
164 
165 	if (list_empty(&parts_head) ||
166 	    (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum)))
167 		ret = rkparm_init_param(dev_desc, &parts_head);
168 
169 	if (ret) {
170 		printf("%s Invalid rkparm partition\n", __func__);
171 		return -1;
172 	}
173 
174 	list_for_each(node, &parts_head) {
175 		p = list_entry(node, struct rkparm_part, node);
176 		if (idx == part_num)
177 			break;
178 		part_num ++;
179 	}
180 
181 	if (part_num > idx) {
182 		printf("%s Invalid partition no.%d\n", __func__, idx);
183 		return -EINVAL;
184 	}
185 
186 	info->start = p->start;
187 	info->size = p->size << 9;
188 	info->blksz = dev_desc->blksz;
189 
190 	sprintf((char *)info->name, "%s", p->name);
191 	strcpy((char *)info->type, "U-Boot");
192 	info->bootable = 0;
193 
194 	return 0;
195 }
196 
197 static int part_test_rkparm(struct blk_desc *dev_desc)
198 {
199 	int ret = 0;
200 
201 	if (list_empty(&parts_head) ||
202 	    (dev_num != ((dev_desc->if_type << 8) + dev_desc->devnum)))
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	= RKPARM_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