1 /* 2 * (C) Copyright 2000-2010 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 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 /* #define DEBUG */ 12 13 #include <common.h> 14 #include <command.h> 15 #include <environment.h> 16 #include <linux/stddef.h> 17 #include <malloc.h> 18 #include <search.h> 19 #include <errno.h> 20 21 DECLARE_GLOBAL_DATA_PTR; 22 23 #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_FLASH) 24 #define CMD_SAVEENV 25 #elif defined(CONFIG_ENV_ADDR_REDUND) 26 #error CONFIG_ENV_ADDR_REDUND must have CONFIG_CMD_SAVEENV & CONFIG_CMD_FLASH 27 #endif 28 29 #if defined(CONFIG_ENV_SIZE_REDUND) && \ 30 (CONFIG_ENV_SIZE_REDUND < CONFIG_ENV_SIZE) 31 #error CONFIG_ENV_SIZE_REDUND should not be less then CONFIG_ENV_SIZE 32 #endif 33 34 char *env_name_spec = "Flash"; 35 36 #ifdef ENV_IS_EMBEDDED 37 env_t *env_ptr = &environment; 38 39 static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR; 40 41 #else /* ! ENV_IS_EMBEDDED */ 42 43 env_t *env_ptr = (env_t *)CONFIG_ENV_ADDR; 44 static env_t *flash_addr = (env_t *)CONFIG_ENV_ADDR; 45 #endif /* ENV_IS_EMBEDDED */ 46 47 #if defined(CMD_SAVEENV) || defined(CONFIG_ENV_ADDR_REDUND) 48 /* CONFIG_ENV_ADDR is supposed to be on sector boundary */ 49 static ulong end_addr = CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1; 50 #endif 51 52 #ifdef CONFIG_ENV_ADDR_REDUND 53 static env_t *flash_addr_new = (env_t *)CONFIG_ENV_ADDR_REDUND; 54 55 /* CONFIG_ENV_ADDR_REDUND is supposed to be on sector boundary */ 56 static ulong end_addr_new = CONFIG_ENV_ADDR_REDUND + CONFIG_ENV_SECT_SIZE - 1; 57 #endif /* CONFIG_ENV_ADDR_REDUND */ 58 59 60 #ifdef CONFIG_ENV_ADDR_REDUND 61 int env_init(void) 62 { 63 int crc1_ok = 0, crc2_ok = 0; 64 65 uchar flag1 = flash_addr->flags; 66 uchar flag2 = flash_addr_new->flags; 67 68 ulong addr_default = (ulong)&default_environment[0]; 69 ulong addr1 = (ulong)&(flash_addr->data); 70 ulong addr2 = (ulong)&(flash_addr_new->data); 71 72 crc1_ok = crc32(0, flash_addr->data, ENV_SIZE) == flash_addr->crc; 73 crc2_ok = 74 crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc; 75 76 if (crc1_ok && !crc2_ok) { 77 gd->env_addr = addr1; 78 gd->env_valid = ENV_VALID; 79 } else if (!crc1_ok && crc2_ok) { 80 gd->env_addr = addr2; 81 gd->env_valid = ENV_VALID; 82 } else if (!crc1_ok && !crc2_ok) { 83 gd->env_addr = addr_default; 84 gd->env_valid = 0; 85 } else if (flag1 == ACTIVE_FLAG && flag2 == OBSOLETE_FLAG) { 86 gd->env_addr = addr1; 87 gd->env_valid = ENV_VALID; 88 } else if (flag1 == OBSOLETE_FLAG && flag2 == ACTIVE_FLAG) { 89 gd->env_addr = addr2; 90 gd->env_valid = ENV_VALID; 91 } else if (flag1 == flag2) { 92 gd->env_addr = addr1; 93 gd->env_valid = ENV_REDUND; 94 } else if (flag1 == 0xFF) { 95 gd->env_addr = addr1; 96 gd->env_valid = ENV_REDUND; 97 } else if (flag2 == 0xFF) { 98 gd->env_addr = addr2; 99 gd->env_valid = ENV_REDUND; 100 } 101 102 return 0; 103 } 104 105 #ifdef CMD_SAVEENV 106 int saveenv(void) 107 { 108 env_t env_new; 109 char *saved_data = NULL; 110 char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG; 111 int rc = 1; 112 #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE 113 ulong up_data = 0; 114 #endif 115 116 debug("Protect off %08lX ... %08lX\n", (ulong)flash_addr, end_addr); 117 118 if (flash_sect_protect(0, (ulong)flash_addr, end_addr)) 119 goto done; 120 121 debug("Protect off %08lX ... %08lX\n", 122 (ulong)flash_addr_new, end_addr_new); 123 124 if (flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new)) 125 goto done; 126 127 rc = env_export(&env_new); 128 if (rc) 129 return rc; 130 env_new.flags = new_flag; 131 132 #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE 133 up_data = end_addr_new + 1 - ((long)flash_addr_new + CONFIG_ENV_SIZE); 134 debug("Data to save 0x%lX\n", up_data); 135 if (up_data) { 136 saved_data = malloc(up_data); 137 if (saved_data == NULL) { 138 printf("Unable to save the rest of sector (%ld)\n", 139 up_data); 140 goto done; 141 } 142 memcpy(saved_data, 143 (void *)((long)flash_addr_new + CONFIG_ENV_SIZE), 144 up_data); 145 debug("Data (start 0x%lX, len 0x%lX) saved at 0x%p\n", 146 (long)flash_addr_new + CONFIG_ENV_SIZE, 147 up_data, saved_data); 148 } 149 #endif 150 puts("Erasing Flash..."); 151 debug(" %08lX ... %08lX ...", (ulong)flash_addr_new, end_addr_new); 152 153 if (flash_sect_erase((ulong)flash_addr_new, end_addr_new)) 154 goto done; 155 156 puts("Writing to Flash... "); 157 debug(" %08lX ... %08lX ...", 158 (ulong)&(flash_addr_new->data), 159 sizeof(env_ptr->data) + (ulong)&(flash_addr_new->data)); 160 rc = flash_write((char *)&env_new, (ulong)flash_addr_new, 161 sizeof(env_new)); 162 if (rc) 163 goto perror; 164 165 rc = flash_write(&flag, (ulong)&(flash_addr->flags), 166 sizeof(flash_addr->flags)); 167 if (rc) 168 goto perror; 169 170 #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE 171 if (up_data) { /* restore the rest of sector */ 172 debug("Restoring the rest of data to 0x%lX len 0x%lX\n", 173 (long)flash_addr_new + CONFIG_ENV_SIZE, up_data); 174 if (flash_write(saved_data, 175 (long)flash_addr_new + CONFIG_ENV_SIZE, 176 up_data)) 177 goto perror; 178 } 179 #endif 180 puts("done\n"); 181 182 { 183 env_t *etmp = flash_addr; 184 ulong ltmp = end_addr; 185 186 flash_addr = flash_addr_new; 187 flash_addr_new = etmp; 188 189 end_addr = end_addr_new; 190 end_addr_new = ltmp; 191 } 192 193 rc = 0; 194 goto done; 195 perror: 196 flash_perror(rc); 197 done: 198 if (saved_data) 199 free(saved_data); 200 /* try to re-protect */ 201 flash_sect_protect(1, (ulong)flash_addr, end_addr); 202 flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new); 203 204 return rc; 205 } 206 #endif /* CMD_SAVEENV */ 207 208 #else /* ! CONFIG_ENV_ADDR_REDUND */ 209 210 int env_init(void) 211 { 212 if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { 213 gd->env_addr = (ulong)&(env_ptr->data); 214 gd->env_valid = ENV_VALID; 215 return 0; 216 } 217 218 gd->env_addr = (ulong)&default_environment[0]; 219 gd->env_valid = 0; 220 return 0; 221 } 222 223 #ifdef CMD_SAVEENV 224 int saveenv(void) 225 { 226 env_t env_new; 227 int rc = 1; 228 char *saved_data = NULL; 229 #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE 230 ulong up_data = 0; 231 232 up_data = end_addr + 1 - ((long)flash_addr + CONFIG_ENV_SIZE); 233 debug("Data to save 0x%lx\n", up_data); 234 if (up_data) { 235 saved_data = malloc(up_data); 236 if (saved_data == NULL) { 237 printf("Unable to save the rest of sector (%ld)\n", 238 up_data); 239 goto done; 240 } 241 memcpy(saved_data, 242 (void *)((long)flash_addr + CONFIG_ENV_SIZE), up_data); 243 debug("Data (start 0x%lx, len 0x%lx) saved at 0x%lx\n", 244 (ulong)flash_addr + CONFIG_ENV_SIZE, 245 up_data, 246 (ulong)saved_data); 247 } 248 #endif /* CONFIG_ENV_SECT_SIZE */ 249 250 debug("Protect off %08lX ... %08lX\n", (ulong)flash_addr, end_addr); 251 252 if (flash_sect_protect(0, (long)flash_addr, end_addr)) 253 goto done; 254 255 rc = env_export(&env_new); 256 if (rc) 257 goto done; 258 259 puts("Erasing Flash..."); 260 if (flash_sect_erase((long)flash_addr, end_addr)) 261 goto done; 262 263 puts("Writing to Flash... "); 264 rc = flash_write((char *)&env_new, (long)flash_addr, CONFIG_ENV_SIZE); 265 if (rc != 0) 266 goto perror; 267 268 #if CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE 269 if (up_data) { /* restore the rest of sector */ 270 debug("Restoring the rest of data to 0x%lx len 0x%lx\n", 271 (ulong)flash_addr + CONFIG_ENV_SIZE, up_data); 272 if (flash_write(saved_data, 273 (long)flash_addr + CONFIG_ENV_SIZE, 274 up_data)) 275 goto perror; 276 } 277 #endif 278 puts("done\n"); 279 rc = 0; 280 goto done; 281 perror: 282 flash_perror(rc); 283 done: 284 if (saved_data) 285 free(saved_data); 286 /* try to re-protect */ 287 flash_sect_protect(1, (long)flash_addr, end_addr); 288 return rc; 289 } 290 #endif /* CMD_SAVEENV */ 291 292 #endif /* CONFIG_ENV_ADDR_REDUND */ 293 294 void env_relocate_spec(void) 295 { 296 #ifdef CONFIG_ENV_ADDR_REDUND 297 if (gd->env_addr != (ulong)&(flash_addr->data)) { 298 env_t *etmp = flash_addr; 299 ulong ltmp = end_addr; 300 301 flash_addr = flash_addr_new; 302 flash_addr_new = etmp; 303 304 end_addr = end_addr_new; 305 end_addr_new = ltmp; 306 } 307 308 if (flash_addr_new->flags != OBSOLETE_FLAG && 309 crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc) { 310 char flag = OBSOLETE_FLAG; 311 312 gd->env_valid = ENV_REDUND; 313 flash_sect_protect(0, (ulong)flash_addr_new, end_addr_new); 314 flash_write(&flag, 315 (ulong)&(flash_addr_new->flags), 316 sizeof(flash_addr_new->flags)); 317 flash_sect_protect(1, (ulong)flash_addr_new, end_addr_new); 318 } 319 320 if (flash_addr->flags != ACTIVE_FLAG && 321 (flash_addr->flags & ACTIVE_FLAG) == ACTIVE_FLAG) { 322 char flag = ACTIVE_FLAG; 323 324 gd->env_valid = ENV_REDUND; 325 flash_sect_protect(0, (ulong)flash_addr, end_addr); 326 flash_write(&flag, 327 (ulong)&(flash_addr->flags), 328 sizeof(flash_addr->flags)); 329 flash_sect_protect(1, (ulong)flash_addr, end_addr); 330 } 331 332 if (gd->env_valid == ENV_REDUND) 333 puts("*** Warning - some problems detected " 334 "reading environment; recovered successfully\n\n"); 335 #endif /* CONFIG_ENV_ADDR_REDUND */ 336 337 env_import((char *)flash_addr, 1); 338 } 339