blob: 95a7d0d3bc993d84fb5ade0b1a2642e45070d70f [file] [log] [blame]
wdenk0bc4a1a2002-09-18 11:09:59 +00001/*
2 * (C) Copyright 2000-2002
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>
wdenk0bc4a1a2002-09-18 11:09:59 +000028#include <command.h>
29#include <environment.h>
wdenk0bc4a1a2002-09-18 11:09:59 +000030#include <linux/stddef.h>
Heiko Schocher9bb0dd52010-01-07 08:55:40 +010031#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
32#include <i2c.h>
33#endif
wdenk0bc4a1a2002-09-18 11:09:59 +000034
Heiko Schochere7193632010-01-07 08:55:44 +010035#ifdef CONFIG_ENV_OFFSET_REDUND
36#define ACTIVE_FLAG 1
37#define OBSOLETE_FLAG 0
38#endif
39
Wolfgang Denk6405a152006-03-31 18:32:53 +020040DECLARE_GLOBAL_DATA_PTR;
41
wdenk0bc4a1a2002-09-18 11:09:59 +000042env_t *env_ptr = NULL;
43
44char * env_name_spec = "EEPROM";
Heiko Schocher9bb0dd52010-01-07 08:55:40 +010045int env_eeprom_bus = -1;
46
47static int eeprom_bus_read (unsigned dev_addr, unsigned offset, uchar *buffer,
48 unsigned cnt)
49{
50 int rcode;
51#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
52 int old_bus = i2c_get_bus_num();
53
54 if (gd->flags & GD_FLG_RELOC) {
55 if (env_eeprom_bus == -1) {
56 I2C_MUX_DEVICE *dev = NULL;
57 dev = i2c_mux_ident_muxstring(
58 (uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
59 if (dev != NULL) {
60 env_eeprom_bus = dev->busid;
61 } else
62 printf ("error adding env eeprom bus.\n");
63 }
64 if (old_bus != env_eeprom_bus) {
65 i2c_set_bus_num(env_eeprom_bus);
66 old_bus = env_eeprom_bus;
67 }
68 } else {
69 rcode = i2c_mux_ident_muxstring_f(
70 (uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
71 }
72#endif
73
74 rcode = eeprom_read (dev_addr, offset, buffer, cnt);
75#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
76 if (old_bus != env_eeprom_bus)
77 i2c_set_bus_num(old_bus);
78#endif
79 return rcode;
80}
81
82static int eeprom_bus_write (unsigned dev_addr, unsigned offset, uchar *buffer,
83 unsigned cnt)
84{
85 int rcode;
86#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
87 int old_bus = i2c_get_bus_num();
88
89 rcode = i2c_mux_ident_muxstring_f((uchar *)CONFIG_I2C_ENV_EEPROM_BUS);
90#endif
91 rcode = eeprom_write (dev_addr, offset, buffer, cnt);
92#if defined(CONFIG_I2C_ENV_EEPROM_BUS)
93 i2c_set_bus_num(old_bus);
94#endif
95 return rcode;
96}
wdenk0bc4a1a2002-09-18 11:09:59 +000097
wdenk0bc4a1a2002-09-18 11:09:59 +000098uchar env_get_char_spec (int index)
99{
100 uchar c;
Heiko Schochere7193632010-01-07 08:55:44 +0100101 unsigned int off;
102 off = CONFIG_ENV_OFFSET;
103#ifdef CONFIG_ENV_OFFSET_REDUND
104 if (gd->env_valid == 2)
105 off = CONFIG_ENV_OFFSET_REDUND;
106#endif
wdenk0bc4a1a2002-09-18 11:09:59 +0000107
Heiko Schocher9bb0dd52010-01-07 08:55:40 +0100108 eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
Heiko Schochere7193632010-01-07 08:55:44 +0100109 off + index + offsetof(env_t,data),
wdenk0bc4a1a2002-09-18 11:09:59 +0000110 &c, 1);
111
112 return (c);
113}
114
115void env_relocate_spec (void)
116{
Heiko Schochere7193632010-01-07 08:55:44 +0100117 unsigned int off = CONFIG_ENV_OFFSET;
118#ifdef CONFIG_ENV_OFFSET_REDUND
119 if (gd->env_valid == 2)
120 off = CONFIG_ENV_OFFSET_REDUND;
121#endif
Heiko Schocher9bb0dd52010-01-07 08:55:40 +0100122 eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
Heiko Schochere7193632010-01-07 08:55:44 +0100123 off,
wdenk0bc4a1a2002-09-18 11:09:59 +0000124 (uchar*)env_ptr,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200125 CONFIG_ENV_SIZE);
wdenk0bc4a1a2002-09-18 11:09:59 +0000126}
127
128int saveenv(void)
129{
Heiko Schochere7193632010-01-07 08:55:44 +0100130 int rc;
131 unsigned int off = CONFIG_ENV_OFFSET;
132#ifdef CONFIG_ENV_OFFSET_REDUND
133 unsigned int off_red = CONFIG_ENV_OFFSET_REDUND;
134 char flag_obsolete = OBSOLETE_FLAG;
135 if (gd->env_valid == 1) {
136 off = CONFIG_ENV_OFFSET_REDUND;
137 off_red = CONFIG_ENV_OFFSET;
138 }
139
140 env_ptr->flags = ACTIVE_FLAG;
141#endif
142
143 rc = eeprom_bus_write (CONFIG_SYS_DEF_EEPROM_ADDR,
144 off,
wdenk0bc4a1a2002-09-18 11:09:59 +0000145 (uchar *)env_ptr,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200146 CONFIG_ENV_SIZE);
Heiko Schochere7193632010-01-07 08:55:44 +0100147
148#ifdef CONFIG_ENV_OFFSET_REDUND
149 if (rc == 0) {
150 eeprom_bus_write (CONFIG_SYS_DEF_EEPROM_ADDR,
151 off_red + offsetof(env_t,flags),
152 (uchar *)&flag_obsolete,
153 1);
154 if (gd->env_valid == 1)
155 gd->env_valid = 2;
156 else
157 gd->env_valid = 1;
158
159 }
160#endif
161
162 return rc;
wdenk0bc4a1a2002-09-18 11:09:59 +0000163}
164
165/************************************************************************
166 * Initialize Environment use
167 *
168 * We are still running from ROM, so data use is limited
169 * Use a (moderately small) buffer on the stack
170 */
Heiko Schochere7193632010-01-07 08:55:44 +0100171
172#ifdef CONFIG_ENV_OFFSET_REDUND
173int env_init(void)
174{
175 ulong len;
176 ulong crc[2], crc_tmp;
177 unsigned int off, off_env[2];
178 uchar buf[64];
179 int crc_ok[2] = {0,0};
180 unsigned char flags[2];
181 int i;
182
183 eeprom_init (); /* prepare for EEPROM read/write */
184
185 off_env[0] = CONFIG_ENV_OFFSET;
186 off_env[1] = CONFIG_ENV_OFFSET_REDUND;
187
188 for (i = 0; i < 2; i++) {
189 /* read CRC */
190 eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
191 off_env[i] + offsetof(env_t,crc),
192 (uchar *)&crc[i], sizeof(ulong));
193 /* read FLAGS */
194 eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
195 off_env[i] + offsetof(env_t,flags),
196 (uchar *)&flags[i], sizeof(uchar));
197
198 crc_tmp= 0;
199 len = ENV_SIZE;
200 off = off_env[i] + offsetof(env_t,data);
201 while (len > 0) {
202 int n = (len > sizeof(buf)) ? sizeof(buf) : len;
203
204 eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR, off,
205 buf, n);
206
207 crc_tmp = crc32 (crc_tmp, buf, n);
208 len -= n;
209 off += n;
210 }
211 if (crc_tmp == crc[i])
212 crc_ok[i] = 1;
213 }
214
215 if (!crc_ok[0] && !crc_ok[1]) {
216 gd->env_addr = 0;
217 gd->env_valid = 0;
218
219 return 0;
220 } else if (crc_ok[0] && !crc_ok[1]) {
221 gd->env_valid = 1;
222 }
223 else if (!crc_ok[0] && crc_ok[1]) {
224 gd->env_valid = 2;
225 } else {
226 /* both ok - check serial */
227 if (flags[0] == ACTIVE_FLAG && flags[1] == OBSOLETE_FLAG)
228 gd->env_valid = 1;
229 else if (flags[0] == OBSOLETE_FLAG && flags[1] == ACTIVE_FLAG)
230 gd->env_valid = 2;
231 else if (flags[0] == 0xFF && flags[1] == 0)
232 gd->env_valid = 2;
233 else if(flags[1] == 0xFF && flags[0] == 0)
234 gd->env_valid = 1;
235 else /* flags are equal - almost impossible */
236 gd->env_valid = 1;
237 }
238
239 if (gd->env_valid == 2)
240 gd->env_addr = off_env[1] + offsetof(env_t,data);
241 else if (gd->env_valid == 1)
242 gd->env_addr = off_env[0] + offsetof(env_t,data);
243
244 return (0);
245}
246#else
wdenk0bc4a1a2002-09-18 11:09:59 +0000247int env_init(void)
248{
wdenk0bc4a1a2002-09-18 11:09:59 +0000249 ulong crc, len, new;
250 unsigned off;
251 uchar buf[64];
252
253 eeprom_init (); /* prepare for EEPROM read/write */
254
255 /* read old CRC */
Heiko Schocher9bb0dd52010-01-07 08:55:40 +0100256 eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +0200257 CONFIG_ENV_OFFSET+offsetof(env_t,crc),
wdenk0bc4a1a2002-09-18 11:09:59 +0000258 (uchar *)&crc, sizeof(ulong));
259
260 new = 0;
261 len = ENV_SIZE;
262 off = offsetof(env_t,data);
263 while (len > 0) {
264 int n = (len > sizeof(buf)) ? sizeof(buf) : len;
265
Heiko Schocher9bb0dd52010-01-07 08:55:40 +0100266 eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
267 CONFIG_ENV_OFFSET + off, buf, n);
wdenk0bc4a1a2002-09-18 11:09:59 +0000268 new = crc32 (new, buf, n);
269 len -= n;
270 off += n;
271 }
272
273 if (crc == new) {
274 gd->env_addr = offsetof(env_t,data);
275 gd->env_valid = 1;
276 } else {
277 gd->env_addr = 0;
278 gd->env_valid = 0;
279 }
280
281 return (0);
282}
Heiko Schochere7193632010-01-07 08:55:44 +0100283#endif
284