mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-29 16:10:24 +09:00
Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
* 'master' of git://git.denx.de/u-boot-nand-flash: PPC: Fix socrates NAND problem PPC: Fix fsl_upm.c by renaming nand handling functions NAND: Make page, erase, oob size available via cmd_nand mtd: eLBC NAND: remove elbc_fcm_ctrl->oob_poi NAND: Add -y option to nand scrub command NAND: Add nand read.raw and write.raw commands NAND: Really ignore bad blocks when scrubbing spl, nand: add 4bit HW ecc oob first nand_read_page function mxc_nand: fix a problem writing more than 32MB mxc_nand: fixed some typos (cosmetic) nand: increase chip_delay in mv kirkwood nand driver
This commit is contained in:
commit
4f7549d2dc
@ -29,13 +29,13 @@
|
|||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
static int state;
|
static int state;
|
||||||
static void nand_write_byte(struct mtd_info *mtd, u_char byte);
|
static void sc_nand_write_byte(struct mtd_info *mtd, u_char byte);
|
||||||
static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
|
static void sc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
|
||||||
static u_char nand_read_byte(struct mtd_info *mtd);
|
static u_char sc_nand_read_byte(struct mtd_info *mtd);
|
||||||
static u16 nand_read_word(struct mtd_info *mtd);
|
static u16 sc_nand_read_word(struct mtd_info *mtd);
|
||||||
static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
|
static void sc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
|
||||||
static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
|
static int sc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
|
||||||
static int nand_device_ready(struct mtd_info *mtdinfo);
|
static int sc_nand_device_ready(struct mtd_info *mtdinfo);
|
||||||
|
|
||||||
#define FPGA_NAND_CMD_MASK (0x7 << 28)
|
#define FPGA_NAND_CMD_MASK (0x7 << 28)
|
||||||
#define FPGA_NAND_CMD_COMMAND (0x0 << 28)
|
#define FPGA_NAND_CMD_COMMAND (0x0 << 28)
|
||||||
@ -47,22 +47,22 @@ static int nand_device_ready(struct mtd_info *mtdinfo);
|
|||||||
#define FPGA_NAND_DATA_SHIFT 16
|
#define FPGA_NAND_DATA_SHIFT 16
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_write_byte - write one byte to the chip
|
* sc_nand_write_byte - write one byte to the chip
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @byte: pointer to data byte to write
|
* @byte: pointer to data byte to write
|
||||||
*/
|
*/
|
||||||
static void nand_write_byte(struct mtd_info *mtd, u_char byte)
|
static void sc_nand_write_byte(struct mtd_info *mtd, u_char byte)
|
||||||
{
|
{
|
||||||
nand_write_buf(mtd, (const uchar *)&byte, sizeof(byte));
|
sc_nand_write_buf(mtd, (const uchar *)&byte, sizeof(byte));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_write_buf - write buffer to chip
|
* sc_nand_write_buf - write buffer to chip
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: data buffer
|
* @buf: data buffer
|
||||||
* @len: number of bytes to write
|
* @len: number of bytes to write
|
||||||
*/
|
*/
|
||||||
static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
static void sc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
@ -75,34 +75,34 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_read_byte - read one byte from the chip
|
* sc_nand_read_byte - read one byte from the chip
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
*/
|
*/
|
||||||
static u_char nand_read_byte(struct mtd_info *mtd)
|
static u_char sc_nand_read_byte(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
u8 byte;
|
u8 byte;
|
||||||
nand_read_buf(mtd, (uchar *)&byte, sizeof(byte));
|
sc_nand_read_buf(mtd, (uchar *)&byte, sizeof(byte));
|
||||||
return byte;
|
return byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_read_word - read one word from the chip
|
* sc_nand_read_word - read one word from the chip
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
*/
|
*/
|
||||||
static u16 nand_read_word(struct mtd_info *mtd)
|
static u16 sc_nand_read_word(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
u16 word;
|
u16 word;
|
||||||
nand_read_buf(mtd, (uchar *)&word, sizeof(word));
|
sc_nand_read_buf(mtd, (uchar *)&word, sizeof(word));
|
||||||
return word;
|
return word;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_read_buf - read chip data into buffer
|
* sc_nand_read_buf - read chip data into buffer
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: buffer to store date
|
* @buf: buffer to store date
|
||||||
* @len: number of bytes to read
|
* @len: number of bytes to read
|
||||||
*/
|
*/
|
||||||
static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
static void sc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
@ -117,27 +117,27 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_verify_buf - Verify chip data against buffer
|
* sc_nand_verify_buf - Verify chip data against buffer
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @buf: buffer containing the data to compare
|
* @buf: buffer containing the data to compare
|
||||||
* @len: number of bytes to compare
|
* @len: number of bytes to compare
|
||||||
*/
|
*/
|
||||||
static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
static int sc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
if (buf[i] != nand_read_byte(mtd));
|
if (buf[i] != sc_nand_read_byte(mtd));
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_device_ready - Check the NAND device is ready for next command.
|
* sc_nand_device_ready - Check the NAND device is ready for next command.
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
*/
|
*/
|
||||||
static int nand_device_ready(struct mtd_info *mtdinfo)
|
static int sc_nand_device_ready(struct mtd_info *mtdinfo)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtdinfo->priv;
|
struct nand_chip *this = mtdinfo->priv;
|
||||||
|
|
||||||
@ -147,11 +147,11 @@ static int nand_device_ready(struct mtd_info *mtdinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_hwcontrol - NAND control functions wrapper.
|
* sc_nand_hwcontrol - NAND control functions wrapper.
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @cmd: Command
|
* @cmd: Command
|
||||||
*/
|
*/
|
||||||
static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd, unsigned int ctrl)
|
static void sc_nand_hwcontrol(struct mtd_info *mtdinfo, int cmd, unsigned int ctrl)
|
||||||
{
|
{
|
||||||
if (ctrl & NAND_CTRL_CHANGE) {
|
if (ctrl & NAND_CTRL_CHANGE) {
|
||||||
state &= ~(FPGA_NAND_CMD_MASK | FPGA_NAND_ENABLE);
|
state &= ~(FPGA_NAND_CMD_MASK | FPGA_NAND_ENABLE);
|
||||||
@ -178,19 +178,19 @@ static void nand_hwcontrol(struct mtd_info *mtdinfo, int cmd, unsigned int ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cmd != NAND_CMD_NONE)
|
if (cmd != NAND_CMD_NONE)
|
||||||
nand_write_byte(mtdinfo, cmd);
|
sc_nand_write_byte(mtdinfo, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int board_nand_init(struct nand_chip *nand)
|
int board_nand_init(struct nand_chip *nand)
|
||||||
{
|
{
|
||||||
nand->cmd_ctrl = nand_hwcontrol;
|
nand->cmd_ctrl = sc_nand_hwcontrol;
|
||||||
nand->ecc.mode = NAND_ECC_SOFT;
|
nand->ecc.mode = NAND_ECC_SOFT;
|
||||||
nand->dev_ready = nand_device_ready;
|
nand->dev_ready = sc_nand_device_ready;
|
||||||
nand->read_byte = nand_read_byte;
|
nand->read_byte = sc_nand_read_byte;
|
||||||
nand->read_word = nand_read_word;
|
nand->read_word = sc_nand_read_word;
|
||||||
nand->write_buf = nand_write_buf;
|
nand->write_buf = sc_nand_write_buf;
|
||||||
nand->read_buf = nand_read_buf;
|
nand->read_buf = sc_nand_read_buf;
|
||||||
nand->verify_buf = nand_verify_buf;
|
nand->verify_buf = sc_nand_verify_buf;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -362,15 +362,31 @@ usage:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void nand_print_info(int idx)
|
static void nand_print_and_set_info(int idx)
|
||||||
{
|
{
|
||||||
nand_info_t *nand = &nand_info[idx];
|
nand_info_t *nand = &nand_info[idx];
|
||||||
struct nand_chip *chip = nand->priv;
|
struct nand_chip *chip = nand->priv;
|
||||||
|
const int bufsz = 32;
|
||||||
|
char buf[bufsz];
|
||||||
|
|
||||||
printf("Device %d: ", idx);
|
printf("Device %d: ", idx);
|
||||||
if (chip->numchips > 1)
|
if (chip->numchips > 1)
|
||||||
printf("%dx ", chip->numchips);
|
printf("%dx ", chip->numchips);
|
||||||
printf("%s, sector size %u KiB\n",
|
printf("%s, sector size %u KiB\n",
|
||||||
nand->name, nand->erasesize >> 10);
|
nand->name, nand->erasesize >> 10);
|
||||||
|
printf(" Page size %8d b\n", nand->writesize);
|
||||||
|
printf(" OOB size %8d b\n", nand->oobsize);
|
||||||
|
printf(" Erase size %8d b\n", nand->erasesize);
|
||||||
|
|
||||||
|
/* Set geometry info */
|
||||||
|
sprintf(buf, "%x", nand->writesize);
|
||||||
|
setenv("nand_writesize", buf);
|
||||||
|
|
||||||
|
sprintf(buf, "%x", nand->oobsize);
|
||||||
|
setenv("nand_oobsize", buf);
|
||||||
|
|
||||||
|
sprintf(buf, "%x", nand->erasesize);
|
||||||
|
setenv("nand_erasesize", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
||||||
@ -407,7 +423,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
|||||||
putc('\n');
|
putc('\n');
|
||||||
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
|
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
|
||||||
if (nand_info[i].name)
|
if (nand_info[i].name)
|
||||||
nand_print_info(i);
|
nand_print_and_set_info(i);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -418,7 +434,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
|||||||
if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
|
if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE)
|
||||||
puts("no devices available\n");
|
puts("no devices available\n");
|
||||||
else
|
else
|
||||||
nand_print_info(dev);
|
nand_print_and_set_info(dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -464,10 +480,21 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
|||||||
nand_erase_options_t opts;
|
nand_erase_options_t opts;
|
||||||
/* "clean" at index 2 means request to write cleanmarker */
|
/* "clean" at index 2 means request to write cleanmarker */
|
||||||
int clean = argc > 2 && !strcmp("clean", argv[2]);
|
int clean = argc > 2 && !strcmp("clean", argv[2]);
|
||||||
int o = clean ? 3 : 2;
|
int scrub_yes = argc > 2 && !strcmp("-y", argv[2]);
|
||||||
|
int o = (clean || scrub_yes) ? 3 : 2;
|
||||||
int scrub = !strncmp(cmd, "scrub", 5);
|
int scrub = !strncmp(cmd, "scrub", 5);
|
||||||
int spread = 0;
|
int spread = 0;
|
||||||
int args = 2;
|
int args = 2;
|
||||||
|
const char *scrub_warn =
|
||||||
|
"Warning: "
|
||||||
|
"scrub option will erase all factory set bad blocks!\n"
|
||||||
|
" "
|
||||||
|
"There is no reliable way to recover them.\n"
|
||||||
|
" "
|
||||||
|
"Use this command only for testing purposes if you\n"
|
||||||
|
" "
|
||||||
|
"are sure of what you are doing!\n"
|
||||||
|
"\nReally scrub this NAND flash? <y/N>\n";
|
||||||
|
|
||||||
if (cmd[5] != 0) {
|
if (cmd[5] != 0) {
|
||||||
if (!strcmp(&cmd[5], ".spread")) {
|
if (!strcmp(&cmd[5], ".spread")) {
|
||||||
@ -504,19 +531,12 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
|||||||
opts.spread = spread;
|
opts.spread = spread;
|
||||||
|
|
||||||
if (scrub) {
|
if (scrub) {
|
||||||
puts("Warning: "
|
if (!scrub_yes)
|
||||||
"scrub option will erase all factory set "
|
puts(scrub_warn);
|
||||||
"bad blocks!\n"
|
|
||||||
" "
|
|
||||||
"There is no reliable way to recover them.\n"
|
|
||||||
" "
|
|
||||||
"Use this command only for testing purposes "
|
|
||||||
"if you\n"
|
|
||||||
" "
|
|
||||||
"are sure of what you are doing!\n"
|
|
||||||
"\nReally scrub this NAND flash? <y/N>\n");
|
|
||||||
|
|
||||||
if (getc() == 'y') {
|
if (scrub_yes)
|
||||||
|
opts.scrub = 1;
|
||||||
|
else if (getc() == 'y') {
|
||||||
puts("y");
|
puts("y");
|
||||||
if (getc() == '\r')
|
if (getc() == '\r')
|
||||||
opts.scrub = 1;
|
opts.scrub = 1;
|
||||||
@ -598,6 +618,22 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
|
|||||||
.mode = MTD_OOB_RAW
|
.mode = MTD_OOB_RAW
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (read)
|
||||||
|
ret = nand->read_oob(nand, off, &ops);
|
||||||
|
else
|
||||||
|
ret = nand->write_oob(nand, off, &ops);
|
||||||
|
} else if (!strcmp(s, ".raw")) {
|
||||||
|
/* Raw access */
|
||||||
|
mtd_oob_ops_t ops = {
|
||||||
|
.datbuf = (u8 *)addr,
|
||||||
|
.oobbuf = ((u8 *)addr) + nand->writesize,
|
||||||
|
.len = nand->writesize,
|
||||||
|
.ooblen = nand->oobsize,
|
||||||
|
.mode = MTD_OOB_RAW
|
||||||
|
};
|
||||||
|
|
||||||
|
rwsize = nand->writesize + nand->oobsize;
|
||||||
|
|
||||||
if (read)
|
if (read)
|
||||||
ret = nand->read_oob(nand, off, &ops);
|
ret = nand->read_oob(nand, off, &ops);
|
||||||
else
|
else
|
||||||
@ -695,6 +731,9 @@ U_BOOT_CMD(
|
|||||||
"nand write - addr off|partition size\n"
|
"nand write - addr off|partition size\n"
|
||||||
" read/write 'size' bytes starting at offset 'off'\n"
|
" read/write 'size' bytes starting at offset 'off'\n"
|
||||||
" to/from memory address 'addr', skipping bad blocks.\n"
|
" to/from memory address 'addr', skipping bad blocks.\n"
|
||||||
|
"nand read.raw - addr off|partition\n"
|
||||||
|
"nand write.raw - addr off|partition\n"
|
||||||
|
" Use read.raw/write.raw to avoid ECC and access the page as-is.\n"
|
||||||
#ifdef CONFIG_CMD_NAND_TRIMFFS
|
#ifdef CONFIG_CMD_NAND_TRIMFFS
|
||||||
"nand write.trimffs - addr off|partition size\n"
|
"nand write.trimffs - addr off|partition size\n"
|
||||||
" write 'size' bytes starting at offset 'off' from memory address\n"
|
" write 'size' bytes starting at offset 'off' from memory address\n"
|
||||||
@ -714,7 +753,7 @@ U_BOOT_CMD(
|
|||||||
"nand erase.chip [clean] - erase entire chip'\n"
|
"nand erase.chip [clean] - erase entire chip'\n"
|
||||||
"nand bad - show bad blocks\n"
|
"nand bad - show bad blocks\n"
|
||||||
"nand dump[.oob] off - dump page\n"
|
"nand dump[.oob] off - dump page\n"
|
||||||
"nand scrub off size | scrub.part partition | scrub.chip\n"
|
"nand scrub [-y] off size | scrub.part partition | scrub.chip\n"
|
||||||
" really clean NAND erasing bad blocks (UNSAFE)\n"
|
" really clean NAND erasing bad blocks (UNSAFE)\n"
|
||||||
"nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
|
"nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n"
|
||||||
"nand biterr off - make a bit error at offset (UNSAFE)"
|
"nand biterr off - make a bit error at offset (UNSAFE)"
|
||||||
|
@ -94,6 +94,15 @@ Commands:
|
|||||||
of data for one 512-byte page or 2 256-byte pages. There is no check
|
of data for one 512-byte page or 2 256-byte pages. There is no check
|
||||||
for bad blocks.
|
for bad blocks.
|
||||||
|
|
||||||
|
nand read.raw addr ofs|partition
|
||||||
|
Read page from `ofs' in NAND flash to `addr'. This reads the raw page,
|
||||||
|
so ECC is avoided and the OOB area is read as well.
|
||||||
|
|
||||||
|
nand write.raw addr ofs|partition
|
||||||
|
Write page from `addr' to `ofs' in NAND flash. This writes the raw page,
|
||||||
|
so ECC is avoided and the OOB area is written as well, making the whole
|
||||||
|
page written as-is.
|
||||||
|
|
||||||
Configuration Options:
|
Configuration Options:
|
||||||
|
|
||||||
CONFIG_CMD_NAND
|
CONFIG_CMD_NAND
|
||||||
|
@ -85,7 +85,6 @@ struct fsl_elbc_ctrl {
|
|||||||
unsigned int mdr; /* UPM/FCM Data Register value */
|
unsigned int mdr; /* UPM/FCM Data Register value */
|
||||||
unsigned int use_mdr; /* Non zero if the MDR is to be set */
|
unsigned int use_mdr; /* Non zero if the MDR is to be set */
|
||||||
unsigned int oob; /* Non zero if operating on OOB data */
|
unsigned int oob; /* Non zero if operating on OOB data */
|
||||||
uint8_t *oob_poi; /* Place to write ECC after read back */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* These map to the positions used by the FCM hardware ECC generator */
|
/* These map to the positions used by the FCM hardware ECC generator */
|
||||||
@ -436,7 +435,6 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
|||||||
|
|
||||||
/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
|
/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
|
||||||
case NAND_CMD_PAGEPROG: {
|
case NAND_CMD_PAGEPROG: {
|
||||||
int full_page;
|
|
||||||
vdbg("fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
|
vdbg("fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
|
||||||
"writing %d bytes.\n", ctrl->index);
|
"writing %d bytes.\n", ctrl->index);
|
||||||
|
|
||||||
@ -445,34 +443,13 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
|||||||
* write so the HW generates the ECC.
|
* write so the HW generates the ECC.
|
||||||
*/
|
*/
|
||||||
if (ctrl->oob || ctrl->column != 0 ||
|
if (ctrl->oob || ctrl->column != 0 ||
|
||||||
ctrl->index != mtd->writesize + mtd->oobsize) {
|
ctrl->index != mtd->writesize + mtd->oobsize)
|
||||||
out_be32(&lbc->fbcr, ctrl->index);
|
out_be32(&lbc->fbcr, ctrl->index);
|
||||||
full_page = 0;
|
else
|
||||||
} else {
|
|
||||||
out_be32(&lbc->fbcr, 0);
|
out_be32(&lbc->fbcr, 0);
|
||||||
full_page = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fsl_elbc_run_command(mtd);
|
fsl_elbc_run_command(mtd);
|
||||||
|
|
||||||
/* Read back the page in order to fill in the ECC for the
|
|
||||||
* caller. Is this really needed?
|
|
||||||
*/
|
|
||||||
if (full_page && ctrl->oob_poi) {
|
|
||||||
out_be32(&lbc->fbcr, 3);
|
|
||||||
set_addr(mtd, 6, page_addr, 1);
|
|
||||||
|
|
||||||
ctrl->read_bytes = mtd->writesize + 9;
|
|
||||||
|
|
||||||
fsl_elbc_do_read(chip, 1);
|
|
||||||
fsl_elbc_run_command(mtd);
|
|
||||||
|
|
||||||
memcpy_fromio(ctrl->oob_poi + 6,
|
|
||||||
&ctrl->addr[ctrl->index], 3);
|
|
||||||
ctrl->index += 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctrl->oob_poi = NULL;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,13 +657,8 @@ static void fsl_elbc_write_page(struct mtd_info *mtd,
|
|||||||
struct nand_chip *chip,
|
struct nand_chip *chip,
|
||||||
const uint8_t *buf)
|
const uint8_t *buf)
|
||||||
{
|
{
|
||||||
struct fsl_elbc_mtd *priv = chip->priv;
|
|
||||||
struct fsl_elbc_ctrl *ctrl = priv->ctrl;
|
|
||||||
|
|
||||||
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
|
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
|
||||||
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
|
||||||
|
|
||||||
ctrl->oob_poi = chip->oob_poi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct fsl_elbc_ctrl *elbc_ctrl;
|
static struct fsl_elbc_ctrl *elbc_ctrl;
|
||||||
|
@ -124,14 +124,14 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
|||||||
fun_wait(fun);
|
fun_wait(fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 nand_read_byte(struct mtd_info *mtd)
|
static u8 upm_nand_read_byte(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
|
|
||||||
return in_8(chip->IO_ADDR_R);
|
return in_8(chip->IO_ADDR_R);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
static void upm_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
@ -147,7 +147,7 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
|||||||
fun_wait(fun);
|
fun_wait(fun);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
static void upm_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
@ -156,7 +156,7 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
|
|||||||
buf[i] = in_8(chip->IO_ADDR_R);
|
buf[i] = in_8(chip->IO_ADDR_R);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
static int upm_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
@ -191,10 +191,10 @@ int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun)
|
|||||||
#if CONFIG_SYS_NAND_MAX_CHIPS > 1
|
#if CONFIG_SYS_NAND_MAX_CHIPS > 1
|
||||||
chip->select_chip = fun_select_chip;
|
chip->select_chip = fun_select_chip;
|
||||||
#endif
|
#endif
|
||||||
chip->read_byte = nand_read_byte;
|
chip->read_byte = upm_nand_read_byte;
|
||||||
chip->read_buf = nand_read_buf;
|
chip->read_buf = upm_nand_read_buf;
|
||||||
chip->write_buf = nand_write_buf;
|
chip->write_buf = upm_nand_write_buf;
|
||||||
chip->verify_buf = nand_verify_buf;
|
chip->verify_buf = upm_nand_verify_buf;
|
||||||
if (fun->dev_ready)
|
if (fun->dev_ready)
|
||||||
chip->dev_ready = nand_dev_ready;
|
chip->dev_ready = nand_dev_ready;
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ int board_nand_init(struct nand_chip *nand)
|
|||||||
nand->options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING;
|
nand->options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING;
|
||||||
nand->ecc.mode = NAND_ECC_SOFT;
|
nand->ecc.mode = NAND_ECC_SOFT;
|
||||||
nand->cmd_ctrl = kw_nand_hwcontrol;
|
nand->cmd_ctrl = kw_nand_hwcontrol;
|
||||||
nand->chip_delay = 30;
|
nand->chip_delay = 40;
|
||||||
nand->select_chip = kw_nand_select_chip;
|
nand->select_chip = kw_nand_select_chip;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -350,7 +350,7 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function requests the NANDFC to initate the transfer
|
* This function requests the NANDFC to initiate the transfer
|
||||||
* of data currently in the NANDFC RAM buffer to the NAND device.
|
* of data currently in the NANDFC RAM buffer to the NAND device.
|
||||||
*/
|
*/
|
||||||
static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
|
static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
|
||||||
@ -394,7 +394,7 @@ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Requests NANDFC to initated the transfer of data from the
|
* Requests NANDFC to initiate the transfer of data from the
|
||||||
* NAND device into in the NANDFC ram buffer.
|
* NAND device into in the NANDFC ram buffer.
|
||||||
*/
|
*/
|
||||||
static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id,
|
static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id,
|
||||||
@ -637,7 +637,7 @@ static int mxc_nand_read_page_syndrome(struct mtd_info *mtd,
|
|||||||
MTDDEBUG(MTD_DEBUG_LEVEL1, "Reading page %u to buf %p oob %p\n",
|
MTDDEBUG(MTD_DEBUG_LEVEL1, "Reading page %u to buf %p oob %p\n",
|
||||||
host->page_addr, buf, oob);
|
host->page_addr, buf, oob);
|
||||||
|
|
||||||
/* first read out the data area and the available portion of OOB */
|
/* first read the data area and the available portion of OOB */
|
||||||
for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) {
|
for (n = 0; eccsteps; n++, eccsteps--, p += eccsize) {
|
||||||
int stat;
|
int stat;
|
||||||
|
|
||||||
@ -1179,7 +1179,7 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command,
|
|||||||
/*
|
/*
|
||||||
* before sending SEQIN command for partial write,
|
* before sending SEQIN command for partial write,
|
||||||
* we need read one page out. FSL NFC does not support
|
* we need read one page out. FSL NFC does not support
|
||||||
* partial write. It alway send out 512+ecc+512+ecc ...
|
* partial write. It always sends out 512+ecc+512+ecc
|
||||||
* for large page nand flash. But for small page nand
|
* for large page nand flash. But for small page nand
|
||||||
* flash, it does support SPARE ONLY operation.
|
* flash, it does support SPARE ONLY operation.
|
||||||
*/
|
*/
|
||||||
@ -1209,7 +1209,7 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command,
|
|||||||
send_prog_page(host, 0, host->spare_only);
|
send_prog_page(host, 0, host->spare_only);
|
||||||
|
|
||||||
if (host->pagesize_2k && !is_mxc_nfc_11()) {
|
if (host->pagesize_2k && !is_mxc_nfc_11()) {
|
||||||
/* data in 4 areas datas */
|
/* data in 4 areas */
|
||||||
send_prog_page(host, 1, host->spare_only);
|
send_prog_page(host, 1, host->spare_only);
|
||||||
send_prog_page(host, 2, host->spare_only);
|
send_prog_page(host, 2, host->spare_only);
|
||||||
send_prog_page(host, 3, host->spare_only);
|
send_prog_page(host, 3, host->spare_only);
|
||||||
@ -1225,10 +1225,9 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command,
|
|||||||
if (column != -1) {
|
if (column != -1) {
|
||||||
/*
|
/*
|
||||||
* MXC NANDFC can only perform full page+spare or
|
* MXC NANDFC can only perform full page+spare or
|
||||||
* spare-only read/write. When the upper layers
|
* spare-only read/write. When the upper layers perform
|
||||||
* layers perform a read/write buf operation,
|
* a read/write buffer operation, we will use the saved
|
||||||
* we will used the saved column adress to index into
|
* column address to index into the full page.
|
||||||
* the full page.
|
|
||||||
*/
|
*/
|
||||||
send_addr(host, 0);
|
send_addr(host, 0);
|
||||||
if (host->pagesize_2k)
|
if (host->pagesize_2k)
|
||||||
@ -1372,12 +1371,23 @@ int board_nand_init(struct nand_chip *this)
|
|||||||
|
|
||||||
/* Blocks to be unlocked */
|
/* Blocks to be unlocked */
|
||||||
writew(0x0, &host->regs->nfc_unlockstart_blkaddr);
|
writew(0x0, &host->regs->nfc_unlockstart_blkaddr);
|
||||||
writew(0x4000, &host->regs->nfc_unlockend_blkaddr);
|
/* Originally (Freescale LTIB 2.6.21) 0x4000 was written to the
|
||||||
|
* unlockend_blkaddr, but the magic 0x4000 does not always work
|
||||||
|
* when writing more than some 32 megabytes (on 2k page nands)
|
||||||
|
* However 0xFFFF doesn't seem to have this kind
|
||||||
|
* of limitation (tried it back and forth several times).
|
||||||
|
* The linux kernel driver sets this to 0xFFFF for the v2 controller
|
||||||
|
* only, but probably this was not tested there for v1.
|
||||||
|
* The very same limitation seems to apply to this kernel driver.
|
||||||
|
* This might be NAND chip specific and the i.MX31 datasheet is
|
||||||
|
* extremely vague about the semantics of this register.
|
||||||
|
*/
|
||||||
|
writew(0xFFFF, &host->regs->nfc_unlockend_blkaddr);
|
||||||
|
|
||||||
/* Unlock Block Command for given address range */
|
/* Unlock Block Command for given address range */
|
||||||
writew(0x4, &host->regs->nfc_wrprot);
|
writew(0x4, &host->regs->nfc_wrprot);
|
||||||
|
|
||||||
/* NAND bus width determines access funtions used by upper layer */
|
/* NAND bus width determines access functions used by upper layer */
|
||||||
if (is_16bit_nand())
|
if (is_16bit_nand())
|
||||||
this->options |= NAND_BUSWIDTH_16;
|
this->options |= NAND_BUSWIDTH_16;
|
||||||
|
|
||||||
|
@ -2224,7 +2224,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
|
|||||||
/*
|
/*
|
||||||
* heck if we have a bad block, we do not erase bad blocks !
|
* heck if we have a bad block, we do not erase bad blocks !
|
||||||
*/
|
*/
|
||||||
if (nand_block_checkbad(mtd, ((loff_t) page) <<
|
if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) <<
|
||||||
chip->page_shift, 0, allowbbt)) {
|
chip->page_shift, 0, allowbbt)) {
|
||||||
printk(KERN_WARNING "nand_erase: attempt to erase a "
|
printk(KERN_WARNING "nand_erase: attempt to erase a "
|
||||||
"bad block at page 0x%08x\n", page);
|
"bad block at page 0x%08x\n", page);
|
||||||
|
@ -57,12 +57,6 @@ typedef struct mtd_info mtd_info_t;
|
|||||||
#define cpu_to_je16(x) (x)
|
#define cpu_to_je16(x) (x)
|
||||||
#define cpu_to_je32(x) (x)
|
#define cpu_to_je32(x) (x)
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_erase_opts: - erase NAND flash with support for various options
|
* nand_erase_opts: - erase NAND flash with support for various options
|
||||||
* (jffs2 formating)
|
* (jffs2 formating)
|
||||||
@ -82,7 +76,6 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
|||||||
int bbtest = 1;
|
int bbtest = 1;
|
||||||
int result;
|
int result;
|
||||||
int percent_complete = -1;
|
int percent_complete = -1;
|
||||||
int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL;
|
|
||||||
const char *mtd_device = meminfo->name;
|
const char *mtd_device = meminfo->name;
|
||||||
struct mtd_oob_ops oob_opts;
|
struct mtd_oob_ops oob_opts;
|
||||||
struct nand_chip *chip = meminfo->priv;
|
struct nand_chip *chip = meminfo->priv;
|
||||||
@ -110,17 +103,15 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
|||||||
* and disable bad block table while erasing.
|
* and disable bad block table while erasing.
|
||||||
*/
|
*/
|
||||||
if (opts->scrub) {
|
if (opts->scrub) {
|
||||||
struct nand_chip *priv_nand = meminfo->priv;
|
erase.scrub = opts->scrub;
|
||||||
|
/*
|
||||||
nand_block_bad_old = priv_nand->block_bad;
|
* We don't need the bad block table anymore...
|
||||||
priv_nand->block_bad = nand_block_bad_scrub;
|
|
||||||
/* we don't need the bad block table anymore...
|
|
||||||
* after scrub, there are no bad blocks left!
|
* after scrub, there are no bad blocks left!
|
||||||
*/
|
*/
|
||||||
if (priv_nand->bbt) {
|
if (chip->bbt) {
|
||||||
kfree(priv_nand->bbt);
|
kfree(chip->bbt);
|
||||||
}
|
}
|
||||||
priv_nand->bbt = NULL;
|
chip->bbt = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (erased_length = 0;
|
for (erased_length = 0;
|
||||||
@ -204,12 +195,8 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
|
|||||||
if (!opts->quiet)
|
if (!opts->quiet)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
if (nand_block_bad_old) {
|
if (opts->scrub)
|
||||||
struct nand_chip *priv_nand = meminfo->priv;
|
chip->scan_bbt(meminfo);
|
||||||
|
|
||||||
priv_nand->block_bad = nand_block_bad_old;
|
|
||||||
priv_nand->scan_bbt(meminfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ struct erase_info {
|
|||||||
u_long priv;
|
u_long priv;
|
||||||
u_char state;
|
u_char state;
|
||||||
struct erase_info *next;
|
struct erase_info *next;
|
||||||
|
int scrub;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mtd_erase_region_info {
|
struct mtd_erase_region_info {
|
||||||
|
@ -135,6 +135,47 @@ static int nand_is_bad_block(struct mtd_info *mtd, int block)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST)
|
||||||
|
static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
|
||||||
|
{
|
||||||
|
struct nand_chip *this = mtd->priv;
|
||||||
|
u_char *ecc_calc;
|
||||||
|
u_char *ecc_code;
|
||||||
|
u_char *oob_data;
|
||||||
|
int i;
|
||||||
|
int eccsize = CONFIG_SYS_NAND_ECCSIZE;
|
||||||
|
int eccbytes = CONFIG_SYS_NAND_ECCBYTES;
|
||||||
|
int eccsteps = CONFIG_SYS_NAND_ECCSTEPS;
|
||||||
|
uint8_t *p = dst;
|
||||||
|
int stat;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No malloc available for now, just use some temporary locations
|
||||||
|
* in SDRAM
|
||||||
|
*/
|
||||||
|
ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000);
|
||||||
|
ecc_code = ecc_calc + 0x100;
|
||||||
|
oob_data = ecc_calc + 0x200;
|
||||||
|
|
||||||
|
nand_command(mtd, block, page, 0, NAND_CMD_READOOB);
|
||||||
|
this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);
|
||||||
|
nand_command(mtd, block, page, 0, NAND_CMD_READ0);
|
||||||
|
|
||||||
|
/* Pick the ECC bytes out of the oob data */
|
||||||
|
for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++)
|
||||||
|
ecc_code[i] = oob_data[nand_ecc_pos[i]];
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
|
||||||
|
this->ecc.hwctl(mtd, NAND_ECC_READ);
|
||||||
|
this->read_buf(mtd, p, eccsize);
|
||||||
|
this->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||||
|
stat = this->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
|
static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *this = mtd->priv;
|
||||||
@ -181,6 +222,7 @@ static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /* #if defined(CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST) */
|
||||||
|
|
||||||
static int nand_load(struct mtd_info *mtd, unsigned int offs,
|
static int nand_load(struct mtd_info *mtd, unsigned int offs,
|
||||||
unsigned int uboot_size, uchar *dst)
|
unsigned int uboot_size, uchar *dst)
|
||||||
|
Loading…
Reference in New Issue
Block a user