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