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