blob: 8058b55c502992540b44b236f625c452fb045b61 [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 *
Wolfgang Denk3765b3e2013-10-07 13:07:26 +020014 * SPDX-License-Identifier: GPL-2.0+
wdenk13a56952004-06-09 14:58:14 +000015 */
16
wdenk13a56952004-06-09 14:58:14 +000017#include <common.h>
wdenk13a56952004-06-09 14:58:14 +000018#include <command.h>
19#include <environment.h>
20#include <linux/stddef.h>
Markus Klotzbuechere443c942006-03-20 18:02:44 +010021#include <malloc.h>
Simon Glasscf92e052015-09-02 17:24:58 -060022#include <memalign.h>
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +010023#include <nand.h>
Wolfgang Denkea882ba2010-06-20 23:33:59 +020024#include <search.h>
25#include <errno.h>
wdenk13a56952004-06-09 14:58:14 +000026
Simon Glass4415f1d2017-08-03 12:21:58 -060027#if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND) && \
28 !defined(CONFIG_SPL_BUILD)
wdenk13a56952004-06-09 14:58:14 +000029#define CMD_SAVEENV
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020030#elif defined(CONFIG_ENV_OFFSET_REDUND)
Igor Grinbergde152b92011-11-07 01:14:10 +000031#error CONFIG_ENV_OFFSET_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_NAND
wdenk13a56952004-06-09 14:58:14 +000032#endif
33
Igor Grinbergde152b92011-11-07 01:14:10 +000034#if defined(CONFIG_ENV_SIZE_REDUND) && \
35 (CONFIG_ENV_SIZE_REDUND != CONFIG_ENV_SIZE)
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020036#error CONFIG_ENV_SIZE_REDUND should be the same as CONFIG_ENV_SIZE
wdenk13a56952004-06-09 14:58:14 +000037#endif
38
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +020039#ifndef CONFIG_ENV_RANGE
40#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE
Stuart Woodcc49cad2008-05-30 16:05:28 -040041#endif
42
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020043#if defined(ENV_IS_EMBEDDED)
Igor Grinberg994bc672011-11-17 06:07:23 +000044env_t *env_ptr = &environment;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020045#elif defined(CONFIG_NAND_ENV_DST)
46env_t *env_ptr = (env_t *)CONFIG_NAND_ENV_DST;
wdenk13a56952004-06-09 14:58:14 +000047#else /* ! ENV_IS_EMBEDDED */
Igor Grinbergde152b92011-11-07 01:14:10 +000048env_t *env_ptr;
wdenk13a56952004-06-09 14:58:14 +000049#endif /* ENV_IS_EMBEDDED */
50
Wolfgang Denkd87080b2006-03-31 18:32:53 +020051DECLARE_GLOBAL_DATA_PTR;
wdenk13a56952004-06-09 14:58:14 +000052
Wolfgang Denkea882ba2010-06-20 23:33:59 +020053/*
54 * This is called before nand_init() so we can't read NAND to
55 * validate env data.
56 *
57 * Mark it OK for now. env_relocate() in env_common.c will call our
58 * relocate function which does the real validation.
Stefan Roesed12ae802006-09-12 20:19:10 +020059 *
60 * When using a NAND boot image (like sequoia_nand), the environment
Wolfgang Denkea882ba2010-06-20 23:33:59 +020061 * can be embedded or attached to the U-Boot image in NAND flash.
62 * This way the SPL loads not only the U-Boot image from NAND but
63 * also the environment.
wdenk13a56952004-06-09 14:58:14 +000064 */
Simon Glasse5bce242017-08-03 12:22:01 -060065static int env_nand_init(void)
wdenk13a56952004-06-09 14:58:14 +000066{
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020067#if defined(ENV_IS_EMBEDDED) || defined(CONFIG_NAND_ENV_DST)
Stefan Roesed12ae802006-09-12 20:19:10 +020068 int crc1_ok = 0, crc2_ok = 0;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020069 env_t *tmp_env1;
70
71#ifdef CONFIG_ENV_OFFSET_REDUND
72 env_t *tmp_env2;
73
74 tmp_env2 = (env_t *)((ulong)env_ptr + CONFIG_ENV_SIZE);
Igor Grinbergde152b92011-11-07 01:14:10 +000075 crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020076#endif
Stefan Roesed12ae802006-09-12 20:19:10 +020077 tmp_env1 = env_ptr;
Igor Grinbergde152b92011-11-07 01:14:10 +000078 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
Stefan Roesed12ae802006-09-12 20:19:10 +020079
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020080 if (!crc1_ok && !crc2_ok) {
Igor Grinbergde152b92011-11-07 01:14:10 +000081 gd->env_addr = 0;
Simon Glass2d7cb5b2017-08-20 04:45:15 -060082 gd->env_valid = ENV_INVALID;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020083
84 return 0;
85 } else if (crc1_ok && !crc2_ok) {
Simon Glass203e94f2017-08-03 12:21:56 -060086 gd->env_valid = ENV_VALID;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020087 }
88#ifdef CONFIG_ENV_OFFSET_REDUND
89 else if (!crc1_ok && crc2_ok) {
Simon Glass203e94f2017-08-03 12:21:56 -060090 gd->env_valid = ENV_REDUND;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +020091 } else {
Stefan Roesed12ae802006-09-12 20:19:10 +020092 /* both ok - check serial */
Igor Grinbergde152b92011-11-07 01:14:10 +000093 if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
Simon Glass203e94f2017-08-03 12:21:56 -060094 gd->env_valid = ENV_REDUND;
Igor Grinbergde152b92011-11-07 01:14:10 +000095 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
Simon Glass203e94f2017-08-03 12:21:56 -060096 gd->env_valid = ENV_VALID;
Igor Grinbergde152b92011-11-07 01:14:10 +000097 else if (tmp_env1->flags > tmp_env2->flags)
Simon Glass203e94f2017-08-03 12:21:56 -060098 gd->env_valid = ENV_VALID;
Igor Grinbergde152b92011-11-07 01:14:10 +000099 else if (tmp_env2->flags > tmp_env1->flags)
Simon Glass203e94f2017-08-03 12:21:56 -0600100 gd->env_valid = ENV_REDUND;
Stefan Roesed12ae802006-09-12 20:19:10 +0200101 else /* flags are equal - almost impossible */
Simon Glass203e94f2017-08-03 12:21:56 -0600102 gd->env_valid = ENV_VALID;
Stefan Roesed12ae802006-09-12 20:19:10 +0200103 }
104
Simon Glass203e94f2017-08-03 12:21:56 -0600105 if (gd->env_valid == ENV_REDUND)
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200106 env_ptr = tmp_env2;
107 else
108#endif
Simon Glass203e94f2017-08-03 12:21:56 -0600109 if (gd->env_valid == ENV_VALID)
Stefan Roesed12ae802006-09-12 20:19:10 +0200110 env_ptr = tmp_env1;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200111
112 gd->env_addr = (ulong)env_ptr->data;
113
114#else /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
Igor Grinbergde152b92011-11-07 01:14:10 +0000115 gd->env_addr = (ulong)&default_environment[0];
Simon Glass203e94f2017-08-03 12:21:56 -0600116 gd->env_valid = ENV_VALID;
Guennadi Liakhovetskib74ab732009-05-18 16:07:22 +0200117#endif /* ENV_IS_EMBEDDED || CONFIG_NAND_ENV_DST */
wdenk13a56952004-06-09 14:58:14 +0000118
Igor Grinbergde152b92011-11-07 01:14:10 +0000119 return 0;
wdenk13a56952004-06-09 14:58:14 +0000120}
121
122#ifdef CMD_SAVEENV
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100123/*
124 * The legacy NAND code saved the environment in the first NAND device i.e.,
125 * nand_dev_desc + 0. This is also the behaviour using the new NAND code.
126 */
Jeroen Hofstee45f08d32014-10-08 22:57:35 +0200127static int writeenv(size_t offset, u_char *buf)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400128{
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200129 size_t end = offset + CONFIG_ENV_RANGE;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400130 size_t amount_saved = 0;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200131 size_t blocksize, len;
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500132 struct mtd_info *mtd;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400133 u_char *char_ptr;
134
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500135 mtd = get_nand_dev_by_index(0);
136 if (!mtd)
137 return 1;
138
139 blocksize = mtd->erasesize;
Masahiro Yamadab4141192014-11-07 03:03:31 +0900140 len = min(blocksize, (size_t)CONFIG_ENV_SIZE);
Stuart Woodcc49cad2008-05-30 16:05:28 -0400141
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200142 while (amount_saved < CONFIG_ENV_SIZE && offset < end) {
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500143 if (nand_block_isbad(mtd, offset)) {
Stuart Woodcc49cad2008-05-30 16:05:28 -0400144 offset += blocksize;
145 } else {
146 char_ptr = &buf[amount_saved];
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500147 if (nand_write(mtd, offset, &len, char_ptr))
Stuart Woodcc49cad2008-05-30 16:05:28 -0400148 return 1;
Igor Grinbergde152b92011-11-07 01:14:10 +0000149
Stuart Woodcc49cad2008-05-30 16:05:28 -0400150 offset += blocksize;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200151 amount_saved += len;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400152 }
153 }
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200154 if (amount_saved != CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400155 return 1;
156
157 return 0;
158}
Scott Woodeef1d712011-02-08 15:25:02 -0600159
Simon Glass42a81802017-08-03 12:21:57 -0600160struct nand_env_location {
Phil Sutter2b262012013-07-19 12:20:26 +0200161 const char *name;
162 const nand_erase_options_t erase_opts;
163};
Scott Woodeef1d712011-02-08 15:25:02 -0600164
Simon Glass42a81802017-08-03 12:21:57 -0600165static int erase_and_write_env(const struct nand_env_location *location,
Phil Sutter2b262012013-07-19 12:20:26 +0200166 u_char *env_new)
wdenk13a56952004-06-09 14:58:14 +0000167{
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500168 struct mtd_info *mtd;
Phil Sutter2b262012013-07-19 12:20:26 +0200169 int ret = 0;
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100170
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500171 mtd = get_nand_dev_by_index(0);
172 if (!mtd)
Tom Rini4cc96992016-08-15 13:02:15 -0400173 return 1;
174
Phil Sutter2b262012013-07-19 12:20:26 +0200175 printf("Erasing %s...\n", location->name);
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500176 if (nand_erase_opts(mtd, &location->erase_opts))
Stuart Woodcc49cad2008-05-30 16:05:28 -0400177 return 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200178
Phil Sutter2b262012013-07-19 12:20:26 +0200179 printf("Writing to %s... ", location->name);
180 ret = writeenv(location->erase_opts.offset, env_new);
181 puts(ret ? "FAILED!\n" : "OK\n");
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200182
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100183 return ret;
184}
Phil Sutter2b262012013-07-19 12:20:26 +0200185
Simon Glasse5bce242017-08-03 12:22:01 -0600186static int env_nand_save(void)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100187{
Igor Grinbergde152b92011-11-07 01:14:10 +0000188 int ret = 0;
Tom Rinicd0f4fa2013-04-05 14:55:21 -0400189 ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
Phil Sutter2b262012013-07-19 12:20:26 +0200190 int env_idx = 0;
Simon Glass42a81802017-08-03 12:21:57 -0600191 static const struct nand_env_location location[] = {
Phil Sutter2b262012013-07-19 12:20:26 +0200192 {
193 .name = "NAND",
194 .erase_opts = {
195 .length = CONFIG_ENV_RANGE,
196 .offset = CONFIG_ENV_OFFSET,
197 },
198 },
199#ifdef CONFIG_ENV_OFFSET_REDUND
200 {
201 .name = "redundant NAND",
202 .erase_opts = {
203 .length = CONFIG_ENV_RANGE,
204 .offset = CONFIG_ENV_OFFSET_REDUND,
205 },
206 },
207#endif
208 };
Wolfgang Denke093a242008-06-28 23:34:37 +0200209
Stuart Woodcc49cad2008-05-30 16:05:28 -0400210
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200211 if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400212 return 1;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200213
Marek Vasut7ce15262014-03-05 19:59:50 +0100214 ret = env_export(env_new);
215 if (ret)
216 return ret;
217
Phil Sutter2b262012013-07-19 12:20:26 +0200218#ifdef CONFIG_ENV_OFFSET_REDUND
Simon Glass203e94f2017-08-03 12:21:56 -0600219 env_idx = (gd->env_valid == ENV_VALID);
Phil Sutter2b262012013-07-19 12:20:26 +0200220#endif
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200221
Phil Sutter2b262012013-07-19 12:20:26 +0200222 ret = erase_and_write_env(&location[env_idx], (u_char *)env_new);
223#ifdef CONFIG_ENV_OFFSET_REDUND
224 if (!ret) {
225 /* preset other copy for next write */
Simon Glass203e94f2017-08-03 12:21:56 -0600226 gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID :
227 ENV_REDUND;
Phil Sutter2b262012013-07-19 12:20:26 +0200228 return ret;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400229 }
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100230
Phil Sutter2b262012013-07-19 12:20:26 +0200231 env_idx = (env_idx + 1) & 1;
232 ret = erase_and_write_env(&location[env_idx], (u_char *)env_new);
233 if (!ret)
234 printf("Warning: primary env write failed,"
235 " redundancy is lost!\n");
236#endif
237
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100238 return ret;
wdenk13a56952004-06-09 14:58:14 +0000239}
240#endif /* CMD_SAVEENV */
241
Tim Harvey9e205602015-05-14 11:48:04 -0700242#if defined(CONFIG_SPL_BUILD)
243static int readenv(size_t offset, u_char *buf)
244{
245 return nand_spl_load_image(offset, CONFIG_ENV_SIZE, buf);
246}
247#else
Jeroen Hofstee45f08d32014-10-08 22:57:35 +0200248static int readenv(size_t offset, u_char *buf)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400249{
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200250 size_t end = offset + CONFIG_ENV_RANGE;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400251 size_t amount_loaded = 0;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200252 size_t blocksize, len;
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500253 struct mtd_info *mtd;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400254 u_char *char_ptr;
255
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500256 mtd = get_nand_dev_by_index(0);
257 if (!mtd)
Mike Frysinger962ad592010-08-11 23:42:26 -0400258 return 1;
Igor Grinbergde152b92011-11-07 01:14:10 +0000259
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500260 blocksize = mtd->erasesize;
Masahiro Yamadab4141192014-11-07 03:03:31 +0900261 len = min(blocksize, (size_t)CONFIG_ENV_SIZE);
Stuart Woodcc49cad2008-05-30 16:05:28 -0400262
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200263 while (amount_loaded < CONFIG_ENV_SIZE && offset < end) {
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500264 if (nand_block_isbad(mtd, offset)) {
Stuart Woodcc49cad2008-05-30 16:05:28 -0400265 offset += blocksize;
266 } else {
267 char_ptr = &buf[amount_loaded];
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500268 if (nand_read_skip_bad(mtd, offset,
Tom Rinic39d6a02013-03-14 05:32:50 +0000269 &len, NULL,
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500270 mtd->size, char_ptr))
Stuart Woodcc49cad2008-05-30 16:05:28 -0400271 return 1;
Igor Grinbergde152b92011-11-07 01:14:10 +0000272
Stuart Woodcc49cad2008-05-30 16:05:28 -0400273 offset += blocksize;
Guennadi Liakhovetskic3db8c62008-07-31 12:38:26 +0200274 amount_loaded += len;
Stuart Woodcc49cad2008-05-30 16:05:28 -0400275 }
276 }
Igor Grinbergde152b92011-11-07 01:14:10 +0000277
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200278 if (amount_loaded != CONFIG_ENV_SIZE)
Stuart Woodcc49cad2008-05-30 16:05:28 -0400279 return 1;
280
281 return 0;
282}
Tim Harvey9e205602015-05-14 11:48:04 -0700283#endif /* #if defined(CONFIG_SPL_BUILD) */
Stuart Woodcc49cad2008-05-30 16:05:28 -0400284
Ben Gardinerc9f73512010-07-05 13:27:07 -0400285#ifdef CONFIG_ENV_OFFSET_OOB
Scott Wood151c06e2016-05-30 13:57:54 -0500286int get_nand_env_oob(struct mtd_info *mtd, unsigned long *result)
Ben Gardinerc9f73512010-07-05 13:27:07 -0400287{
288 struct mtd_oob_ops ops;
Igor Grinbergde152b92011-11-07 01:14:10 +0000289 uint32_t oob_buf[ENV_OFFSET_SIZE / sizeof(uint32_t)];
Ben Gardinerc9f73512010-07-05 13:27:07 -0400290 int ret;
291
Igor Grinbergde152b92011-11-07 01:14:10 +0000292 ops.datbuf = NULL;
293 ops.mode = MTD_OOB_AUTO;
294 ops.ooboffs = 0;
295 ops.ooblen = ENV_OFFSET_SIZE;
296 ops.oobbuf = (void *)oob_buf;
Ben Gardinerc9f73512010-07-05 13:27:07 -0400297
Scott Wood151c06e2016-05-30 13:57:54 -0500298 ret = mtd->read_oob(mtd, ENV_OFFSET_SIZE, &ops);
Scott Wood53504a22010-07-12 18:17:40 -0500299 if (ret) {
Ben Gardinerc9f73512010-07-05 13:27:07 -0400300 printf("error reading OOB block 0\n");
Scott Wood53504a22010-07-12 18:17:40 -0500301 return ret;
Ben Gardinerc9f73512010-07-05 13:27:07 -0400302 }
Scott Wood53504a22010-07-12 18:17:40 -0500303
304 if (oob_buf[0] == ENV_OOB_MARKER) {
Simon Glassc5951992017-08-03 12:22:17 -0600305 *result = ovoid ob_buf[1] * mtd->erasesize;
Scott Wood53504a22010-07-12 18:17:40 -0500306 } else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
307 *result = oob_buf[1];
308 } else {
309 printf("No dynamic environment marker in OOB block 0\n");
310 return -ENOENT;
311 }
312
313 return 0;
Ben Gardinerc9f73512010-07-05 13:27:07 -0400314}
315#endif
316
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200317#ifdef CONFIG_ENV_OFFSET_REDUND
Simon Glassc5951992017-08-03 12:22:17 -0600318static int env_nand_load(void)
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100319{
Simon Glassc5951992017-08-03 12:22:17 -0600320#if defined(ENV_IS_EMBEDDED)
321 return 0;
322#else
Phil Sutterb76a1472013-02-21 18:21:55 +0100323 int read1_fail = 0, read2_fail = 0;
Fiach Antaw9d364af2017-01-25 18:53:12 +1000324 env_t *tmp_env1, *tmp_env2;
Simon Glassc5951992017-08-03 12:22:17 -0600325 int ret = 0;
wdenk13a56952004-06-09 14:58:14 +0000326
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200327 tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
328 tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
Igor Grinbergde152b92011-11-07 01:14:10 +0000329 if (tmp_env1 == NULL || tmp_env2 == NULL) {
Wolfgang Denk15b86c32010-01-16 21:50:26 -0700330 puts("Can't allocate buffers for environment\n");
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200331 set_default_env("!malloc() failed");
Simon Glassc5951992017-08-03 12:22:17 -0600332 ret = -EIO;
Igor Grinbergde152b92011-11-07 01:14:10 +0000333 goto done;
Wolfgang Denk15b86c32010-01-16 21:50:26 -0700334 }
335
Phil Sutterb76a1472013-02-21 18:21:55 +0100336 read1_fail = readenv(CONFIG_ENV_OFFSET, (u_char *) tmp_env1);
337 read2_fail = readenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) tmp_env2);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200338
Phil Sutterb76a1472013-02-21 18:21:55 +0100339 if (read1_fail && read2_fail)
340 puts("*** Error - No Valid Environment Area found\n");
341 else if (read1_fail || read2_fail)
342 puts("*** Warning - some problems detected "
343 "reading environment; recovered successfully\n");
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100344
Fiach Antaw9d364af2017-01-25 18:53:12 +1000345 if (read1_fail && read2_fail) {
346 set_default_env("!bad env area");
Igor Grinbergde152b92011-11-07 01:14:10 +0000347 goto done;
Fiach Antaw9d364af2017-01-25 18:53:12 +1000348 } else if (!read1_fail && read2_fail) {
Simon Glass203e94f2017-08-03 12:21:56 -0600349 gd->env_valid = ENV_VALID;
Fiach Antaw9d364af2017-01-25 18:53:12 +1000350 env_import((char *)tmp_env1, 1);
351 } else if (read1_fail && !read2_fail) {
Simon Glass203e94f2017-08-03 12:21:56 -0600352 gd->env_valid = ENV_REDUND;
Fiach Antaw9d364af2017-01-25 18:53:12 +1000353 env_import((char *)tmp_env2, 1);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200354 } else {
Fiach Antaw9d364af2017-01-25 18:53:12 +1000355 env_import_redund((char *)tmp_env1, (char *)tmp_env2);
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100356 }
357
Igor Grinbergde152b92011-11-07 01:14:10 +0000358done:
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200359 free(tmp_env1);
360 free(tmp_env2);
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100361
Simon Glassc5951992017-08-03 12:22:17 -0600362 return ret;
Markus Klotzbuechere443c942006-03-20 18:02:44 +0100363#endif /* ! ENV_IS_EMBEDDED */
364}
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200365#else /* ! CONFIG_ENV_OFFSET_REDUND */
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100366/*
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200367 * The legacy NAND code saved the environment in the first NAND
368 * device i.e., nand_dev_desc + 0. This is also the behaviour using
369 * the new NAND code.
Bartlomiej Siekaaddb2e12006-03-05 18:57:33 +0100370 */
Simon Glassc5951992017-08-03 12:22:17 -0600371static int env_nand_load(void)
wdenk13a56952004-06-09 14:58:14 +0000372{
373#if !defined(ENV_IS_EMBEDDED)
Wolfgang Denkd52fb7e2006-03-11 22:53:33 +0100374 int ret;
Tom Rinicd0f4fa2013-04-05 14:55:21 -0400375 ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
wdenk13a56952004-06-09 14:58:14 +0000376
Ben Gardinerc9f73512010-07-05 13:27:07 -0400377#if defined(CONFIG_ENV_OFFSET_OOB)
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500378 struct mtd_info *mtd = get_nand_dev_by_index(0);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200379 /*
380 * If unable to read environment offset from NAND OOB then fall through
Ben Gardinerc9f73512010-07-05 13:27:07 -0400381 * to the normal environment reading code below
382 */
Grygorii Strashkoa94a2612017-06-26 19:12:52 -0500383 if (mtd && !get_nand_env_oob(mtd, &nand_env_oob_offset)) {
Ben Gardinerc9f73512010-07-05 13:27:07 -0400384 printf("Found Environment offset in OOB..\n");
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200385 } else {
386 set_default_env("!no env offset in OOB");
387 return;
388 }
Ben Gardinerc9f73512010-07-05 13:27:07 -0400389#endif
390
Tom Rinicd0f4fa2013-04-05 14:55:21 -0400391 ret = readenv(CONFIG_ENV_OFFSET, (u_char *)buf);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200392 if (ret) {
393 set_default_env("!readenv() failed");
Simon Glassc5951992017-08-03 12:22:17 -0600394 return -EIO;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200395 }
wdenk13a56952004-06-09 14:58:14 +0000396
Tom Rinicd0f4fa2013-04-05 14:55:21 -0400397 env_import(buf, 1);
wdenk13a56952004-06-09 14:58:14 +0000398#endif /* ! ENV_IS_EMBEDDED */
Simon Glassc5951992017-08-03 12:22:17 -0600399
400 return 0;
wdenk13a56952004-06-09 14:58:14 +0000401}
Jean-Christophe PLAGNIOL-VILLARD0e8d1582008-09-10 22:48:06 +0200402#endif /* CONFIG_ENV_OFFSET_REDUND */
Simon Glass4415f1d2017-08-03 12:21:58 -0600403
404U_BOOT_ENV_LOCATION(nand) = {
405 .location = ENVL_NAND,
Simon Glassac358be2017-08-03 12:22:03 -0600406 ENV_NAME("NAND")
Simon Glasse5bce242017-08-03 12:22:01 -0600407 .load = env_nand_load,
Simon Glass4415f1d2017-08-03 12:21:58 -0600408#if defined(CMD_SAVEENV)
Simon Glasse5bce242017-08-03 12:22:01 -0600409 .save = env_save_ptr(env_nand_save),
Simon Glass4415f1d2017-08-03 12:21:58 -0600410#endif
Simon Glasse5bce242017-08-03 12:22:01 -0600411 .init = env_nand_init,
Simon Glass4415f1d2017-08-03 12:21:58 -0600412};