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