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 * (C) Copyright 2008 Atmel Corporation 9 * 10 * SPDX-License-Identifier: GPL-2.0+ 11 */ 12 #include <common.h> 13 #include <dm.h> 14 #include <environment.h> 15 #include <malloc.h> 16 #include <spi.h> 17 #include <spi_flash.h> 18 #include <search.h> 19 #include <errno.h> 20 #include <dm/device-internal.h> 21 22 #ifndef CONFIG_ENV_SPI_BUS 23 # define CONFIG_ENV_SPI_BUS CONFIG_SF_DEFAULT_BUS 24 #endif 25 #ifndef CONFIG_ENV_SPI_CS 26 # define CONFIG_ENV_SPI_CS CONFIG_SF_DEFAULT_CS 27 #endif 28 #ifndef CONFIG_ENV_SPI_MAX_HZ 29 # define CONFIG_ENV_SPI_MAX_HZ CONFIG_SF_DEFAULT_SPEED 30 #endif 31 #ifndef CONFIG_ENV_SPI_MODE 32 # define CONFIG_ENV_SPI_MODE CONFIG_SF_DEFAULT_MODE 33 #endif 34 35 #ifdef CONFIG_ENV_OFFSET_REDUND 36 static ulong env_offset = CONFIG_ENV_OFFSET; 37 static ulong env_new_offset = CONFIG_ENV_OFFSET_REDUND; 38 39 #define ACTIVE_FLAG 1 40 #define OBSOLETE_FLAG 0 41 #endif /* CONFIG_ENV_OFFSET_REDUND */ 42 43 DECLARE_GLOBAL_DATA_PTR; 44 45 char *env_name_spec = "SPI Flash"; 46 47 static struct spi_flash *env_flash; 48 49 static int setup_flash_device(void) 50 { 51 #ifdef CONFIG_DM_SPI_FLASH 52 struct udevice *new; 53 int ret; 54 55 /* speed and mode will be read from DT */ 56 ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, 57 0, 0, &new); 58 if (ret) { 59 set_default_env("!spi_flash_probe_bus_cs() failed"); 60 return 1; 61 } 62 63 env_flash = dev_get_uclass_priv(new); 64 #else 65 66 if (!env_flash) { 67 env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, 68 CONFIG_ENV_SPI_CS, 69 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE); 70 if (!env_flash) { 71 set_default_env("!spi_flash_probe() failed"); 72 return 1; 73 } 74 } 75 #endif 76 return 0; 77 } 78 79 #if defined(CONFIG_ENV_OFFSET_REDUND) 80 int saveenv(void) 81 { 82 env_t env_new; 83 char *saved_buffer = NULL, flag = OBSOLETE_FLAG; 84 u32 saved_size, saved_offset, sector; 85 int ret; 86 87 ret = setup_flash_device(); 88 if (ret) 89 return ret; 90 91 ret = env_export(&env_new); 92 if (ret) 93 return ret; 94 env_new.flags = ACTIVE_FLAG; 95 96 if (gd->env_valid == ENV_VALID) { 97 env_new_offset = CONFIG_ENV_OFFSET_REDUND; 98 env_offset = CONFIG_ENV_OFFSET; 99 } else { 100 env_new_offset = CONFIG_ENV_OFFSET; 101 env_offset = CONFIG_ENV_OFFSET_REDUND; 102 } 103 104 /* Is the sector larger than the env (i.e. embedded) */ 105 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) { 106 saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE; 107 saved_offset = env_new_offset + CONFIG_ENV_SIZE; 108 saved_buffer = memalign(ARCH_DMA_MINALIGN, saved_size); 109 if (!saved_buffer) { 110 ret = 1; 111 goto done; 112 } 113 ret = spi_flash_read(env_flash, saved_offset, 114 saved_size, saved_buffer); 115 if (ret) 116 goto done; 117 } 118 119 sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, CONFIG_ENV_SECT_SIZE); 120 121 puts("Erasing SPI flash..."); 122 ret = spi_flash_erase(env_flash, env_new_offset, 123 sector * CONFIG_ENV_SECT_SIZE); 124 if (ret) 125 goto done; 126 127 puts("Writing to SPI flash..."); 128 129 ret = spi_flash_write(env_flash, env_new_offset, 130 CONFIG_ENV_SIZE, &env_new); 131 if (ret) 132 goto done; 133 134 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) { 135 ret = spi_flash_write(env_flash, saved_offset, 136 saved_size, saved_buffer); 137 if (ret) 138 goto done; 139 } 140 141 ret = spi_flash_write(env_flash, env_offset + offsetof(env_t, flags), 142 sizeof(env_new.flags), &flag); 143 if (ret) 144 goto done; 145 146 puts("done\n"); 147 148 gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND; 149 150 printf("Valid environment: %d\n", (int)gd->env_valid); 151 152 done: 153 if (saved_buffer) 154 free(saved_buffer); 155 156 return ret; 157 } 158 159 void env_relocate_spec(void) 160 { 161 int ret; 162 int crc1_ok = 0, crc2_ok = 0; 163 env_t *tmp_env1 = NULL; 164 env_t *tmp_env2 = NULL; 165 env_t *ep = NULL; 166 167 tmp_env1 = (env_t *)memalign(ARCH_DMA_MINALIGN, 168 CONFIG_ENV_SIZE); 169 tmp_env2 = (env_t *)memalign(ARCH_DMA_MINALIGN, 170 CONFIG_ENV_SIZE); 171 if (!tmp_env1 || !tmp_env2) { 172 set_default_env("!malloc() failed"); 173 goto out; 174 } 175 176 ret = setup_flash_device(); 177 if (ret) 178 goto out; 179 180 ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET, 181 CONFIG_ENV_SIZE, tmp_env1); 182 if (ret) { 183 set_default_env("!spi_flash_read() failed"); 184 goto err_read; 185 } 186 187 if (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc) 188 crc1_ok = 1; 189 190 ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET_REDUND, 191 CONFIG_ENV_SIZE, tmp_env2); 192 if (!ret) { 193 if (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc) 194 crc2_ok = 1; 195 } 196 197 if (!crc1_ok && !crc2_ok) { 198 set_default_env("!bad CRC"); 199 goto err_read; 200 } else if (crc1_ok && !crc2_ok) { 201 gd->env_valid = ENV_VALID; 202 } else if (!crc1_ok && crc2_ok) { 203 gd->env_valid = ENV_REDUND; 204 } else if (tmp_env1->flags == ACTIVE_FLAG && 205 tmp_env2->flags == OBSOLETE_FLAG) { 206 gd->env_valid = ENV_VALID; 207 } else if (tmp_env1->flags == OBSOLETE_FLAG && 208 tmp_env2->flags == ACTIVE_FLAG) { 209 gd->env_valid = ENV_REDUND; 210 } else if (tmp_env1->flags == tmp_env2->flags) { 211 gd->env_valid = ENV_VALID; 212 } else if (tmp_env1->flags == 0xFF) { 213 gd->env_valid = ENV_VALID; 214 } else if (tmp_env2->flags == 0xFF) { 215 gd->env_valid = ENV_REDUND; 216 } else { 217 /* 218 * this differs from code in env_flash.c, but I think a sane 219 * default path is desirable. 220 */ 221 gd->env_valid = ENV_VALID; 222 } 223 224 if (gd->env_valid == ENV_VALID) 225 ep = tmp_env1; 226 else 227 ep = tmp_env2; 228 229 ret = env_import((char *)ep, 0); 230 if (!ret) { 231 error("Cannot import environment: errno = %d\n", errno); 232 set_default_env("!env_import failed"); 233 } 234 235 err_read: 236 spi_flash_free(env_flash); 237 env_flash = NULL; 238 out: 239 free(tmp_env1); 240 free(tmp_env2); 241 } 242 #else 243 int saveenv(void) 244 { 245 u32 saved_size, saved_offset, sector; 246 char *saved_buffer = NULL; 247 int ret = 1; 248 env_t env_new; 249 250 ret = setup_flash_device(); 251 if (ret) 252 return ret; 253 254 /* Is the sector larger than the env (i.e. embedded) */ 255 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) { 256 saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE; 257 saved_offset = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE; 258 saved_buffer = malloc(saved_size); 259 if (!saved_buffer) 260 goto done; 261 262 ret = spi_flash_read(env_flash, saved_offset, 263 saved_size, saved_buffer); 264 if (ret) 265 goto done; 266 } 267 268 ret = env_export(&env_new); 269 if (ret) 270 goto done; 271 272 sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, CONFIG_ENV_SECT_SIZE); 273 274 puts("Erasing SPI flash..."); 275 ret = spi_flash_erase(env_flash, CONFIG_ENV_OFFSET, 276 sector * CONFIG_ENV_SECT_SIZE); 277 if (ret) 278 goto done; 279 280 puts("Writing to SPI flash..."); 281 ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET, 282 CONFIG_ENV_SIZE, &env_new); 283 if (ret) 284 goto done; 285 286 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) { 287 ret = spi_flash_write(env_flash, saved_offset, 288 saved_size, saved_buffer); 289 if (ret) 290 goto done; 291 } 292 293 ret = 0; 294 puts("done\n"); 295 296 done: 297 if (saved_buffer) 298 free(saved_buffer); 299 300 return ret; 301 } 302 303 void env_relocate_spec(void) 304 { 305 int ret; 306 char *buf = NULL; 307 308 buf = (char *)memalign(ARCH_DMA_MINALIGN, CONFIG_ENV_SIZE); 309 if (!buf) { 310 set_default_env("!malloc() failed"); 311 return; 312 } 313 314 ret = setup_flash_device(); 315 if (ret) 316 goto out; 317 318 ret = spi_flash_read(env_flash, 319 CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf); 320 if (ret) { 321 set_default_env("!spi_flash_read() failed"); 322 goto err_read; 323 } 324 325 ret = env_import(buf, 1); 326 if (ret) 327 gd->env_valid = ENV_VALID; 328 329 err_read: 330 spi_flash_free(env_flash); 331 env_flash = NULL; 332 out: 333 free(buf); 334 } 335 #endif 336 337 int env_init(void) 338 { 339 /* SPI flash isn't usable before relocation */ 340 gd->env_addr = (ulong)&default_environment[0]; 341 gd->env_valid = ENV_VALID; 342 343 return 0; 344 } 345