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