2 * (C) Copyright 2000-2010
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
6 * Andreas Heppel <aheppel@sysgo.de>
8 * (C) Copyright 2008 Atmel Corporation
10 * See file CREDITS for list of people who contributed to this
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation; either version 2 of
16 * the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29 #include <environment.h>
31 #include <spi_flash.h>
35 #ifndef CONFIG_ENV_SPI_BUS
36 # define CONFIG_ENV_SPI_BUS 0
38 #ifndef CONFIG_ENV_SPI_CS
39 # define CONFIG_ENV_SPI_CS 0
41 #ifndef CONFIG_ENV_SPI_MAX_HZ
42 # define CONFIG_ENV_SPI_MAX_HZ 1000000
44 #ifndef CONFIG_ENV_SPI_MODE
45 # define CONFIG_ENV_SPI_MODE SPI_MODE_3
48 #ifdef CONFIG_ENV_OFFSET_REDUND
49 static ulong env_offset = CONFIG_ENV_OFFSET;
50 static ulong env_new_offset = CONFIG_ENV_OFFSET_REDUND;
53 #define OBSOLETE_FLAG 0
54 #endif /* CONFIG_ENV_ADDR_REDUND */
56 DECLARE_GLOBAL_DATA_PTR;
58 /* references to names in env_common.c */
59 extern uchar default_environment[];
61 char * env_name_spec = "SPI Flash";
64 static struct spi_flash *env_flash;
66 uchar env_get_char_spec(int index)
68 return *((uchar *)(gd->env_addr + index));
71 #if defined(CONFIG_ENV_OFFSET_REDUND)
74 ulong tmp_offset = env_offset;
76 env_offset = env_new_offset;
77 env_new_offset = tmp_offset;
85 u32 saved_size, saved_offset;
86 char *saved_buffer = NULL;
89 char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG;
92 puts("Environment SPI flash not initialized\n");
96 res = (char *)&env_new.data;
97 len = hexport('\0', &res, ENV_SIZE);
99 error("Cannot export environment: errno = %d\n", errno);
102 env_new.crc = crc32(0, env_new.data, ENV_SIZE);
103 env_new.flags = ACTIVE_FLAG;
105 /* Is the sector larger than the env (i.e. embedded) */
106 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
107 saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
108 saved_offset = env_new_offset + CONFIG_ENV_SIZE;
109 saved_buffer = malloc(saved_size);
114 ret = spi_flash_read(env_flash, saved_offset,
115 saved_size, saved_buffer);
120 if (CONFIG_ENV_SIZE > CONFIG_ENV_SECT_SIZE) {
121 sector = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE;
122 if (CONFIG_ENV_SIZE % CONFIG_ENV_SECT_SIZE)
126 puts("Erasing SPI flash...");
127 ret = spi_flash_erase(env_flash, env_new_offset,
128 sector * CONFIG_ENV_SECT_SIZE);
132 puts("Writing to SPI flash...");
133 ret = spi_flash_write(env_flash,
134 env_new_offset + offsetof(env_t, data),
135 sizeof(env_new.data), env_new.data);
139 ret = spi_flash_write(env_flash,
140 env_new_offset + offsetof(env_t, crc),
141 sizeof(env_new.crc), &env_new.crc);
145 ret = spi_flash_write(env_flash,
146 env_offset + offsetof(env_t, flags),
147 sizeof(env_new.flags), &flag);
151 ret = spi_flash_write(env_flash,
152 env_new_offset + offsetof(env_t, flags),
153 sizeof(env_new.flags), &new_flag);
157 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
158 ret = spi_flash_write(env_flash, saved_offset,
159 saved_size, saved_buffer);
175 void env_relocate_spec(void)
178 int crc1_ok = 0, crc2_ok = 0;
179 env_t *tmp_env1 = NULL;
180 env_t *tmp_env2 = NULL;
183 /* current_env is set only in case both areas are valid! */
186 tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE);
187 tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE);
189 if (!tmp_env1 || !tmp_env2) {
192 set_default_env("!malloc() failed");
196 env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
197 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
199 set_default_env("!spi_flash_probe() failed");
203 ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET,
204 CONFIG_ENV_SIZE, tmp_env1);
206 set_default_env("!spi_flash_read() failed");
210 if (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc)
212 flag1 = tmp_env1->flags;
214 ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET_REDUND,
215 CONFIG_ENV_SIZE, tmp_env2);
217 if (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc)
219 flag2 = tmp_env2->flags;
222 if (!crc1_ok && !crc2_ok)
224 else if (crc1_ok && !crc2_ok) {
227 } else if (!crc1_ok && crc2_ok) {
231 } else if (flag1 == ACTIVE_FLAG && flag2 == OBSOLETE_FLAG) {
234 } else if (flag1 == OBSOLETE_FLAG && flag2 == ACTIVE_FLAG) {
238 } else if (flag1 == flag2) {
242 } else if (flag1 == 0xFF) {
248 * this differs from code in env_flash.c, but I think a sane
249 * default path is desirable.
257 rc = env_import((char *)ep, 0);
259 error("Cannot import environment: errno = %d\n", errno);
263 if (current_env == 1) {
264 if (flag2 != OBSOLETE_FLAG) {
265 flag2 = OBSOLETE_FLAG;
266 spi_flash_write(env_flash,
267 env_new_offset + offsetof(env_t, flags),
268 sizeof(env_new.flags), &flag2);
270 if (flag1 != ACTIVE_FLAG) {
272 spi_flash_write(env_flash,
273 env_offset + offsetof(env_t, flags),
274 sizeof(env_new.flags), &flag1);
276 } else if (current_env == 2) {
277 if (flag1 != OBSOLETE_FLAG) {
278 flag1 = OBSOLETE_FLAG;
279 spi_flash_write(env_flash,
280 env_new_offset + offsetof(env_t, flags),
281 sizeof(env_new.flags), &flag1);
283 if (flag2 != ACTIVE_FLAG) {
285 spi_flash_write(env_flash,
286 env_offset + offsetof(env_t, flags),
287 sizeof(env_new.flags), &flag2);
290 if (gd->env_valid == 2) {
291 puts("*** Warning - some problems detected "
292 "reading environment; recovered successfully\n\n");
301 spi_flash_free(env_flash);
310 u32 saved_size, saved_offset;
311 char *saved_buffer = NULL;
316 puts("Environment SPI flash not initialized\n");
320 /* Is the sector larger than the env (i.e. embedded) */
321 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
322 saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE;
323 saved_offset = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
324 saved_buffer = malloc(saved_size);
329 ret = spi_flash_read(env_flash, saved_offset, saved_size, saved_buffer);
334 if (CONFIG_ENV_SIZE > CONFIG_ENV_SECT_SIZE) {
335 sector = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE;
336 if (CONFIG_ENV_SIZE % CONFIG_ENV_SECT_SIZE)
340 puts("Erasing SPI flash...");
341 ret = spi_flash_erase(env_flash, CONFIG_ENV_OFFSET, sector * CONFIG_ENV_SECT_SIZE);
345 puts("Writing to SPI flash...");
346 ret = spi_flash_write(env_flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, env_ptr);
350 if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) {
351 ret = spi_flash_write(env_flash, saved_offset, saved_size, saved_buffer);
365 void env_relocate_spec(void)
367 char buf[CONFIG_ENV_SIZE];
370 env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
371 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
373 set_default_env("!spi_flash_probe() failed");
377 ret = spi_flash_read(env_flash,
378 CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf);
380 set_default_env("!spi_flash_read() failed");
384 ret = env_import(buf, 1);
389 spi_flash_free(env_flash);
396 /* SPI flash isn't usable before relocation */
397 gd->env_addr = (ulong)&default_environment[0];