2 * (C) Copyright 2000-2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
6 * Andreas Heppel <aheppel@sysgo.de>
8 * See file CREDITS for list of people who contributed to this
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.
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.
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,
31 #if defined(CFG_ENV_IS_IN_FLASH) /* Environment is in Flash */
34 #include <environment.h>
35 #include <linux/stddef.h>
39 DECLARE_GLOBAL_DATA_PTR;
41 #if ((CONFIG_COMMANDS & (CFG_CMD_ENV | CFG_CMD_FLASH)) == (CFG_CMD_ENV | CFG_CMD_FLASH))
43 #elif defined(CFG_ENV_ADDR_REDUND)
44 #error Cannot use CFG_ENV_ADDR_REDUND without CFG_CMD_ENV & CFG_CMD_FLASH
47 #if defined(CFG_ENV_SIZE_REDUND) && (CFG_ENV_SIZE_REDUND < CFG_ENV_SIZE)
48 #error CFG_ENV_SIZE_REDUND should not be less then CFG_ENV_SIZE
51 const char *env_name_spec = "FLASH";
53 #ifdef ENV_IS_EMBEDDED
55 extern uchar environment[];
56 env_t *env_ptr = (env_t *)(&environment[0]);
59 /* static env_t *flash_addr = (env_t *)(&environment[0]);-broken on ARM-wd-*/
60 static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
63 #else /* ! ENV_IS_EMBEDDED */
65 env_t *env_ptr = (env_t *)CFG_ENV_ADDR;
68 static env_t *flash_addr = (env_t *)CFG_ENV_ADDR;
71 #endif /* ENV_IS_EMBEDDED */
73 #ifdef CFG_ENV_ADDR_REDUND
74 static env_t *flash_addr_new = (env_t *)CFG_ENV_ADDR_REDUND;
76 /* CFG_ENV_ADDR is supposed to be on sector boundary */
77 static ulong end_addr = CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1;
78 static ulong end_addr_new = CFG_ENV_ADDR_REDUND + CFG_ENV_SECT_SIZE - 1;
81 #define OBSOLETE_FLAG 0
82 #endif /* CFG_ENV_ADDR_REDUND */
84 extern uchar default_environment[];
85 extern int default_environment_size;
87 uchar env_get_char_spec(int index){
88 return(*((uchar *)(gd->env_addr + index)));
91 #ifdef CFG_ENV_ADDR_REDUND
94 int crc1_ok = 0, crc2_ok = 0;
96 uchar flag1 = flash_addr->flags;
97 uchar flag2 = flash_addr_new->flags;
99 ulong addr_default = (ulong)&default_environment[0];
100 ulong addr1 = (ulong)&(flash_addr->data);
101 ulong addr2 = (ulong)&(flash_addr_new->data);
103 crc1_ok = (tinf_crc32(flash_addr->data, ENV_SIZE) == flash_addr->crc);
104 crc2_ok = (tinf_crc32(flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc);
106 if(crc1_ok && !crc2_ok){
107 gd->env_addr = addr1;
109 } else if(!crc1_ok && crc2_ok){
110 gd->env_addr = addr2;
112 } else if(!crc1_ok && !crc2_ok){
113 gd->env_addr = addr_default;
115 } else if(flag1 == ACTIVE_FLAG && flag2 == OBSOLETE_FLAG){
116 gd->env_addr = addr1;
118 } else if(flag1 == OBSOLETE_FLAG && flag2 == ACTIVE_FLAG){
119 gd->env_addr = addr2;
121 } else if(flag1 == flag2){
122 gd->env_addr = addr1;
124 } else if(flag1 == 0xFF){
125 gd->env_addr = addr1;
127 } else if(flag2 == 0xFF){
128 gd->env_addr = addr2;
137 char *saved_data = NULL;
139 char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
140 #if CFG_ENV_SECT_SIZE > CFG_ENV_SIZE
143 up_data = (end_addr_new + 1 - ((long)flash_addr_new + CFG_ENV_SIZE));
146 if((saved_data = malloc(up_data)) == NULL){
147 printf("## Error: unable to save the rest of sector (%ld)\n", up_data);
151 memcpy(saved_data, (void *)((long)flash_addr_new + CFG_ENV_SIZE), up_data);
154 if(flash_sect_erase((ulong)flash_addr_new, end_addr_new)){
158 if((rc = flash_write((char *)env_ptr->data, (ulong)&(flash_addr_new->data), sizeof(env_ptr->data))) ||
159 (rc = flash_write((char *)&(env_ptr->crc), (ulong)&(flash_addr_new->crc), sizeof(env_ptr->crc))) ||
160 (rc = flash_write(&flag, (ulong)&(flash_addr->flags), sizeof(flash_addr->flags))) ||
161 (rc = flash_write(&new_flag, (ulong)&(flash_addr_new->flags), sizeof(flash_addr_new->flags)))){
166 #if CFG_ENV_SECT_SIZE > CFG_ENV_SIZE
167 if(up_data){ /* restore the rest of sector */
168 if(flash_write(saved_data, (long)flash_addr_new + CFG_ENV_SIZE, up_data)){
174 env_t * etmp = flash_addr;
175 ulong ltmp = end_addr;
177 flash_addr = flash_addr_new;
178 flash_addr_new = etmp;
180 end_addr = end_addr_new;
193 #endif /* CMD_SAVEENV */
195 #else /* ! CFG_ENV_ADDR_REDUND */
197 if(tinf_crc32(env_ptr->data, ENV_SIZE) == env_ptr->crc){
198 gd->env_addr = (ulong)&(env_ptr->data);
204 gd->env_addr = (ulong)&default_environment[0];
213 ulong end_addr, flash_sect_addr;
214 #if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
216 uchar env_buffer[CFG_ENV_SECT_SIZE];
218 uchar *env_buffer = (uchar *)env_ptr;
219 #endif /* CFG_ENV_SECT_SIZE */
222 #if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
224 flash_offset = ((ulong)flash_addr) & (CFG_ENV_SECT_SIZE-1);
225 flash_sect_addr = ((ulong)flash_addr) & ~(CFG_ENV_SECT_SIZE-1);
227 //debug("copy old content: sect_addr: %08lX env_addr: %08lX offset: %08lX\n", flash_sect_addr, (ulong)flash_addr, flash_offset);
229 /* copy old contents to temporary buffer */
230 memcpy(env_buffer, (void *)flash_sect_addr, CFG_ENV_SECT_SIZE);
232 /* copy current environment to temporary buffer */
233 memcpy((uchar *)((unsigned long)env_buffer + flash_offset), env_ptr, CFG_ENV_SIZE);
235 len = CFG_ENV_SECT_SIZE;
237 flash_sect_addr = (ulong)flash_addr;
239 #endif /* CFG_ENV_SECT_SIZE */
241 end_addr = flash_sect_addr + len - 1;
243 if(flash_sect_erase(flash_sect_addr, end_addr)){
247 rc = flash_write((char *)env_buffer, flash_sect_addr, len);
259 #endif /* CMD_SAVEENV */
261 #endif /* CFG_ENV_ADDR_REDUND */
263 void env_relocate_spec(void){
264 #if !defined(ENV_IS_EMBEDDED) || defined(CFG_ENV_ADDR_REDUND)
265 #ifdef CFG_ENV_ADDR_REDUND
266 if(gd->env_addr != (ulong)&(flash_addr->data)){
267 env_t * etmp = flash_addr;
268 ulong ltmp = end_addr;
270 flash_addr = flash_addr_new;
271 flash_addr_new = etmp;
273 end_addr = end_addr_new;
277 if(flash_addr_new->flags != OBSOLETE_FLAG && tinf_crc32(flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc){
278 char flag = OBSOLETE_FLAG;
282 flash_write(&flag, (ulong)&(flash_addr_new->flags), sizeof(flash_addr_new->flags));
285 if(flash_addr->flags != ACTIVE_FLAG && (flash_addr->flags & ACTIVE_FLAG) == ACTIVE_FLAG){
286 char flag = ACTIVE_FLAG;
290 flash_write(&flag, (ulong)&(flash_addr->flags), sizeof(flash_addr->flags));
293 if(gd->env_valid == 2){
294 puts("** Warning: some problems detected reading environment, recovered successfully\n");
296 #endif /* CFG_ENV_ADDR_REDUND */
298 memcpy(env_ptr, (void*)flash_addr, CFG_ENV_SIZE);
300 #endif /* ! ENV_IS_EMBEDDED || CFG_ENV_ADDR_REDUND */
303 #endif /* CFG_ENV_IS_IN_FLASH */