xref: /openbmc/u-boot/env/sf.c (revision 2d59ec84829ff339041667c857afe94d5160f4b4)
1  // SPDX-License-Identifier: GPL-2.0+
2  /*
3   * (C) Copyright 2000-2010
4   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5   *
6   * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
7   * Andreas Heppel <aheppel@sysgo.de>
8   *
9   * (C) Copyright 2008 Atmel Corporation
10   */
11  #include <common.h>
12  #include <dm.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  #ifndef CONFIG_SPL_BUILD
35  #define CMD_SAVEENV
36  #define INITENV
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  				     CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE,
62  				     &new);
63  	if (ret) {
64  		set_default_env("spi_flash_probe_bus_cs() failed", 0);
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", 0);
77  			return -EIO;
78  		}
79  	}
80  #endif
81  	return 0;
82  }
83  
84  static int is_end(const char *addr, size_t size)
85  {
86  	/* The end of env variables is marked by '\0\0' */
87  	int i = 0;
88  
89  	for (i = 0; i < size - 1; ++i)
90  		if (addr[i] == 0x0 && addr[i + 1] == 0x0)
91  			return 1;
92  	return 0;
93  }
94  
95  static int spi_flash_read_env(struct spi_flash *flash, u32 offset, size_t len,
96  			      void *buf)
97  {
98  	u32 addr = 0;
99  	u32 page_size = flash->page_size;
100  
101  	memset(buf, 0x0, len);
102  	for (int i = 0; i < len / page_size; ++i) {
103  		int ret = spi_flash_read(flash, offset, page_size,
104  					 &((char *)buf)[addr]);
105  
106  		if (ret < 0)
107  			return ret;
108  
109  		if (is_end(&((char *)buf)[addr], page_size))
110  			return 0;
111  
112  		addr += page_size;
113  		offset += page_size;
114  	}
115  	return 0;
116  }
117  
118  #if defined(CONFIG_ENV_OFFSET_REDUND)
119  #ifdef CMD_SAVEENV
120  static int env_sf_save(void)
121  {
122  	env_t	env_new;
123  	char	*saved_buffer = NULL, flag = OBSOLETE_FLAG;
124  	u32	saved_size, saved_offset, sector;
125  	int	ret;
126  
127  	ret = setup_flash_device();
128  	if (ret)
129  		return ret;
130  
131  	ret = env_export(&env_new);
132  	if (ret)
133  		return -EIO;
134  	env_new.flags	= ACTIVE_FLAG;
135  
136  	if (gd->env_valid == ENV_VALID) {
137  		env_new_offset = CONFIG_ENV_OFFSET_REDUND;
138  		env_offset = CONFIG_ENV_OFFSET;
139  	} else {
140  		env_new_offset = CONFIG_ENV_OFFSET;
141  		env_offset = CONFIG_ENV_OFFSET_REDUND;
142  	}
143  
144  	/* Is the sector larger than the env (i.e. embedded) */
145  	if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
146  		saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
147  		saved_offset = env_new_offset + CONFIG_ENV_SIZE;
148  		saved_buffer = memalign(ARCH_DMA_MINALIGN, saved_size);
149  		if (!saved_buffer) {
150  			ret = -ENOMEM;
151  			goto done;
152  		}
153  		ret = spi_flash_read_env(env_flash, saved_offset,
154  					 saved_size, saved_buffer);
155  		if (ret)
156  			goto done;
157  	}
158  
159  	sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, CONFIG_ENV_SECT_SIZE);
160  
161  	puts("Erasing SPI flash...");
162  	ret = spi_flash_erase(env_flash, env_new_offset,
163  				sector * CONFIG_ENV_SECT_SIZE);
164  	if (ret)
165  		goto done;
166  
167  	puts("Writing to SPI flash...");
168  
169  	ret = spi_flash_write(env_flash, env_new_offset,
170  		CONFIG_ENV_SIZE, &env_new);
171  	if (ret)
172  		goto done;
173  
174  	if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
175  		ret = spi_flash_write(env_flash, saved_offset,
176  					saved_size, saved_buffer);
177  		if (ret)
178  			goto done;
179  	}
180  
181  	ret = spi_flash_write(env_flash, env_offset + offsetof(env_t, flags),
182  				sizeof(env_new.flags), &flag);
183  	if (ret)
184  		goto done;
185  
186  	puts("done\n");
187  
188  	gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
189  
190  	printf("Valid environment: %d\n", (int)gd->env_valid);
191  
192   done:
193  	if (saved_buffer)
194  		free(saved_buffer);
195  
196  	return ret;
197  }
198  #endif /* CMD_SAVEENV */
199  
200  static int env_sf_load(void)
201  {
202  	int ret;
203  	int read1_fail, read2_fail;
204  	env_t *tmp_env1, *tmp_env2;
205  
206  	tmp_env1 = (env_t *)memalign(ARCH_DMA_MINALIGN,
207  			CONFIG_ENV_SIZE);
208  	tmp_env2 = (env_t *)memalign(ARCH_DMA_MINALIGN,
209  			CONFIG_ENV_SIZE);
210  	if (!tmp_env1 || !tmp_env2) {
211  		set_default_env("malloc() failed", 0);
212  		ret = -EIO;
213  		goto out;
214  	}
215  
216  	ret = setup_flash_device();
217  	if (ret)
218  		goto out;
219  
220  	read1_fail = spi_flash_read_env(env_flash, CONFIG_ENV_OFFSET,
221  					CONFIG_ENV_SIZE, tmp_env1);
222  	read2_fail = spi_flash_read_env(env_flash, CONFIG_ENV_OFFSET_REDUND,
223  					CONFIG_ENV_SIZE, tmp_env2);
224  
225  	ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
226  				read2_fail);
227  
228  	spi_flash_free(env_flash);
229  	env_flash = NULL;
230  out:
231  	free(tmp_env1);
232  	free(tmp_env2);
233  
234  	return ret;
235  }
236  #else
237  #ifdef CMD_SAVEENV
238  static int env_sf_save(void)
239  {
240  	u32	saved_size, saved_offset, sector;
241  	char	*saved_buffer = NULL;
242  	int	ret = 1;
243  	env_t	env_new;
244  
245  	ret = setup_flash_device();
246  	if (ret)
247  		return ret;
248  
249  	/* Is the sector larger than the env (i.e. embedded) */
250  	if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
251  		saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
252  		saved_offset = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
253  		saved_buffer = malloc(saved_size);
254  		if (!saved_buffer)
255  			goto done;
256  
257  		ret = spi_flash_read_env(env_flash, saved_offset,
258  					 saved_size, saved_buffer);
259  		if (ret)
260  			goto done;
261  	}
262  
263  	ret = env_export(&env_new);
264  	if (ret)
265  		goto done;
266  
267  	sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, CONFIG_ENV_SECT_SIZE);
268  
269  	puts("Erasing SPI flash...");
270  	ret = spi_flash_erase(env_flash, CONFIG_ENV_OFFSET,
271  		sector * CONFIG_ENV_SECT_SIZE);
272  	if (ret)
273  		goto done;
274  
275  	puts("Writing to SPI flash...");
276  	ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET,
277  		CONFIG_ENV_SIZE, &env_new);
278  	if (ret)
279  		goto done;
280  
281  	if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
282  		ret = spi_flash_write(env_flash, saved_offset,
283  			saved_size, saved_buffer);
284  		if (ret)
285  			goto done;
286  	}
287  
288  	ret = 0;
289  	puts("done\n");
290  
291   done:
292  	if (saved_buffer)
293  		free(saved_buffer);
294  
295  	return ret;
296  }
297  #endif /* CMD_SAVEENV */
298  
299  static int env_sf_load(void)
300  {
301  	int ret;
302  	char *buf = NULL;
303  
304  	buf = (char *)memalign(ARCH_DMA_MINALIGN, CONFIG_ENV_SIZE);
305  	if (!buf) {
306  		set_default_env("malloc() failed", 0);
307  		return -EIO;
308  	}
309  
310  	ret = setup_flash_device();
311  	if (ret)
312  		goto out;
313  
314  	ret = spi_flash_read_env(env_flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE,
315  				 buf);
316  	if (ret) {
317  		set_default_env("spi_flash_read_env() failed", 0);
318  		goto err_read;
319  	}
320  
321  	ret = env_import(buf, 1);
322  	if (!ret)
323  		gd->env_valid = ENV_VALID;
324  
325  err_read:
326  	spi_flash_free(env_flash);
327  	env_flash = NULL;
328  out:
329  	free(buf);
330  
331  	return ret;
332  }
333  #endif
334  
335  #ifdef CONFIG_ENV_ADDR
336  __weak void *env_sf_get_env_addr(void)
337  {
338  	return (void *)CONFIG_ENV_ADDR;
339  }
340  #endif
341  
342  #if defined(INITENV) && defined(CONFIG_ENV_ADDR)
343  static int env_sf_init(void)
344  {
345  	env_t *env_ptr = (env_t *)env_sf_get_env_addr();
346  
347  	if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
348  		gd->env_addr	= (ulong)&(env_ptr->data);
349  		gd->env_valid	= 1;
350  	} else {
351  		gd->env_addr = (ulong)&default_environment[0];
352  		gd->env_valid = 1;
353  	}
354  
355  	return 0;
356  }
357  #endif
358  
359  U_BOOT_ENV_LOCATION(sf) = {
360  	.location	= ENVL_SPI_FLASH,
361  	ENV_NAME("SPI Flash")
362  	.load		= env_sf_load,
363  #ifdef CMD_SAVEENV
364  	.save		= env_save_ptr(env_sf_save),
365  #endif
366  #if defined(INITENV) && defined(CONFIG_ENV_ADDR)
367  	.init		= env_sf_init,
368  #endif
369  };
370