blob: 5531293e05697c8a6d29e45826641a10830f1bc9 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Haavard Skinnemoen8c664972008-05-16 11:10:35 +02002/*
Wolfgang Denkea882ba2010-06-20 23:33:59 +02003 * (C) Copyright 2000-2010
Haavard Skinnemoen8c664972008-05-16 11:10:35 +02004 * 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
Haavard Skinnemoen8c664972008-05-16 11:10:35 +020010 */
11#include <common.h>
Simon Glass9d922452017-05-17 17:18:03 -060012#include <dm.h>
Simon Glass0ac7d722019-08-01 09:47:00 -060013#include <env.h>
Haavard Skinnemoen8c664972008-05-16 11:10:35 +020014#include <environment.h>
Mike Frysinger5b3375a2008-12-11 06:23:37 -050015#include <malloc.h>
Simon Glass843c9e82014-10-13 23:41:55 -060016#include <spi.h>
Haavard Skinnemoen8c664972008-05-16 11:10:35 +020017#include <spi_flash.h>
Wolfgang Denkea882ba2010-06-20 23:33:59 +020018#include <search.h>
19#include <errno.h>
Gong Qianyu19c31282016-01-26 15:06:42 +080020#include <dm/device-internal.h>
Haavard Skinnemoen8c664972008-05-16 11:10:35 +020021
Simon Glass4415f1d2017-08-03 12:21:58 -060022#ifndef CONFIG_SPL_BUILD
23#define CMD_SAVEENV
Ashish Kumarb500c922017-12-14 17:37:08 +053024#define INITENV
Simon Glass4415f1d2017-08-03 12:21:58 -060025#endif
26
Wolfgang Wegner7319bca2010-04-23 17:22:55 +020027#ifdef CONFIG_ENV_OFFSET_REDUND
Simon Glass4415f1d2017-08-03 12:21:58 -060028#ifdef CMD_SAVEENV
Igor Grinbergeb58a7f2011-11-07 01:14:08 +000029static ulong env_offset = CONFIG_ENV_OFFSET;
30static ulong env_new_offset = CONFIG_ENV_OFFSET_REDUND;
Simon Glass4415f1d2017-08-03 12:21:58 -060031#endif
Wolfgang Wegner7319bca2010-04-23 17:22:55 +020032
Igor Grinbergeb58a7f2011-11-07 01:14:08 +000033#define ACTIVE_FLAG 1
34#define OBSOLETE_FLAG 0
Stefano Babica3110f02010-10-27 11:06:20 +020035#endif /* CONFIG_ENV_OFFSET_REDUND */
Wolfgang Wegner7319bca2010-04-23 17:22:55 +020036
Haavard Skinnemoen8c664972008-05-16 11:10:35 +020037DECLARE_GLOBAL_DATA_PTR;
38
Haavard Skinnemoen8c664972008-05-16 11:10:35 +020039static struct spi_flash *env_flash;
40
Andreas Fenkartafa81a72017-04-08 11:59:31 +020041static int setup_flash_device(void)
Wolfgang Wegner7319bca2010-04-23 17:22:55 +020042{
Gong Qianyu19c31282016-01-26 15:06:42 +080043#ifdef CONFIG_DM_SPI_FLASH
44 struct udevice *new;
Andreas Fenkartafa81a72017-04-08 11:59:31 +020045 int ret;
Gong Qianyu19c31282016-01-26 15:06:42 +080046
Vignesh R96907c02016-07-06 10:04:28 +053047 /* speed and mode will be read from DT */
Gong Qianyu19c31282016-01-26 15:06:42 +080048 ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
Konstantin Porotchkin25a17652018-08-29 16:34:52 +030049 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE,
50 &new);
Gong Qianyu19c31282016-01-26 15:06:42 +080051 if (ret) {
Simon Glass0ac7d722019-08-01 09:47:00 -060052 env_set_default("spi_flash_probe_bus_cs() failed", 0);
Simon Glassc5951992017-08-03 12:22:17 -060053 return ret;
Gong Qianyu19c31282016-01-26 15:06:42 +080054 }
55
56 env_flash = dev_get_uclass_priv(new);
57#else
Wolfgang Wegner7319bca2010-04-23 17:22:55 +020058
59 if (!env_flash) {
Stefano Babica3110f02010-10-27 11:06:20 +020060 env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS,
61 CONFIG_ENV_SPI_CS,
62 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
63 if (!env_flash) {
Simon Glass0ac7d722019-08-01 09:47:00 -060064 env_set_default("spi_flash_probe() failed", 0);
Simon Glassc5951992017-08-03 12:22:17 -060065 return -EIO;
Stefano Babica3110f02010-10-27 11:06:20 +020066 }
Wolfgang Wegner7319bca2010-04-23 17:22:55 +020067 }
Gong Qianyu19c31282016-01-26 15:06:42 +080068#endif
Andreas Fenkartafa81a72017-04-08 11:59:31 +020069 return 0;
70}
71
72#if defined(CONFIG_ENV_OFFSET_REDUND)
Simon Glass4415f1d2017-08-03 12:21:58 -060073#ifdef CMD_SAVEENV
Simon Glasse5bce242017-08-03 12:22:01 -060074static int env_sf_save(void)
Andreas Fenkartafa81a72017-04-08 11:59:31 +020075{
76 env_t env_new;
77 char *saved_buffer = NULL, flag = OBSOLETE_FLAG;
Andreas Fenkart0b2e5bb2017-04-08 11:59:34 +020078 u32 saved_size, saved_offset, sector;
Andreas Fenkartafa81a72017-04-08 11:59:31 +020079 int ret;
80
81 ret = setup_flash_device();
82 if (ret)
83 return ret;
Wolfgang Wegner7319bca2010-04-23 17:22:55 +020084
Marek Vasut7ce15262014-03-05 19:59:50 +010085 ret = env_export(&env_new);
86 if (ret)
Simon Glassc5951992017-08-03 12:22:17 -060087 return -EIO;
Tom Rinicd0f4fa2013-04-05 14:55:21 -040088 env_new.flags = ACTIVE_FLAG;
Wolfgang Denkea882ba2010-06-20 23:33:59 +020089
Simon Glass203e94f2017-08-03 12:21:56 -060090 if (gd->env_valid == ENV_VALID) {
Stefano Babica3110f02010-10-27 11:06:20 +020091 env_new_offset = CONFIG_ENV_OFFSET_REDUND;
92 env_offset = CONFIG_ENV_OFFSET;
93 } else {
94 env_new_offset = CONFIG_ENV_OFFSET;
95 env_offset = CONFIG_ENV_OFFSET_REDUND;
96 }
97
Wolfgang Wegner7319bca2010-04-23 17:22:55 +020098 /* Is the sector larger than the env (i.e. embedded) */
99 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
100 saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
101 saved_offset = env_new_offset + CONFIG_ENV_SIZE;
Ravi Babu7dd01742015-08-17 13:29:49 +0530102 saved_buffer = memalign(ARCH_DMA_MINALIGN, saved_size);
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200103 if (!saved_buffer) {
Simon Glassc5951992017-08-03 12:22:17 -0600104 ret = -ENOMEM;
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200105 goto done;
106 }
Heiko Schocher9ba5e5b2019-03-13 12:15:45 +0100107 ret = spi_flash_read(env_flash, saved_offset,
108 saved_size, saved_buffer);
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200109 if (ret)
110 goto done;
111 }
112
Andreas Fenkart0b2e5bb2017-04-08 11:59:34 +0200113 sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, CONFIG_ENV_SECT_SIZE);
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200114
115 puts("Erasing SPI flash...");
116 ret = spi_flash_erase(env_flash, env_new_offset,
117 sector * CONFIG_ENV_SECT_SIZE);
118 if (ret)
119 goto done;
120
121 puts("Writing to SPI flash...");
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200122
Stefano Babica3110f02010-10-27 11:06:20 +0200123 ret = spi_flash_write(env_flash, env_new_offset,
Tom Rinicd0f4fa2013-04-05 14:55:21 -0400124 CONFIG_ENV_SIZE, &env_new);
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200125 if (ret)
126 goto done;
127
128 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
129 ret = spi_flash_write(env_flash, saved_offset,
130 saved_size, saved_buffer);
131 if (ret)
132 goto done;
133 }
134
Igor Grinbergeb58a7f2011-11-07 01:14:08 +0000135 ret = spi_flash_write(env_flash, env_offset + offsetof(env_t, flags),
Tom Rinicd0f4fa2013-04-05 14:55:21 -0400136 sizeof(env_new.flags), &flag);
Stefano Babica3110f02010-10-27 11:06:20 +0200137 if (ret)
138 goto done;
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200139
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200140 puts("done\n");
141
Simon Glass203e94f2017-08-03 12:21:56 -0600142 gd->env_valid = gd->env_valid == ENV_REDUND ? ENV_VALID : ENV_REDUND;
Stefano Babica3110f02010-10-27 11:06:20 +0200143
thomas.langer@lantiq.com2dc55d92011-03-29 02:35:14 +0000144 printf("Valid environment: %d\n", (int)gd->env_valid);
Stefano Babica3110f02010-10-27 11:06:20 +0200145
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200146 done:
147 if (saved_buffer)
148 free(saved_buffer);
Igor Grinbergeb58a7f2011-11-07 01:14:08 +0000149
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200150 return ret;
151}
Simon Glass4415f1d2017-08-03 12:21:58 -0600152#endif /* CMD_SAVEENV */
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200153
Simon Glassc5951992017-08-03 12:22:17 -0600154static int env_sf_load(void)
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200155{
156 int ret;
Simon Goldschmidt80719932018-01-31 14:47:13 +0100157 int read1_fail, read2_fail;
158 env_t *tmp_env1, *tmp_env2;
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200159
Ravi Babu7dd01742015-08-17 13:29:49 +0530160 tmp_env1 = (env_t *)memalign(ARCH_DMA_MINALIGN,
161 CONFIG_ENV_SIZE);
162 tmp_env2 = (env_t *)memalign(ARCH_DMA_MINALIGN,
163 CONFIG_ENV_SIZE);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200164 if (!tmp_env1 || !tmp_env2) {
Simon Glass0ac7d722019-08-01 09:47:00 -0600165 env_set_default("malloc() failed", 0);
Simon Glassc5951992017-08-03 12:22:17 -0600166 ret = -EIO;
thomas.langer@lantiq.com2dc55d92011-03-29 02:35:14 +0000167 goto out;
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200168 }
169
Andreas Fenkart8fee8842017-04-08 11:59:32 +0200170 ret = setup_flash_device();
171 if (ret)
thomas.langer@lantiq.com2dc55d92011-03-29 02:35:14 +0000172 goto out;
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200173
Heiko Schocher9ba5e5b2019-03-13 12:15:45 +0100174 read1_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET,
175 CONFIG_ENV_SIZE, tmp_env1);
176 read2_fail = spi_flash_read(env_flash, CONFIG_ENV_OFFSET_REDUND,
177 CONFIG_ENV_SIZE, tmp_env2);
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200178
Simon Goldschmidt80719932018-01-31 14:47:13 +0100179 ret = env_import_redund((char *)tmp_env1, read1_fail, (char *)tmp_env2,
180 read2_fail);
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200181
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200182 spi_flash_free(env_flash);
183 env_flash = NULL;
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200184out:
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200185 free(tmp_env1);
186 free(tmp_env2);
Simon Glassc5951992017-08-03 12:22:17 -0600187
188 return ret;
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200189}
190#else
Simon Glass4415f1d2017-08-03 12:21:58 -0600191#ifdef CMD_SAVEENV
Simon Glasse5bce242017-08-03 12:22:01 -0600192static int env_sf_save(void)
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200193{
Andreas Fenkart0b2e5bb2017-04-08 11:59:34 +0200194 u32 saved_size, saved_offset, sector;
Marek Vasut7ce15262014-03-05 19:59:50 +0100195 char *saved_buffer = NULL;
Igor Grinbergeb58a7f2011-11-07 01:14:08 +0000196 int ret = 1;
Tom Rinicd0f4fa2013-04-05 14:55:21 -0400197 env_t env_new;
Gong Qianyu19c31282016-01-26 15:06:42 +0800198
Andreas Fenkartafa81a72017-04-08 11:59:31 +0200199 ret = setup_flash_device();
200 if (ret)
201 return ret;
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200202
Mike Frysinger5b3375a2008-12-11 06:23:37 -0500203 /* Is the sector larger than the env (i.e. embedded) */
204 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
205 saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
206 saved_offset = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
207 saved_buffer = malloc(saved_size);
Igor Grinbergeb58a7f2011-11-07 01:14:08 +0000208 if (!saved_buffer)
Mike Frysinger5b3375a2008-12-11 06:23:37 -0500209 goto done;
Igor Grinbergeb58a7f2011-11-07 01:14:08 +0000210
Heiko Schocher9ba5e5b2019-03-13 12:15:45 +0100211 ret = spi_flash_read(env_flash, saved_offset,
212 saved_size, saved_buffer);
Mike Frysinger5b3375a2008-12-11 06:23:37 -0500213 if (ret)
214 goto done;
215 }
216
Marek Vasut7ce15262014-03-05 19:59:50 +0100217 ret = env_export(&env_new);
218 if (ret)
Stefano Babica3110f02010-10-27 11:06:20 +0200219 goto done;
Stefano Babica3110f02010-10-27 11:06:20 +0200220
Andreas Fenkart0b2e5bb2017-04-08 11:59:34 +0200221 sector = DIV_ROUND_UP(CONFIG_ENV_SIZE, CONFIG_ENV_SECT_SIZE);
222
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200223 puts("Erasing SPI flash...");
Stefano Babica3110f02010-10-27 11:06:20 +0200224 ret = spi_flash_erase(env_flash, CONFIG_ENV_OFFSET,
225 sector * CONFIG_ENV_SECT_SIZE);
Mike Frysinger5b3375a2008-12-11 06:23:37 -0500226 if (ret)
227 goto done;
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200228
229 puts("Writing to SPI flash...");
Stefano Babica3110f02010-10-27 11:06:20 +0200230 ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET,
Tom Rinicd0f4fa2013-04-05 14:55:21 -0400231 CONFIG_ENV_SIZE, &env_new);
Mike Frysinger5b3375a2008-12-11 06:23:37 -0500232 if (ret)
233 goto done;
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200234
Mike Frysinger5b3375a2008-12-11 06:23:37 -0500235 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
Stefano Babica3110f02010-10-27 11:06:20 +0200236 ret = spi_flash_write(env_flash, saved_offset,
237 saved_size, saved_buffer);
Mike Frysinger5b3375a2008-12-11 06:23:37 -0500238 if (ret)
239 goto done;
240 }
241
242 ret = 0;
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200243 puts("done\n");
Mike Frysinger5b3375a2008-12-11 06:23:37 -0500244
245 done:
246 if (saved_buffer)
247 free(saved_buffer);
Igor Grinbergeb58a7f2011-11-07 01:14:08 +0000248
Mike Frysinger5b3375a2008-12-11 06:23:37 -0500249 return ret;
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200250}
Simon Glass4415f1d2017-08-03 12:21:58 -0600251#endif /* CMD_SAVEENV */
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200252
Simon Glassc5951992017-08-03 12:22:17 -0600253static int env_sf_load(void)
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200254{
255 int ret;
Ying Zhang5a89fa92014-01-24 15:50:07 +0800256 char *buf = NULL;
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200257
Ravi Babu7dd01742015-08-17 13:29:49 +0530258 buf = (char *)memalign(ARCH_DMA_MINALIGN, CONFIG_ENV_SIZE);
Andreas Fenkartc041c602017-04-08 11:59:33 +0200259 if (!buf) {
Simon Glass0ac7d722019-08-01 09:47:00 -0600260 env_set_default("malloc() failed", 0);
Simon Glassc5951992017-08-03 12:22:17 -0600261 return -EIO;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200262 }
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200263
Andreas Fenkartc041c602017-04-08 11:59:33 +0200264 ret = setup_flash_device();
265 if (ret)
266 goto out;
267
Heiko Schocher9ba5e5b2019-03-13 12:15:45 +0100268 ret = spi_flash_read(env_flash,
269 CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf);
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200270 if (ret) {
Simon Glass0ac7d722019-08-01 09:47:00 -0600271 env_set_default("spi_flash_read() failed", 0);
Andreas Fenkartc041c602017-04-08 11:59:33 +0200272 goto err_read;
Wolfgang Denkea882ba2010-06-20 23:33:59 +0200273 }
274
275 ret = env_import(buf, 1);
Simon Goldschmidt42a18202018-01-31 14:47:10 +0100276 if (!ret)
Simon Glass203e94f2017-08-03 12:21:56 -0600277 gd->env_valid = ENV_VALID;
Andreas Fenkartc041c602017-04-08 11:59:33 +0200278
279err_read:
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200280 spi_flash_free(env_flash);
281 env_flash = NULL;
Andreas Fenkartc041c602017-04-08 11:59:33 +0200282out:
283 free(buf);
Simon Glassc5951992017-08-03 12:22:17 -0600284
285 return ret;
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200286}
Wolfgang Wegner7319bca2010-04-23 17:22:55 +0200287#endif
Haavard Skinnemoen8c664972008-05-16 11:10:35 +0200288
Rajesh Bhagat119c01c22018-11-05 18:01:15 +0000289#ifdef CONFIG_ENV_ADDR
290__weak void *env_sf_get_env_addr(void)
291{
292 return (void *)CONFIG_ENV_ADDR;
293}
294#endif
295
Ashish Kumarb500c922017-12-14 17:37:08 +0530296#if defined(INITENV) && defined(CONFIG_ENV_ADDR)
297static int env_sf_init(void)
298{
Rajesh Bhagat119c01c22018-11-05 18:01:15 +0000299 env_t *env_ptr = (env_t *)env_sf_get_env_addr();
Ashish Kumarb500c922017-12-14 17:37:08 +0530300
301 if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
302 gd->env_addr = (ulong)&(env_ptr->data);
303 gd->env_valid = 1;
304 } else {
305 gd->env_addr = (ulong)&default_environment[0];
306 gd->env_valid = 1;
307 }
308
309 return 0;
310}
311#endif
312
Simon Glass4415f1d2017-08-03 12:21:58 -0600313U_BOOT_ENV_LOCATION(sf) = {
314 .location = ENVL_SPI_FLASH,
Simon Glassac358be2017-08-03 12:22:03 -0600315 ENV_NAME("SPI Flash")
Simon Glasse5bce242017-08-03 12:22:01 -0600316 .load = env_sf_load,
Simon Glass4415f1d2017-08-03 12:21:58 -0600317#ifdef CMD_SAVEENV
Simon Glasse5bce242017-08-03 12:22:01 -0600318 .save = env_save_ptr(env_sf_save),
Simon Glass4415f1d2017-08-03 12:21:58 -0600319#endif
Ashish Kumarb500c922017-12-14 17:37:08 +0530320#if defined(INITENV) && defined(CONFIG_ENV_ADDR)
321 .init = env_sf_init,
322#endif
Simon Glass4415f1d2017-08-03 12:21:58 -0600323};