edb93xx: Fix SDRAM initialization
[platform/kernel/u-boot.git] / common / env_eeprom.c
1 /*
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>
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
35 #ifdef CONFIG_ENV_OFFSET_REDUND
36 #define ACTIVE_FLAG   1
37 #define OBSOLETE_FLAG 0
38 #endif
39
40 DECLARE_GLOBAL_DATA_PTR;
41
42 env_t *env_ptr = NULL;
43
44 char * env_name_spec = "EEPROM";
45 int env_eeprom_bus = -1;
46
47 static 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
82 static 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 }
97
98 uchar env_get_char_spec (int index)
99 {
100         uchar c;
101         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
107
108         eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
109                      off + index + offsetof(env_t,data),
110                      &c, 1);
111
112         return (c);
113 }
114
115 void env_relocate_spec (void)
116 {
117         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
122         eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
123                      off,
124                      (uchar*)env_ptr,
125                      CONFIG_ENV_SIZE);
126 }
127
128 int saveenv(void)
129 {
130         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,
145                              (uchar *)env_ptr,
146                              CONFIG_ENV_SIZE);
147
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;
163 }
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  */
171
172 #ifdef CONFIG_ENV_OFFSET_REDUND
173 int 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
247 int env_init(void)
248 {
249         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 */
256         eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
257                      CONFIG_ENV_OFFSET+offsetof(env_t,crc),
258                      (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
266                 eeprom_bus_read (CONFIG_SYS_DEF_EEPROM_ADDR,
267                                 CONFIG_ENV_OFFSET + off, buf, n);
268                 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 }
283 #endif
284