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