Merge branch 'master' of git://www.denx.de/git/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 = 1;
192         } else if (tmp_env1->flags == 0xFF) {
193                 gd->env_valid = 1;
194         } else if (tmp_env2->flags == 0xFF) {
195                 gd->env_valid = 2;
196         } else {
197                 /*
198                  * this differs from code in env_flash.c, but I think a sane
199                  * default path is desirable.
200                  */
201                 gd->env_valid = 1;
202         }
203
204         if (gd->env_valid == 1)
205                 ep = tmp_env1;
206         else
207                 ep = tmp_env2;
208
209         ret = env_import((char *)ep, 0);
210         if (!ret) {
211                 error("Cannot import environment: errno = %d\n", errno);
212                 set_default_env("env_import failed");
213         }
214
215 err_read:
216         spi_flash_free(env_flash);
217         env_flash = NULL;
218 out:
219         free(tmp_env1);
220         free(tmp_env2);
221 }
222 #else
223 int saveenv(void)
224 {
225         u32     saved_size, saved_offset, sector = 1;
226         char    *saved_buffer = NULL;
227         int     ret = 1;
228         env_t   env_new;
229
230         if (!env_flash) {
231                 env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
232                         CONFIG_ENV_SPI_CS,
233                         CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
234                 if (!env_flash) {
235                         set_default_env("!spi_flash_probe() failed");
236                         return 1;
237                 }
238         }
239
240         /* Is the sector larger than the env (i.e. embedded) */
241         if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
242                 saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
243                 saved_offset = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
244                 saved_buffer = malloc(saved_size);
245                 if (!saved_buffer)
246                         goto done;
247
248                 ret = spi_flash_read(env_flash, saved_offset,
249                         saved_size, saved_buffer);
250                 if (ret)
251                         goto done;
252         }
253
254         if (CONFIG_ENV_SIZE > CONFIG_ENV_SECT_SIZE) {
255                 sector = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE;
256                 if (CONFIG_ENV_SIZE % CONFIG_ENV_SECT_SIZE)
257                         sector++;
258         }
259
260         ret = env_export(&env_new);
261         if (ret)
262                 goto done;
263
264         puts("Erasing SPI flash...");
265         ret = spi_flash_erase(env_flash, CONFIG_ENV_OFFSET,
266                 sector * CONFIG_ENV_SECT_SIZE);
267         if (ret)
268                 goto done;
269
270         puts("Writing to SPI flash...");
271         ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET,
272                 CONFIG_ENV_SIZE, &env_new);
273         if (ret)
274                 goto done;
275
276         if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
277                 ret = spi_flash_write(env_flash, saved_offset,
278                         saved_size, saved_buffer);
279                 if (ret)
280                         goto done;
281         }
282
283         ret = 0;
284         puts("done\n");
285
286  done:
287         if (saved_buffer)
288                 free(saved_buffer);
289
290         return ret;
291 }
292
293 void env_relocate_spec(void)
294 {
295         int ret;
296         char *buf = NULL;
297
298         buf = (char *)malloc(CONFIG_ENV_SIZE);
299         env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
300                         CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
301         if (!env_flash) {
302                 set_default_env("!spi_flash_probe() failed");
303                 if (buf)
304                         free(buf);
305                 return;
306         }
307
308         ret = spi_flash_read(env_flash,
309                 CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf);
310         if (ret) {
311                 set_default_env("!spi_flash_read() failed");
312                 goto out;
313         }
314
315         ret = env_import(buf, 1);
316         if (ret)
317                 gd->env_valid = 1;
318 out:
319         spi_flash_free(env_flash);
320         if (buf)
321                 free(buf);
322         env_flash = NULL;
323 }
324 #endif
325
326 int env_init(void)
327 {
328         /* SPI flash isn't usable before relocation */
329         gd->env_addr = (ulong)&default_environment[0];
330         gd->env_valid = 1;
331
332         return 0;
333 }