Merge branch 'sf' of git://git.denx.de/u-boot-blackfin

* 'sf' of git://git.denx.de/u-boot-blackfin:
  sf: eon: add support for EN25Q32B parts
  cmd_sf: add "update" subcommand to do smart SPI flash update
This commit is contained in:
Wolfgang Denk 2011-10-01 21:44:07 +02:00
commit 1e02c20ac9
2 changed files with 91 additions and 3 deletions

View file

@ -6,6 +6,7 @@
*/
#include <common.h>
#include <malloc.h>
#include <spi_flash.h>
#include <asm/io.h>
@ -109,6 +110,80 @@ static int do_spi_flash_probe(int argc, char * const argv[])
return 0;
}
/**
* Write a block of data to SPI flash, first checking if it is different from
* what is already there.
*
* If the data being written is the same, then *skipped is incremented by len.
*
* @param flash flash context pointer
* @param offset flash offset to write
* @param len number of bytes to write
* @param buf buffer to write from
* @param cmp_buf read buffer to use to compare data
* @param skipped Count of skipped data (incremented by this function)
* @return NULL if OK, else a string containing the stage which failed
*/
static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset,
size_t len, const char *buf, char *cmp_buf, size_t *skipped)
{
debug("offset=%#x, sector_size=%#x, len=%#x\n",
offset, flash->sector_size, len);
if (spi_flash_read(flash, offset, len, cmp_buf))
return "read";
if (memcmp(cmp_buf, buf, len) == 0) {
debug("Skip region %x size %x: no change\n",
offset, len);
*skipped += len;
return NULL;
}
if (spi_flash_erase(flash, offset, len))
return "erase";
if (spi_flash_write(flash, offset, len, buf))
return "write";
return NULL;
}
/**
* Update an area of SPI flash by erasing and writing any blocks which need
* to change. Existing blocks with the correct data are left unchanged.
*
* @param flash flash context pointer
* @param offset flash offset to write
* @param len number of bytes to write
* @param buf buffer to write from
* @return 0 if ok, 1 on error
*/
static int spi_flash_update(struct spi_flash *flash, u32 offset,
size_t len, const char *buf)
{
const char *err_oper = NULL;
char *cmp_buf;
const char *end = buf + len;
size_t todo; /* number of bytes to do in this pass */
size_t skipped; /* statistics */
cmp_buf = malloc(flash->sector_size);
if (cmp_buf) {
for (skipped = 0; buf < end && !err_oper;
buf += todo, offset += todo) {
todo = min(end - buf, flash->sector_size);
err_oper = spi_flash_update_block(flash, offset, todo,
buf, cmp_buf, &skipped);
}
} else {
err_oper = "malloc";
}
free(cmp_buf);
if (err_oper) {
printf("SPI flash failed in %s step\n", err_oper);
return 1;
}
printf("%zu bytes written, %zu bytes skipped\n", len - skipped,
skipped);
return 0;
}
static int do_spi_flash_read_write(int argc, char * const argv[])
{
unsigned long addr;
@ -137,7 +212,9 @@ static int do_spi_flash_read_write(int argc, char * const argv[])
return 1;
}
if (strcmp(argv[0], "read") == 0)
if (strcmp(argv[0], "update") == 0)
ret = spi_flash_update(flash, offset, len, buf);
else if (strcmp(argv[0], "read") == 0)
ret = spi_flash_read(flash, offset, len, buf);
else
ret = spi_flash_write(flash, offset, len, buf);
@ -203,7 +280,8 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[
return 1;
}
if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0)
if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0 ||
strcmp(cmd, "update") == 0)
ret = do_spi_flash_read_write(argc, argv);
else if (strcmp(cmd, "erase") == 0)
ret = do_spi_flash_erase(argc, argv);
@ -228,5 +306,7 @@ U_BOOT_CMD(
"sf write addr offset len - write `len' bytes from memory\n"
" at `addr' to flash at `offset'\n"
"sf erase offset [+]len - erase `len' bytes from `offset'\n"
" `+len' round up `len' to block size"
" `+len' round up `len' to block size\n"
"sf update addr offset len - erase and write `len' bytes from memory\n"
" at `addr' to flash at `offset'"
);

View file

@ -33,6 +33,14 @@ struct eon_spi_flash_params {
};
static const struct eon_spi_flash_params eon_spi_flash_table[] = {
{
.idcode1 = 0x16,
.page_size = 256,
.pages_per_sector = 16,
.sectors_per_block = 16,
.nr_sectors = 1024,
.name = "EN25Q32B",
},
{
.idcode1 = 0x18,
.page_size = 256,