Newer
Older
/*
* Driver for NAND support, Rick Bronson
* borrowed heavily from:
* (c) 1999 Machine Vision Holdings, Inc.
* (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
*/
#include <common.h>
#include <command.h>
#include <malloc.h>
#include <asm/io.h>
#ifdef CONFIG_SHOW_BOOT_PROGRESS
# include <status_led.h>
# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
#else
# define SHOW_BOOT_PROGRESS(arg)
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ids.h>
#ifdef CONFIG_OMAP1510
void archflashwp(void *archdata, int wp);
#endif
#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
/*
* Definition of the out of band configuration structure
*/
struct nand_oob_config {
int ecc_pos[6]; /* position of ECC bytes inside oob */
int badblock_pos; /* position of bad block flag inside oob -1 = inactive */
int eccvalid_pos; /* position of ECC valid flag inside oob -1 = inactive */
} oob_config = { {0}, 0, 0};
/* ****************** WARNING *********************
* When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will
* erase (or at least attempt to erase) blocks that are marked
* bad. This can be very handy if you are _sure_ that the block
* is OK, say because you marked a good block bad to test bad
* block handling and you are done testing, or if you have
* accidentally marked blocks bad.
*
* Erasing factory marked bad blocks is a _bad_ idea. If the
* erase succeeds there is no reliable way to find them again,
* and attempting to program or erase bad blocks can affect
* the data in _other_ (good) blocks.
*/
#define ALLOW_ERASE_BAD_DEBUG 0
#define CONFIG_MTD_NAND_ECC /* enable ECC */
/* bits for nand_rw() `cmd'; or together as needed */
#define NANDRW_READ 0x01
#define NANDRW_WRITE 0x00
#define NANDRW_JFFS2 0x02
#define NANDRW_JFFS2_SKIP 0x04
/*
* Function Prototypes
*/
static void nand_print(struct nand_chip *nand);
static int nand_rw (struct nand_chip* nand, int cmd,
size_t start, size_t len,
size_t * retlen, u_char * buf);
static int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean);
static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len,
size_t * retlen, u_char *buf, u_char *ecc_code);
static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,
size_t * retlen, const u_char * buf, u_char * ecc_code);
static void nand_print_bad(struct nand_chip *nand);
static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,
size_t * retlen, u_char * buf);
static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,
size_t * retlen, const u_char * buf);
static int NanD_WaitReady(struct nand_chip *nand, int ale_wait);
#ifdef CONFIG_MTD_NAND_ECC
static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
#endif
struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE] = {{0}};
/* Current NAND Device */
static int curr_device = -1;
/* ------------------------------------------------------------------------- */
int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int rcode = 0;
switch (argc) {
case 0:
case 1:
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
case 2:
int i;
putc ('\n');
for (i=0; i<CFG_MAX_NAND_DEVICE; ++i) {
if(nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN)
continue; /* list only known devices */
printf ("Device %d: ", i);
nand_print(&nand_dev_desc[i]);
}
return 0;
} else if (strcmp(argv[1],"device") == 0) {
if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
puts ("\nno devices available\n");
return 1;
}
printf ("\nDevice %d: ", curr_device);
nand_print(&nand_dev_desc[curr_device]);
return 0;
} else if (strcmp(argv[1],"bad") == 0) {
if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
puts ("\nno devices available\n");
return 1;
}
printf ("\nDevice %d bad blocks:\n", curr_device);
nand_print_bad(&nand_dev_desc[curr_device]);
return 0;
}
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
case 3:
if (strcmp(argv[1],"device") == 0) {
int dev = (int)simple_strtoul(argv[2], NULL, 10);
printf ("\nDevice %d: ", dev);
if (dev >= CFG_MAX_NAND_DEVICE) {
puts ("unknown device\n");
return 1;
}
nand_print(&nand_dev_desc[dev]);
/*nand_print (dev);*/
if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) {
return 1;
}
curr_device = dev;
puts ("... is now current device\n");
return 0;
}
else if (strcmp(argv[1],"erase") == 0 && strcmp(argv[2], "clean") == 0) {
struct nand_chip* nand = &nand_dev_desc[curr_device];
ulong off = 0;
ulong size = nand->totlen;
int ret;
printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
curr_device, off, size);
ret = nand_erase (nand, off, size, 1);
printf("%s\n", ret ? "ERROR" : "OK");
return ret;
}
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
default:
/* at least 4 args */
if (strncmp(argv[1], "read", 4) == 0 ||
strncmp(argv[1], "write", 5) == 0) {
ulong addr = simple_strtoul(argv[2], NULL, 16);
ulong off = simple_strtoul(argv[3], NULL, 16);
ulong size = simple_strtoul(argv[4], NULL, 16);
int cmd = (strncmp(argv[1], "read", 4) == 0) ?
NANDRW_READ : NANDRW_WRITE;
char* cmdtail = strchr(argv[1], '.');
if (cmdtail && !strncmp(cmdtail, ".oob", 2)) {
/* read out-of-band data */
if (cmd & NANDRW_READ) {
ret = nand_read_oob(nand_dev_desc + curr_device,
off, size, &total,
(u_char*)addr);
}
else {
ret = nand_write_oob(nand_dev_desc + curr_device,
off, size, &total,
(u_char*)addr);
}
return ret;
}
else if (cmdtail && !strncmp(cmdtail, ".jffs2", 2))
cmd |= NANDRW_JFFS2; /* skip bad blocks */
else if (cmdtail && !strncmp(cmdtail, ".jffs2s", 2)) {
cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */
if (cmd & NANDRW_READ)
cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */
}
#ifdef SXNI855T
/* need ".e" same as ".j" for compatibility with older units */
else if (cmdtail && !strcmp(cmdtail, ".e"))
cmd |= NANDRW_JFFS2; /* skip bad blocks */
#endif
else if (cmdtail) {
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
}
printf ("\nNAND %s: device %d offset %ld, size %ld ... ",
(cmd & NANDRW_READ) ? "read" : "write",
curr_device, off, size);
ret = nand_rw(nand_dev_desc + curr_device, cmd, off, size,
&total, (u_char*)addr);
printf (" %d bytes %s: %s\n", total,
(cmd & NANDRW_READ) ? "read" : "written",
ret ? "ERROR" : "OK");
return ret;
} else if (strcmp(argv[1],"erase") == 0 &&
(argc == 4 || strcmp("clean", argv[2]) == 0)) {
int clean = argc == 5;
ulong off = simple_strtoul(argv[2 + clean], NULL, 16);
ulong size = simple_strtoul(argv[3 + clean], NULL, 16);
int ret;
printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
curr_device, off, size);
ret = nand_erase (nand_dev_desc + curr_device, off, size, clean);
printf("%s\n", ret ? "ERROR" : "OK");
return ret;
} else {
printf ("Usage:\n%s\n", cmdtp->usage);
rcode = 1;
}
return rcode;
}
}
U_BOOT_CMD(
nand, 5, 1, do_nand,
"nand - NAND sub-system\n",
"info - show available NAND devices\n"
"nand device [dev] - show or set current device\n"
"nand read[.jffs2[s]] addr off size\n"
"nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
" at offset `off' to/from memory address `addr'\n"
"nand erase [clean] [off size] - erase `size' bytes from\n"
" offset `off' (entire device if not specified)\n"
"nand bad - show bad blocks\n"
"nand read.oob addr off size - read out-of-band data\n"
"nand write.oob addr off size - read out-of-band data\n"
);
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
char *boot_device = NULL;
char *ep;
int dev;
ulong cnt;
ulong addr;
ulong offset = 0;
image_header_t *hdr;
int rcode = 0;
switch (argc) {
case 1:
addr = CFG_LOAD_ADDR;
boot_device = getenv ("bootdevice");
break;
case 2:
addr = simple_strtoul(argv[1], NULL, 16);
boot_device = getenv ("bootdevice");
break;
case 3:
addr = simple_strtoul(argv[1], NULL, 16);
boot_device = argv[2];
break;
case 4:
addr = simple_strtoul(argv[1], NULL, 16);
boot_device = argv[2];
offset = simple_strtoul(argv[3], NULL, 16);
break;
default:
printf ("Usage:\n%s\n", cmdtp->usage);
SHOW_BOOT_PROGRESS (-1);
return 1;
}
if (!boot_device) {
puts ("\n** No boot device **\n");
SHOW_BOOT_PROGRESS (-1);
return 1;
}
dev = simple_strtoul(boot_device, &ep, 16);
if ((dev >= CFG_MAX_NAND_DEVICE) ||
(nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) {
printf ("\n** Device %d not available\n", dev);
SHOW_BOOT_PROGRESS (-1);
return 1;
}
printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n",
dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR,
offset);
if (nand_rw (nand_dev_desc + dev, NANDRW_READ, offset,
SECTORSIZE, NULL, (u_char *)addr)) {
printf ("** Read error on %d\n", dev);
SHOW_BOOT_PROGRESS (-1);
return 1;
}
hdr = (image_header_t *)addr;
if (ntohl(hdr->ih_magic) == IH_MAGIC) {
print_image_hdr (hdr);
cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t));
cnt -= SECTORSIZE;
} else {
printf ("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic);
SHOW_BOOT_PROGRESS (-1);
return 1;
}
if (nand_rw (nand_dev_desc + dev, NANDRW_READ, offset + SECTORSIZE, cnt,
NULL, (u_char *)(addr+SECTORSIZE))) {
printf ("** Read error on %d\n", dev);
SHOW_BOOT_PROGRESS (-1);
return 1;
}
/* Loading ok, update default load address */
load_addr = addr;
/* Check if we should attempt an auto-start */
if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
char *local_args[2];
extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
local_args[0] = argv[0];
local_args[1] = NULL;
printf ("Automatic boot of image at addr 0x%08lx ...\n", addr);
do_bootm (cmdtp, 0, 1, local_args);
rcode = 1;
}
return rcode;
}
U_BOOT_CMD(
nboot, 4, 1, do_nandboot,
"nboot - boot from NAND device\n",
"loadAddr dev\n"
);
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
/* returns 0 if block containing pos is OK:
* valid erase block and
* not marked bad, or no bad mark position is specified
* returns 1 if marked bad or otherwise invalid
*/
int check_block(struct nand_chip* nand, unsigned long pos)
{
int retlen;
uint8_t oob_data;
int page0 = pos & (-nand->erasesize);
int page1 = page0 + nand->oobblock;
int badpos = oob_config.badblock_pos;
if (pos >= nand->totlen)
return 1;
if (badpos < 0)
return 0; /* no way to check, assume OK */
/* Note - bad block marker can be on first or second page */
if (nand_read_oob(nand, page0 + badpos, 1, &retlen, &oob_data) ||
oob_data != 0xff ||
nand_read_oob(nand, page1 + badpos, 1, &retlen, &oob_data) ||
oob_data != 0xff)
return 1;
return 0;
}
/* print bad blocks in NAND flash */
static void nand_print_bad(struct nand_chip* nand)
{
unsigned long pos;
for (pos = 0; pos < nand->totlen; pos += nand->erasesize) {
if (check_block(nand, pos))
printf(" 0x%8.8lx\n", pos);
}
puts("\n");
}
/* cmd: 0: NANDRW_WRITE write, fail on bad block
* 1: NANDRW_READ read, fail on bad block
* 2: NANDRW_WRITE | NANDRW_JFFS2 write, skip bad blocks
* 3: NANDRW_READ | NANDRW_JFFS2 read, data all 0xff for bad blocks
* 7: NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks
static int nand_rw (struct nand_chip* nand, int cmd,
size_t start, size_t len,
size_t * retlen, u_char * buf)
{
/* eblk (once set) is the start of the erase block containing the
* data being processed.
*/
unsigned long eblk = ~0; /* force mismatch on first pass */
unsigned long erasesize = nand->erasesize;
while (len) {
if ((start & (-erasesize)) != eblk) {
/* have crossed into new erase block, deal with
* it if it is sure marked bad.
*/
eblk = start & (-erasesize); /* start of block */
if (check_block(nand, eblk)) {
if (cmd == (NANDRW_READ | NANDRW_JFFS2)) {
while (len > 0 &&
start - eblk < erasesize) {
*(buf++) = 0xff;
++start;
++total;
--len;
}
continue;
}
else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) {
start += erasesize;
continue;
}
else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) {
/* skip bad block */
start += erasesize;
continue;
}
else {
ret = 1;
break;
}
}
}
/* The ECC will not be calculated correctly if
less than 512 is written or read */
/* Is request at least 512 bytes AND it starts on a proper boundry */
if((start != ROUND_DOWN(start, 0x200)) || (len < 0x200))
printf("Warning block writes should be at least 512 bytes and start on a 512 byte boundry\n");
if (cmd & NANDRW_READ)
ret = nand_read_ecc(nand, start,
min(len, eblk + erasesize - start),
ret = nand_write_ecc(nand, start,
min(len, eblk + erasesize - start),
if (ret)
break;
start += n;
buf += n;
total += n;
len -= n;
}
if (retlen)
*retlen = total;
return ret;
}
static void nand_print(struct nand_chip *nand)
if (nand->numchips > 1) {
printf("%s at 0x%lx,\n"
"\t %d chips %s, size %d MB, \n"
"\t total size %ld MB, sector size %ld kB\n",
nand->name, nand->IO_ADDR, nand->numchips,
nand->chips_name, 1 << (nand->chipshift - 20),
nand->totlen >> 20, nand->erasesize >> 10);
}
else {
printf("%s at 0x%lx (", nand->chips_name, nand->IO_ADDR);
print_size(nand->totlen, ", ");
print_size(nand->erasesize, " sector)\n");
}
}
/* ------------------------------------------------------------------------- */
static int NanD_WaitReady(struct nand_chip *nand, int ale_wait)
{
/* This is inline, to optimise the common case, where it's ready instantly */
int ret = 0;
#ifdef NAND_NO_RB /* in config file, shorter delays currently wrap accesses */
if(ale_wait)
NAND_WAIT_READY(nand); /* do the worst case 25us wait */
else
udelay(10);
#else /* has functional r/b signal */
return ret;
}
/* NanD_Command: Send a flash command to the flash chip */
static inline int NanD_Command(struct nand_chip *nand, unsigned char command)
{
unsigned long nandptr = nand->IO_ADDR;
/* Assert the CLE (Command Latch Enable) line to the flash chip */
NAND_CTL_SETCLE(nandptr);
/* Send the command */
WRITE_NAND_COMMAND(command, nandptr);
/* Lower the CLE line */
NAND_CTL_CLRCLE(nandptr);
#ifdef NAND_NO_RB
if(command == NAND_CMD_RESET){
u_char ret_val;
NanD_Command(nand, NAND_CMD_STATUS);
do{
ret_val = READ_NAND(nandptr);/* wait till ready */
} while((ret_val & 0x40) != 0x40);
}
#endif
return NanD_WaitReady(nand, 0);
}
/* NanD_Address: Set the current address for the flash chip */
static int NanD_Address(struct nand_chip *nand, int numbytes, unsigned long ofs)
{
unsigned long nandptr;
int i;
/* Assert the ALE (Address Latch Enable) line to the flash chip */
NAND_CTL_SETALE(nandptr);
/* Send the address */
/* Devices with 256-byte page are addressed as:
* Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)
* there is no device on the market with page256
* and more than 24 bits.
* Devices with 512-byte page are addressed as:
* Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)
* 25-31 is sent only if the chip support it.
* bit 8 changes the read command to be sent
* (NAND_CMD_READ0 or NAND_CMD_READ1).
if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE)
WRITE_NAND_ADDRESS(ofs, nandptr);
ofs = ofs >> nand->page_shift;
if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE)
for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8)
WRITE_NAND_ADDRESS(ofs, nandptr);
/* Lower the ALE line */
NAND_CTL_CLRALE(nandptr);
Loading
Loading full blame...