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