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