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