diff options
author | Wolfgang Denk <wd@denx.de> | 2011-10-04 22:20:25 +0200 |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2011-10-04 22:20:25 +0200 |
commit | 4f7549d2dc00023c5f33d1adc7fee0a77575fcb2 (patch) | |
tree | f87d6f02fe74f832d18ab8c11feb0978da53014a | |
parent | 1fed668b3fb9c35932f58af00ff5539239fa4e1d (diff) | |
parent | 169de9059f24f50c4c7ac794ded060b2c133a29c (diff) | |
download | u-boot-imx-4f7549d2dc00023c5f33d1adc7fee0a77575fcb2.zip u-boot-imx-4f7549d2dc00023c5f33d1adc7fee0a77575fcb2.tar.gz u-boot-imx-4f7549d2dc00023c5f33d1adc7fee0a77575fcb2.tar.bz2 |
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
-rw-r--r-- | board/socrates/nand.c | 70 | ||||
-rw-r--r-- | common/cmd_nand.c | 75 | ||||
-rw-r--r-- | doc/README.nand | 9 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_elbc_nand.c | 32 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_upm.c | 16 | ||||
-rw-r--r-- | drivers/mtd/nand/kirkwood_nand.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 32 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_util.c | 29 | ||||
-rw-r--r-- | include/linux/mtd/mtd.h | 1 | ||||
-rw-r--r-- | nand_spl/nand_boot.c | 42 |
11 files changed, 185 insertions, 125 deletions
diff --git a/board/socrates/nand.c b/board/socrates/nand.c index 7d76f42..823fe80 100644 --- a/board/socrates/nand.c +++ b/board/socrates/nand.c @@ -29,13 +29,13 @@ #include <asm/io.h> static int state; -static void 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 u_char nand_read_byte(struct mtd_info *mtd); -static u16 nand_read_word(struct mtd_info *mtd); -static void 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 nand_device_ready(struct mtd_info *mtdinfo); +static void sc_nand_write_byte(struct mtd_info *mtd, u_char byte); +static void sc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len); +static u_char sc_nand_read_byte(struct mtd_info *mtd); +static u16 sc_nand_read_word(struct mtd_info *mtd); +static void sc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len); +static int sc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len); +static int sc_nand_device_ready(struct mtd_info *mtdinfo); #define FPGA_NAND_CMD_MASK (0x7 << 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 /** - * nand_write_byte - write one byte to the chip + * sc_nand_write_byte - write one byte to the chip * @mtd: MTD device structure * @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 * @buf: data buffer * @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; 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 */ -static u_char nand_read_byte(struct mtd_info *mtd) +static u_char sc_nand_read_byte(struct mtd_info *mtd) { u8 byte; - nand_read_buf(mtd, (uchar *)&byte, sizeof(byte)); + sc_nand_read_buf(mtd, (uchar *)&byte, sizeof(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 */ -static u16 nand_read_word(struct mtd_info *mtd) +static u16 sc_nand_read_word(struct mtd_info *mtd) { u16 word; - nand_read_buf(mtd, (uchar *)&word, sizeof(word)); + sc_nand_read_buf(mtd, (uchar *)&word, sizeof(word)); return word; } /** - * nand_read_buf - read chip data into buffer + * sc_nand_read_buf - read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @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; 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 * @buf: buffer containing the data 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; for (i = 0; i < len; i++) { - if (buf[i] != nand_read_byte(mtd)); + if (buf[i] != sc_nand_read_byte(mtd)); return -EFAULT; } 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 */ -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; @@ -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 * @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) { 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) - nand_write_byte(mtdinfo, cmd); + sc_nand_write_byte(mtdinfo, cmd); } 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->dev_ready = nand_device_ready; - nand->read_byte = nand_read_byte; - nand->read_word = nand_read_word; - nand->write_buf = nand_write_buf; - nand->read_buf = nand_read_buf; - nand->verify_buf = nand_verify_buf; + nand->dev_ready = sc_nand_device_ready; + nand->read_byte = sc_nand_read_byte; + nand->read_word = sc_nand_read_word; + nand->write_buf = sc_nand_write_buf; + nand->read_buf = sc_nand_read_buf; + nand->verify_buf = sc_nand_verify_buf; return 0; } diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 6edca76..3e2edb8 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -362,15 +362,31 @@ usage: #endif -static void nand_print_info(int idx) +static void nand_print_and_set_info(int idx) { nand_info_t *nand = &nand_info[idx]; struct nand_chip *chip = nand->priv; + const int bufsz = 32; + char buf[bufsz]; + printf("Device %d: ", idx); if (chip->numchips > 1) printf("%dx ", chip->numchips); printf("%s, sector size %u KiB\n", 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[]) @@ -407,7 +423,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) putc('\n'); for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { if (nand_info[i].name) - nand_print_info(i); + nand_print_and_set_info(i); } 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) puts("no devices available\n"); else - nand_print_info(dev); + nand_print_and_set_info(dev); 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; /* "clean" at index 2 means request to write cleanmarker */ 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 spread = 0; 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 (!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; if (scrub) { - puts("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 (getc() == 'y') { + if (!scrub_yes) + puts(scrub_warn); + + if (scrub_yes) + opts.scrub = 1; + else if (getc() == 'y') { puts("y"); if (getc() == '\r') opts.scrub = 1; @@ -602,6 +622,22 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 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) + ret = nand->read_oob(nand, off, &ops); + else + ret = nand->write_oob(nand, off, &ops); } else { printf("Unknown nand command suffix '%s'.\n", s); return 1; @@ -695,6 +731,9 @@ U_BOOT_CMD( "nand write - addr off|partition size\n" " read/write 'size' bytes starting at offset 'off'\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 "nand write.trimffs - addr off|partition size\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 bad - show bad blocks\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" "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)\n" "nand biterr off - make a bit error at offset (UNSAFE)" diff --git a/doc/README.nand b/doc/README.nand index 751b693..023740e 100644 --- a/doc/README.nand +++ b/doc/README.nand @@ -94,6 +94,15 @@ Commands: of data for one 512-byte page or 2 256-byte pages. There is no check 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: CONFIG_CMD_NAND diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index acdb431..4d1e527 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -85,7 +85,6 @@ struct fsl_elbc_ctrl { unsigned int mdr; /* UPM/FCM Data Register value */ unsigned int use_mdr; /* Non zero if the MDR is to be set */ 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 */ @@ -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 */ case NAND_CMD_PAGEPROG: { - int full_page; vdbg("fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " "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. */ if (ctrl->oob || ctrl->column != 0 || - ctrl->index != mtd->writesize + mtd->oobsize) { + ctrl->index != mtd->writesize + mtd->oobsize) out_be32(&lbc->fbcr, ctrl->index); - full_page = 0; - } else { + else out_be32(&lbc->fbcr, 0); - full_page = 1; - } 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; } @@ -680,13 +657,8 @@ static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, 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, chip->oob_poi, mtd->oobsize); - - ctrl->oob_poi = chip->oob_poi; } static struct fsl_elbc_ctrl *elbc_ctrl; diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index c33e278..31c174b 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -124,14 +124,14 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) 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; 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; 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); } -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; 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); } -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; 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 chip->select_chip = fun_select_chip; #endif - chip->read_byte = nand_read_byte; - chip->read_buf = nand_read_buf; - chip->write_buf = nand_write_buf; - chip->verify_buf = nand_verify_buf; + chip->read_byte = upm_nand_read_byte; + chip->read_buf = upm_nand_read_buf; + chip->write_buf = upm_nand_write_buf; + chip->verify_buf = upm_nand_verify_buf; if (fun->dev_ready) chip->dev_ready = nand_dev_ready; diff --git a/drivers/mtd/nand/kirkwood_nand.c b/drivers/mtd/nand/kirkwood_nand.c index 376378e..bdab5aa 100644 --- a/drivers/mtd/nand/kirkwood_nand.c +++ b/drivers/mtd/nand/kirkwood_nand.c @@ -76,7 +76,7 @@ int board_nand_init(struct nand_chip *nand) nand->options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING; nand->ecc.mode = NAND_ECC_SOFT; nand->cmd_ctrl = kw_nand_hwcontrol; - nand->chip_delay = 30; + nand->chip_delay = 40; nand->select_chip = kw_nand_select_chip; return 0; } diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 2a8dd7e..35e89a0 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -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. */ 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. */ 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", 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) { int stat; @@ -1179,7 +1179,7 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command, /* * before sending SEQIN command for partial write, * 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 * 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); 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, 2, 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) { /* * MXC NANDFC can only perform full page+spare or - * spare-only read/write. When the upper layers - * layers perform a read/write buf operation, - * we will used the saved column adress to index into - * the full page. + * spare-only read/write. When the upper layers perform + * a read/write buffer operation, we will use the saved + * column address to index into the full page. */ send_addr(host, 0); if (host->pagesize_2k) @@ -1372,12 +1371,23 @@ int board_nand_init(struct nand_chip *this) /* Blocks to be unlocked */ 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 */ 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()) this->options |= NAND_BUSWIDTH_16; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e7dfcb1..6aac6a2 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -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 ! */ - if (nand_block_checkbad(mtd, ((loff_t) page) << + if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, 0, allowbbt)) { printk(KERN_WARNING "nand_erase: attempt to erase a " "bad block at page 0x%08x\n", page); diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 81bf366..60c778e 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -57,12 +57,6 @@ typedef struct mtd_info mtd_info_t; #define cpu_to_je16(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 * (jffs2 formating) @@ -82,7 +76,6 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) int bbtest = 1; int result; int percent_complete = -1; - int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL; const char *mtd_device = meminfo->name; struct mtd_oob_ops oob_opts; 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. */ if (opts->scrub) { - struct nand_chip *priv_nand = meminfo->priv; - - nand_block_bad_old = priv_nand->block_bad; - priv_nand->block_bad = nand_block_bad_scrub; - /* we don't need the bad block table anymore... + erase.scrub = opts->scrub; + /* + * We don't need the bad block table anymore... * after scrub, there are no bad blocks left! */ - if (priv_nand->bbt) { - kfree(priv_nand->bbt); + if (chip->bbt) { + kfree(chip->bbt); } - priv_nand->bbt = NULL; + chip->bbt = NULL; } 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) printf("\n"); - if (nand_block_bad_old) { - struct nand_chip *priv_nand = meminfo->priv; - - priv_nand->block_bad = nand_block_bad_old; - priv_nand->scan_bbt(meminfo); - } + if (opts->scrub) + chip->scan_bbt(meminfo); return 0; } diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index d36d584..141c960 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -55,6 +55,7 @@ struct erase_info { u_long priv; u_char state; struct erase_info *next; + int scrub; }; struct mtd_erase_region_info { diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c index 4683c7c..615ef25 100644 --- a/nand_spl/nand_boot.c +++ b/nand_spl/nand_boot.c @@ -135,6 +135,47 @@ static int nand_is_bad_block(struct mtd_info *mtd, int block) 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) { 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; } +#endif /* #if defined(CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST) */ static int nand_load(struct mtd_info *mtd, unsigned int offs, unsigned int uboot_size, uchar *dst) |