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