blob: 1b12c68d68806d4e49b66670de38408dec999aff [file] [log] [blame]
wdenk13a56952004-06-09 14:58:14 +00001/*
Wolfgang Denkea882ba2010-06-20 23:33:59 +02002 * (C) Copyright 2000-2010
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Stuart Woodcc49cad2008-05-30 16:05:28 -04005 * (C) Copyright 2008
6 * Stuart Wood, Lab X Technologies <stuart.wood@labxtechnologies.com>
7 *
wdenk13a56952004-06-09 14:58:14 +00008 * (C) Copyright 2004
9 * Jian Zhang, Texas Instruments, jzhang@ti.com.
wdenk13a56952004-06-09 14:58:14 +000010 *
11 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
12 * Andreas Heppel <aheppel@sysgo.de>
Wolfgang Denkea882ba2010-06-20 23:33:59 +020013 *
wdenk13a56952004-06-09 14:58:14 +000014 * 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
Wolfgang Denkea882ba2010-06-20 23:33:59 +020033#define DEBUG
wdenk13a56952004-06-09 14:58:14 +000034
35#include <common.h>
wdenk13a56952004-06-09 14:58:14 +000036#include <command.h>
37#include <environment.h>
38#include <linux/stddef.h>
Markus Klotzbuechere443c942006-03-20 18:02:44 +010039#include <malloc.h>
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +010040#include <nand.h>
Wolfgang Denkea882ba2010-06-20 23:33:59 +020041#include <search.h>
42#include <errno.h>
wdenk13a56952004-06-09 14:58:14 +000043
Mike Frysingerbdab39d2009-01-28 19:08:14 -050044#if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
wdenk13a56952004-06-09 14:58:14 +000045#define CMD_SAVEENV
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020046#elif defined(CONFIG_ENV_OFFSET_REDUND)
Mike Frysingerbdab39d2009-01-28 19:08:14 -050047#error Cannot use CONFIG_ENV_OFFSET_REDUND without CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND
wdenk13a56952004-06-09 14:58:14 +000048#endif
49
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020050#if defined(CONFIG_ENV_SIZE_REDUND) && (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
51#error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
wdenk13a56952004-06-09 14:58:14 +000052#endif
53
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020054#ifndef CONFIG_ENV_RANGE
55#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
Stuart Woodcc49cad2008-05-30 16:05:28 -040056#endif
57
Wolfgang Denkea882ba2010-06-20 23:33:59 +020058char *env_name_spec = "NAND";
wdenk13a56952004-06-09 14:58:14 +000059
60
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020061#if defined(ENV_IS_EMBEDDED)
wdenk13a56952004-06-09 14:58:14 +000062extern uchar environment[];
63env_t *env_ptr = (env_t *)(&environment[0]);
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020064#elif defined(CONFIG_NAND_ENV_DST)
65env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST;
wdenk13a56952004-06-09 14:58:14 +000066#else /* ! ENV_IS_EMBEDDED */
wdenk49822e22004-06-19 21:19:10 +000067env_t *env_ptr = 0;
wdenk13a56952004-06-09 14:58:14 +000068#endif /* ENV_IS_EMBEDDED */
69
Wolfgang Denkd87080b2006-03-31 18:32:53 +020070DECLARE_GLOBAL_DATA_PTR;
wdenk13a56952004-06-09 14:58:14 +000071
72uchar env_get_char_spec (int index)
73{
wdenk13a56952004-06-09 14:58:14 +000074 return ( *((uchar *)(gd->env_addr + index)) );
75}
76
Wolfgang Denkea882ba2010-06-20 23:33:59 +020077/*
78 * This is called before nand_init() so we can't read NAND to
79 * validate env data.
80 *
81 * Mark it OK for now. env_relocate() in env_common.c will call our
82 * relocate function which does the real validation.
Stefan Roesed12ae802006-09-12 20:19:10 +020083 *
84 * When using a NAND boot image (like sequoia_nand), the environment
Wolfgang Denkea882ba2010-06-20 23:33:59 +020085 * can be embedded or attached to the U-Boot image in NAND flash.
86 * This way the SPL loads not only the U-Boot image from NAND but
87 * also the environment.
wdenk13a56952004-06-09 14:58:14 +000088 */
89int env_init(void)
90{
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020091#if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
Stefan Roesed12ae802006-09-12 20:19:10 +020092 int crc1_ok = 0, crc2_ok = 0;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020093 env_t *tmp_env1;
94
95#ifdef CONFIG_ENV_OFFSET_REDUND
96 env_t *tmp_env2;
97
98 tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
99 crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
100#endif
Stefan Roesed12ae802006-09-12 20:19:10 +0200101
Stefan Roesed12ae802006-09-12 20:19:10 +0200102 tmp_env1 = env_ptr;
Stefan Roesed12ae802006-09-12 20:19:10 +0200103
104 crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
Stefan Roesed12ae802006-09-12 20:19:10 +0200105
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200106 if (!crc1_ok && !crc2_ok) {
107 gd->env_addr = 0;
Stefan Roesed12ae802006-09-12 20:19:10 +0200108 gd->env_valid = 0;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200109
110 return 0;
111 } else if (crc1_ok && !crc2_ok) {
Stefan Roesed12ae802006-09-12 20:19:10 +0200112 gd->env_valid = 1;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200113 }
114#ifdef CONFIG_ENV_OFFSET_REDUND
115 else if (!crc1_ok && crc2_ok) {
Stefan Roesed12ae802006-09-12 20:19:10 +0200116 gd->env_valid = 2;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200117 } else {
Stefan Roesed12ae802006-09-12 20:19:10 +0200118 /* both ok - check serial */
119 if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
120 gd->env_valid = 2;
121 else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
122 gd->env_valid = 1;
123 else if(tmp_env1->flags > tmp_env2->flags)
124 gd->env_valid = 1;
125 else if(tmp_env2->flags > tmp_env1->flags)
126 gd->env_valid = 2;
127 else /* flags are equal - almost impossible */
128 gd->env_valid = 1;
129 }
130
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200131 if (gd->env_valid == 2)
132 env_ptr = tmp_env2;
133 else
134#endif
Stefan Roesed12ae802006-09-12 20:19:10 +0200135 if (gd->env_valid == 1)
136 env_ptr = tmp_env1;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200137
138 gd->env_addr = (ulong)env_ptr->data;
139
140#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100141 gd->env_addr = (ulong)&default_environment[0];
wdenk13a56952004-06-09 14:58:14 +0000142 gd->env_valid = 1;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200143#endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
wdenk13a56952004-06-09 14:58:14 +0000144
145 return (0);
146}
147
148#ifdef CMD_SAVEENV
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100149/*
150 * The legacy NAND code saved the environment in the first NAND device i.e.,
151 * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
152 */
Stuart Woodcc49cad2008-05-30 16:05:28 -0400153int writeenv(size_t offset, u_char *buf)
154{
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200155 size_t end = offset + CONFIG_ENV_RANGE;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400156 size_t amount_saved = 0;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200157 size_t blocksize, len;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400158
159 u_char *char_ptr;
160
161 blocksize = nand_info[0].erasesize;
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200162 len = min(blocksize, CONFIG_ENV_SIZE);
Stuart Woodcc49cad2008-05-30 16:05:28 -0400163
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200164 while (amount_saved < CONFIG_ENV_SIZE && offset < end) {
Stuart Woodcc49cad2008-05-30 16:05:28 -0400165 if (nand_block_isbad(&nand_info[0], offset)) {
166 offset += blocksize;
167 } else {
168 char_ptr = &buf[amount_saved];
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200169 if (nand_write(&nand_info[0], offset, &len,
Stuart Woodcc49cad2008-05-30 16:05:28 -0400170 char_ptr))
171 return 1;
172 offset += blocksize;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200173 amount_saved += len;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400174 }
175 }
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200176 if (amount_saved != CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400177 return 1;
178
179 return 0;
180}
Scott Woodeef1d712011-02-08 15:25:02 -0600181
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200182#ifdef CONFIG_ENV_OFFSET_REDUND
Scott Woodeef1d712011-02-08 15:25:02 -0600183static unsigned char env_flags;
184
wdenk13a56952004-06-09 14:58:14 +0000185int saveenv(void)
186{
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200187 env_t env_new;
188 ssize_t len;
189 char *res;
190 int ret = 0;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400191 nand_erase_options_t nand_erase_options;
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100192
Daniel Hobi3b250ff2011-05-18 15:21:08 +0200193 memset(&nand_erase_options, 0, sizeof(nand_erase_options));
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200194 nand_erase_options.length = CONFIG_ENV_RANGE;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400195
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200196 if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400197 return 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200198
199 res = (char *)&env_new.data;
Wolfgang Denk37f2fe72011-11-06 22:49:44 +0100200 len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200201 if (len < 0) {
202 error("Cannot export environment: errno = %d\n", errno);
203 return 1;
204 }
205 env_new.crc = crc32(0, env_new.data, ENV_SIZE);
Scott Woodeef1d712011-02-08 15:25:02 -0600206 env_new.flags = ++env_flags; /* increase the serial */
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200207
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100208 if(gd->env_valid == 1) {
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200209 puts("Erasing redundant NAND...\n");
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200210 nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400211 if (nand_erase_opts(&nand_info[0], &nand_erase_options))
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100212 return 1;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400213
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200214 puts("Writing to redundant NAND... ");
215 ret = writeenv(CONFIG_ENV_OFFSET_REDUND,
216 (u_char *)&env_new);
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100217 } else {
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200218 puts("Erasing NAND...\n");
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200219 nand_erase_options.offset = CONFIG_ENV_OFFSET;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400220 if (nand_erase_opts(&nand_info[0], &nand_erase_options))
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100221 return 1;
222
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200223 puts("Writing to NAND... ");
224 ret = writeenv(CONFIG_ENV_OFFSET,
225 (u_char *)&env_new);
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100226 }
Stuart Woodcc49cad2008-05-30 16:05:28 -0400227 if (ret) {
228 puts("FAILED!\n");
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100229 return 1;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400230 }
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100231
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200232 puts("done\n");
233
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100234 gd->env_valid = (gd->env_valid == 2 ? 1 : 2);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200235
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100236 return ret;
237}
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200238#else /* ! CONFIG_ENV_OFFSET_REDUND */
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100239int saveenv(void)
240{
Wolfgang Denkd52fb7e2006-03-11 22:53:33 +0100241 int ret = 0;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200242 env_t env_new;
243 ssize_t len;
244 char *res;
Philip Balister9e4006bc2008-06-16 08:58:07 -0400245 nand_erase_options_t nand_erase_options;
Wolfgang Denke093a242008-06-28 23:34:37 +0200246
Daniel Hobi3b250ff2011-05-18 15:21:08 +0200247 memset(&nand_erase_options, 0, sizeof(nand_erase_options));
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200248 nand_erase_options.length = CONFIG_ENV_RANGE;
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200249 nand_erase_options.offset = CONFIG_ENV_OFFSET;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400250
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200251 if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400252 return 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200253
254 res = (char *)&env_new.data;
Wolfgang Denk37f2fe72011-11-06 22:49:44 +0100255 len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200256 if (len < 0) {
257 error("Cannot export environment: errno = %d\n", errno);
258 return 1;
259 }
260 env_new.crc = crc32(0, env_new.data, ENV_SIZE);
261
262 puts("Erasing Nand...\n");
Stuart Woodcc49cad2008-05-30 16:05:28 -0400263 if (nand_erase_opts(&nand_info[0], &nand_erase_options))
wdenk13a56952004-06-09 14:58:14 +0000264 return 1;
265
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200266 puts("Writing to Nand... ");
267 if (writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new)) {
Stuart Woodcc49cad2008-05-30 16:05:28 -0400268 puts("FAILED!\n");
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100269 return 1;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400270 }
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100271
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200272 puts("done\n");
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100273 return ret;
wdenk13a56952004-06-09 14:58:14 +0000274}
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200275#endif /* CONFIG_ENV_OFFSET_REDUND */
wdenk13a56952004-06-09 14:58:14 +0000276#endif /* CMD_SAVEENV */
277
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200278int readenv(size_t offset, u_char * buf)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400279{
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200280 size_t end = offset + CONFIG_ENV_RANGE;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400281 size_t amount_loaded = 0;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200282 size_t blocksize, len;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400283
284 u_char *char_ptr;
285
286 blocksize = nand_info[0].erasesize;
Mike Frysinger962ad592010-08-11 23:42:26 -0400287 if (!blocksize)
288 return 1;
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200289 len = min(blocksize, CONFIG_ENV_SIZE);
Stuart Woodcc49cad2008-05-30 16:05:28 -0400290
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200291 while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
Stuart Woodcc49cad2008-05-30 16:05:28 -0400292 if (nand_block_isbad(&nand_info[0], offset)) {
293 offset += blocksize;
294 } else {
295 char_ptr = &buf[amount_loaded];
Steve Sakoman068a2082010-12-03 13:25:43 +0000296 if (nand_read_skip_bad(&nand_info[0], offset, &len, char_ptr))
Stuart Woodcc49cad2008-05-30 16:05:28 -0400297 return 1;
298 offset += blocksize;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200299 amount_loaded += len;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400300 }
301 }
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200302 if (amount_loaded != CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400303 return 1;
304
305 return 0;
306}
307
Ben Gardinerc9f73512010-07-05 13:27:07 -0400308#ifdef CONFIG_ENV_OFFSET_OOB
309int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
310{
311 struct mtd_oob_ops ops;
312 uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
313 int ret;
314
315 ops.datbuf = NULL;
316 ops.mode = MTD_OOB_AUTO;
317 ops.ooboffs = 0;
318 ops.ooblen = ENV_OFFSET_SIZE;
319 ops.oobbuf = (void *) oob_buf;
320
321 ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
Scott Wood53504a22010-07-12 18:17:40 -0500322 if (ret) {
Ben Gardinerc9f73512010-07-05 13:27:07 -0400323 printf("error reading OOB block 0\n");
Scott Wood53504a22010-07-12 18:17:40 -0500324 return ret;
Ben Gardinerc9f73512010-07-05 13:27:07 -0400325 }
Scott Wood53504a22010-07-12 18:17:40 -0500326
327 if (oob_buf[0] == ENV_OOB_MARKER) {
328 *result = oob_buf[1] * nand->erasesize;
329 } else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
330 *result = oob_buf[1];
331 } else {
332 printf("No dynamic environment marker in OOB block 0\n");
333 return -ENOENT;
334 }
335
336 return 0;
Ben Gardinerc9f73512010-07-05 13:27:07 -0400337}
338#endif
339
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200340#ifdef CONFIG_ENV_OFFSET_REDUND
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200341void env_relocate_spec(void)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100342{
343#if !defined(ENV_IS_EMBEDDED)
Markus Klotzbuecher2770bcb2006-03-24 15:43:16 +0100344 int crc1_ok = 0, crc2_ok = 0;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200345 env_t *ep, *tmp_env1, *tmp_env2;
wdenk13a56952004-06-09 14:58:14 +0000346
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200347 tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
348 tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100349
Wolfgang Denk15b86c32010-01-16 21:50:26 -0700350 if ((tmp_env1 == NULL) || (tmp_env2 == NULL)) {
351 puts("Can't allocate buffers for environment\n");
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200352 free(tmp_env1);
353 free(tmp_env2);
354 set_default_env("!malloc() failed");
355 return;
Wolfgang Denk15b86c32010-01-16 21:50:26 -0700356 }
357
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200358 if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1))
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200359 puts("No Valid Environment Area found\n");
360
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200361 if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2))
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200362 puts("No Valid Redundant Environment Area found\n");
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100363
364 crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
365 crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
366
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200367 if (!crc1_ok && !crc2_ok) {
derek@siconix.com5a9427d2009-01-26 14:08:17 -0700368 free(tmp_env1);
369 free(tmp_env2);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200370 set_default_env("!bad CRC");
371 return;
372 } else if (crc1_ok && !crc2_ok) {
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100373 gd->env_valid = 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200374 } else if (!crc1_ok && crc2_ok) {
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100375 gd->env_valid = 2;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200376 } else {
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100377 /* both ok - check serial */
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200378 if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100379 gd->env_valid = 2;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200380 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100381 gd->env_valid = 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200382 else if (tmp_env1->flags > tmp_env2->flags)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100383 gd->env_valid = 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200384 else if (tmp_env2->flags > tmp_env1->flags)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100385 gd->env_valid = 2;
386 else /* flags are equal - almost impossible */
387 gd->env_valid = 1;
388
389 }
390
391 free(env_ptr);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200392
393 if (gd->env_valid == 1)
394 ep = tmp_env1;
395 else
396 ep = tmp_env2;
397
Scott Woodeef1d712011-02-08 15:25:02 -0600398 env_flags = ep->flags;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200399 env_import((char *)ep, 0);
400
401 free(tmp_env1);
402 free(tmp_env2);
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100403
404#endif /* ! ENV_IS_EMBEDDED */
405}
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200406#else /* ! CONFIG_ENV_OFFSET_REDUND */
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100407/*
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200408 * The legacy NAND code saved the environment in the first NAND
409 * device i.e., nand_dev_desc + 0. This is also the behaviour using
410 * the new NAND code.
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100411 */
wdenk13a56952004-06-09 14:58:14 +0000412void env_relocate_spec (void)
413{
414#if !defined(ENV_IS_EMBEDDED)
Wolfgang Denkd52fb7e2006-03-11 22:53:33 +0100415 int ret;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200416 char buf[CONFIG_ENV_SIZE];
wdenk13a56952004-06-09 14:58:14 +0000417
Ben Gardinerc9f73512010-07-05 13:27:07 -0400418#if defined(CONFIG_ENV_OFFSET_OOB)
419 ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200420 /*
421 * If unable to read environment offset from NAND OOB then fall through
Ben Gardinerc9f73512010-07-05 13:27:07 -0400422 * to the normal environment reading code below
423 */
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200424 if (!ret) {
Ben Gardinerc9f73512010-07-05 13:27:07 -0400425 printf("Found Environment offset in OOB..\n");
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200426 } else {
427 set_default_env("!no env offset in OOB");
428 return;
429 }
Ben Gardinerc9f73512010-07-05 13:27:07 -0400430#endif
431
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200432 ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
433 if (ret) {
434 set_default_env("!readenv() failed");
435 return;
436 }
wdenk13a56952004-06-09 14:58:14 +0000437
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200438 env_import(buf, 1);
wdenk13a56952004-06-09 14:58:14 +0000439#endif /* ! ENV_IS_EMBEDDED */
wdenk13a56952004-06-09 14:58:14 +0000440}
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200441#endif /* CONFIG_ENV_OFFSET_REDUND */