From 7319bcaf8ba1cddba2e56a722144eafc98868f77 Mon Sep 17 00:00:00 2001 From: Wolfgang Wegner Date: Fri, 23 Apr 2010 17:22:55 +0200 Subject: add redundant environment for env_sf.c This patch adds redundant environment for environment in SPI flash. I took env_flash.c as an example and slightly modified it. Apart from adapting things to SF, I also slightly changed the decision logic to use area 2 as a default in case the flags are wrong because not having a default path worried me. I did not add a section for CONFIG_ENV_IS_IN_SPI_FLASH in environment.h because I did not understand if this is desired and/or needed. So to use the feature, one has to set CONFIG_ENV_OFFSET_REDUND _and_ CONFIG_SYS_REDUNDAND_ENVIRONMENT. I checked it by powering off my board several times during flash erase or write, because I do not know if there are other stress test scenarios. Signed-off-by: Wolfgang Wegner Acked-by: Mike Frysinger --- common/env_sf.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) diff --git a/common/env_sf.c b/common/env_sf.c index 6575b6d..4391d61 100644 --- a/common/env_sf.c +++ b/common/env_sf.c @@ -43,6 +43,14 @@ # define CONFIG_ENV_SPI_MODE SPI_MODE_3 #endif +#ifdef CONFIG_ENV_OFFSET_REDUND +static ulong env_offset = CONFIG_ENV_OFFSET; +static ulong env_new_offset = CONFIG_ENV_OFFSET_REDUND; + +#define ACTIVE_FLAG 1 +#define OBSOLETE_FLAG 0 +#endif /* CONFIG_ENV_ADDR_REDUND */ + DECLARE_GLOBAL_DATA_PTR; /* references to names in env_common.c */ @@ -58,6 +66,229 @@ uchar env_get_char_spec(int index) return *((uchar *)(gd->env_addr + index)); } +#if defined(CONFIG_ENV_OFFSET_REDUND) +void swap_env(void) +{ + ulong tmp_offset = env_offset; + + env_offset = env_new_offset; + env_new_offset = tmp_offset; +} + +int saveenv(void) +{ + u32 saved_size, saved_offset; + char *saved_buffer = NULL; + u32 sector = 1; + int ret; + char flag = OBSOLETE_FLAG, new_flag = ACTIVE_FLAG; + + if (!env_flash) { + puts("Environment SPI flash not initialized\n"); + return 1; + } + + /* Is the sector larger than the env (i.e. embedded) */ + if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) { + saved_size = CONFIG_ENV_SECT_SIZE - CONFIG_ENV_SIZE; + saved_offset = env_new_offset + CONFIG_ENV_SIZE; + saved_buffer = malloc(saved_size); + if (!saved_buffer) { + ret = 1; + goto done; + } + ret = spi_flash_read(env_flash, saved_offset, + saved_size, saved_buffer); + if (ret) + goto done; + } + + if (CONFIG_ENV_SIZE > CONFIG_ENV_SECT_SIZE) { + sector = CONFIG_ENV_SIZE / CONFIG_ENV_SECT_SIZE; + if (CONFIG_ENV_SIZE % CONFIG_ENV_SECT_SIZE) + sector++; + } + + puts("Erasing SPI flash..."); + ret = spi_flash_erase(env_flash, env_new_offset, + sector * CONFIG_ENV_SECT_SIZE); + if (ret) + goto done; + + puts("Writing to SPI flash..."); + ret = spi_flash_write(env_flash, + env_new_offset + offsetof(env_t, data), + sizeof(env_ptr->data), env_ptr->data); + if (ret) + goto done; + + ret = spi_flash_write(env_flash, + env_new_offset + offsetof(env_t, crc), + sizeof(env_ptr->crc), &env_ptr->crc); + if (ret) + goto done; + + ret = spi_flash_write(env_flash, + env_offset + offsetof(env_t, flags), + sizeof(env_ptr->flags), &flag); + if (ret) + goto done; + + ret = spi_flash_write(env_flash, + env_new_offset + offsetof(env_t, flags), + sizeof(env_ptr->flags), &new_flag); + if (ret) + goto done; + + if (CONFIG_ENV_SECT_SIZE > CONFIG_ENV_SIZE) { + ret = spi_flash_write(env_flash, saved_offset, + saved_size, saved_buffer); + if (ret) + goto done; + } + + swap_env(); + + ret = 0; + puts("done\n"); + + done: + if (saved_buffer) + free(saved_buffer); + return ret; +} + +void env_relocate_spec(void) +{ + int ret; + int crc1_ok = 0, crc2_ok = 0; + env_t *tmp_env1 = NULL; + env_t *tmp_env2 = NULL; + uchar flag1, flag2; + /* current_env is set only in case both areas are valid! */ + int current_env = 0; + + tmp_env1 = (env_t *)malloc(CONFIG_ENV_SIZE); + if (!tmp_env1) { + puts("*** Warning: could not init environment," + " using defaults\n\n"); + goto out; + } + + tmp_env2 = (env_t *)malloc(CONFIG_ENV_SIZE); + if (!tmp_env2) { + puts("*** Warning: could not init environment," + " using defaults\n\n"); + goto out; + } + + env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, + CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE); + if (!env_flash) + goto err_probe; + + ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET, + CONFIG_ENV_SIZE, tmp_env1); + if (ret) + goto err_read; + + if (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc) + crc1_ok = 1; + flag1 = tmp_env1->flags; + + ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET_REDUND, + CONFIG_ENV_SIZE, tmp_env2); + if (!ret) { + if (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc) + crc2_ok = 1; + flag2 = tmp_env2->flags; + } + + if (!crc1_ok && !crc2_ok) + goto err_crc; + else if (crc1_ok && !crc2_ok) { + gd->env_valid = 1; + memcpy(env_ptr, tmp_env1, CONFIG_ENV_SIZE); + } else if (!crc1_ok && crc2_ok) { + gd->env_valid = 1; + memcpy(env_ptr, tmp_env2, CONFIG_ENV_SIZE); + swap_env(); + } else if (flag1 == ACTIVE_FLAG && flag2 == OBSOLETE_FLAG) { + gd->env_valid = 1; + memcpy(env_ptr, tmp_env1, CONFIG_ENV_SIZE); + } else if (flag1 == OBSOLETE_FLAG && flag2 == ACTIVE_FLAG) { + gd->env_valid = 1; + memcpy(env_ptr, tmp_env2, CONFIG_ENV_SIZE); + swap_env(); + } else if (flag1 == flag2) { + gd->env_valid = 2; + memcpy(env_ptr, tmp_env1, CONFIG_ENV_SIZE); + current_env = 1; + } else if (flag1 == 0xFF) { + gd->env_valid = 2; + memcpy(env_ptr, tmp_env1, CONFIG_ENV_SIZE); + current_env = 1; + } else { + /* + * this differs from code in env_flash.c, but I think a sane + * default path is desirable. + */ + gd->env_valid = 2; + memcpy(env_ptr, tmp_env2, CONFIG_ENV_SIZE); + swap_env(); + current_env = 2; + } + if (current_env == 1) { + if (flag2 != OBSOLETE_FLAG) { + flag2 = OBSOLETE_FLAG; + spi_flash_write(env_flash, + env_new_offset + offsetof(env_t, flags), + sizeof(env_ptr->flags), &flag2); + } + if (flag1 != ACTIVE_FLAG) { + flag1 = ACTIVE_FLAG; + spi_flash_write(env_flash, + env_offset + offsetof(env_t, flags), + sizeof(env_ptr->flags), &flag1); + } + } else if (current_env == 2) { + if (flag1 != OBSOLETE_FLAG) { + flag1 = OBSOLETE_FLAG; + spi_flash_write(env_flash, + env_new_offset + offsetof(env_t, flags), + sizeof(env_ptr->flags), &flag1); + } + if (flag2 != ACTIVE_FLAG) { + flag2 = ACTIVE_FLAG; + spi_flash_write(env_flash, + env_offset + offsetof(env_t, flags), + sizeof(env_ptr->flags), &flag2); + } + } + if (gd->env_valid == 2) { + puts("*** Warning - some problems detected " + "reading environment; recovered successfully\n\n"); + } + if (tmp_env1) + free(tmp_env1); + if (tmp_env2) + free(tmp_env2); + return; + +err_read: + spi_flash_free(env_flash); + env_flash = NULL; +err_probe: +err_crc: + puts("*** Warning - bad CRC, using default environment\n\n"); +out: + if (tmp_env1) + free(tmp_env1); + if (tmp_env2) + free(tmp_env2); + set_default_env(); +} +#else int saveenv(void) { u32 saved_size, saved_offset; @@ -144,6 +375,7 @@ err_crc: set_default_env(); } +#endif int env_init(void) { -- cgit v1.1 From 12c2e3bbbe873ca79817845077dd8e6630d71158 Mon Sep 17 00:00:00 2001 From: Thomas Chou Date: Fri, 30 Apr 2010 21:11:20 +0800 Subject: spi_flash: support old STMicro parts with RES Some old STMicro parts do not support JEDEC ID (0x9f). This patch uses RES (0xab) to get Electronic ID and translates it to JEDEC ID. Signed-off-by: Thomas Chou Acked-by: Mike Frysinger --- drivers/mtd/spi/spi_flash.c | 1 + drivers/mtd/spi/stmicro.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 612f819..dd0dbbf 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -147,6 +147,7 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, #endif #ifdef CONFIG_SPI_FLASH_STMICRO case 0x20: + case 0xff: /* Let the stmicro func handle non-JEDEC ids */ flash = spi_flash_probe_stmicro(spi, idcode); break; #endif diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index ae0d047..21e9b00 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -46,6 +46,7 @@ #define CMD_M25PXX_DP 0xb9 /* Deep Power-down */ #define CMD_M25PXX_RES 0xab /* Release from DP, and Read Signature */ +#define STM_ID_M25P10 0x11 #define STM_ID_M25P16 0x15 #define STM_ID_M25P20 0x12 #define STM_ID_M25P32 0x16 @@ -78,6 +79,13 @@ static inline struct stmicro_spi_flash *to_stmicro_spi_flash(struct spi_flash static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { { + .idcode1 = STM_ID_M25P10, + .page_size = 256, + .pages_per_sector = 128, + .nr_sectors = 4, + .name = "M25P10", + }, + { .idcode1 = STM_ID_M25P16, .page_size = 256, .pages_per_sector = 256, @@ -316,6 +324,19 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) struct stmicro_spi_flash *stm; unsigned int i; + if (idcode[0] == 0xff) { + i = spi_flash_cmd(spi, CMD_M25PXX_RES, + idcode, 4); + if (i) + return NULL; + if ((idcode[3] & 0xf0) == 0x10) { + idcode[0] = 0x20; + idcode[1] = 0x20; + idcode[2] = idcode[3] + 1; + } else + return NULL; + } + for (i = 0; i < ARRAY_SIZE(stmicro_spi_flash_table); i++) { params = &stmicro_spi_flash_table[i]; if (params->idcode1 == idcode[2]) { -- cgit v1.1 From b376bbb49f42ed8ea566ca1b3e440240204008ca Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 29 Apr 2010 00:35:12 -0400 Subject: sf: move useful messages from debug to printf At the moment, the default SPI flash subsystem is quite terse. Errors and successes both result in a generic message. So move the useful errors and useful successes to printf output by default. While we're here, also convert the messages to use print_size(). Signed-off-by: Mike Frysinger --- drivers/mtd/spi/atmel.c | 7 ++++--- drivers/mtd/spi/macronix.c | 5 +++-- drivers/mtd/spi/spansion.c | 5 +++-- drivers/mtd/spi/spi_flash.c | 4 ++-- drivers/mtd/spi/sst.c | 5 +++-- drivers/mtd/spi/stmicro.c | 5 +++-- drivers/mtd/spi/winbond.c | 7 ++++--- 7 files changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c index 8306c00..8d02169 100644 --- a/drivers/mtd/spi/atmel.c +++ b/drivers/mtd/spi/atmel.c @@ -467,7 +467,7 @@ out: struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode) { const struct atmel_spi_flash_params *params; - unsigned long page_size; + unsigned page_size; unsigned int family; struct atmel_spi_flash *asf; unsigned int i; @@ -540,8 +540,9 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode) * params->blocks_per_sector * params->nr_sectors; - debug("SF: Detected %s with page size %lu, total %u bytes\n", - params->name, page_size, asf->flash.size); + printf("SF: Detected %s with page size %u, total ", + params->name, page_size); + print_size(asf->flash.size, "\n"); return &asf->flash; diff --git a/drivers/mtd/spi/macronix.c b/drivers/mtd/spi/macronix.c index fe1310b..76d5284 100644 --- a/drivers/mtd/spi/macronix.c +++ b/drivers/mtd/spi/macronix.c @@ -330,8 +330,9 @@ struct spi_flash *spi_flash_probe_macronix(struct spi_slave *spi, u8 *idcode) mcx->flash.size = params->page_size * params->pages_per_sector * params->sectors_per_block * params->nr_blocks; - printf("SF: Detected %s with page size %u, total %u bytes\n", - params->name, params->page_size, mcx->flash.size); + printf("SF: Detected %s with page size %u, total ", + params->name, params->page_size); + print_size(mcx->flash.size, "\n"); return &mcx->flash; } diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index fdb7917..d6c1a5f 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -343,8 +343,9 @@ struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode) spsn->flash.size = params->page_size * params->pages_per_sector * params->nr_sectors; - debug("SF: Detected %s with page size %u, total %u bytes\n", - params->name, params->page_size, spsn->flash.size); + printf("SF: Detected %s with page size %u, total ", + params->name, params->page_size); + print_size(spsn->flash.size, "\n"); return &spsn->flash; } diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index dd0dbbf..ea875dc 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -106,7 +106,7 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, spi = spi_setup_slave(bus, cs, max_hz, spi_mode); if (!spi) { - debug("SF: Failed to set up slave\n"); + printf("SF: Failed to set up slave\n"); return NULL; } @@ -157,7 +157,7 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, break; #endif default: - debug("SF: Unsupported manufacturer %02X\n", idcode[0]); + printf("SF: Unsupported manufacturer %02X\n", idcode[0]); flash = NULL; break; } diff --git a/drivers/mtd/spi/sst.c b/drivers/mtd/spi/sst.c index 50e9299..2557891 100644 --- a/drivers/mtd/spi/sst.c +++ b/drivers/mtd/spi/sst.c @@ -364,8 +364,9 @@ spi_flash_probe_sst(struct spi_slave *spi, u8 *idcode) stm->flash.read = sst_read_fast; stm->flash.size = SST_SECTOR_SIZE * params->nr_sectors; - debug("SF: Detected %s with page size %u, total %u bytes\n", - params->name, SST_SECTOR_SIZE, stm->flash.size); + printf("SF: Detected %s with page size %u, total ", + params->name, SST_SECTOR_SIZE); + print_size(stm->flash.size, "\n"); /* Flash powers up read-only, so clear BP# bits */ sst_unlock(&stm->flash); diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index 21e9b00..3134027 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -365,8 +365,9 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) stm->flash.size = params->page_size * params->pages_per_sector * params->nr_sectors; - debug("SF: Detected %s with page size %u, total %u bytes\n", - params->name, params->page_size, stm->flash.size); + printf("SF: Detected %s with page size %u, total ", + params->name, params->page_size); + print_size(stm->flash.size, "\n"); return &stm->flash; } diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index b8da923..ff1df25 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -289,7 +289,7 @@ out: struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) { const struct winbond_spi_flash_params *params; - unsigned long page_size; + unsigned page_size; struct winbond_spi_flash *stm; unsigned int i; @@ -325,8 +325,9 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) * params->sectors_per_block * params->nr_blocks; - debug("SF: Detected %s with page size %u, total %u bytes\n", - params->name, page_size, stm->flash.size); + printf("SF: Detected %s with page size %u, total ", + params->name, page_size); + print_size(stm->flash.size, "\n"); return &stm->flash; } -- cgit v1.1