]>
Commit | Line | Data |
---|---|---|
13a5695b | 1 | /* |
cc49cade SW |
2 | * (C) Copyright 2008 |
3 | * Stuart Wood, Lab X Technologies <stuart.wood@labxtechnologies.com> | |
4 | * | |
13a5695b WD |
5 | * (C) Copyright 2004 |
6 | * Jian Zhang, Texas Instruments, jzhang@ti.com. | |
7 | ||
d12ae808 | 8 | * (C) Copyright 2000-2006 |
13a5695b WD |
9 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. |
10 | * | |
11 | * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
12 | * Andreas Heppel <aheppel@sysgo.de> | |
13 | ||
14 | * See file CREDITS for list of people who contributed to this | |
15 | * project. | |
16 | * | |
17 | * This program is free software; you can redistribute it and/or | |
18 | * modify it under the terms of the GNU General Public License as | |
19 | * published by the Free Software Foundation; either version 2 of | |
20 | * the License, or (at your option) any later version. | |
21 | * | |
22 | * This program is distributed in the hope that it will be useful, | |
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
25 | * GNU General Public License for more details. | |
26 | * | |
27 | * You should have received a copy of the GNU General Public License | |
28 | * along with this program; if not, write to the Free Software | |
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
30 | * MA 02111-1307 USA | |
31 | */ | |
32 | ||
33 | /* #define DEBUG */ | |
34 | ||
35 | #include <common.h> | |
13a5695b WD |
36 | #include <command.h> |
37 | #include <environment.h> | |
38 | #include <linux/stddef.h> | |
e443c944 | 39 | #include <malloc.h> |
addb2e16 | 40 | #include <nand.h> |
13a5695b | 41 | |
bdab39d3 | 42 | #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND) |
13a5695b | 43 | #define CMD_SAVEENV |
0e8d1586 | 44 | #elif defined(CONFIG_ENV_OFFSET_REDUND) |
bdab39d3 | 45 | #error Cannot use CONFIG_ENV_OFFSET_REDUND without CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND |
13a5695b WD |
46 | #endif |
47 | ||
0e8d1586 JCPV |
48 | #if defined(CONFIG_ENV_SIZE_REDUND) && (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE) |
49 | #error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE | |
13a5695b WD |
50 | #endif |
51 | ||
13a5695b WD |
52 | #ifdef CONFIG_INFERNO |
53 | #error CONFIG_INFERNO not supported yet | |
54 | #endif | |
55 | ||
0e8d1586 JCPV |
56 | #ifndef CONFIG_ENV_RANGE |
57 | #define CONFIG_ENV_RANGE CONFIG_ENV_SIZE | |
cc49cade SW |
58 | #endif |
59 | ||
13a5695b WD |
60 | /* references to names in env_common.c */ |
61 | extern uchar default_environment[]; | |
62 | extern int default_environment_size; | |
63 | ||
64 | char * env_name_spec = "NAND"; | |
65 | ||
66 | ||
b74ab737 | 67 | #if defined(ENV_IS_EMBEDDED) |
13a5695b WD |
68 | extern uchar environment[]; |
69 | env_t *env_ptr = (env_t *)(&environment[0]); | |
b74ab737 GL |
70 | #elif defined(CONFIG_NAND_ENV_DST) |
71 | env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST; | |
13a5695b | 72 | #else /* ! ENV_IS_EMBEDDED */ |
49822e23 | 73 | env_t *env_ptr = 0; |
13a5695b WD |
74 | #endif /* ENV_IS_EMBEDDED */ |
75 | ||
76 | ||
77 | /* local functions */ | |
d12ae808 | 78 | #if !defined(ENV_IS_EMBEDDED) |
13a5695b | 79 | static void use_default(void); |
d12ae808 | 80 | #endif |
13a5695b | 81 | |
d87080b7 | 82 | DECLARE_GLOBAL_DATA_PTR; |
13a5695b WD |
83 | |
84 | uchar env_get_char_spec (int index) | |
85 | { | |
13a5695b WD |
86 | return ( *((uchar *)(gd->env_addr + index)) ); |
87 | } | |
88 | ||
89 | ||
90 | /* this is called before nand_init() | |
91 | * so we can't read Nand to validate env data. | |
92 | * Mark it OK for now. env_relocate() in env_common.c | |
99c2b434 MZ |
93 | * will call our relocate function which does the real |
94 | * validation. | |
d12ae808 SR |
95 | * |
96 | * When using a NAND boot image (like sequoia_nand), the environment | |
97 | * can be embedded or attached to the U-Boot image in NAND flash. This way | |
98 | * the SPL loads not only the U-Boot image from NAND but also the | |
99 | * environment. | |
13a5695b WD |
100 | */ |
101 | int env_init(void) | |
102 | { | |
b74ab737 | 103 | #if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST) |
d12ae808 | 104 | int crc1_ok = 0, crc2_ok = 0; |
b74ab737 GL |
105 | env_t *tmp_env1; |
106 | ||
107 | #ifdef CONFIG_ENV_OFFSET_REDUND | |
108 | env_t *tmp_env2; | |
d12ae808 | 109 | |
0e8d1586 | 110 | tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE); |
b74ab737 GL |
111 | crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc); |
112 | #endif | |
113 | ||
114 | tmp_env1 = env_ptr; | |
d12ae808 SR |
115 | |
116 | crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc); | |
d12ae808 | 117 | |
b74ab737 GL |
118 | if (!crc1_ok && !crc2_ok) { |
119 | gd->env_addr = 0; | |
d12ae808 | 120 | gd->env_valid = 0; |
b74ab737 GL |
121 | |
122 | return 0; | |
123 | } else if (crc1_ok && !crc2_ok) { | |
d12ae808 | 124 | gd->env_valid = 1; |
b74ab737 GL |
125 | } |
126 | #ifdef CONFIG_ENV_OFFSET_REDUND | |
127 | else if (!crc1_ok && crc2_ok) { | |
d12ae808 | 128 | gd->env_valid = 2; |
b74ab737 | 129 | } else { |
d12ae808 SR |
130 | /* both ok - check serial */ |
131 | if(tmp_env1->flags == 255 && tmp_env2->flags == 0) | |
132 | gd->env_valid = 2; | |
133 | else if(tmp_env2->flags == 255 && tmp_env1->flags == 0) | |
134 | gd->env_valid = 1; | |
135 | else if(tmp_env1->flags > tmp_env2->flags) | |
136 | gd->env_valid = 1; | |
137 | else if(tmp_env2->flags > tmp_env1->flags) | |
138 | gd->env_valid = 2; | |
139 | else /* flags are equal - almost impossible */ | |
140 | gd->env_valid = 1; | |
141 | } | |
142 | ||
b74ab737 GL |
143 | if (gd->env_valid == 2) |
144 | env_ptr = tmp_env2; | |
145 | else | |
146 | #endif | |
d12ae808 SR |
147 | if (gd->env_valid == 1) |
148 | env_ptr = tmp_env1; | |
b74ab737 GL |
149 | |
150 | gd->env_addr = (ulong)env_ptr->data; | |
151 | ||
152 | #else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */ | |
e443c944 | 153 | gd->env_addr = (ulong)&default_environment[0]; |
13a5695b | 154 | gd->env_valid = 1; |
b74ab737 | 155 | #endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */ |
13a5695b WD |
156 | |
157 | return (0); | |
158 | } | |
159 | ||
160 | #ifdef CMD_SAVEENV | |
addb2e16 BS |
161 | /* |
162 | * The legacy NAND code saved the environment in the first NAND device i.e., | |
163 | * nand_dev_desc + 0. This is also the behaviour using the new NAND code. | |
164 | */ | |
cc49cade SW |
165 | int writeenv(size_t offset, u_char *buf) |
166 | { | |
0e8d1586 | 167 | size_t end = offset + CONFIG_ENV_RANGE; |
cc49cade | 168 | size_t amount_saved = 0; |
c3db8c64 | 169 | size_t blocksize, len; |
cc49cade SW |
170 | |
171 | u_char *char_ptr; | |
172 | ||
173 | blocksize = nand_info[0].erasesize; | |
0e8d1586 | 174 | len = min(blocksize, CONFIG_ENV_SIZE); |
cc49cade | 175 | |
0e8d1586 | 176 | while (amount_saved < CONFIG_ENV_SIZE && offset < end) { |
cc49cade SW |
177 | if (nand_block_isbad(&nand_info[0], offset)) { |
178 | offset += blocksize; | |
179 | } else { | |
180 | char_ptr = &buf[amount_saved]; | |
c3db8c64 | 181 | if (nand_write(&nand_info[0], offset, &len, |
cc49cade SW |
182 | char_ptr)) |
183 | return 1; | |
184 | offset += blocksize; | |
c3db8c64 | 185 | amount_saved += len; |
cc49cade SW |
186 | } |
187 | } | |
0e8d1586 | 188 | if (amount_saved != CONFIG_ENV_SIZE) |
cc49cade SW |
189 | return 1; |
190 | ||
191 | return 0; | |
192 | } | |
0e8d1586 | 193 | #ifdef CONFIG_ENV_OFFSET_REDUND |
13a5695b WD |
194 | int saveenv(void) |
195 | { | |
2770bcb2 | 196 | int ret = 0; |
cc49cade | 197 | nand_erase_options_t nand_erase_options; |
e443c944 | 198 | |
e443c944 | 199 | env_ptr->flags++; |
e443c944 | 200 | |
0e8d1586 | 201 | nand_erase_options.length = CONFIG_ENV_RANGE; |
cc49cade SW |
202 | nand_erase_options.quiet = 0; |
203 | nand_erase_options.jffs2 = 0; | |
204 | nand_erase_options.scrub = 0; | |
205 | ||
0e8d1586 | 206 | if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) |
cc49cade | 207 | return 1; |
e443c944 | 208 | if(gd->env_valid == 1) { |
cc49cade | 209 | puts ("Erasing redundant Nand...\n"); |
0e8d1586 | 210 | nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; |
cc49cade | 211 | if (nand_erase_opts(&nand_info[0], &nand_erase_options)) |
e443c944 | 212 | return 1; |
cc49cade | 213 | |
e443c944 | 214 | puts ("Writing to redundant Nand... "); |
0e8d1586 | 215 | ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) env_ptr); |
e443c944 | 216 | } else { |
cc49cade | 217 | puts ("Erasing Nand...\n"); |
0e8d1586 | 218 | nand_erase_options.offset = CONFIG_ENV_OFFSET; |
cc49cade | 219 | if (nand_erase_opts(&nand_info[0], &nand_erase_options)) |
e443c944 MK |
220 | return 1; |
221 | ||
222 | puts ("Writing to Nand... "); | |
0e8d1586 | 223 | ret = writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr); |
e443c944 | 224 | } |
cc49cade SW |
225 | if (ret) { |
226 | puts("FAILED!\n"); | |
e443c944 | 227 | return 1; |
cc49cade | 228 | } |
e443c944 MK |
229 | |
230 | puts ("done\n"); | |
231 | gd->env_valid = (gd->env_valid == 2 ? 1 : 2); | |
232 | return ret; | |
233 | } | |
0e8d1586 | 234 | #else /* ! CONFIG_ENV_OFFSET_REDUND */ |
e443c944 MK |
235 | int saveenv(void) |
236 | { | |
d52fb7e3 | 237 | int ret = 0; |
9e4006bc | 238 | nand_erase_options_t nand_erase_options; |
e093a247 | 239 | |
0e8d1586 | 240 | nand_erase_options.length = CONFIG_ENV_RANGE; |
cc49cade SW |
241 | nand_erase_options.quiet = 0; |
242 | nand_erase_options.jffs2 = 0; | |
243 | nand_erase_options.scrub = 0; | |
0e8d1586 | 244 | nand_erase_options.offset = CONFIG_ENV_OFFSET; |
cc49cade | 245 | |
0e8d1586 | 246 | if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) |
cc49cade SW |
247 | return 1; |
248 | puts ("Erasing Nand...\n"); | |
249 | if (nand_erase_opts(&nand_info[0], &nand_erase_options)) | |
addb2e16 | 250 | return 1; |
13a5695b WD |
251 | |
252 | puts ("Writing to Nand... "); | |
0e8d1586 | 253 | if (writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr)) { |
cc49cade | 254 | puts("FAILED!\n"); |
13a5695b | 255 | return 1; |
cc49cade | 256 | } |
13a5695b | 257 | |
addb2e16 BS |
258 | puts ("done\n"); |
259 | return ret; | |
13a5695b | 260 | } |
0e8d1586 | 261 | #endif /* CONFIG_ENV_OFFSET_REDUND */ |
13a5695b WD |
262 | #endif /* CMD_SAVEENV */ |
263 | ||
cc49cade SW |
264 | int readenv (size_t offset, u_char * buf) |
265 | { | |
0e8d1586 | 266 | size_t end = offset + CONFIG_ENV_RANGE; |
cc49cade | 267 | size_t amount_loaded = 0; |
c3db8c64 | 268 | size_t blocksize, len; |
cc49cade SW |
269 | |
270 | u_char *char_ptr; | |
271 | ||
272 | blocksize = nand_info[0].erasesize; | |
0e8d1586 | 273 | len = min(blocksize, CONFIG_ENV_SIZE); |
cc49cade | 274 | |
0e8d1586 | 275 | while (amount_loaded < CONFIG_ENV_SIZE && offset < end) { |
cc49cade SW |
276 | if (nand_block_isbad(&nand_info[0], offset)) { |
277 | offset += blocksize; | |
278 | } else { | |
279 | char_ptr = &buf[amount_loaded]; | |
c3db8c64 | 280 | if (nand_read(&nand_info[0], offset, &len, char_ptr)) |
cc49cade SW |
281 | return 1; |
282 | offset += blocksize; | |
c3db8c64 | 283 | amount_loaded += len; |
cc49cade SW |
284 | } |
285 | } | |
0e8d1586 | 286 | if (amount_loaded != CONFIG_ENV_SIZE) |
cc49cade SW |
287 | return 1; |
288 | ||
289 | return 0; | |
290 | } | |
291 | ||
0e8d1586 | 292 | #ifdef CONFIG_ENV_OFFSET_REDUND |
e443c944 MK |
293 | void env_relocate_spec (void) |
294 | { | |
295 | #if !defined(ENV_IS_EMBEDDED) | |
2770bcb2 | 296 | int crc1_ok = 0, crc2_ok = 0; |
e443c944 MK |
297 | env_t *tmp_env1, *tmp_env2; |
298 | ||
0e8d1586 JCPV |
299 | tmp_env1 = (env_t *) malloc(CONFIG_ENV_SIZE); |
300 | tmp_env2 = (env_t *) malloc(CONFIG_ENV_SIZE); | |
e443c944 | 301 | |
0e8d1586 | 302 | if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1)) |
cc49cade | 303 | puts("No Valid Environment Area Found\n"); |
0e8d1586 | 304 | if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2)) |
cc49cade | 305 | puts("No Valid Reundant Environment Area Found\n"); |
e443c944 MK |
306 | |
307 | crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc); | |
308 | crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc); | |
309 | ||
5a9427dc | 310 | if(!crc1_ok && !crc2_ok) { |
311 | free(tmp_env1); | |
312 | free(tmp_env2); | |
e443c944 | 313 | return use_default(); |
5a9427dc | 314 | } else if(crc1_ok && !crc2_ok) |
e443c944 MK |
315 | gd->env_valid = 1; |
316 | else if(!crc1_ok && crc2_ok) | |
317 | gd->env_valid = 2; | |
318 | else { | |
319 | /* both ok - check serial */ | |
320 | if(tmp_env1->flags == 255 && tmp_env2->flags == 0) | |
321 | gd->env_valid = 2; | |
322 | else if(tmp_env2->flags == 255 && tmp_env1->flags == 0) | |
323 | gd->env_valid = 1; | |
324 | else if(tmp_env1->flags > tmp_env2->flags) | |
325 | gd->env_valid = 1; | |
326 | else if(tmp_env2->flags > tmp_env1->flags) | |
327 | gd->env_valid = 2; | |
328 | else /* flags are equal - almost impossible */ | |
329 | gd->env_valid = 1; | |
13a5695b | 330 | |
e443c944 MK |
331 | } |
332 | ||
333 | free(env_ptr); | |
334 | if(gd->env_valid == 1) { | |
335 | env_ptr = tmp_env1; | |
336 | free(tmp_env2); | |
337 | } else { | |
338 | env_ptr = tmp_env2; | |
339 | free(tmp_env1); | |
340 | } | |
341 | ||
342 | #endif /* ! ENV_IS_EMBEDDED */ | |
343 | } | |
0e8d1586 | 344 | #else /* ! CONFIG_ENV_OFFSET_REDUND */ |
addb2e16 BS |
345 | /* |
346 | * The legacy NAND code saved the environment in the first NAND device i.e., | |
347 | * nand_dev_desc + 0. This is also the behaviour using the new NAND code. | |
348 | */ | |
13a5695b WD |
349 | void env_relocate_spec (void) |
350 | { | |
351 | #if !defined(ENV_IS_EMBEDDED) | |
d52fb7e3 | 352 | int ret; |
13a5695b | 353 | |
0e8d1586 | 354 | ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr); |
c3db8c64 | 355 | if (ret) |
13a5695b WD |
356 | return use_default(); |
357 | ||
358 | if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) | |
359 | return use_default(); | |
360 | #endif /* ! ENV_IS_EMBEDDED */ | |
13a5695b | 361 | } |
0e8d1586 | 362 | #endif /* CONFIG_ENV_OFFSET_REDUND */ |
13a5695b | 363 | |
d12ae808 | 364 | #if !defined(ENV_IS_EMBEDDED) |
13a5695b WD |
365 | static void use_default() |
366 | { | |
13a5695b | 367 | puts ("*** Warning - bad CRC or NAND, using default environment\n\n"); |
5bb12dbd | 368 | set_default_env(); |
13a5695b | 369 | } |
d12ae808 | 370 | #endif |