xref: /OK3568_Linux_fs/u-boot/env/env_blk.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4  */
5 
6 #include <common.h>
7 #include <environment.h>
8 #include <memalign.h>
9 #include <boot_rkimg.h>
10 
11 #define __STR(X) #X
12 #define STR(X) __STR(X)
13 
14 #if defined(CONFIG_ENV_SIZE_REDUND) &&  \
15 	(CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
16 #error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
17 #endif
18 
19 DECLARE_GLOBAL_DATA_PTR;
20 
get_env_addr(struct blk_desc * blk_desc,int copy,u32 * env_addr)21 int get_env_addr(struct blk_desc *blk_desc, int copy, u32 *env_addr)
22 {
23 	s64 offset = CONFIG_ENV_OFFSET;
24 
25 #if defined(CONFIG_ENV_OFFSET_REDUND)
26 	if (copy)
27 		offset = CONFIG_ENV_OFFSET_REDUND;
28 #endif
29 	if (offset < 0)
30 		return -EINVAL;
31 
32 	*env_addr = offset;
33 
34 	return 0;
35 }
36 
get_env_dev(void)37 int get_env_dev(void)
38 {
39 	return CONFIG_SYS_MMC_ENV_DEV;
40 }
41 
42 #ifdef CONFIG_SYS_MMC_ENV_PART
43 static unsigned char env_org_hwpart;
44 
get_env_part(void)45 int get_env_part(void)
46 {
47 	return CONFIG_SYS_MMC_ENV_PART;
48 }
49 
init_blk_hwpart_for_env(struct blk_desc * blk_desc)50 static const char *init_blk_hwpart_for_env(struct blk_desc *blk_desc)
51 {
52 	enum if_type if_type;
53 	const char *devtype;
54 	int devnum, devpart, ret;
55 
56 	devtype = env_get("devtype");
57 	devnum = env_get_ulong("devnum", 10, 0);
58 	devpart = get_env_part();
59 	if_type = if_typename_to_iftype(devtype);
60 
61 	env_org_hwpart = blk_desc->hwpart;
62 	ret = blk_select_hwpart_devnum(if_type, devnum, devpart);
63 	if (ret)
64 		return "!Partition switch failed";
65 
66 	return NULL;
67 }
68 
fini_blk_hwpart_for_env(void)69 static void fini_blk_hwpart_for_env(void)
70 {
71 	enum if_type if_type;
72 	const char *devtype;
73 	int devnum;
74 
75 	devtype = env_get("devtype");
76 	devnum = env_get_ulong("devnum", 10, 0);
77 	if_type = if_typename_to_iftype(devtype);
78 
79 	blk_select_hwpart_devnum(if_type, devnum, env_org_hwpart);
80 }
81 #else
init_blk_hwpart_for_env(struct blk_desc * blk_desc)82 static inline const char *init_blk_hwpart_for_env(struct blk_desc *blk_desc)
83 { return NULL; }
fini_blk_hwpart_for_env(void)84 static inline void fini_blk_hwpart_for_env(void) {}
85 #endif
86 
87 #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_SPL_BUILD)
write_env(struct blk_desc * blk_desc,unsigned long size,unsigned long offset,const void * buffer)88 static inline int write_env(struct blk_desc *blk_desc, unsigned long size,
89 			    unsigned long offset, const void *buffer)
90 {
91 	uint blk_start, blk_cnt, n;
92 
93 	blk_start = ALIGN(offset, blk_desc->blksz) / blk_desc->blksz;
94 	blk_cnt	  = ALIGN(size, blk_desc->blksz) / blk_desc->blksz;
95 
96 	n = blk_dwrite(blk_desc, blk_start, blk_cnt, (u_char *)buffer);
97 
98 	return (n == blk_cnt) ? 0 : -1;
99 }
100 
env_blk_save(void)101 static int env_blk_save(void)
102 {
103 	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
104 	struct blk_desc *blk_desc;
105 	const char *errmsg = NULL;
106 	int ret, copy = 0;
107 	u32 offset;
108 
109 	blk_desc = rockchip_get_bootdev();
110 	if (!blk_desc) {
111 		puts("Can't find bootdev\n");
112 		return -EIO;
113 	}
114 
115 	errmsg = init_blk_hwpart_for_env(blk_desc);
116 	if (errmsg) {
117 		puts(errmsg);
118 		return -EIO;
119 	}
120 
121 	ret = env_export(env_new);
122 	if (ret)
123 		goto fini;
124 
125 #ifdef CONFIG_ENV_OFFSET_REDUND
126 	if (gd->env_valid == ENV_VALID)
127 		copy = 1;
128 #endif
129 
130 	if (get_env_addr(blk_desc, copy, &offset)) {
131 		ret = 1;
132 		goto fini;
133 	}
134 
135 	printf("Writing to %s%s(%s)... ", copy ? "redundant " : "",
136 	       env_get("devtype"), env_get("devnum"));
137 
138 	if (write_env(blk_desc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {
139 		puts("failed\n");
140 		ret = 1;
141 		goto fini;
142 	}
143 
144 	puts("done\n");
145 	ret = 0;
146 
147 #ifdef CONFIG_ENV_OFFSET_REDUND
148 	gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
149 #endif
150 
151 fini:
152 	fini_blk_hwpart_for_env();
153 
154 	return ret;
155 }
156 #endif /* CONFIG_CMD_SAVEENV && !CONFIG_SPL_BUILD */
157 
read_env(struct blk_desc * blk_desc,unsigned long size,unsigned long offset,const void * buffer)158 static inline int read_env(struct blk_desc *blk_desc, unsigned long size,
159 			   unsigned long offset, const void *buffer)
160 {
161 	uint blk_start, blk_cnt, n;
162 
163 	blk_start = ALIGN(offset, blk_desc->blksz) / blk_desc->blksz;
164 	blk_cnt	  = ALIGN(size, blk_desc->blksz) / blk_desc->blksz;
165 
166 	n = blk_dread(blk_desc, blk_start, blk_cnt, (uchar *)buffer);
167 
168 	return (n == blk_cnt) ? 0 : -1;
169 }
170 
171 #ifdef CONFIG_ENV_OFFSET_REDUND
env_blk_load(void)172 static int env_blk_load(void)
173 {
174 #if !defined(ENV_IS_EMBEDDED)
175 	struct blk_desc *blk_desc;
176 	const char *errmsg = NULL;
177 	int read1_fail = 0, read2_fail = 0;
178 	u32 offset1, offset2;
179 	int ret;
180 
181 	ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env1, 1);
182 	ALLOC_CACHE_ALIGN_BUFFER(env_t, tmp_env2, 1);
183 
184 	blk_desc = rockchip_get_bootdev();
185 	if (!blk_desc) {
186 		puts("Can't find bootdev\n");
187 		return -EIO;
188 	}
189 
190 	errmsg = init_blk_hwpart_for_env(blk_desc);
191 	if (errmsg) {
192 		ret = -EIO;
193 		goto err;
194 	}
195 
196 	if (get_env_addr(blk_desc, 0, &offset1) ||
197 	    get_env_addr(blk_desc, 1, &offset2)) {
198 		ret = -EIO;
199 		goto fini;
200 	}
201 
202 	read1_fail = read_env(blk_desc, CONFIG_ENV_SIZE, offset1, tmp_env1);
203 	read2_fail = read_env(blk_desc, CONFIG_ENV_SIZE, offset2, tmp_env2);
204 
205 	if (read1_fail && read2_fail)
206 		puts("*** Error - No Valid Environment Area found\n");
207 	else if (read1_fail || read2_fail)
208 		puts("*** Warning - some problems detected "
209 		     "reading environment; recovered successfully\n");
210 
211 	if (read1_fail && read2_fail) {
212 		errmsg = "!bad CRC";
213 		ret = -EIO;
214 		goto fini;
215 	} else if (!read1_fail && read2_fail) {
216 		gd->env_valid = ENV_VALID;
217 		env_import((char *)tmp_env1, 1);
218 	} else if (read1_fail && !read2_fail) {
219 		gd->env_valid = ENV_REDUND;
220 		env_import((char *)tmp_env2, 1);
221 	} else {
222 		env_import_redund((char *)tmp_env1, (char *)tmp_env2);
223 	}
224 
225 	ret = 0;
226 
227 fini:
228 	fini_blk_hwpart_for_env();
229 err:
230 	if (ret)
231 		set_default_env(errmsg);
232 
233 #endif
234 	return ret;
235 }
236 #else /* ! CONFIG_ENV_OFFSET_REDUND */
env_blk_load(void)237 static int env_blk_load(void)
238 {
239 #if !defined(ENV_IS_EMBEDDED)
240 	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
241 	struct blk_desc *blk_desc;
242 	const char *errmsg = NULL;
243 	u32 offset;
244 	int ret;
245 
246 	blk_desc = rockchip_get_bootdev();
247 	if (!blk_desc) {
248 		puts("Can't find bootdev\n");
249 		return -EIO;
250 	}
251 
252 	errmsg = init_blk_hwpart_for_env(blk_desc);
253 	if (errmsg) {
254 		ret = -EIO;
255 		puts(errmsg);
256 		goto err;
257 	}
258 
259 	if (get_env_addr(blk_desc, 0, &offset)) {
260 		ret = -EIO;
261 		goto fini;
262 	}
263 
264 	if (read_env(blk_desc, CONFIG_ENV_SIZE, offset, buf)) {
265 		errmsg = "!read failed";
266 		ret = -EIO;
267 		goto fini;
268 	}
269 
270 	env_import(buf, 1);
271 	ret = 0;
272 
273 fini:
274 	fini_blk_hwpart_for_env();
275 err:
276 	if (ret)
277 		set_default_env(errmsg);
278 #endif
279 	return ret;
280 }
281 #endif /* CONFIG_ENV_OFFSET_REDUND */
282 
283 U_BOOT_ENV_LOCATION(env_blk) = {
284 	.location	= ENVL_BLK,
285 	ENV_NAME("ENV_BLK")
286 	.load		= env_blk_load,
287 #ifndef CONFIG_SPL_BUILD
288 	.save		= env_save_ptr(env_blk_save),
289 #endif
290 };
291