Atmel DataFlashes by default operate with pages that are slightly bigger than normal binary sizes (i.e. many are 1056 byte pages rather than 1024 bytes). However, they also have a "power of 2" mode where the pages show up with the normal binary size. The latter mode is required in order to boot with a Blackfin processor, so many people wish to convert their DataFlashes on their development systems to this mode. This standalone application does just that. Signed-off-by: Mike Frysinger <vapier@gentoo.org>master
parent
cb95c7a935
commit
65f6f07b72
@ -0,0 +1,209 @@ |
||||
/*
|
||||
* atmel_df_pow2.c - convert Atmel Dataflashes to Power of 2 mode |
||||
* |
||||
* Copyright 2009 Analog Devices Inc. |
||||
* |
||||
* Licensed under the 2-clause BSD. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <exports.h> |
||||
|
||||
#define CMD_ID 0x9f |
||||
#define CMD_STAT 0xd7 |
||||
#define CMD_CFG 0x3d |
||||
|
||||
static int flash_cmd(struct spi_slave *slave, uchar cmd, uchar *buf, int len) |
||||
{ |
||||
buf[0] = cmd; |
||||
return spi_xfer(slave, 8 * len, buf, buf, SPI_XFER_BEGIN | SPI_XFER_END); |
||||
} |
||||
|
||||
static int flash_status(struct spi_slave *slave) |
||||
{ |
||||
uchar buf[2]; |
||||
if (flash_cmd(slave, CMD_STAT, buf, sizeof(buf))) |
||||
return -1; |
||||
return buf[1]; |
||||
} |
||||
|
||||
static int flash_set_pow2(struct spi_slave *slave) |
||||
{ |
||||
int ret; |
||||
uchar buf[4]; |
||||
|
||||
buf[1] = 0x2a; |
||||
buf[2] = 0x80; |
||||
buf[3] = 0xa6; |
||||
|
||||
ret = flash_cmd(slave, CMD_CFG, buf, sizeof(buf)); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
/* wait Tp, or 6 msec */ |
||||
udelay(6000); |
||||
|
||||
ret = flash_status(slave); |
||||
if (ret == -1) |
||||
return 1; |
||||
|
||||
return ret & 0x1 ? 0 : 1; |
||||
} |
||||
|
||||
static int flash_check(struct spi_slave *slave) |
||||
{ |
||||
int ret; |
||||
uchar buf[4]; |
||||
|
||||
ret = flash_cmd(slave, CMD_ID, buf, sizeof(buf)); |
||||
if (ret) |
||||
return ret; |
||||
|
||||
if (buf[1] != 0x1F) { |
||||
printf("atmel flash not found (id[0] = %#x)\n", buf[1]); |
||||
return 1; |
||||
} |
||||
|
||||
if ((buf[2] >> 5) != 0x1) { |
||||
printf("AT45 flash not found (id[0] = %#x)\n", buf[2]); |
||||
return 2; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static char *getline(void) |
||||
{ |
||||
static char buffer[100]; |
||||
char c; |
||||
size_t i; |
||||
|
||||
i = 0; |
||||
while (1) { |
||||
buffer[i] = '\0'; |
||||
|
||||
c = getc(); |
||||
|
||||
switch (c) { |
||||
case '\r': /* Enter/Return key */ |
||||
case '\n': |
||||
puts("\n"); |
||||
return buffer; |
||||
|
||||
case 0x03: /* ^C - break */ |
||||
return NULL; |
||||
|
||||
case 0x5F: |
||||
case 0x08: /* ^H - backspace */ |
||||
case 0x7F: /* DEL - backspace */ |
||||
if (i) { |
||||
puts("\b \b"); |
||||
i--; |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
/* Ignore control characters */ |
||||
if (c < 0x20) |
||||
break; |
||||
/* Queue up all other characters */ |
||||
buffer[i++] = c; |
||||
printf("%c", c); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
int atmel_df_pow2(int argc, char *argv[]) |
||||
{ |
||||
/* Print the ABI version */ |
||||
app_startup(argv); |
||||
if (XF_VERSION != get_version()) { |
||||
printf("Expects ABI version %d\n", XF_VERSION); |
||||
printf("Actual U-Boot ABI version %lu\n", get_version()); |
||||
printf("Can't run\n\n"); |
||||
return 1; |
||||
} |
||||
|
||||
spi_init(); |
||||
|
||||
while (1) { |
||||
struct spi_slave *slave; |
||||
char *line, *p; |
||||
int bus, cs, status; |
||||
|
||||
puts("\nenter the [BUS:]CS of the SPI flash: "); |
||||
line = getline(); |
||||
|
||||
/* CTRL+C */ |
||||
if (!line) |
||||
return 0; |
||||
if (line[0] == '\0') |
||||
continue; |
||||
|
||||
bus = cs = simple_strtoul(line, &p, 10); |
||||
if (*p) { |
||||
if (*p == ':') { |
||||
++p; |
||||
cs = simple_strtoul(p, &p, 10); |
||||
} |
||||
if (*p) { |
||||
puts("invalid format, please try again\n"); |
||||
continue; |
||||
} |
||||
} else |
||||
bus = 0; |
||||
|
||||
printf("\ngoing to work with dataflash at %i:%i\n", bus, cs); |
||||
|
||||
/* use a low speed -- it'll work with all devices, and
|
||||
* speed here doesn't really matter. |
||||
*/ |
||||
slave = spi_setup_slave(bus, cs, 1000, SPI_MODE_3); |
||||
if (!slave) { |
||||
puts("unable to setup slave\n"); |
||||
continue; |
||||
} |
||||
|
||||
if (spi_claim_bus(slave)) { |
||||
spi_free_slave(slave); |
||||
continue; |
||||
} |
||||
|
||||
if (flash_check(slave)) { |
||||
puts("no flash found\n"); |
||||
goto done; |
||||
} |
||||
|
||||
status = flash_status(slave); |
||||
if (status == -1) { |
||||
puts("unable to read status register\n"); |
||||
goto done; |
||||
} |
||||
if (status & 0x1) { |
||||
puts("flash is already in power-of-2 mode!\n"); |
||||
goto done; |
||||
} |
||||
|
||||
puts("are you sure you wish to set power-of-2 mode?\n"); |
||||
puts("this operation is permanent and irreversible\n"); |
||||
printf("enter YES to continue: "); |
||||
line = getline(); |
||||
if (!line || strcmp(line, "YES")) |
||||
goto done; |
||||
|
||||
if (flash_set_pow2(slave)) { |
||||
puts("setting pow2 mode failed\n"); |
||||
goto done; |
||||
} |
||||
|
||||
puts( |
||||
"Configuration should be updated now. You will have to\n" |
||||
"power cycle the part in order to finish the conversion.\n" |
||||
); |
||||
|
||||
done: |
||||
spi_release_bus(slave); |
||||
spi_free_slave(slave); |
||||
} |
||||
} |
Loading…
Reference in new issue