blob: 3cb75c89624d087019dacfcc6f21a1f4e7e0a3ad [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
wdenk13a56952004-06-09 14:58:14 +000033#include <common.h>
wdenk13a56952004-06-09 14:58:14 +000034#include <command.h>
35#include <environment.h>
36#include <linux/stddef.h>
Markus Klotzbuechere443c942006-03-20 18:02:44 +010037#include <malloc.h>
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +010038#include <nand.h>
Wolfgang Denkea882ba2010-06-20 23:33:59 +020039#include <search.h>
40#include <errno.h>
wdenk13a56952004-06-09 14:58:14 +000041
Mike Frysingerbdab39d2009-01-28 19:08:14 -050042#if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
wdenk13a56952004-06-09 14:58:14 +000043#define CMD_SAVEENV
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020044#elif defined(CONFIG_ENV_OFFSET_REDUND)
Igor Grinbergde152b92011-11-07 01:14:10 +000045#error CONFIG_ENV_OFFSET_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND
wdenk13a56952004-06-09 14:58:14 +000046#endif
47
Igor Grinbergde152b92011-11-07 01:14:10 +000048#if defined(CONFIG_ENV_SIZE_REDUND) && \
49 (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020050#error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
wdenk13a56952004-06-09 14:58:14 +000051#endif
52
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020053#ifndef CONFIG_ENV_RANGE
54#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
Stuart Woodcc49cad2008-05-30 16:05:28 -040055#endif
56
Wolfgang Denkea882ba2010-06-20 23:33:59 +020057char *env_name_spec = "NAND";
wdenk13a56952004-06-09 14:58:14 +000058
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020059#if defined(ENV_IS_EMBEDDED)
Igor Grinberg994bc672011-11-17 06:07:23 +000060env_t *env_ptr = &environment;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020061#elif defined(CONFIG_NAND_ENV_DST)
62env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST;
wdenk13a56952004-06-09 14:58:14 +000063#else /* ! ENV_IS_EMBEDDED */
Igor Grinbergde152b92011-11-07 01:14:10 +000064env_t *env_ptr;
wdenk13a56952004-06-09 14:58:14 +000065#endif /* ENV_IS_EMBEDDED */
66
Wolfgang Denkd87080b2006-03-31 18:32:53 +020067DECLARE_GLOBAL_DATA_PTR;
wdenk13a56952004-06-09 14:58:14 +000068
Igor Grinbergde152b92011-11-07 01:14:10 +000069uchar env_get_char_spec(int index)
wdenk13a56952004-06-09 14:58:14 +000070{
Igor Grinbergde152b92011-11-07 01:14:10 +000071 return *((uchar *)(gd->env_addr + index));
wdenk13a56952004-06-09 14:58:14 +000072}
73
Wolfgang Denkea882ba2010-06-20 23:33:59 +020074/*
75 * This is called before nand_init() so we can't read NAND to
76 * validate env data.
77 *
78 * Mark it OK for now. env_relocate() in env_common.c will call our
79 * relocate function which does the real validation.
Stefan Roesed12ae802006-09-12 20:19:10 +020080 *
81 * When using a NAND boot image (like sequoia_nand), the environment
Wolfgang Denkea882ba2010-06-20 23:33:59 +020082 * can be embedded or attached to the U-Boot image in NAND flash.
83 * This way the SPL loads not only the U-Boot image from NAND but
84 * also the environment.
wdenk13a56952004-06-09 14:58:14 +000085 */
86int env_init(void)
87{
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020088#if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
Stefan Roesed12ae802006-09-12 20:19:10 +020089 int crc1_ok = 0, crc2_ok = 0;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020090 env_t *tmp_env1;
91
92#ifdef CONFIG_ENV_OFFSET_REDUND
93 env_t *tmp_env2;
94
95 tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
Igor Grinbergde152b92011-11-07 01:14:10 +000096 crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020097#endif
Stefan Roesed12ae802006-09-12 20:19:10 +020098 tmp_env1 = env_ptr;
Igor Grinbergde152b92011-11-07 01:14:10 +000099 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
Stefan Roesed12ae802006-09-12 20:19:10 +0200100
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200101 if (!crc1_ok && !crc2_ok) {
Igor Grinbergde152b92011-11-07 01:14:10 +0000102 gd->env_addr = 0;
103 gd->env_valid = 0;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200104
105 return 0;
106 } else if (crc1_ok && !crc2_ok) {
Stefan Roesed12ae802006-09-12 20:19:10 +0200107 gd->env_valid = 1;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200108 }
109#ifdef CONFIG_ENV_OFFSET_REDUND
110 else if (!crc1_ok && crc2_ok) {
Stefan Roesed12ae802006-09-12 20:19:10 +0200111 gd->env_valid = 2;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200112 } else {
Stefan Roesed12ae802006-09-12 20:19:10 +0200113 /* both ok - check serial */
Igor Grinbergde152b92011-11-07 01:14:10 +0000114 if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
Stefan Roesed12ae802006-09-12 20:19:10 +0200115 gd->env_valid = 2;
Igor Grinbergde152b92011-11-07 01:14:10 +0000116 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
Stefan Roesed12ae802006-09-12 20:19:10 +0200117 gd->env_valid = 1;
Igor Grinbergde152b92011-11-07 01:14:10 +0000118 else if (tmp_env1->flags > tmp_env2->flags)
Stefan Roesed12ae802006-09-12 20:19:10 +0200119 gd->env_valid = 1;
Igor Grinbergde152b92011-11-07 01:14:10 +0000120 else if (tmp_env2->flags > tmp_env1->flags)
Stefan Roesed12ae802006-09-12 20:19:10 +0200121 gd->env_valid = 2;
122 else /* flags are equal - almost impossible */
123 gd->env_valid = 1;
124 }
125
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200126 if (gd->env_valid == 2)
127 env_ptr = tmp_env2;
128 else
129#endif
Stefan Roesed12ae802006-09-12 20:19:10 +0200130 if (gd->env_valid == 1)
131 env_ptr = tmp_env1;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200132
133 gd->env_addr = (ulong)env_ptr->data;
134
135#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
Igor Grinbergde152b92011-11-07 01:14:10 +0000136 gd->env_addr = (ulong)&default_environment[0];
137 gd->env_valid = 1;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200138#endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
wdenk13a56952004-06-09 14:58:14 +0000139
Igor Grinbergde152b92011-11-07 01:14:10 +0000140 return 0;
wdenk13a56952004-06-09 14:58:14 +0000141}
142
143#ifdef CMD_SAVEENV
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100144/*
145 * The legacy NAND code saved the environment in the first NAND device i.e.,
146 * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
147 */
Stuart Woodcc49cad2008-05-30 16:05:28 -0400148int writeenv(size_t offset, u_char *buf)
149{
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200150 size_t end = offset + CONFIG_ENV_RANGE;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400151 size_t amount_saved = 0;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200152 size_t blocksize, len;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400153 u_char *char_ptr;
154
155 blocksize = nand_info[0].erasesize;
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200156 len = min(blocksize, CONFIG_ENV_SIZE);
Stuart Woodcc49cad2008-05-30 16:05:28 -0400157
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200158 while (amount_saved < CONFIG_ENV_SIZE && offset < end) {
Stuart Woodcc49cad2008-05-30 16:05:28 -0400159 if (nand_block_isbad(&nand_info[0], offset)) {
160 offset += blocksize;
161 } else {
162 char_ptr = &buf[amount_saved];
Igor Grinbergde152b92011-11-07 01:14:10 +0000163 if (nand_write(&nand_info[0], offset, &len, char_ptr))
Stuart Woodcc49cad2008-05-30 16:05:28 -0400164 return 1;
Igor Grinbergde152b92011-11-07 01:14:10 +0000165
Stuart Woodcc49cad2008-05-30 16:05:28 -0400166 offset += blocksize;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200167 amount_saved += len;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400168 }
169 }
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200170 if (amount_saved != CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400171 return 1;
172
173 return 0;
174}
Scott Woodeef1d712011-02-08 15:25:02 -0600175
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200176#ifdef CONFIG_ENV_OFFSET_REDUND
Scott Woodeef1d712011-02-08 15:25:02 -0600177static unsigned char env_flags;
178
wdenk13a56952004-06-09 14:58:14 +0000179int saveenv(void)
180{
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200181 env_t env_new;
182 ssize_t len;
183 char *res;
184 int ret = 0;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400185 nand_erase_options_t nand_erase_options;
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100186
Daniel Hobi3b250ff2011-05-18 15:21:08 +0200187 memset(&nand_erase_options, 0, sizeof(nand_erase_options));
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200188 nand_erase_options.length = CONFIG_ENV_RANGE;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400189
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200190 if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400191 return 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200192
193 res = (char *)&env_new.data;
Wolfgang Denk37f2fe72011-11-06 22:49:44 +0100194 len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200195 if (len < 0) {
196 error("Cannot export environment: errno = %d\n", errno);
197 return 1;
198 }
Igor Grinbergde152b92011-11-07 01:14:10 +0000199 env_new.crc = crc32(0, env_new.data, ENV_SIZE);
200 env_new.flags = ++env_flags; /* increase the serial */
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200201
Igor Grinbergde152b92011-11-07 01:14:10 +0000202 if (gd->env_valid == 1) {
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200203 puts("Erasing redundant NAND...\n");
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200204 nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400205 if (nand_erase_opts(&nand_info[0], &nand_erase_options))
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100206 return 1;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400207
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200208 puts("Writing to redundant NAND... ");
Igor Grinbergde152b92011-11-07 01:14:10 +0000209 ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *)&env_new);
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100210 } else {
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200211 puts("Erasing NAND...\n");
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200212 nand_erase_options.offset = CONFIG_ENV_OFFSET;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400213 if (nand_erase_opts(&nand_info[0], &nand_erase_options))
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100214 return 1;
215
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200216 puts("Writing to NAND... ");
Igor Grinbergde152b92011-11-07 01:14:10 +0000217 ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new);
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100218 }
Stuart Woodcc49cad2008-05-30 16:05:28 -0400219 if (ret) {
220 puts("FAILED!\n");
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100221 return 1;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400222 }
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100223
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200224 puts("done\n");
225
Igor Grinbergde152b92011-11-07 01:14:10 +0000226 gd->env_valid = gd->env_valid == 2 ? 1 : 2;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200227
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100228 return ret;
229}
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200230#else /* ! CONFIG_ENV_OFFSET_REDUND */
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100231int saveenv(void)
232{
Igor Grinbergde152b92011-11-07 01:14:10 +0000233 int ret = 0;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200234 env_t env_new;
235 ssize_t len;
236 char *res;
Philip Balister9e4006bc2008-06-16 08:58:07 -0400237 nand_erase_options_t nand_erase_options;
Wolfgang Denke093a242008-06-28 23:34:37 +0200238
Daniel Hobi3b250ff2011-05-18 15:21:08 +0200239 memset(&nand_erase_options, 0, sizeof(nand_erase_options));
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200240 nand_erase_options.length = CONFIG_ENV_RANGE;
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200241 nand_erase_options.offset = CONFIG_ENV_OFFSET;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400242
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200243 if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400244 return 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200245
246 res = (char *)&env_new.data;
Wolfgang Denk37f2fe72011-11-06 22:49:44 +0100247 len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200248 if (len < 0) {
249 error("Cannot export environment: errno = %d\n", errno);
250 return 1;
251 }
Igor Grinbergde152b92011-11-07 01:14:10 +0000252 env_new.crc = crc32(0, env_new.data, ENV_SIZE);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200253
254 puts("Erasing Nand...\n");
Stuart Woodcc49cad2008-05-30 16:05:28 -0400255 if (nand_erase_opts(&nand_info[0], &nand_erase_options))
wdenk13a56952004-06-09 14:58:14 +0000256 return 1;
257
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200258 puts("Writing to Nand... ");
259 if (writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new)) {
Stuart Woodcc49cad2008-05-30 16:05:28 -0400260 puts("FAILED!\n");
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100261 return 1;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400262 }
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100263
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200264 puts("done\n");
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100265 return ret;
wdenk13a56952004-06-09 14:58:14 +0000266}
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200267#endif /* CONFIG_ENV_OFFSET_REDUND */
wdenk13a56952004-06-09 14:58:14 +0000268#endif /* CMD_SAVEENV */
269
Igor Grinbergde152b92011-11-07 01:14:10 +0000270int readenv(size_t offset, u_char *buf)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400271{
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200272 size_t end = offset + CONFIG_ENV_RANGE;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400273 size_t amount_loaded = 0;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200274 size_t blocksize, len;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400275 u_char *char_ptr;
276
277 blocksize = nand_info[0].erasesize;
Mike Frysinger962ad592010-08-11 23:42:26 -0400278 if (!blocksize)
279 return 1;
Igor Grinbergde152b92011-11-07 01:14:10 +0000280
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200281 len = min(blocksize, CONFIG_ENV_SIZE);
Stuart Woodcc49cad2008-05-30 16:05:28 -0400282
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200283 while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
Stuart Woodcc49cad2008-05-30 16:05:28 -0400284 if (nand_block_isbad(&nand_info[0], offset)) {
285 offset += blocksize;
286 } else {
287 char_ptr = &buf[amount_loaded];
Igor Grinbergde152b92011-11-07 01:14:10 +0000288 if (nand_read_skip_bad(&nand_info[0], offset,
289 &len, char_ptr))
Stuart Woodcc49cad2008-05-30 16:05:28 -0400290 return 1;
Igor Grinbergde152b92011-11-07 01:14:10 +0000291
Stuart Woodcc49cad2008-05-30 16:05:28 -0400292 offset += blocksize;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200293 amount_loaded += len;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400294 }
295 }
Igor Grinbergde152b92011-11-07 01:14:10 +0000296
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200297 if (amount_loaded != CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400298 return 1;
299
300 return 0;
301}
302
Ben Gardinerc9f73512010-07-05 13:27:07 -0400303#ifdef CONFIG_ENV_OFFSET_OOB
304int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
305{
306 struct mtd_oob_ops ops;
Igor Grinbergde152b92011-11-07 01:14:10 +0000307 uint32_t oob_buf[ENV_OFFSET_SIZE / sizeof(uint32_t)];
Ben Gardinerc9f73512010-07-05 13:27:07 -0400308 int ret;
309
Igor Grinbergde152b92011-11-07 01:14:10 +0000310 ops.datbuf = NULL;
311 ops.mode = MTD_OOB_AUTO;
312 ops.ooboffs = 0;
313 ops.ooblen = ENV_OFFSET_SIZE;
314 ops.oobbuf = (void *)oob_buf;
Ben Gardinerc9f73512010-07-05 13:27:07 -0400315
316 ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
Scott Wood53504a22010-07-12 18:17:40 -0500317 if (ret) {
Ben Gardinerc9f73512010-07-05 13:27:07 -0400318 printf("error reading OOB block 0\n");
Scott Wood53504a22010-07-12 18:17:40 -0500319 return ret;
Ben Gardinerc9f73512010-07-05 13:27:07 -0400320 }
Scott Wood53504a22010-07-12 18:17:40 -0500321
322 if (oob_buf[0] == ENV_OOB_MARKER) {
323 *result = oob_buf[1] * nand->erasesize;
324 } else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
325 *result = oob_buf[1];
326 } else {
327 printf("No dynamic environment marker in OOB block 0\n");
328 return -ENOENT;
329 }
330
331 return 0;
Ben Gardinerc9f73512010-07-05 13:27:07 -0400332}
333#endif
334
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200335#ifdef CONFIG_ENV_OFFSET_REDUND
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200336void env_relocate_spec(void)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100337{
338#if !defined(ENV_IS_EMBEDDED)
Markus Klotzbuecher2770bcb2006-03-24 15:43:16 +0100339 int crc1_ok = 0, crc2_ok = 0;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200340 env_t *ep, *tmp_env1, *tmp_env2;
wdenk13a56952004-06-09 14:58:14 +0000341
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200342 tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
343 tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
Igor Grinbergde152b92011-11-07 01:14:10 +0000344 if (tmp_env1 == NULL || tmp_env2 == NULL) {
Wolfgang Denk15b86c32010-01-16 21:50:26 -0700345 puts("Can't allocate buffers for environment\n");
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200346 set_default_env("!malloc() failed");
Igor Grinbergde152b92011-11-07 01:14:10 +0000347 goto done;
Wolfgang Denk15b86c32010-01-16 21:50:26 -0700348 }
349
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200350 if (readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1))
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200351 puts("No Valid Environment Area found\n");
352
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200353 if (readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2))
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200354 puts("No Valid Redundant Environment Area found\n");
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100355
Igor Grinbergde152b92011-11-07 01:14:10 +0000356 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
357 crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100358
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200359 if (!crc1_ok && !crc2_ok) {
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200360 set_default_env("!bad CRC");
Igor Grinbergde152b92011-11-07 01:14:10 +0000361 goto done;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200362 } else if (crc1_ok && !crc2_ok) {
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100363 gd->env_valid = 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200364 } else if (!crc1_ok && crc2_ok) {
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100365 gd->env_valid = 2;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200366 } else {
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100367 /* both ok - check serial */
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200368 if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100369 gd->env_valid = 2;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200370 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100371 gd->env_valid = 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200372 else if (tmp_env1->flags > tmp_env2->flags)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100373 gd->env_valid = 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200374 else if (tmp_env2->flags > tmp_env1->flags)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100375 gd->env_valid = 2;
376 else /* flags are equal - almost impossible */
377 gd->env_valid = 1;
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100378 }
379
380 free(env_ptr);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200381
382 if (gd->env_valid == 1)
383 ep = tmp_env1;
384 else
385 ep = tmp_env2;
386
Scott Woodeef1d712011-02-08 15:25:02 -0600387 env_flags = ep->flags;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200388 env_import((char *)ep, 0);
389
Igor Grinbergde152b92011-11-07 01:14:10 +0000390done:
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200391 free(tmp_env1);
392 free(tmp_env2);
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100393
394#endif /* ! ENV_IS_EMBEDDED */
395}
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200396#else /* ! CONFIG_ENV_OFFSET_REDUND */
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100397/*
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200398 * The legacy NAND code saved the environment in the first NAND
399 * device i.e., nand_dev_desc + 0. This is also the behaviour using
400 * the new NAND code.
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100401 */
Igor Grinbergde152b92011-11-07 01:14:10 +0000402void env_relocate_spec(void)
wdenk13a56952004-06-09 14:58:14 +0000403{
404#if !defined(ENV_IS_EMBEDDED)
Wolfgang Denkd52fb7e2006-03-11 22:53:33 +0100405 int ret;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200406 char buf[CONFIG_ENV_SIZE];
wdenk13a56952004-06-09 14:58:14 +0000407
Ben Gardinerc9f73512010-07-05 13:27:07 -0400408#if defined(CONFIG_ENV_OFFSET_OOB)
409 ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200410 /*
411 * If unable to read environment offset from NAND OOB then fall through
Ben Gardinerc9f73512010-07-05 13:27:07 -0400412 * to the normal environment reading code below
413 */
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200414 if (!ret) {
Ben Gardinerc9f73512010-07-05 13:27:07 -0400415 printf("Found Environment offset in OOB..\n");
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200416 } else {
417 set_default_env("!no env offset in OOB");
418 return;
419 }
Ben Gardinerc9f73512010-07-05 13:27:07 -0400420#endif
421
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200422 ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
423 if (ret) {
424 set_default_env("!readenv() failed");
425 return;
426 }
wdenk13a56952004-06-09 14:58:14 +0000427
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200428 env_import(buf, 1);
wdenk13a56952004-06-09 14:58:14 +0000429#endif /* ! ENV_IS_EMBEDDED */
wdenk13a56952004-06-09 14:58:14 +0000430}
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200431#endif /* CONFIG_ENV_OFFSET_REDUND */