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