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