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