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 <env.h> 14#include <env_internal.h> 15#include <malloc.h> 16#include <spi.h> 17#include <spi_flash.h> 18#include <search.h> 19#include <errno.h> 20#include <uuid.h> 21#include <asm/cache.h> 22#include <asm/global_data.h> 23#include <dm/device-internal.h> 24#include <u-boot/crc.h> 25 26#define OFFSET_INVALID (~(u32)0) 27 28#ifdef CONFIG_ENV_OFFSET_REDUND 29#define ENV_OFFSET_REDUND CONFIG_ENV_OFFSET_REDUND 30 31static ulong env_offset = CONFIG_ENV_OFFSET; 32static ulong env_new_offset = CONFIG_ENV_OFFSET_REDUND; 33 34#else 35 36#define ENV_OFFSET_REDUND OFFSET_INVALID 37 38#endif /* CONFIG_ENV_OFFSET_REDUND */ 39 40DECLARE_GLOBAL_DATA_PTR; 41 42static int setup_flash_device(struct spi_flash **env_flash) 43{ 44#if CONFIG_IS_ENABLED(DM_SPI_FLASH) 45 struct udevice *new; 46 int ret; 47 48 /* speed and mode will be read from DT */ 49 ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, 50 &new); 51 if (ret) { 52 env_set_default("spi_flash_probe_bus_cs() failed", 0); 53 return ret; 54 } 55 56 *env_flash = dev_get_uclass_priv(new); 57#else 58 *env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, 59 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE); 60 if (!*env_flash) { 61 env_set_default("spi_flash_probe() failed", 0); 62 return -EIO; 63 } 64#endif 65 return 0; 66} 67 68#if defined(CONFIG_ENV_OFFSET_REDUND) 69static int env_sf_save(void) 70{ 71 env_t env_new; 72 char *saved_buffer = NULL, flag = ENV_REDUND_OBSOLETE; 73 u32 saved_size = 0, saved_offset = 0, sector; 74 u32 sect_size = CONFIG_ENV_SECT_SIZE; 75 int ret; 76 struct spi_flash *env_flash; 77 78 ret = setup_flash_device(&env_flash); 79 if (ret) 80 return ret; 81 82 if (IS_ENABLED(CONFIG_ENV_SECT_SIZE_AUTO)) 83 sect_size = env_flash->mtd.erasesize; 84 85 ret = env_export(&env_new); 86 if (ret) 87 return -EIO; 88 env_new.flags = ENV_REDUND_ACTIVE; 89 90 if (gd->env_valid == ENV_VALID) { 91 env_new_offset = CONFIG_ENV_OFFSET_REDUND; 92 env_offset = CONFIG_ENV_OFFSET; 93 } else { 94 env_new_offset = CONFIG_ENV_OFFSET; 95 env_offset = CONFIG_ENV_OFFSET_REDUND; 96 } 97 98 /* Is the sector larger than the env (i.e. embedded) */ 99 if (sect_size > CONFIG_ENV_SIZE) { 100 saved_size = sect_size - CONFIG_ENV_SIZE; 101 saved_offset = env_new_offset + CONFIG_ENV_SIZE; 102 saved_buffer = memalign(ARCH_DMA_MINALIGN, saved_size); 103 if (!saved_buffer) { 104 ret = -ENOMEM; 105 goto done; 106 } 107 ret = spi_flash_read(env_flash, saved_offset, 108 saved_size, saved_buffer); 109 if (ret) 110 goto done; 111 } 112 113 sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, sect_size); 114 115 puts("Erasing SPI flash..."); 116 ret = spi_flash_erase(env_flash, env_new_offset, 117 sector * sect_size); 118 if (ret) 119 goto done; 120 121 puts("Writing to SPI flash..."); 122 123 ret = spi_flash_write(env_flash, env_new_offset, 124 CONFIG_ENV_SIZE, &env_new); 125 if (ret) 126 goto done; 127 128 if (sect_size > CONFIG_ENV_SIZE) { 129 ret = spi_flash_write(env_flash, saved_offset, 130 saved_size, saved_buffer); 131 if (ret) 132 goto done; 133 } 134 135 ret = spi_flash_write(env_flash, env_offset + offsetof(env_t, flags), 136 sizeof(env_new.flags), &flag); 137 if (ret) 138 goto done; 139 140 puts("done\n"); 141 142 gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND; 143 144 printf("Valid environment: %d\n", (int)gd->env_valid); 145 146done: 147 spi_flash_free(env_flash); 148 149 if (saved_buffer) 150 free(saved_buffer); 151 152 return ret; 153} 154 155static int env_sf_load(void) 156{ 157 int ret; 158 int read1_fail, read2_fail; 159 env_t *tmp_env1, *tmp_env2; 160 struct spi_flash *env_flash; 161 162 tmp_env1 = (env_t *)memalign(ARCH_DMA_MINALIGN, 163 CONFIG_ENV_SIZE); 164 tmp_env2 = (env_t *)memalign(ARCH_DMA_MINALIGN, 165 CONFIG_ENV_SIZE); 166 if (!tmp_env1 || !tmp_env2) { 167 env_set_default("malloc() failed", 0); 168 ret = -EIO; 169 goto out; 170 } 171 172 ret = setup_flash_device(&env_flash); 173 if (ret) 174 goto out; 175 176 read1_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET, 177 CONFIG_ENV_SIZE, tmp_env1); 178 read2_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET_REDUND, 179 CONFIG_ENV_SIZE, tmp_env2); 180 181 ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2, 182 read2_fail, H_EXTERNAL); 183 184 spi_flash_free(env_flash); 185out: 186 free(tmp_env1); 187 free(tmp_env2); 188 189 return ret; 190} 191#else 192static int env_sf_save(void) 193{ 194 u32 saved_size = 0, saved_offset = 0, sector; 195 u32 sect_size = CONFIG_ENV_SECT_SIZE; 196 char *saved_buffer = NULL; 197 int ret = 1; 198 env_t env_new; 199 struct spi_flash *env_flash; 200 201 ret = setup_flash_device(&env_flash); 202 if (ret) 203 return ret; 204 205 if (IS_ENABLED(CONFIG_ENV_SECT_SIZE_AUTO)) 206 sect_size = env_flash->mtd.erasesize; 207 208 /* Is the sector larger than the env (i.e. embedded) */ 209 if (sect_size > CONFIG_ENV_SIZE) { 210 saved_size = sect_size - CONFIG_ENV_SIZE; 211 saved_offset = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE; 212 saved_buffer = malloc(saved_size); 213 if (!saved_buffer) { 214 ret = -ENOMEM; 215 goto done; 216 } 217 218 ret = spi_flash_read(env_flash, saved_offset, 219 saved_size, saved_buffer); 220 if (ret) 221 goto done; 222 } 223 224 ret = env_export(&env_new); 225 if (ret) 226 goto done; 227 228 sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, sect_size); 229 230 puts("Erasing SPI flash..."); 231 ret = spi_flash_erase(env_flash, CONFIG_ENV_OFFSET, 232 sector * sect_size); 233 if (ret) 234 goto done; 235 236 puts("Writing to SPI flash..."); 237 ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET, 238 CONFIG_ENV_SIZE, &env_new); 239 if (ret) 240 goto done; 241 242 if (sect_size > CONFIG_ENV_SIZE) { 243 ret = spi_flash_write(env_flash, saved_offset, 244 saved_size, saved_buffer); 245 if (ret) 246 goto done; 247 } 248 249 ret = 0; 250 puts("done\n"); 251 252done: 253 spi_flash_free(env_flash); 254 255 if (saved_buffer) 256 free(saved_buffer); 257 258 return ret; 259} 260 261static int env_sf_load(void) 262{ 263 int ret; 264 char *buf = NULL; 265 struct spi_flash *env_flash; 266 267 buf = (char *)memalign(ARCH_DMA_MINALIGN, CONFIG_ENV_SIZE); 268 if (!buf) { 269 env_set_default("malloc() failed", 0); 270 return -EIO; 271 } 272 273 ret = setup_flash_device(&env_flash); 274 if (ret) 275 goto out; 276 277 ret = spi_flash_read(env_flash, 278 CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf); 279 if (ret) { 280 env_set_default("spi_flash_read() failed", 0); 281 goto err_read; 282 } 283 284 ret = env_import(buf, 1, H_EXTERNAL); 285 if (!ret) 286 gd->env_valid = ENV_VALID; 287 288err_read: 289 spi_flash_free(env_flash); 290out: 291 free(buf); 292 293 return ret; 294} 295#endif 296 297static int env_sf_erase(void) 298{ 299 int ret; 300 env_t env; 301 struct spi_flash *env_flash; 302 303 ret = setup_flash_device(&env_flash); 304 if (ret) 305 return ret; 306 307 memset(&env, 0, sizeof(env_t)); 308 ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, &env); 309 if (ret) 310 goto done; 311 312 if (ENV_OFFSET_REDUND != OFFSET_INVALID) 313 ret = spi_flash_write(env_flash, ENV_OFFSET_REDUND, CONFIG_ENV_SIZE, &env); 314 315done: 316 spi_flash_free(env_flash); 317 318 return ret; 319} 320 321__weak void *env_sf_get_env_addr(void) 322{ 323#ifndef CONFIG_SPL_BUILD 324 return (void *)CONFIG_ENV_ADDR; 325#else 326 return NULL; 327#endif 328} 329 330/* 331 * check if Environment on CONFIG_ENV_ADDR is valid. 332 */ 333static int env_sf_init_addr(void) 334{ 335 env_t *env_ptr = (env_t *)env_sf_get_env_addr(); 336 337 if (!env_ptr) 338 return -ENOENT; 339 340 if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) { 341 gd->env_addr = (ulong)&(env_ptr->data); 342 gd->env_valid = ENV_VALID; 343 } else { 344 gd->env_valid = ENV_INVALID; 345 } 346 347 return 0; 348} 349 350#if defined(CONFIG_ENV_SPI_EARLY) 351/* 352 * early load environment from SPI flash (before relocation) 353 * and check if it is valid. 354 */ 355static int env_sf_init_early(void) 356{ 357 int ret; 358 int read1_fail; 359 int read2_fail; 360 int crc1_ok; 361 env_t *tmp_env2 = NULL; 362 env_t *tmp_env1; 363 struct spi_flash *env_flash; 364 365 /* 366 * if malloc is not ready yet, we cannot use 367 * this part yet. 368 */ 369 if (!gd->malloc_limit) 370 return -ENOENT; 371 372 tmp_env1 = (env_t *)memalign(ARCH_DMA_MINALIGN, 373 CONFIG_ENV_SIZE); 374 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) 375 tmp_env2 = (env_t *)memalign(ARCH_DMA_MINALIGN, 376 CONFIG_ENV_SIZE); 377 378 if (!tmp_env1 || !tmp_env2) 379 goto out; 380 381 ret = setup_flash_device(&env_flash); 382 if (ret) 383 goto out; 384 385 read1_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET, 386 CONFIG_ENV_SIZE, tmp_env1); 387 388 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) { 389 read2_fail = spi_flash_read(env_flash, 390 CONFIG_ENV_OFFSET_REDUND, 391 CONFIG_ENV_SIZE, tmp_env2); 392 ret = env_check_redund((char *)tmp_env1, read1_fail, 393 (char *)tmp_env2, read2_fail); 394 395 if (ret < 0) 396 goto err_read; 397 398 if (gd->env_valid == ENV_VALID) 399 gd->env_addr = (unsigned long)&tmp_env1->data; 400 else 401 gd->env_addr = (unsigned long)&tmp_env2->data; 402 } else { 403 if (read1_fail) 404 goto err_read; 405 406 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == 407 tmp_env1->crc; 408 if (!crc1_ok) 409 goto err_read; 410 411 /* if valid -> this is our env */ 412 gd->env_valid = ENV_VALID; 413 gd->env_addr = (unsigned long)&tmp_env1->data; 414 } 415 416 spi_flash_free(env_flash); 417 418 return 0; 419err_read: 420 spi_flash_free(env_flash); 421 422 free(tmp_env1); 423 if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) 424 free(tmp_env2); 425out: 426 /* env is not valid. always return 0 */ 427 gd->env_valid = ENV_INVALID; 428 return 0; 429} 430#endif 431 432static int env_sf_init(void) 433{ 434 int ret = env_sf_init_addr(); 435 if (ret != -ENOENT) 436 return ret; 437#ifdef CONFIG_ENV_SPI_EARLY 438 return env_sf_init_early(); 439#endif 440 /* 441 * return here -ENOENT, so env_init() 442 * can set the init bit and later if no 443 * other Environment storage is defined 444 * can set the default environment 445 */ 446 return -ENOENT; 447} 448 449U_BOOT_ENV_LOCATION(sf) = { 450 .location = ENVL_SPI_FLASH, 451 ENV_NAME("SPIFlash") 452 .load = env_sf_load, 453 .save = ENV_SAVE_PTR(env_sf_save), 454 .erase = ENV_ERASE_PTR(env_sf_erase), 455 .init = env_sf_init, 456}; 457