uboot/common/env_eeprom.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 * See file CREDITS for list of people who contributed to this
   9 * project.
  10 *
  11 * This program is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU General Public License as
  13 * published by the Free Software Foundation; either version 2 of
  14 * the License, or (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  24 * MA 02111-1307 USA
  25 */
  26
  27#include <common.h>
  28#include <command.h>
  29#include <environment.h>
  30#include <linux/stddef.h>
  31#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  32#include <i2c.h>
  33#endif
  34#include <search.h>
  35#include <errno.h>
  36#include <linux/compiler.h>     /* for BUG_ON */
  37
  38DECLARE_GLOBAL_DATA_PTR;
  39
  40env_t *env_ptr = NULL;
  41
  42char *env_name_spec = "EEPROM";
  43int env_eeprom_bus = -1;
  44
  45static int eeprom_bus_read(unsigned dev_addr, unsigned offset,
  46        uchar *buffer, unsigned cnt)
  47{
  48        int rcode;
  49#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  50        int old_bus = i2c_get_bus_num();
  51
  52        if (gd->flags & GD_FLG_RELOC) {
  53                if (env_eeprom_bus == -1) {
  54                        I2C_MUX_DEVICE *dev = NULL;
  55                        dev = i2c_mux_ident_muxstring(
  56                                (uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
  57                        if (dev != NULL)
  58                                env_eeprom_bus = dev->busid;
  59                        else
  60                                printf ("error adding env eeprom bus.\n");
  61                }
  62                if (old_bus != env_eeprom_bus) {
  63                        i2c_set_bus_num(env_eeprom_bus);
  64                        old_bus = env_eeprom_bus;
  65                }
  66        } else {
  67                rcode = i2c_mux_ident_muxstring_f(
  68                                (uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
  69        }
  70#endif
  71
  72        rcode = eeprom_read (dev_addr, offset, buffer, cnt);
  73
  74#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  75        if (old_bus != env_eeprom_bus)
  76                i2c_set_bus_num(old_bus);
  77#endif
  78        return rcode;
  79}
  80
  81static int eeprom_bus_write(unsigned dev_addr, unsigned offset,
  82        uchar *buffer, unsigned cnt)
  83{
  84        int rcode;
  85#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  86        int old_bus = i2c_get_bus_num();
  87
  88        rcode = i2c_mux_ident_muxstring_f((uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
  89#endif
  90        rcode = eeprom_write(dev_addr, offset, buffer, cnt);
  91#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
  92        i2c_set_bus_num(old_bus);
  93#endif
  94        return rcode;
  95}
  96
  97uchar env_get_char_spec (int index)
  98{
  99        uchar c;
 100        unsigned int off;
 101        off = CONFIG_ENV_OFFSET;
 102
 103#ifdef CONFIG_ENV_OFFSET_REDUND
 104        if (gd->env_valid == 2)
 105                off = CONFIG_ENV_OFFSET_REDUND;
 106#endif
 107        eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 108                     off + index + offsetof(env_t,data),
 109                     &c, 1);
 110
 111        return (c);
 112}
 113
 114void env_relocate_spec (void)
 115{
 116        char buf[CONFIG_ENV_SIZE];
 117        unsigned int off = CONFIG_ENV_OFFSET;
 118
 119#ifdef CONFIG_ENV_OFFSET_REDUND
 120        if (gd->env_valid == 2)
 121                off = CONFIG_ENV_OFFSET_REDUND;
 122#endif
 123        eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 124                     off,
 125                     (uchar *)buf,
 126                     CONFIG_ENV_SIZE);
 127
 128        env_import(buf, 1);
 129}
 130
 131int saveenv(void)
 132{
 133        env_t   env_new;
 134        ssize_t len;
 135        char    *res;
 136        int rc;
 137        unsigned int off = CONFIG_ENV_OFFSET;
 138#ifdef CONFIG_ENV_OFFSET_REDUND
 139        unsigned int off_red = CONFIG_ENV_OFFSET_REDUND;
 140        char flag_obsolete = OBSOLETE_FLAG;
 141#endif
 142
 143        BUG_ON(env_ptr != NULL);
 144
 145        res = (char *)&env_new.data;
 146        len = hexport('\0', &res, ENV_SIZE);
 147        if (len < 0) {
 148                error("Cannot export environment: errno = %d\n", errno);
 149                return 1;
 150        }
 151        env_new.crc = crc32(0, env_new.data, ENV_SIZE);
 152
 153#ifdef CONFIG_ENV_OFFSET_REDUND
 154        if (gd->env_valid == 1) {
 155                off = CONFIG_ENV_OFFSET_REDUND;
 156                off_red = CONFIG_ENV_OFFSET;
 157        }
 158
 159        env_new.flags = ACTIVE_FLAG;
 160#endif
 161
 162        rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
 163                             off,
 164                             (uchar *)&env_new,
 165                             CONFIG_ENV_SIZE);
 166
 167#ifdef CONFIG_ENV_OFFSET_REDUND
 168        if (rc == 0) {
 169                eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
 170                                  off_red + offsetof(env_t,flags),
 171                                  (uchar *)&flag_obsolete,
 172                                  1);
 173                if (gd->env_valid == 1)
 174                        gd->env_valid = 2;
 175                else
 176                        gd->env_valid = 1;
 177
 178        }
 179#endif
 180
 181        return rc;
 182}
 183
 184/*
 185 * Initialize Environment use
 186 *
 187 * We are still running from ROM, so data use is limited.
 188 * Use a (moderately small) buffer on the stack
 189 */
 190
 191#ifdef CONFIG_ENV_OFFSET_REDUND
 192int env_init(void)
 193{
 194        ulong len;
 195        ulong crc[2], crc_tmp;
 196        unsigned int off, off_env[2];
 197        uchar buf[64];
 198        int crc_ok[2] = {0,0};
 199        unsigned char flags[2];
 200        int i;
 201
 202        eeprom_init();  /* prepare for EEPROM read/write */
 203
 204        off_env[0] = CONFIG_ENV_OFFSET;
 205        off_env[1] = CONFIG_ENV_OFFSET_REDUND;
 206
 207        for (i = 0; i < 2; i++) {
 208                /* read CRC */
 209                eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 210                        off_env[i] + offsetof(env_t,crc),
 211                        (uchar *)&crc[i], sizeof(ulong));
 212                /* read FLAGS */
 213                eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 214                        off_env[i] + offsetof(env_t,flags),
 215                        (uchar *)&flags[i], sizeof(uchar));
 216
 217                crc_tmp = 0;
 218                len = ENV_SIZE;
 219                off = off_env[i] + offsetof(env_t,data);
 220                while (len > 0) {
 221                        int n = (len > sizeof(buf)) ? sizeof(buf) : len;
 222
 223                        eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR, off,
 224                                buf, n);
 225
 226                        crc_tmp = crc32(crc_tmp, buf, n);
 227                        len -= n;
 228                        off += n;
 229                }
 230                if (crc_tmp == crc[i])
 231                        crc_ok[i] = 1;
 232        }
 233
 234        if (!crc_ok[0] && !crc_ok[1]) {
 235                gd->env_addr  = 0;
 236                gd->env_valid = 0;
 237
 238                return 0;
 239        } else if (crc_ok[0] && !crc_ok[1]) {
 240                gd->env_valid = 1;
 241        }
 242        else if (!crc_ok[0] && crc_ok[1]) {
 243                gd->env_valid = 2;
 244        } else {
 245                /* both ok - check serial */
 246                if (flags[0] == ACTIVE_FLAG && flags[1] == OBSOLETE_FLAG)
 247                        gd->env_valid = 1;
 248                else if (flags[0] == OBSOLETE_FLAG && flags[1] == ACTIVE_FLAG)
 249                        gd->env_valid = 2;
 250                else if (flags[0] == 0xFF && flags[1] == 0)
 251                        gd->env_valid = 2;
 252                else if(flags[1] == 0xFF && flags[0] == 0)
 253                        gd->env_valid = 1;
 254                else /* flags are equal - almost impossible */
 255                        gd->env_valid = 1;
 256        }
 257
 258        if (gd->env_valid == 2)
 259                gd->env_addr = off_env[1] + offsetof(env_t,data);
 260        else if (gd->env_valid == 1)
 261                gd->env_addr = off_env[0] + offsetof(env_t,data);
 262
 263        return (0);
 264}
 265#else
 266int env_init(void)
 267{
 268        ulong crc, len, new;
 269        unsigned off;
 270        uchar buf[64];
 271
 272        eeprom_init();  /* prepare for EEPROM read/write */
 273
 274        /* read old CRC */
 275        eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 276                     CONFIG_ENV_OFFSET+offsetof(env_t,crc),
 277                     (uchar *)&crc, sizeof(ulong));
 278
 279        new = 0;
 280        len = ENV_SIZE;
 281        off = offsetof(env_t,data);
 282
 283        while (len > 0) {
 284                int n = (len > sizeof(buf)) ? sizeof(buf) : len;
 285
 286                eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
 287                                CONFIG_ENV_OFFSET + off, buf, n);
 288                new = crc32(new, buf, n);
 289                len -= n;
 290                off += n;
 291        }
 292
 293        if (crc == new) {
 294                gd->env_addr  = offsetof(env_t,data);
 295                gd->env_valid = 1;
 296        } else {
 297                gd->env_addr  = 0;
 298                gd->env_valid = 0;
 299        }
 300
 301        return (0);
 302}
 303#endif
 304