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