blob: 925c5a02dfb32b1fd6c8b8a1c9b12761ac99b172 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2000-2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
6 * Andreas Heppel <aheppel@sysgo.de>
7
8 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 */
26
27/* #define DEBUG */
28
29#include <common.h>
wdenkc6097192002-11-03 00:24:07 +000030#include <command.h>
31#include <environment.h>
wdenkc6097192002-11-03 00:24:07 +000032#include <linux/stddef.h>
wdenkcc1e2562003-03-06 13:39:27 +000033#include <malloc.h>
wdenkc6097192002-11-03 00:24:07 +000034
Wolfgang Denk6405a152006-03-31 18:32:53 +020035DECLARE_GLOBAL_DATA_PTR;
36
Mike Frysinger78dcaf42009-01-28 19:08:14 -050037#if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_FLASH)
wdenkc6097192002-11-03 00:24:07 +000038#define CMD_SAVEENV
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020039#elif defined(CONFIG_ENV_ADDR_REDUND)
Mike Frysinger78dcaf42009-01-28 19:08:14 -050040#error Cannot use CONFIG_ENV_ADDR_REDUND without CONFIG_CMD_SAVEENV & CONFIG_CMD_FLASH
wdenkc6097192002-11-03 00:24:07 +000041#endif
42
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020043#if defined(CONFIG_ENV_SIZE_REDUND) && (CONFIG_ENV_SIZE_REDUND < CONFIG_ENV_SIZE)
44#error CONFIG_ENV_SIZE_REDUND should not be less then CONFIG_ENV_SIZE
wdenkc6097192002-11-03 00:24:07 +000045#endif
46
wdenkc6097192002-11-03 00:24:07 +000047char * env_name_spec = "Flash";
48
49#ifdef ENV_IS_EMBEDDED
50
51extern uchar environment[];
52env_t *env_ptr = (env_t *)(&environment[0]);
53
54#ifdef CMD_SAVEENV
55/* static env_t *flash_addr = (env_t *)(&environment[0]);-broken on ARM-wd-*/
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020056static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR;
wdenkc6097192002-11-03 00:24:07 +000057#endif
58
59#else /* ! ENV_IS_EMBEDDED */
60
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020061env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR;
wdenkc6097192002-11-03 00:24:07 +000062#ifdef CMD_SAVEENV
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020063static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR;
wdenkc6097192002-11-03 00:24:07 +000064#endif
65
66#endif /* ENV_IS_EMBEDDED */
67
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020068#ifdef CONFIG_ENV_ADDR_REDUND
69static env_t *flash_addr_new = (env_t *)CONFIG_ENV_ADDR_REDUND;
wdenkc6097192002-11-03 00:24:07 +000070
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020071/* CONFIG_ENV_ADDR is supposed to be on sector boundary */
72static ulong end_addr = CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1;
73static ulong end_addr_new = CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1;
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020074#endif /* CONFIG_ENV_ADDR_REDUND */
wdenkc6097192002-11-03 00:24:07 +000075
76extern uchar default_environment[];
wdenkc6097192002-11-03 00:24:07 +000077
78
79uchar env_get_char_spec (int index)
80{
wdenkc6097192002-11-03 00:24:07 +000081 return ( *((uchar *)(gd->env_addr + index)) );
82}
83
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020084#ifdef CONFIG_ENV_ADDR_REDUND
wdenkc6097192002-11-03 00:24:07 +000085
86int env_init(void)
87{
wdenkf8062712005-01-09 23:16:25 +000088 int crc1_ok = 0, crc2_ok = 0;
wdenkc6097192002-11-03 00:24:07 +000089
90 uchar flag1 = flash_addr->flags;
91 uchar flag2 = flash_addr_new->flags;
92
93 ulong addr_default = (ulong)&default_environment[0];
94 ulong addr1 = (ulong)&(flash_addr->data);
95 ulong addr2 = (ulong)&(flash_addr_new->data);
96
wdenkf8062712005-01-09 23:16:25 +000097 crc1_ok = (crc32(0, flash_addr->data, ENV_SIZE) == flash_addr->crc);
98 crc2_ok = (crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc);
99
wdenkacd9b102004-03-14 00:59:59 +0000100 if (crc1_ok && ! crc2_ok) {
wdenkc6097192002-11-03 00:24:07 +0000101 gd->env_addr = addr1;
102 gd->env_valid = 1;
wdenkacd9b102004-03-14 00:59:59 +0000103 } else if (! crc1_ok && crc2_ok) {
wdenkc6097192002-11-03 00:24:07 +0000104 gd->env_addr = addr2;
105 gd->env_valid = 1;
wdenkacd9b102004-03-14 00:59:59 +0000106 } else if (! crc1_ok && ! crc2_ok) {
wdenkc6097192002-11-03 00:24:07 +0000107 gd->env_addr = addr_default;
108 gd->env_valid = 0;
wdenkacd9b102004-03-14 00:59:59 +0000109 } else if (flag1 == ACTIVE_FLAG && flag2 == OBSOLETE_FLAG) {
wdenkc6097192002-11-03 00:24:07 +0000110 gd->env_addr = addr1;
111 gd->env_valid = 1;
wdenkacd9b102004-03-14 00:59:59 +0000112 } else if (flag1 == OBSOLETE_FLAG && flag2 == ACTIVE_FLAG) {
wdenkc6097192002-11-03 00:24:07 +0000113 gd->env_addr = addr2;
114 gd->env_valid = 1;
wdenkacd9b102004-03-14 00:59:59 +0000115 } else if (flag1 == flag2) {
wdenkc6097192002-11-03 00:24:07 +0000116 gd->env_addr = addr1;
117 gd->env_valid = 2;
wdenkacd9b102004-03-14 00:59:59 +0000118 } else if (flag1 == 0xFF) {
wdenkc6097192002-11-03 00:24:07 +0000119 gd->env_addr = addr1;
120 gd->env_valid = 2;
wdenkacd9b102004-03-14 00:59:59 +0000121 } else if (flag2 == 0xFF) {
wdenkc6097192002-11-03 00:24:07 +0000122 gd->env_addr = addr2;
123 gd->env_valid = 2;
124 }
125
126 return (0);
127}
128
129#ifdef CMD_SAVEENV
130int saveenv(void)
131{
wdenkd730fbc2003-03-06 14:23:06 +0000132 char *saved_data = NULL;
wdenkc6097192002-11-03 00:24:07 +0000133 int rc = 1;
wdenkacd9b102004-03-14 00:59:59 +0000134 char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200135#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
wdenkcc1e2562003-03-06 13:39:27 +0000136 ulong up_data = 0;
wdenkd730fbc2003-03-06 14:23:06 +0000137#endif
wdenkc6097192002-11-03 00:24:07 +0000138
139 debug ("Protect off %08lX ... %08lX\n",
140 (ulong)flash_addr, end_addr);
141
142 if (flash_sect_protect (0, (ulong)flash_addr, end_addr)) {
143 goto Done;
144 }
145
146 debug ("Protect off %08lX ... %08lX\n",
147 (ulong)flash_addr_new, end_addr_new);
148
149 if (flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new)) {
150 goto Done;
151 }
152
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200153#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
154 up_data = (end_addr_new + 1 - ((long)flash_addr_new + CONFIG_ENV_SIZE));
wdenkcc1e2562003-03-06 13:39:27 +0000155 debug ("Data to save 0x%x\n", up_data);
156 if (up_data) {
157 if ((saved_data = malloc(up_data)) == NULL) {
wdenk57b2d802003-06-27 21:31:46 +0000158 printf("Unable to save the rest of sector (%ld)\n",
wdenkcc1e2562003-03-06 13:39:27 +0000159 up_data);
160 goto Done;
161 }
wdenk57b2d802003-06-27 21:31:46 +0000162 memcpy(saved_data,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200163 (void *)((long)flash_addr_new + CONFIG_ENV_SIZE), up_data);
wdenk57b2d802003-06-27 21:31:46 +0000164 debug ("Data (start 0x%x, len 0x%x) saved at 0x%x\n",
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200165 (long)flash_addr_new + CONFIG_ENV_SIZE,
wdenkcc1e2562003-03-06 13:39:27 +0000166 up_data, saved_data);
167 }
168#endif
wdenkc6097192002-11-03 00:24:07 +0000169 puts ("Erasing Flash...");
170 debug (" %08lX ... %08lX ...",
171 (ulong)flash_addr_new, end_addr_new);
172
173 if (flash_sect_erase ((ulong)flash_addr_new, end_addr_new)) {
174 goto Done;
175 }
176
177 puts ("Writing to Flash... ");
178 debug (" %08lX ... %08lX ...",
179 (ulong)&(flash_addr_new->data),
180 sizeof(env_ptr->data)+(ulong)&(flash_addr_new->data));
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200181 if ((rc = flash_write((char *)env_ptr->data,
wdenk57b2d802003-06-27 21:31:46 +0000182 (ulong)&(flash_addr_new->data),
wdenkf602aa02004-03-13 23:29:43 +0000183 sizeof(env_ptr->data))) ||
wdenkf602aa02004-03-13 23:29:43 +0000184 (rc = flash_write((char *)&(env_ptr->crc),
wdenk57b2d802003-06-27 21:31:46 +0000185 (ulong)&(flash_addr_new->crc),
wdenkf602aa02004-03-13 23:29:43 +0000186 sizeof(env_ptr->crc))) ||
wdenkacd9b102004-03-14 00:59:59 +0000187 (rc = flash_write(&flag,
wdenk57b2d802003-06-27 21:31:46 +0000188 (ulong)&(flash_addr->flags),
wdenkf602aa02004-03-13 23:29:43 +0000189 sizeof(flash_addr->flags))) ||
wdenkacd9b102004-03-14 00:59:59 +0000190 (rc = flash_write(&new_flag,
wdenk57b2d802003-06-27 21:31:46 +0000191 (ulong)&(flash_addr_new->flags),
wdenkf602aa02004-03-13 23:29:43 +0000192 sizeof(flash_addr_new->flags))))
wdenkc6097192002-11-03 00:24:07 +0000193 {
194 flash_perror (rc);
195 goto Done;
196 }
197 puts ("done\n");
198
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200199#if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE
wdenkcc1e2562003-03-06 13:39:27 +0000200 if (up_data) { /* restore the rest of sector */
201 debug ("Restoring the rest of data to 0x%x len 0x%x\n",
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200202 (long)flash_addr_new + CONFIG_ENV_SIZE, up_data);
wdenk57b2d802003-06-27 21:31:46 +0000203 if (flash_write(saved_data,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200204 (long)flash_addr_new + CONFIG_ENV_SIZE,
wdenkcc1e2562003-03-06 13:39:27 +0000205 up_data)) {
206 flash_perror(rc);
207 goto Done;
208 }
209 }
210#endif
wdenkc6097192002-11-03 00:24:07 +0000211 {
212 env_t * etmp = flash_addr;
213 ulong ltmp = end_addr;
214
215 flash_addr = flash_addr_new;
216 flash_addr_new = etmp;
217
218 end_addr = end_addr_new;
219 end_addr_new = ltmp;
220 }
221
222 rc = 0;
223Done:
224
wdenkcc1e2562003-03-06 13:39:27 +0000225 if (saved_data)
226 free (saved_data);
wdenkc6097192002-11-03 00:24:07 +0000227 /* try to re-protect */
228 (void) flash_sect_protect (1, (ulong)flash_addr, end_addr);
229 (void) flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
230
231 return rc;
232}
233#endif /* CMD_SAVEENV */
234
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200235#else /* ! CONFIG_ENV_ADDR_REDUND */
wdenkc6097192002-11-03 00:24:07 +0000236
237int env_init(void)
238{
wdenkc6097192002-11-03 00:24:07 +0000239 if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
240 gd->env_addr = (ulong)&(env_ptr->data);
241 gd->env_valid = 1;
wdenkf8062712005-01-09 23:16:25 +0000242 return(0);
wdenkc6097192002-11-03 00:24:07 +0000243 }
Dirk Behmeafa1dd52007-08-20 07:09:05 +0200244
wdenkf8062712005-01-09 23:16:25 +0000245 gd->env_addr = (ulong)&default_environment[0];
246 gd->env_valid = 0;
wdenkc6097192002-11-03 00:24:07 +0000247 return (0);
248}
249
250#ifdef CMD_SAVEENV
251
252int saveenv(void)
253{
254 int len, rc;
255 ulong end_addr;
256 ulong flash_sect_addr;
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200257#if defined(CONFIG_ENV_SECT_SIZE) && (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE)
wdenkc6097192002-11-03 00:24:07 +0000258 ulong flash_offset;
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200259 uchar env_buffer[CONFIG_ENV_SECT_SIZE];
wdenkc6097192002-11-03 00:24:07 +0000260#else
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200261 uchar *env_buffer = (uchar *)env_ptr;
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200262#endif /* CONFIG_ENV_SECT_SIZE */
wdenkc6097192002-11-03 00:24:07 +0000263 int rcode = 0;
264
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200265#if defined(CONFIG_ENV_SECT_SIZE) && (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE)
wdenkc6097192002-11-03 00:24:07 +0000266
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200267 flash_offset = ((ulong)flash_addr) & (CONFIG_ENV_SECT_SIZE-1);
268 flash_sect_addr = ((ulong)flash_addr) & ~(CONFIG_ENV_SECT_SIZE-1);
wdenkc6097192002-11-03 00:24:07 +0000269
270 debug ( "copy old content: "
271 "sect_addr: %08lX env_addr: %08lX offset: %08lX\n",
272 flash_sect_addr, (ulong)flash_addr, flash_offset);
273
274 /* copy old contents to temporary buffer */
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200275 memcpy (env_buffer, (void *)flash_sect_addr, CONFIG_ENV_SECT_SIZE);
wdenkc6097192002-11-03 00:24:07 +0000276
277 /* copy current environment to temporary buffer */
278 memcpy ((uchar *)((unsigned long)env_buffer + flash_offset),
279 env_ptr,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200280 CONFIG_ENV_SIZE);
wdenkc6097192002-11-03 00:24:07 +0000281
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200282 len = CONFIG_ENV_SECT_SIZE;
wdenkc6097192002-11-03 00:24:07 +0000283#else
284 flash_sect_addr = (ulong)flash_addr;
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200285 len = CONFIG_ENV_SIZE;
286#endif /* CONFIG_ENV_SECT_SIZE */
wdenkc6097192002-11-03 00:24:07 +0000287
wdenkc6097192002-11-03 00:24:07 +0000288 end_addr = flash_sect_addr + len - 1;
wdenkc6097192002-11-03 00:24:07 +0000289
290 debug ("Protect off %08lX ... %08lX\n",
291 (ulong)flash_sect_addr, end_addr);
292
293 if (flash_sect_protect (0, flash_sect_addr, end_addr))
294 return 1;
295
296 puts ("Erasing Flash...");
297 if (flash_sect_erase (flash_sect_addr, end_addr))
298 return 1;
299
300 puts ("Writing to Flash... ");
Wolfgang Denk7fb52662005-10-13 16:45:02 +0200301 rc = flash_write((char *)env_buffer, flash_sect_addr, len);
wdenkc6097192002-11-03 00:24:07 +0000302 if (rc != 0) {
303 flash_perror (rc);
304 rcode = 1;
305 } else {
306 puts ("done\n");
307 }
308
309 /* try to re-protect */
310 (void) flash_sect_protect (1, flash_sect_addr, end_addr);
311 return rcode;
312}
313
314#endif /* CMD_SAVEENV */
315
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200316#endif /* CONFIG_ENV_ADDR_REDUND */
wdenkc6097192002-11-03 00:24:07 +0000317
318void env_relocate_spec (void)
319{
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200320#if !defined(ENV_IS_EMBEDDED) || defined(CONFIG_ENV_ADDR_REDUND)
321#ifdef CONFIG_ENV_ADDR_REDUND
wdenkacd9b102004-03-14 00:59:59 +0000322 if (gd->env_addr != (ulong)&(flash_addr->data)) {
wdenkc6097192002-11-03 00:24:07 +0000323 env_t * etmp = flash_addr;
324 ulong ltmp = end_addr;
325
326 flash_addr = flash_addr_new;
327 flash_addr_new = etmp;
328
329 end_addr = end_addr_new;
330 end_addr_new = ltmp;
331 }
332
wdenkacd9b102004-03-14 00:59:59 +0000333 if (flash_addr_new->flags != OBSOLETE_FLAG &&
wdenkc6097192002-11-03 00:24:07 +0000334 crc32(0, flash_addr_new->data, ENV_SIZE) ==
wdenkacd9b102004-03-14 00:59:59 +0000335 flash_addr_new->crc) {
336 char flag = OBSOLETE_FLAG;
337
wdenkc6097192002-11-03 00:24:07 +0000338 gd->env_valid = 2;
339 flash_sect_protect (0, (ulong)flash_addr_new, end_addr_new);
wdenkacd9b102004-03-14 00:59:59 +0000340 flash_write(&flag,
wdenk57b2d802003-06-27 21:31:46 +0000341 (ulong)&(flash_addr_new->flags),
342 sizeof(flash_addr_new->flags));
wdenkc6097192002-11-03 00:24:07 +0000343 flash_sect_protect (1, (ulong)flash_addr_new, end_addr_new);
344 }
345
wdenkacd9b102004-03-14 00:59:59 +0000346 if (flash_addr->flags != ACTIVE_FLAG &&
347 (flash_addr->flags & ACTIVE_FLAG) == ACTIVE_FLAG) {
348 char flag = ACTIVE_FLAG;
349
wdenkc6097192002-11-03 00:24:07 +0000350 gd->env_valid = 2;
351 flash_sect_protect (0, (ulong)flash_addr, end_addr);
wdenkacd9b102004-03-14 00:59:59 +0000352 flash_write(&flag,
wdenk57b2d802003-06-27 21:31:46 +0000353 (ulong)&(flash_addr->flags),
354 sizeof(flash_addr->flags));
wdenkc6097192002-11-03 00:24:07 +0000355 flash_sect_protect (1, (ulong)flash_addr, end_addr);
356 }
357
358 if (gd->env_valid == 2)
359 puts ("*** Warning - some problems detected "
360 "reading environment; recovered successfully\n\n");
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200361#endif /* CONFIG_ENV_ADDR_REDUND */
Mike Frysinger45cdb5f2008-05-02 18:17:50 -0400362#ifdef CMD_SAVEENV
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200363 memcpy (env_ptr, (void*)flash_addr, CONFIG_ENV_SIZE);
Mike Frysinger45cdb5f2008-05-02 18:17:50 -0400364#endif
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200365#endif /* ! ENV_IS_EMBEDDED || CONFIG_ENV_ADDR_REDUND */
wdenkc6097192002-11-03 00:24:07 +0000366}