]> git.ipfire.org Git - people/ms/u-boot.git/blame - common/env_eeprom.c
Merge branch 'master' of git://git.denx.de/u-boot-74xx-7xx
[people/ms/u-boot.git] / common / env_eeprom.c
CommitLineData
0bc4a1ac 1/*
ea882baf 2 * (C) Copyright 2000-2010
0bc4a1ac
WD
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>
ea882baf 7 *
0bc4a1ac
WD
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>
0bc4a1ac
WD
28#include <command.h>
29#include <environment.h>
0bc4a1ac 30#include <linux/stddef.h>
548738b4
HS
31#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
32#include <i2c.h>
33#endif
ea882baf
WD
34#include <search.h>
35#include <errno.h>
36#include <linux/compiler.h> /* for BUG_ON */
0bc4a1ac 37
d87080b7
WD
38DECLARE_GLOBAL_DATA_PTR;
39
dd2a233c 40env_t *env_ptr;
0bc4a1ac 41
ea882baf 42char *env_name_spec = "EEPROM";
548738b4
HS
43int env_eeprom_bus = -1;
44
ea882baf 45static int eeprom_bus_read(unsigned dev_addr, unsigned offset,
dd2a233c 46 uchar *buffer, unsigned cnt)
548738b4
HS
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);
ea882baf 57 if (dev != NULL)
548738b4 58 env_eeprom_bus = dev->busid;
ea882baf 59 else
dd2a233c 60 printf("error adding env eeprom bus.\n");
548738b4
HS
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
dd2a233c 72 rcode = eeprom_read(dev_addr, offset, buffer, cnt);
ea882baf 73
548738b4
HS
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
ea882baf 81static int eeprom_bus_write(unsigned dev_addr, unsigned offset,
dd2a233c 82 uchar *buffer, unsigned cnt)
548738b4
HS
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
ea882baf 90 rcode = eeprom_write(dev_addr, offset, buffer, cnt);
548738b4
HS
91#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
92 i2c_set_bus_num(old_bus);
93#endif
94 return rcode;
95}
0bc4a1ac 96
dd2a233c 97uchar env_get_char_spec(int index)
0bc4a1ac
WD
98{
99 uchar c;
dd2a233c 100 unsigned int off = CONFIG_ENV_OFFSET;
ea882baf 101
1567b596
HS
102#ifdef CONFIG_ENV_OFFSET_REDUND
103 if (gd->env_valid == 2)
104 off = CONFIG_ENV_OFFSET_REDUND;
105#endif
ea882baf 106 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c 107 off + index + offsetof(env_t, data), &c, 1);
0bc4a1ac 108
dd2a233c 109 return c;
0bc4a1ac
WD
110}
111
dd2a233c 112void env_relocate_spec(void)
0bc4a1ac 113{
cd0f4fa1 114 char buf[CONFIG_ENV_SIZE];
1567b596 115 unsigned int off = CONFIG_ENV_OFFSET;
ea882baf 116
1567b596
HS
117#ifdef CONFIG_ENV_OFFSET_REDUND
118 if (gd->env_valid == 2)
119 off = CONFIG_ENV_OFFSET_REDUND;
120#endif
ea882baf 121 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c 122 off, (uchar *)buf, CONFIG_ENV_SIZE);
ea882baf
WD
123
124 env_import(buf, 1);
0bc4a1ac
WD
125}
126
127int saveenv(void)
128{
cd0f4fa1 129 env_t env_new;
ea882baf
WD
130 ssize_t len;
131 char *res;
dd2a233c
IG
132 int rc;
133 unsigned int off = CONFIG_ENV_OFFSET;
1567b596 134#ifdef CONFIG_ENV_OFFSET_REDUND
dd2a233c
IG
135 unsigned int off_red = CONFIG_ENV_OFFSET_REDUND;
136 char flag_obsolete = OBSOLETE_FLAG;
ea882baf
WD
137#endif
138
139 BUG_ON(env_ptr != NULL);
140
cd0f4fa1 141 res = (char *)&env_new.data;
be11235a 142 len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
ea882baf
WD
143 if (len < 0) {
144 error("Cannot export environment: errno = %d\n", errno);
145 return 1;
146 }
cd0f4fa1 147 env_new.crc = crc32(0, env_new.data, ENV_SIZE);
ea882baf
WD
148
149#ifdef CONFIG_ENV_OFFSET_REDUND
1567b596 150 if (gd->env_valid == 1) {
dd2a233c
IG
151 off = CONFIG_ENV_OFFSET_REDUND;
152 off_red = CONFIG_ENV_OFFSET;
1567b596
HS
153 }
154
cd0f4fa1 155 env_new.flags = ACTIVE_FLAG;
1567b596
HS
156#endif
157
ea882baf 158 rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
cd0f4fa1 159 off, (uchar *)&env_new, CONFIG_ENV_SIZE);
1567b596
HS
160
161#ifdef CONFIG_ENV_OFFSET_REDUND
162 if (rc == 0) {
ea882baf 163 eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c
IG
164 off_red + offsetof(env_t, flags),
165 (uchar *)&flag_obsolete, 1);
166
1567b596
HS
167 if (gd->env_valid == 1)
168 gd->env_valid = 2;
169 else
170 gd->env_valid = 1;
1567b596
HS
171 }
172#endif
1567b596 173 return rc;
0bc4a1ac
WD
174}
175
ea882baf 176/*
0bc4a1ac
WD
177 * Initialize Environment use
178 *
ea882baf 179 * We are still running from ROM, so data use is limited.
0bc4a1ac
WD
180 * Use a (moderately small) buffer on the stack
181 */
1567b596
HS
182#ifdef CONFIG_ENV_OFFSET_REDUND
183int env_init(void)
184{
dd2a233c 185 ulong len, crc[2], crc_tmp;
1567b596 186 unsigned int off, off_env[2];
dd2a233c
IG
187 uchar buf[64], flags[2];
188 int i, crc_ok[2] = {0, 0};
1567b596 189
ea882baf 190 eeprom_init(); /* prepare for EEPROM read/write */
1567b596
HS
191
192 off_env[0] = CONFIG_ENV_OFFSET;
193 off_env[1] = CONFIG_ENV_OFFSET_REDUND;
194
195 for (i = 0; i < 2; i++) {
196 /* read CRC */
ea882baf 197 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c
IG
198 off_env[i] + offsetof(env_t, crc),
199 (uchar *)&crc[i], sizeof(ulong));
1567b596 200 /* read FLAGS */
ea882baf 201 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c
IG
202 off_env[i] + offsetof(env_t, flags),
203 (uchar *)&flags[i], sizeof(uchar));
1567b596 204
ea882baf 205 crc_tmp = 0;
1567b596 206 len = ENV_SIZE;
dd2a233c 207 off = off_env[i] + offsetof(env_t, data);
1567b596
HS
208 while (len > 0) {
209 int n = (len > sizeof(buf)) ? sizeof(buf) : len;
210
ea882baf 211 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR, off,
dd2a233c 212 buf, n);
1567b596 213
ea882baf 214 crc_tmp = crc32(crc_tmp, buf, n);
1567b596
HS
215 len -= n;
216 off += n;
217 }
dd2a233c 218
1567b596
HS
219 if (crc_tmp == crc[i])
220 crc_ok[i] = 1;
221 }
222
223 if (!crc_ok[0] && !crc_ok[1]) {
dd2a233c
IG
224 gd->env_addr = 0;
225 gd->env_valid = 0;
1567b596
HS
226
227 return 0;
228 } else if (crc_ok[0] && !crc_ok[1]) {
229 gd->env_valid = 1;
dd2a233c 230 } else if (!crc_ok[0] && crc_ok[1]) {
1567b596
HS
231 gd->env_valid = 2;
232 } else {
233 /* both ok - check serial */
234 if (flags[0] == ACTIVE_FLAG && flags[1] == OBSOLETE_FLAG)
235 gd->env_valid = 1;
236 else if (flags[0] == OBSOLETE_FLAG && flags[1] == ACTIVE_FLAG)
237 gd->env_valid = 2;
238 else if (flags[0] == 0xFF && flags[1] == 0)
239 gd->env_valid = 2;
dd2a233c 240 else if (flags[1] == 0xFF && flags[0] == 0)
1567b596
HS
241 gd->env_valid = 1;
242 else /* flags are equal - almost impossible */
243 gd->env_valid = 1;
244 }
245
246 if (gd->env_valid == 2)
dd2a233c 247 gd->env_addr = off_env[1] + offsetof(env_t, data);
1567b596 248 else if (gd->env_valid == 1)
dd2a233c 249 gd->env_addr = off_env[0] + offsetof(env_t, data);
1567b596 250
dd2a233c 251 return 0;
1567b596
HS
252}
253#else
0bc4a1ac
WD
254int env_init(void)
255{
0bc4a1ac
WD
256 ulong crc, len, new;
257 unsigned off;
258 uchar buf[64];
259
ea882baf 260 eeprom_init(); /* prepare for EEPROM read/write */
0bc4a1ac
WD
261
262 /* read old CRC */
ea882baf 263 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
dd2a233c
IG
264 CONFIG_ENV_OFFSET + offsetof(env_t, crc),
265 (uchar *)&crc, sizeof(ulong));
0bc4a1ac
WD
266
267 new = 0;
268 len = ENV_SIZE;
dd2a233c 269 off = offsetof(env_t, data);
ea882baf 270
0bc4a1ac
WD
271 while (len > 0) {
272 int n = (len > sizeof(buf)) ? sizeof(buf) : len;
273
ea882baf 274 eeprom_bus_read(CONFIG_SYS_DEF_EEPROM_ADDR,
548738b4 275 CONFIG_ENV_OFFSET + off, buf, n);
ea882baf 276 new = crc32(new, buf, n);
0bc4a1ac
WD
277 len -= n;
278 off += n;
279 }
280
281 if (crc == new) {
dd2a233c
IG
282 gd->env_addr = offsetof(env_t, data);
283 gd->env_valid = 1;
0bc4a1ac 284 } else {
dd2a233c
IG
285 gd->env_addr = 0;
286 gd->env_valid = 0;
0bc4a1ac
WD
287 }
288
dd2a233c 289 return 0;
0bc4a1ac 290}
1567b596 291#endif