mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-21 14:41:31 +00:00
mtd: nand: Sync with Linux v4.6
Updates the NAND code to match Linux v4.6. The previous sync was from
Linux v4.1 in commit d3963721d9
.
Note that none of the individual NAND drivers tracked Linux closely
enough to be synced themselves, other than manually applying a few
cross-tree changes.
Signed-off-by: Scott Wood <oss@buserror.net>
Tested-by: Heiko Schocher <hs@denx.de>
This commit is contained in:
parent
81c772521f
commit
ceee07b658
20 changed files with 347 additions and 202 deletions
|
@ -513,7 +513,7 @@ normal_check:
|
||||||
if (err_nbr == -1) {
|
if (err_nbr == -1) {
|
||||||
dev_err(host->dev, "PMECC: Too many errors\n");
|
dev_err(host->dev, "PMECC: Too many errors\n");
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
return -EIO;
|
return -EBADMSG;
|
||||||
} else {
|
} else {
|
||||||
pmecc_correct_data(mtd, buf_pos, ecc, i,
|
pmecc_correct_data(mtd, buf_pos, ecc, i,
|
||||||
host->pmecc_bytes_per_sector, err_nbr);
|
host->pmecc_bytes_per_sector, err_nbr);
|
||||||
|
@ -562,7 +562,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
|
||||||
stat = pmecc_readl(host->pmecc, isr);
|
stat = pmecc_readl(host->pmecc, isr);
|
||||||
if (stat != 0)
|
if (stat != 0)
|
||||||
if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
|
if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
|
||||||
return -EIO;
|
return -EBADMSG;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1112,7 +1112,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
|
||||||
* We can't correct so many errors */
|
* We can't correct so many errors */
|
||||||
dev_warn(host->dev, "atmel_nand : multiple errors detected."
|
dev_warn(host->dev, "atmel_nand : multiple errors detected."
|
||||||
" Unable to correct.\n");
|
" Unable to correct.\n");
|
||||||
return -EIO;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if there's a single bit error : we can correct it */
|
/* if there's a single bit error : we can correct it */
|
||||||
|
|
|
@ -243,7 +243,7 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||||
"%d\n", find_byte, find_bit);
|
"%d\n", find_byte, find_bit);
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
} else if (!(diff & (diff - 1))) {
|
} else if (!(diff & (diff - 1))) {
|
||||||
/* Single bit ECC error in the ECC itself,
|
/* Single bit ECC error in the ECC itself,
|
||||||
|
@ -254,7 +254,7 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||||
} else {
|
} else {
|
||||||
/* Uncorrectable error */
|
/* Uncorrectable error */
|
||||||
MTDDEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
|
MTDDEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
|
||||||
return -1;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -701,7 +701,7 @@ static int nand_davinci_4bit_correct_data(struct mtd_info *mtd, uint8_t *dat,
|
||||||
return 0;
|
return 0;
|
||||||
} else if (iserror == ECC_STATE_TOO_MANY_ERRS) {
|
} else if (iserror == ECC_STATE_TOO_MANY_ERRS) {
|
||||||
val = __raw_readl(&davinci_emif_regs->nanderrval1);
|
val = __raw_readl(&davinci_emif_regs->nanderrval1);
|
||||||
return -1;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
numerrors = ((__raw_readl(&davinci_emif_regs->nandfsr) >> 16)
|
numerrors = ((__raw_readl(&davinci_emif_regs->nandfsr) >> 16)
|
||||||
|
|
|
@ -48,8 +48,10 @@ static int onfi_timing_mode = NAND_DEFAULT_TIMINGS;
|
||||||
* this macro allows us to convert from an MTD structure to our own
|
* this macro allows us to convert from an MTD structure to our own
|
||||||
* device context (denali) structure.
|
* device context (denali) structure.
|
||||||
*/
|
*/
|
||||||
#define mtd_to_denali(m) \
|
static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
|
||||||
container_of(mtd_to_nand(m), struct denali_nand_info, nand)
|
{
|
||||||
|
return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These constants are defined by the driver to enable common driver
|
* These constants are defined by the driver to enable common driver
|
||||||
|
@ -866,8 +868,7 @@ static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
* by write_page above.
|
* by write_page above.
|
||||||
*/
|
*/
|
||||||
static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
const uint8_t *buf, int oob_required,
|
const uint8_t *buf, int oob_required, int page)
|
||||||
int page)
|
|
||||||
{
|
{
|
||||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||||
|
|
||||||
|
@ -891,8 +892,8 @@ static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
* write_page() function above.
|
* write_page() function above.
|
||||||
*/
|
*/
|
||||||
static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
const uint8_t *buf, int oob_required,
|
const uint8_t *buf, int oob_required,
|
||||||
int page)
|
int page)
|
||||||
{
|
{
|
||||||
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
struct denali_nand_info *denali = mtd_to_denali(mtd);
|
||||||
|
|
||||||
|
@ -991,7 +992,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
debug(" ECC error cause by erased block\n");
|
debug(" ECC error cause by erased block\n");
|
||||||
/* false alarm, return the 0xFF */
|
/* false alarm, return the 0xFF */
|
||||||
} else {
|
} else {
|
||||||
return -EIO;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memcpy(buf, denali->buf.dma_buf, mtd->writesize);
|
memcpy(buf, denali->buf.dma_buf, mtd->writesize);
|
||||||
|
@ -1176,12 +1177,13 @@ static struct nand_ecclayout nand_oob;
|
||||||
|
|
||||||
static int denali_init(struct denali_nand_info *denali)
|
static int denali_init(struct denali_nand_info *denali)
|
||||||
{
|
{
|
||||||
|
struct mtd_info *mtd = nand_to_mtd(&denali->nand);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
denali_hw_init(denali);
|
denali_hw_init(denali);
|
||||||
|
|
||||||
denali->mtd->name = "denali-nand";
|
mtd->name = "denali-nand";
|
||||||
denali->mtd->owner = THIS_MODULE;
|
mtd->owner = THIS_MODULE;
|
||||||
|
|
||||||
/* register the driver with the NAND core subsystem */
|
/* register the driver with the NAND core subsystem */
|
||||||
denali->nand.select_chip = denali_select_chip;
|
denali->nand.select_chip = denali_select_chip;
|
||||||
|
@ -1195,7 +1197,7 @@ static int denali_init(struct denali_nand_info *denali)
|
||||||
* this is the first stage in a two step process to register
|
* this is the first stage in a two step process to register
|
||||||
* with the nand subsystem
|
* with the nand subsystem
|
||||||
*/
|
*/
|
||||||
if (nand_scan_ident(denali->mtd, denali->max_banks, NULL)) {
|
if (nand_scan_ident(mtd, denali->max_banks, NULL)) {
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -1241,13 +1243,13 @@ static int denali_init(struct denali_nand_info *denali)
|
||||||
nand_oob.eccbytes = denali->nand.ecc.bytes;
|
nand_oob.eccbytes = denali->nand.ecc.bytes;
|
||||||
denali->nand.ecc.layout = &nand_oob;
|
denali->nand.ecc.layout = &nand_oob;
|
||||||
|
|
||||||
writel(denali->mtd->erasesize / denali->mtd->writesize,
|
writel(mtd->erasesize / mtd->writesize,
|
||||||
denali->flash_reg + PAGES_PER_BLOCK);
|
denali->flash_reg + PAGES_PER_BLOCK);
|
||||||
writel(denali->nand.options & NAND_BUSWIDTH_16 ? 1 : 0,
|
writel(denali->nand.options & NAND_BUSWIDTH_16 ? 1 : 0,
|
||||||
denali->flash_reg + DEVICE_WIDTH);
|
denali->flash_reg + DEVICE_WIDTH);
|
||||||
writel(denali->mtd->writesize,
|
writel(mtd->writesize,
|
||||||
denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
|
denali->flash_reg + DEVICE_MAIN_AREA_SIZE);
|
||||||
writel(denali->mtd->oobsize,
|
writel(mtd->oobsize,
|
||||||
denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
|
denali->flash_reg + DEVICE_SPARE_AREA_SIZE);
|
||||||
if (readl(denali->flash_reg + DEVICES_CONNECTED) == 0)
|
if (readl(denali->flash_reg + DEVICES_CONNECTED) == 0)
|
||||||
writel(1, denali->flash_reg + DEVICES_CONNECTED);
|
writel(1, denali->flash_reg + DEVICES_CONNECTED);
|
||||||
|
@ -1260,12 +1262,12 @@ static int denali_init(struct denali_nand_info *denali)
|
||||||
denali->nand.ecc.read_oob = denali_read_oob;
|
denali->nand.ecc.read_oob = denali_read_oob;
|
||||||
denali->nand.ecc.write_oob = denali_write_oob;
|
denali->nand.ecc.write_oob = denali_write_oob;
|
||||||
|
|
||||||
if (nand_scan_tail(denali->mtd)) {
|
if (nand_scan_tail(mtd)) {
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = nand_register(0, denali->mtd);
|
ret = nand_register(0, mtd);
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1279,13 +1281,6 @@ static int __board_nand_init(void)
|
||||||
if (!denali)
|
if (!denali)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/*
|
|
||||||
* If CONFIG_SYS_NAND_SELF_INIT is defined, each driver is responsible
|
|
||||||
* for instantiating struct nand_chip, while drivers/mtd/nand/nand.c
|
|
||||||
* still provides a "struct mtd_info nand_info" instance.
|
|
||||||
*/
|
|
||||||
denali->mtd = &denali->nand.mtd;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the future, these base addresses should be taken from
|
* In the future, these base addresses should be taken from
|
||||||
* Device Tree or platform data.
|
* Device Tree or platform data.
|
||||||
|
|
|
@ -436,7 +436,6 @@ struct nand_buf {
|
||||||
#define DT 3
|
#define DT 3
|
||||||
|
|
||||||
struct denali_nand_info {
|
struct denali_nand_info {
|
||||||
struct mtd_info *mtd;
|
|
||||||
struct nand_chip nand;
|
struct nand_chip nand;
|
||||||
int flash_bank; /* currently selected chip */
|
int flash_bank; /* currently selected chip */
|
||||||
int status;
|
int status;
|
||||||
|
|
|
@ -41,7 +41,7 @@ static int wait_for_irq(uint32_t irq_mask)
|
||||||
|
|
||||||
if (intr_status & INTR_STATUS__ECC_UNCOR_ERR) {
|
if (intr_status & INTR_STATUS__ECC_UNCOR_ERR) {
|
||||||
debug("Uncorrected ECC detected\n");
|
debug("Uncorrected ECC detected\n");
|
||||||
return -EIO;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intr_status & irq_mask)
|
if (intr_status & irq_mask)
|
||||||
|
|
|
@ -100,7 +100,6 @@
|
||||||
#define NFC_WPC_UNLOCK (1 << 2)
|
#define NFC_WPC_UNLOCK (1 << 2)
|
||||||
|
|
||||||
struct mpc5121_nfc_prv {
|
struct mpc5121_nfc_prv {
|
||||||
struct mtd_info mtd;
|
|
||||||
struct nand_chip chip;
|
struct nand_chip chip;
|
||||||
int irq;
|
int irq;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#define DRIVER_NAME "mxc_nand"
|
#define DRIVER_NAME "mxc_nand"
|
||||||
|
|
||||||
struct mxc_nand_host {
|
struct mxc_nand_host {
|
||||||
struct mtd_info mtd;
|
|
||||||
struct nand_chip *nand;
|
struct nand_chip *nand;
|
||||||
|
|
||||||
struct mxc_nand_regs __iomem *regs;
|
struct mxc_nand_regs __iomem *regs;
|
||||||
|
@ -681,7 +680,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||||
mtd->writesize / nand_chip->subpagesize
|
mtd->writesize / nand_chip->subpagesize
|
||||||
- subpages);
|
- subpages);
|
||||||
}
|
}
|
||||||
return -1;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
ecc_status >>= 4;
|
ecc_status >>= 4;
|
||||||
subpages--;
|
subpages--;
|
||||||
|
@ -713,7 +712,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||||
if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
|
if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
|
||||||
MTDDEBUG(MTD_DEBUG_LEVEL0,
|
MTDDEBUG(MTD_DEBUG_LEVEL0,
|
||||||
"MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
|
"MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
|
||||||
return -1;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -232,7 +232,7 @@ static int nfc_read_page(unsigned int page_address, unsigned char *buf)
|
||||||
nfc_nand_read_page(page_address);
|
nfc_nand_read_page(page_address);
|
||||||
|
|
||||||
if (nfc_nand_check_ecc())
|
if (nfc_nand_check_ecc())
|
||||||
return -1;
|
return -EBADMSG;
|
||||||
|
|
||||||
src = (u32 *)&nfc->main_area[0][0];
|
src = (u32 *)&nfc->main_area[0][0];
|
||||||
dst = (u32 *)buf;
|
dst = (u32 *)buf;
|
||||||
|
|
|
@ -961,7 +961,7 @@ static int mxs_nand_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *nand,
|
||||||
* Thus, this function is only called when we want *all* blocks to look good,
|
* Thus, this function is only called when we want *all* blocks to look good,
|
||||||
* so it *always* return success.
|
* so it *always* return success.
|
||||||
*/
|
*/
|
||||||
static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* drivers/mtd/nand.c
|
|
||||||
*
|
|
||||||
* Overview:
|
* Overview:
|
||||||
* This is the generic MTD driver for NAND flash devices. It should be
|
* This is the generic MTD driver for NAND flash devices. It should be
|
||||||
* capable of working with almost all NAND chips currently available.
|
* capable of working with almost all NAND chips currently available.
|
||||||
|
@ -45,8 +43,6 @@
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/errno.h>
|
#include <asm/errno.h>
|
||||||
|
|
||||||
static bool is_module_text_address(unsigned long addr) {return 0;}
|
|
||||||
|
|
||||||
/* Define default oob placement schemes for large and small page devices */
|
/* Define default oob placement schemes for large and small page devices */
|
||||||
static struct nand_ecclayout nand_oob_8 = {
|
static struct nand_ecclayout nand_oob_8 = {
|
||||||
.eccbytes = 3,
|
.eccbytes = 3,
|
||||||
|
@ -343,13 +339,12 @@ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
|
||||||
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
|
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @ofs: offset from device start
|
* @ofs: offset from device start
|
||||||
* @getchip: 0, if the chip is already selected
|
|
||||||
*
|
*
|
||||||
* Check, if the block is bad.
|
* Check, if the block is bad.
|
||||||
*/
|
*/
|
||||||
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
|
||||||
{
|
{
|
||||||
int page, chipnr, res = 0, i = 0;
|
int page, res = 0, i = 0;
|
||||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
u16 bad;
|
u16 bad;
|
||||||
|
|
||||||
|
@ -358,15 +353,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||||
|
|
||||||
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
|
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
|
||||||
|
|
||||||
if (getchip) {
|
|
||||||
chipnr = (int)(ofs >> chip->chip_shift);
|
|
||||||
|
|
||||||
nand_get_device(mtd, FL_READING);
|
|
||||||
|
|
||||||
/* Select the NAND device */
|
|
||||||
chip->select_chip(mtd, chipnr);
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (chip->options & NAND_BUSWIDTH_16) {
|
if (chip->options & NAND_BUSWIDTH_16) {
|
||||||
chip->cmdfunc(mtd, NAND_CMD_READOOB,
|
chip->cmdfunc(mtd, NAND_CMD_READOOB,
|
||||||
|
@ -391,11 +377,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||||
i++;
|
i++;
|
||||||
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
|
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
|
||||||
|
|
||||||
if (getchip) {
|
|
||||||
chip->select_chip(mtd, -1);
|
|
||||||
nand_release_device(mtd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,14 +514,12 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
|
||||||
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
|
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @ofs: offset from device start
|
* @ofs: offset from device start
|
||||||
* @getchip: 0, if the chip is already selected
|
|
||||||
* @allowbbt: 1, if its allowed to access the bbt area
|
* @allowbbt: 1, if its allowed to access the bbt area
|
||||||
*
|
*
|
||||||
* Check, if the block is bad. Either by reading the bad block table or
|
* Check, if the block is bad. Either by reading the bad block table or
|
||||||
* calling of the scan function.
|
* calling of the scan function.
|
||||||
*/
|
*/
|
||||||
static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
|
static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
|
||||||
int allowbbt)
|
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
|
|
||||||
|
@ -551,17 +530,22 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!chip->bbt)
|
if (!chip->bbt)
|
||||||
return chip->block_bad(mtd, ofs, getchip);
|
return chip->block_bad(mtd, ofs);
|
||||||
|
|
||||||
/* Return info from the table */
|
/* Return info from the table */
|
||||||
return nand_isbad_bbt(mtd, ofs, allowbbt);
|
return nand_isbad_bbt(mtd, ofs, allowbbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for the ready pin, after a command. The timeout is caught later. */
|
/**
|
||||||
|
* nand_wait_ready - [GENERIC] Wait for the ready pin after commands.
|
||||||
|
* @mtd: MTD device structure
|
||||||
|
*
|
||||||
|
* Wait for the ready pin after a command, and warn if a timeout occurs.
|
||||||
|
*/
|
||||||
void nand_wait_ready(struct mtd_info *mtd)
|
void nand_wait_ready(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
u32 timeo = (CONFIG_SYS_HZ * 20) / 1000;
|
u32 timeo = (CONFIG_SYS_HZ * 400) / 1000;
|
||||||
u32 time_start;
|
u32 time_start;
|
||||||
|
|
||||||
time_start = get_timer(0);
|
time_start = get_timer(0);
|
||||||
|
@ -571,6 +555,9 @@ void nand_wait_ready(struct mtd_info *mtd)
|
||||||
if (chip->dev_ready(mtd))
|
if (chip->dev_ready(mtd))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!chip->dev_ready(mtd))
|
||||||
|
pr_warn("timeout while waiting for chip to become ready\n");
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nand_wait_ready);
|
EXPORT_SYMBOL_GPL(nand_wait_ready);
|
||||||
|
|
||||||
|
@ -871,15 +858,13 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
* @chip: NAND chip structure
|
* @chip: NAND chip structure
|
||||||
*
|
*
|
||||||
* Wait for command done. This applies to erase and program only. Erase can
|
* Wait for command done. This applies to erase and program only.
|
||||||
* take up to 400ms and program up to 20ms according to general NAND and
|
|
||||||
* SmartMedia specs.
|
|
||||||
*/
|
*/
|
||||||
static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
|
|
||||||
int status, state = chip->state;
|
int status;
|
||||||
unsigned long timeo = (state == FL_ERASING ? 400 : 20);
|
unsigned long timeo = 400;
|
||||||
|
|
||||||
led_trigger_event(nand_led_trigger, LED_FULL);
|
led_trigger_event(nand_led_trigger, LED_FULL);
|
||||||
|
|
||||||
|
@ -912,6 +897,135 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BITS_PER_BYTE 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nand_check_erased_buf - check if a buffer contains (almost) only 0xff data
|
||||||
|
* @buf: buffer to test
|
||||||
|
* @len: buffer length
|
||||||
|
* @bitflips_threshold: maximum number of bitflips
|
||||||
|
*
|
||||||
|
* Check if a buffer contains only 0xff, which means the underlying region
|
||||||
|
* has been erased and is ready to be programmed.
|
||||||
|
* The bitflips_threshold specify the maximum number of bitflips before
|
||||||
|
* considering the region is not erased.
|
||||||
|
* Note: The logic of this function has been extracted from the memweight
|
||||||
|
* implementation, except that nand_check_erased_buf function exit before
|
||||||
|
* testing the whole buffer if the number of bitflips exceed the
|
||||||
|
* bitflips_threshold value.
|
||||||
|
*
|
||||||
|
* Returns a positive number of bitflips less than or equal to
|
||||||
|
* bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
|
||||||
|
* threshold.
|
||||||
|
*/
|
||||||
|
static int nand_check_erased_buf(void *buf, int len, int bitflips_threshold)
|
||||||
|
{
|
||||||
|
const unsigned char *bitmap = buf;
|
||||||
|
int bitflips = 0;
|
||||||
|
int weight;
|
||||||
|
|
||||||
|
for (; len && ((uintptr_t)bitmap) % sizeof(long);
|
||||||
|
len--, bitmap++) {
|
||||||
|
weight = hweight8(*bitmap);
|
||||||
|
bitflips += BITS_PER_BYTE - weight;
|
||||||
|
if (unlikely(bitflips > bitflips_threshold))
|
||||||
|
return -EBADMSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; len >= 4; len -= 4, bitmap += 4) {
|
||||||
|
weight = hweight32(*((u32 *)bitmap));
|
||||||
|
bitflips += 32 - weight;
|
||||||
|
if (unlikely(bitflips > bitflips_threshold))
|
||||||
|
return -EBADMSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; len > 0; len--, bitmap++) {
|
||||||
|
weight = hweight8(*bitmap);
|
||||||
|
bitflips += BITS_PER_BYTE - weight;
|
||||||
|
if (unlikely(bitflips > bitflips_threshold))
|
||||||
|
return -EBADMSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitflips;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nand_check_erased_ecc_chunk - check if an ECC chunk contains (almost) only
|
||||||
|
* 0xff data
|
||||||
|
* @data: data buffer to test
|
||||||
|
* @datalen: data length
|
||||||
|
* @ecc: ECC buffer
|
||||||
|
* @ecclen: ECC length
|
||||||
|
* @extraoob: extra OOB buffer
|
||||||
|
* @extraooblen: extra OOB length
|
||||||
|
* @bitflips_threshold: maximum number of bitflips
|
||||||
|
*
|
||||||
|
* Check if a data buffer and its associated ECC and OOB data contains only
|
||||||
|
* 0xff pattern, which means the underlying region has been erased and is
|
||||||
|
* ready to be programmed.
|
||||||
|
* The bitflips_threshold specify the maximum number of bitflips before
|
||||||
|
* considering the region as not erased.
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* 1/ ECC algorithms are working on pre-defined block sizes which are usually
|
||||||
|
* different from the NAND page size. When fixing bitflips, ECC engines will
|
||||||
|
* report the number of errors per chunk, and the NAND core infrastructure
|
||||||
|
* expect you to return the maximum number of bitflips for the whole page.
|
||||||
|
* This is why you should always use this function on a single chunk and
|
||||||
|
* not on the whole page. After checking each chunk you should update your
|
||||||
|
* max_bitflips value accordingly.
|
||||||
|
* 2/ When checking for bitflips in erased pages you should not only check
|
||||||
|
* the payload data but also their associated ECC data, because a user might
|
||||||
|
* have programmed almost all bits to 1 but a few. In this case, we
|
||||||
|
* shouldn't consider the chunk as erased, and checking ECC bytes prevent
|
||||||
|
* this case.
|
||||||
|
* 3/ The extraoob argument is optional, and should be used if some of your OOB
|
||||||
|
* data are protected by the ECC engine.
|
||||||
|
* It could also be used if you support subpages and want to attach some
|
||||||
|
* extra OOB data to an ECC chunk.
|
||||||
|
*
|
||||||
|
* Returns a positive number of bitflips less than or equal to
|
||||||
|
* bitflips_threshold, or -ERROR_CODE for bitflips in excess of the
|
||||||
|
* threshold. In case of success, the passed buffers are filled with 0xff.
|
||||||
|
*/
|
||||||
|
int nand_check_erased_ecc_chunk(void *data, int datalen,
|
||||||
|
void *ecc, int ecclen,
|
||||||
|
void *extraoob, int extraooblen,
|
||||||
|
int bitflips_threshold)
|
||||||
|
{
|
||||||
|
int data_bitflips = 0, ecc_bitflips = 0, extraoob_bitflips = 0;
|
||||||
|
|
||||||
|
data_bitflips = nand_check_erased_buf(data, datalen,
|
||||||
|
bitflips_threshold);
|
||||||
|
if (data_bitflips < 0)
|
||||||
|
return data_bitflips;
|
||||||
|
|
||||||
|
bitflips_threshold -= data_bitflips;
|
||||||
|
|
||||||
|
ecc_bitflips = nand_check_erased_buf(ecc, ecclen, bitflips_threshold);
|
||||||
|
if (ecc_bitflips < 0)
|
||||||
|
return ecc_bitflips;
|
||||||
|
|
||||||
|
bitflips_threshold -= ecc_bitflips;
|
||||||
|
|
||||||
|
extraoob_bitflips = nand_check_erased_buf(extraoob, extraooblen,
|
||||||
|
bitflips_threshold);
|
||||||
|
if (extraoob_bitflips < 0)
|
||||||
|
return extraoob_bitflips;
|
||||||
|
|
||||||
|
if (data_bitflips)
|
||||||
|
memset(data, 0xff, datalen);
|
||||||
|
|
||||||
|
if (ecc_bitflips)
|
||||||
|
memset(ecc, 0xff, ecclen);
|
||||||
|
|
||||||
|
if (extraoob_bitflips)
|
||||||
|
memset(extraoob, 0xff, extraooblen);
|
||||||
|
|
||||||
|
return data_bitflips + ecc_bitflips + extraoob_bitflips;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(nand_check_erased_ecc_chunk);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_read_page_raw - [INTERN] read raw page data without ecc
|
* nand_read_page_raw - [INTERN] read raw page data without ecc
|
||||||
* @mtd: mtd info structure
|
* @mtd: mtd info structure
|
||||||
|
@ -1103,6 +1217,16 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
|
|
||||||
stat = chip->ecc.correct(mtd, p,
|
stat = chip->ecc.correct(mtd, p,
|
||||||
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
|
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
|
||||||
|
if (stat == -EBADMSG &&
|
||||||
|
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
|
||||||
|
/* check for empty pages with bitflips */
|
||||||
|
stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
|
||||||
|
&chip->buffers->ecccode[i],
|
||||||
|
chip->ecc.bytes,
|
||||||
|
NULL, 0,
|
||||||
|
chip->ecc.strength);
|
||||||
|
}
|
||||||
|
|
||||||
if (stat < 0) {
|
if (stat < 0) {
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1152,6 +1276,15 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
int stat;
|
int stat;
|
||||||
|
|
||||||
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
|
||||||
|
if (stat == -EBADMSG &&
|
||||||
|
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
|
||||||
|
/* check for empty pages with bitflips */
|
||||||
|
stat = nand_check_erased_ecc_chunk(p, eccsize,
|
||||||
|
&ecc_code[i], eccbytes,
|
||||||
|
NULL, 0,
|
||||||
|
chip->ecc.strength);
|
||||||
|
}
|
||||||
|
|
||||||
if (stat < 0) {
|
if (stat < 0) {
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1204,6 +1337,15 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
|
||||||
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
|
||||||
|
|
||||||
stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
|
stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);
|
||||||
|
if (stat == -EBADMSG &&
|
||||||
|
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
|
||||||
|
/* check for empty pages with bitflips */
|
||||||
|
stat = nand_check_erased_ecc_chunk(p, eccsize,
|
||||||
|
&ecc_code[i], eccbytes,
|
||||||
|
NULL, 0,
|
||||||
|
chip->ecc.strength);
|
||||||
|
}
|
||||||
|
|
||||||
if (stat < 0) {
|
if (stat < 0) {
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1231,6 +1373,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
int i, eccsize = chip->ecc.size;
|
int i, eccsize = chip->ecc.size;
|
||||||
int eccbytes = chip->ecc.bytes;
|
int eccbytes = chip->ecc.bytes;
|
||||||
int eccsteps = chip->ecc.steps;
|
int eccsteps = chip->ecc.steps;
|
||||||
|
int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad;
|
||||||
uint8_t *p = buf;
|
uint8_t *p = buf;
|
||||||
uint8_t *oob = chip->oob_poi;
|
uint8_t *oob = chip->oob_poi;
|
||||||
unsigned int max_bitflips = 0;
|
unsigned int max_bitflips = 0;
|
||||||
|
@ -1250,19 +1393,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
chip->read_buf(mtd, oob, eccbytes);
|
chip->read_buf(mtd, oob, eccbytes);
|
||||||
stat = chip->ecc.correct(mtd, p, oob, NULL);
|
stat = chip->ecc.correct(mtd, p, oob, NULL);
|
||||||
|
|
||||||
if (stat < 0) {
|
|
||||||
mtd->ecc_stats.failed++;
|
|
||||||
} else {
|
|
||||||
mtd->ecc_stats.corrected += stat;
|
|
||||||
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
|
||||||
}
|
|
||||||
|
|
||||||
oob += eccbytes;
|
oob += eccbytes;
|
||||||
|
|
||||||
if (chip->ecc.postpad) {
|
if (chip->ecc.postpad) {
|
||||||
chip->read_buf(mtd, oob, chip->ecc.postpad);
|
chip->read_buf(mtd, oob, chip->ecc.postpad);
|
||||||
oob += chip->ecc.postpad;
|
oob += chip->ecc.postpad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stat == -EBADMSG &&
|
||||||
|
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
|
||||||
|
/* check for empty pages with bitflips */
|
||||||
|
stat = nand_check_erased_ecc_chunk(p, chip->ecc.size,
|
||||||
|
oob - eccpadbytes,
|
||||||
|
eccpadbytes,
|
||||||
|
NULL, 0,
|
||||||
|
chip->ecc.strength);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat < 0) {
|
||||||
|
mtd->ecc_stats.failed++;
|
||||||
|
} else {
|
||||||
|
mtd->ecc_stats.corrected += stat;
|
||||||
|
max_bitflips = max_t(unsigned int, max_bitflips, stat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate remaining oob bytes */
|
/* Calculate remaining oob bytes */
|
||||||
|
@ -1361,8 +1514,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
uint32_t readlen = ops->len;
|
uint32_t readlen = ops->len;
|
||||||
uint32_t oobreadlen = ops->ooblen;
|
uint32_t oobreadlen = ops->ooblen;
|
||||||
uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ?
|
uint32_t max_oobsize = mtd_oobavail(mtd, ops);
|
||||||
mtd->oobavail : mtd->oobsize;
|
|
||||||
|
|
||||||
uint8_t *bufpoi, *oob, *buf;
|
uint8_t *bufpoi, *oob, *buf;
|
||||||
int use_bufpoi;
|
int use_bufpoi;
|
||||||
|
@ -1712,10 +1864,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
|
||||||
|
|
||||||
stats = mtd->ecc_stats;
|
stats = mtd->ecc_stats;
|
||||||
|
|
||||||
if (ops->mode == MTD_OPS_AUTO_OOB)
|
len = mtd_oobavail(mtd, ops);
|
||||||
len = chip->ecc.layout->oobavail;
|
|
||||||
else
|
|
||||||
len = mtd->oobsize;
|
|
||||||
|
|
||||||
if (unlikely(ops->ooboffs >= len)) {
|
if (unlikely(ops->ooboffs >= len)) {
|
||||||
pr_debug("%s: attempt to start read outside oob\n",
|
pr_debug("%s: attempt to start read outside oob\n",
|
||||||
|
@ -1845,8 +1994,7 @@ out:
|
||||||
* Not for syndrome calculating ECC controllers, which use a special oob layout.
|
* Not for syndrome calculating ECC controllers, which use a special oob layout.
|
||||||
*/
|
*/
|
||||||
static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
const uint8_t *buf, int oob_required,
|
const uint8_t *buf, int oob_required, int page)
|
||||||
int page)
|
|
||||||
{
|
{
|
||||||
chip->write_buf(mtd, buf, mtd->writesize);
|
chip->write_buf(mtd, buf, mtd->writesize);
|
||||||
if (oob_required)
|
if (oob_required)
|
||||||
|
@ -1861,6 +2009,7 @@ static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
* @chip: nand chip info structure
|
* @chip: nand chip info structure
|
||||||
* @buf: data buffer
|
* @buf: data buffer
|
||||||
* @oob_required: must write chip->oob_poi to OOB
|
* @oob_required: must write chip->oob_poi to OOB
|
||||||
|
* @page: page number to write
|
||||||
*
|
*
|
||||||
* We need a special oob layout and handling even when ECC isn't checked.
|
* We need a special oob layout and handling even when ECC isn't checked.
|
||||||
*/
|
*/
|
||||||
|
@ -1907,8 +2056,8 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
|
||||||
* @page: page number to write
|
* @page: page number to write
|
||||||
*/
|
*/
|
||||||
static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
const uint8_t *buf, int oob_required,
|
const uint8_t *buf, int oob_required,
|
||||||
int page)
|
int page)
|
||||||
{
|
{
|
||||||
int i, eccsize = chip->ecc.size;
|
int i, eccsize = chip->ecc.size;
|
||||||
int eccbytes = chip->ecc.bytes;
|
int eccbytes = chip->ecc.bytes;
|
||||||
|
@ -2029,6 +2178,7 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
|
||||||
* @chip: nand chip info structure
|
* @chip: nand chip info structure
|
||||||
* @buf: data buffer
|
* @buf: data buffer
|
||||||
* @oob_required: must write chip->oob_poi to OOB
|
* @oob_required: must write chip->oob_poi to OOB
|
||||||
|
* @page: page number to write
|
||||||
*
|
*
|
||||||
* The hw generator calculates the error syndrome automatically. Therefore we
|
* The hw generator calculates the error syndrome automatically. Therefore we
|
||||||
* need a special oob layout and handling.
|
* need a special oob layout and handling.
|
||||||
|
@ -2103,7 +2253,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
oob_required, page);
|
oob_required, page);
|
||||||
else if (subpage)
|
else if (subpage)
|
||||||
status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
|
status = chip->ecc.write_subpage(mtd, chip, offset, data_len,
|
||||||
buf, oob_required, page);
|
buf, oob_required, page);
|
||||||
else
|
else
|
||||||
status = chip->ecc.write_page(mtd, chip, buf, oob_required,
|
status = chip->ecc.write_page(mtd, chip, buf, oob_required,
|
||||||
page);
|
page);
|
||||||
|
@ -2145,7 +2295,6 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
* @oob: oob data buffer
|
* @oob: oob data buffer
|
||||||
* @len: oob data write length
|
* @len: oob data write length
|
||||||
* @ops: oob ops structure
|
* @ops: oob ops structure
|
||||||
* @page: page number to write
|
|
||||||
*/
|
*/
|
||||||
static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
|
static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len,
|
||||||
struct mtd_oob_ops *ops)
|
struct mtd_oob_ops *ops)
|
||||||
|
@ -2214,8 +2363,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
|
||||||
uint32_t writelen = ops->len;
|
uint32_t writelen = ops->len;
|
||||||
|
|
||||||
uint32_t oobwritelen = ops->ooblen;
|
uint32_t oobwritelen = ops->ooblen;
|
||||||
uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ?
|
uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
|
||||||
mtd->oobavail : mtd->oobsize;
|
|
||||||
|
|
||||||
uint8_t *oob = ops->oobbuf;
|
uint8_t *oob = ops->oobbuf;
|
||||||
uint8_t *buf = ops->datbuf;
|
uint8_t *buf = ops->datbuf;
|
||||||
|
@ -2404,10 +2552,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
|
||||||
pr_debug("%s: to = 0x%08x, len = %i\n",
|
pr_debug("%s: to = 0x%08x, len = %i\n",
|
||||||
__func__, (unsigned int)to, (int)ops->ooblen);
|
__func__, (unsigned int)to, (int)ops->ooblen);
|
||||||
|
|
||||||
if (ops->mode == MTD_OPS_AUTO_OOB)
|
len = mtd_oobavail(mtd, ops);
|
||||||
len = chip->ecc.layout->oobavail;
|
|
||||||
else
|
|
||||||
len = mtd->oobsize;
|
|
||||||
|
|
||||||
/* Do not allow write past end of page */
|
/* Do not allow write past end of page */
|
||||||
if ((ops->ooboffs + ops->ooblen) > len) {
|
if ((ops->ooboffs + ops->ooblen) > len) {
|
||||||
|
@ -2597,7 +2742,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
|
||||||
|
|
||||||
/* Check if we have a bad block, we do not erase bad blocks! */
|
/* Check if we have a bad block, we do not erase bad blocks! */
|
||||||
if (!instr->scrub && 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, allowbbt)) {
|
||||||
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
|
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
|
||||||
__func__, page);
|
__func__, page);
|
||||||
instr->state = MTD_ERASE_FAILED;
|
instr->state = MTD_ERASE_FAILED;
|
||||||
|
@ -2684,7 +2829,20 @@ static void nand_sync(struct mtd_info *mtd)
|
||||||
*/
|
*/
|
||||||
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
|
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
|
||||||
{
|
{
|
||||||
return nand_block_checkbad(mtd, offs, 1, 0);
|
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||||
|
int chipnr = (int)(offs >> chip->chip_shift);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Select the NAND device */
|
||||||
|
nand_get_device(mtd, FL_READING);
|
||||||
|
chip->select_chip(mtd, chipnr);
|
||||||
|
|
||||||
|
ret = nand_block_checkbad(mtd, offs, 0);
|
||||||
|
|
||||||
|
chip->select_chip(mtd, -1);
|
||||||
|
nand_release_device(mtd);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2756,9 +2914,6 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* clear the sub feature parameters */
|
|
||||||
memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
|
|
||||||
|
|
||||||
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
|
chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
|
||||||
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
|
for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
|
||||||
*subfeature_param++ = chip->read_byte(mtd);
|
*subfeature_param++ = chip->read_byte(mtd);
|
||||||
|
@ -3491,7 +3646,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
if (find_full_id_nand(mtd, chip, type, id_data, &busw))
|
if (find_full_id_nand(mtd, chip, type, id_data, &busw))
|
||||||
goto ident_done;
|
goto ident_done;
|
||||||
} else if (*dev_id == type->dev_id) {
|
} else if (*dev_id == type->dev_id) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3514,10 +3669,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
|
|
||||||
chip->chipsize = (uint64_t)type->chipsize << 20;
|
chip->chipsize = (uint64_t)type->chipsize << 20;
|
||||||
|
|
||||||
if (!type->pagesize && chip->init_size) {
|
if (!type->pagesize) {
|
||||||
/* Set the pagesize, oobsize, erasesize by the driver */
|
|
||||||
busw = chip->init_size(mtd, chip, id_data);
|
|
||||||
} else if (!type->pagesize) {
|
|
||||||
/* Decode parameters from extended ID */
|
/* Decode parameters from extended ID */
|
||||||
nand_decode_ext_id(mtd, chip, id_data, &busw);
|
nand_decode_ext_id(mtd, chip, id_data, &busw);
|
||||||
} else {
|
} else {
|
||||||
|
@ -3621,7 +3773,6 @@ ident_done:
|
||||||
* This is the first phase of the normal nand_scan() function. It reads the
|
* This is the first phase of the normal nand_scan() function. It reads the
|
||||||
* flash ID and sets up MTD fields accordingly.
|
* flash ID and sets up MTD fields accordingly.
|
||||||
*
|
*
|
||||||
* The mtd->owner field must be set to the module of the caller.
|
|
||||||
*/
|
*/
|
||||||
int nand_scan_ident(struct mtd_info *mtd, int maxchips,
|
int nand_scan_ident(struct mtd_info *mtd, int maxchips,
|
||||||
struct nand_flash_dev *table)
|
struct nand_flash_dev *table)
|
||||||
|
@ -3797,7 +3948,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||||
ecc->write_oob = nand_write_oob_std;
|
ecc->write_oob = nand_write_oob_std;
|
||||||
if (!ecc->read_subpage)
|
if (!ecc->read_subpage)
|
||||||
ecc->read_subpage = nand_read_subpage;
|
ecc->read_subpage = nand_read_subpage;
|
||||||
if (!ecc->write_subpage)
|
if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
|
||||||
ecc->write_subpage = nand_write_subpage_hwecc;
|
ecc->write_subpage = nand_write_subpage_hwecc;
|
||||||
|
|
||||||
case NAND_ECC_HW_SYNDROME:
|
case NAND_ECC_HW_SYNDROME:
|
||||||
|
@ -3875,10 +4026,8 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See nand_bch_init() for details. */
|
/* See nand_bch_init() for details. */
|
||||||
ecc->bytes = DIV_ROUND_UP(
|
ecc->bytes = 0;
|
||||||
ecc->strength * fls(8 * ecc->size), 8);
|
ecc->priv = nand_bch_init(mtd);
|
||||||
ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
|
|
||||||
&ecc->layout);
|
|
||||||
if (!ecc->priv) {
|
if (!ecc->priv) {
|
||||||
pr_warn("BCH ECC initialization failed!\n");
|
pr_warn("BCH ECC initialization failed!\n");
|
||||||
BUG();
|
BUG();
|
||||||
|
@ -3913,11 +4062,11 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||||
* The number of bytes available for a client to place data into
|
* The number of bytes available for a client to place data into
|
||||||
* the out of band area.
|
* the out of band area.
|
||||||
*/
|
*/
|
||||||
ecc->layout->oobavail = 0;
|
mtd->oobavail = 0;
|
||||||
for (i = 0; ecc->layout->oobfree[i].length
|
if (ecc->layout) {
|
||||||
&& i < ARRAY_SIZE(ecc->layout->oobfree); i++)
|
for (i = 0; ecc->layout->oobfree[i].length; i++)
|
||||||
ecc->layout->oobavail += ecc->layout->oobfree[i].length;
|
mtd->oobavail += ecc->layout->oobfree[i].length;
|
||||||
mtd->oobavail = ecc->layout->oobavail;
|
}
|
||||||
|
|
||||||
/* ECC sanity check: warn if it's too weak */
|
/* ECC sanity check: warn if it's too weak */
|
||||||
if (!nand_ecc_strength_good(mtd))
|
if (!nand_ecc_strength_good(mtd))
|
||||||
|
@ -4002,18 +4151,6 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(nand_scan_tail);
|
EXPORT_SYMBOL(nand_scan_tail);
|
||||||
|
|
||||||
/*
|
|
||||||
* is_module_text_address() isn't exported, and it's mostly a pointless
|
|
||||||
* test if this is a module _anyway_ -- they'd have to try _really_ hard
|
|
||||||
* to call us from in-kernel code if the core NAND support is modular.
|
|
||||||
*/
|
|
||||||
#ifdef MODULE
|
|
||||||
#define caller_is_module() (1)
|
|
||||||
#else
|
|
||||||
#define caller_is_module() \
|
|
||||||
is_module_text_address((unsigned long)__builtin_return_address(0))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_scan - [NAND Interface] Scan for the NAND device
|
* nand_scan - [NAND Interface] Scan for the NAND device
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
|
@ -4021,19 +4158,12 @@ EXPORT_SYMBOL(nand_scan_tail);
|
||||||
*
|
*
|
||||||
* This fills out all the uninitialized function pointers with the defaults.
|
* This fills out all the uninitialized function pointers with the defaults.
|
||||||
* The flash ID is read and the mtd/chip structures are filled with the
|
* The flash ID is read and the mtd/chip structures are filled with the
|
||||||
* appropriate values. The mtd->owner field must be set to the module of the
|
* appropriate values.
|
||||||
* caller.
|
|
||||||
*/
|
*/
|
||||||
int nand_scan(struct mtd_info *mtd, int maxchips)
|
int nand_scan(struct mtd_info *mtd, int maxchips)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Many callers got this wrong, so check for it for a while... */
|
|
||||||
if (!mtd->owner && caller_is_module()) {
|
|
||||||
pr_crit("%s called with NULL mtd->owner!\n", __func__);
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = nand_scan_ident(mtd, maxchips, NULL);
|
ret = nand_scan_ident(mtd, maxchips, NULL);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = nand_scan_tail(mtd);
|
ret = nand_scan_tail(mtd);
|
||||||
|
@ -4041,9 +4171,6 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(nand_scan);
|
EXPORT_SYMBOL(nand_scan);
|
||||||
|
|
||||||
module_init(nand_base_init);
|
|
||||||
module_exit(nand_base_exit);
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
|
MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>");
|
||||||
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
|
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* drivers/mtd/nand_bbt.c
|
|
||||||
*
|
|
||||||
* Overview:
|
* Overview:
|
||||||
* Bad block table support for the NAND driver
|
* Bad block table support for the NAND driver
|
||||||
*
|
*
|
||||||
|
@ -65,7 +63,6 @@
|
||||||
#include <linux/mtd/mtd.h>
|
#include <linux/mtd/mtd.h>
|
||||||
#include <linux/mtd/bbm.h>
|
#include <linux/mtd/bbm.h>
|
||||||
#include <linux/mtd/nand.h>
|
#include <linux/mtd/nand.h>
|
||||||
#include <linux/mtd/nand_ecc.h>
|
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
|
|
||||||
|
@ -718,7 +715,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
|
||||||
/* Must we save the block contents? */
|
/* Must we save the block contents? */
|
||||||
if (td->options & NAND_BBT_SAVECONTENT) {
|
if (td->options & NAND_BBT_SAVECONTENT) {
|
||||||
/* Make it block aligned */
|
/* Make it block aligned */
|
||||||
to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1));
|
to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1);
|
||||||
len = 1 << this->bbt_erase_shift;
|
len = 1 << this->bbt_erase_shift;
|
||||||
res = mtd_read(mtd, to, len, &retlen, buf);
|
res = mtd_read(mtd, to, len, &retlen, buf);
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
|
@ -1073,15 +1070,15 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||||
* The bad block table memory is allocated here. It must be freed by calling
|
* The bad block table memory is allocated here. It must be freed by calling
|
||||||
* the nand_free_bbt function.
|
* the nand_free_bbt function.
|
||||||
*/
|
*/
|
||||||
int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd_to_nand(mtd);
|
struct nand_chip *this = mtd_to_nand(mtd);
|
||||||
int len, res = 0;
|
int len, res;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
struct nand_bbt_descr *td = this->bbt_td;
|
struct nand_bbt_descr *td = this->bbt_td;
|
||||||
struct nand_bbt_descr *md = this->bbt_md;
|
struct nand_bbt_descr *md = this->bbt_md;
|
||||||
|
|
||||||
len = mtd->size >> (this->bbt_erase_shift + 2);
|
len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1;
|
||||||
/*
|
/*
|
||||||
* Allocate memory (2bit per block) and clear the memory bad block
|
* Allocate memory (2bit per block) and clear the memory bad block
|
||||||
* table.
|
* table.
|
||||||
|
@ -1097,10 +1094,9 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||||
if (!td) {
|
if (!td) {
|
||||||
if ((res = nand_memory_bbt(mtd, bd))) {
|
if ((res = nand_memory_bbt(mtd, bd))) {
|
||||||
pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
|
pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
|
||||||
kfree(this->bbt);
|
goto err;
|
||||||
this->bbt = NULL;
|
|
||||||
}
|
}
|
||||||
return res;
|
return 0;
|
||||||
}
|
}
|
||||||
verify_bbt_descr(mtd, td);
|
verify_bbt_descr(mtd, td);
|
||||||
verify_bbt_descr(mtd, md);
|
verify_bbt_descr(mtd, md);
|
||||||
|
@ -1110,9 +1106,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||||
len += (len >> this->page_shift) * mtd->oobsize;
|
len += (len >> this->page_shift) * mtd->oobsize;
|
||||||
buf = vmalloc(len);
|
buf = vmalloc(len);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
kfree(this->bbt);
|
res = -ENOMEM;
|
||||||
this->bbt = NULL;
|
goto err;
|
||||||
return -ENOMEM;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is the bbt at a given page? */
|
/* Is the bbt at a given page? */
|
||||||
|
@ -1124,6 +1119,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||||
}
|
}
|
||||||
|
|
||||||
res = check_create(mtd, buf, bd);
|
res = check_create(mtd, buf, bd);
|
||||||
|
if (res)
|
||||||
|
goto err;
|
||||||
|
|
||||||
/* Prevent the bbt regions from erasing / writing */
|
/* Prevent the bbt regions from erasing / writing */
|
||||||
mark_bbt_region(mtd, td);
|
mark_bbt_region(mtd, td);
|
||||||
|
@ -1131,6 +1128,11 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
|
||||||
mark_bbt_region(mtd, md);
|
mark_bbt_region(mtd, md);
|
||||||
|
|
||||||
vfree(buf);
|
vfree(buf);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
kfree(this->bbt);
|
||||||
|
this->bbt = NULL;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1369,5 +1371,3 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(nand_scan_bbt);
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||||
}
|
}
|
||||||
} else if (count < 0) {
|
} else if (count < 0) {
|
||||||
printk(KERN_ERR "ecc unrecoverable error\n");
|
printk(KERN_ERR "ecc unrecoverable error\n");
|
||||||
count = -1;
|
count = -EBADMSG;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -94,9 +94,6 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||||
/**
|
/**
|
||||||
* nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
|
* nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
|
||||||
* @mtd: MTD block structure
|
* @mtd: MTD block structure
|
||||||
* @eccsize: ecc block size in bytes
|
|
||||||
* @eccbytes: ecc length in bytes
|
|
||||||
* @ecclayout: output default layout
|
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* a pointer to a new NAND BCH control structure, or NULL upon failure
|
* a pointer to a new NAND BCH control structure, or NULL upon failure
|
||||||
|
@ -110,14 +107,21 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||||
* @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
|
* @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
|
||||||
* @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
|
* @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
|
||||||
*/
|
*/
|
||||||
struct nand_bch_control *
|
struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
|
||||||
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
|
|
||||||
struct nand_ecclayout **ecclayout)
|
|
||||||
{
|
{
|
||||||
|
struct nand_chip *nand = mtd_to_nand(mtd);
|
||||||
unsigned int m, t, eccsteps, i;
|
unsigned int m, t, eccsteps, i;
|
||||||
struct nand_ecclayout *layout;
|
struct nand_ecclayout *layout = nand->ecc.layout;
|
||||||
struct nand_bch_control *nbc = NULL;
|
struct nand_bch_control *nbc = NULL;
|
||||||
unsigned char *erased_page;
|
unsigned char *erased_page;
|
||||||
|
unsigned int eccsize = nand->ecc.size;
|
||||||
|
unsigned int eccbytes = nand->ecc.bytes;
|
||||||
|
unsigned int eccstrength = nand->ecc.strength;
|
||||||
|
|
||||||
|
if (!eccbytes && eccstrength) {
|
||||||
|
eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
|
||||||
|
nand->ecc.bytes = eccbytes;
|
||||||
|
}
|
||||||
|
|
||||||
if (!eccsize || !eccbytes) {
|
if (!eccsize || !eccbytes) {
|
||||||
printk(KERN_WARNING "ecc parameters not supplied\n");
|
printk(KERN_WARNING "ecc parameters not supplied\n");
|
||||||
|
@ -145,7 +149,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
|
||||||
eccsteps = mtd->writesize/eccsize;
|
eccsteps = mtd->writesize/eccsize;
|
||||||
|
|
||||||
/* if no ecc placement scheme was provided, build one */
|
/* if no ecc placement scheme was provided, build one */
|
||||||
if (!*ecclayout) {
|
if (!layout) {
|
||||||
|
|
||||||
/* handle large page devices only */
|
/* handle large page devices only */
|
||||||
if (mtd->oobsize < 64) {
|
if (mtd->oobsize < 64) {
|
||||||
|
@ -171,7 +175,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
|
||||||
layout->oobfree[0].offset = 2;
|
layout->oobfree[0].offset = 2;
|
||||||
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
|
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
|
||||||
|
|
||||||
*ecclayout = layout;
|
nand->ecc.layout = layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sanity checks */
|
/* sanity checks */
|
||||||
|
@ -179,7 +183,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
|
||||||
printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
|
printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
|
if (layout->eccbytes != (eccsteps*eccbytes)) {
|
||||||
printk(KERN_WARNING "invalid ecc layout\n");
|
printk(KERN_WARNING "invalid ecc layout\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -203,6 +207,9 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
|
||||||
for (i = 0; i < eccbytes; i++)
|
for (i = 0; i < eccbytes; i++)
|
||||||
nbc->eccmask[i] ^= 0xff;
|
nbc->eccmask[i] ^= 0xff;
|
||||||
|
|
||||||
|
if (!eccstrength)
|
||||||
|
nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
|
||||||
|
|
||||||
return nbc;
|
return nbc;
|
||||||
fail:
|
fail:
|
||||||
nand_bch_free(nbc);
|
nand_bch_free(nbc);
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* drivers/mtd/nandids.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
|
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -41,6 +39,10 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||||
* listed by full ID. We list them first so that we can easily identify
|
* listed by full ID. We list them first so that we can easily identify
|
||||||
* the most specific match.
|
* the most specific match.
|
||||||
*/
|
*/
|
||||||
|
{"TC58NVG0S3E 1G 3.3V 8-bit",
|
||||||
|
{ .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} },
|
||||||
|
SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512),
|
||||||
|
2 },
|
||||||
{"TC58NVG2S0F 4G 3.3V 8-bit",
|
{"TC58NVG2S0F 4G 3.3V 8-bit",
|
||||||
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
|
{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
|
||||||
SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
|
SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
|
||||||
|
@ -58,8 +60,8 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||||
SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
|
SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
|
||||||
{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
|
{"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
|
||||||
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
|
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
|
||||||
SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
|
SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
|
||||||
4 },
|
NAND_ECC_INFO(40, SZ_1K), 4 },
|
||||||
|
|
||||||
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
|
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
|
||||||
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
|
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Overview:
|
* Overview:
|
||||||
* Platform independend driver for NDFC (NanD Flash Controller)
|
* Platform independent driver for NDFC (NanD Flash Controller)
|
||||||
* integrated into IBM/AMCC PPC4xx cores
|
* integrated into IBM/AMCC PPC4xx cores
|
||||||
*
|
*
|
||||||
* (C) Copyright 2006-2009
|
* (C) Copyright 2006-2009
|
||||||
|
|
|
@ -163,7 +163,7 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
|
||||||
return 0;
|
return 0;
|
||||||
printf("Error: Bad compare! failed\n");
|
printf("Error: Bad compare! failed\n");
|
||||||
/* detected 2 bit error */
|
/* detected 2 bit error */
|
||||||
return -1;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -104,7 +104,7 @@ static int s3c24x0_nand_correct_data(struct mtd_info *mtd, u_char *dat,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
printf("s3c24x0_nand_correct_data: not implemented\n");
|
printf("s3c24x0_nand_correct_data: not implemented\n");
|
||||||
return -1;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,6 @@ enum vf610_nfc_alt_buf {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vf610_nfc {
|
struct vf610_nfc {
|
||||||
struct mtd_info *mtd;
|
|
||||||
struct nand_chip chip;
|
struct nand_chip chip;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
uint buf_offset;
|
uint buf_offset;
|
||||||
|
|
|
@ -278,6 +278,11 @@ struct mtd_info {
|
||||||
int usecount;
|
int usecount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline int mtd_oobavail(struct mtd_info *mtd, struct mtd_oob_ops *ops)
|
||||||
|
{
|
||||||
|
return ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize;
|
||||||
|
}
|
||||||
|
|
||||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
|
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
|
||||||
#ifndef __UBOOT__
|
#ifndef __UBOOT__
|
||||||
int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
struct mtd_info;
|
struct mtd_info;
|
||||||
struct nand_flash_dev;
|
struct nand_flash_dev;
|
||||||
|
struct device_node;
|
||||||
|
|
||||||
/* Scan and identify a NAND device */
|
/* Scan and identify a NAND device */
|
||||||
extern int nand_scan(struct mtd_info *mtd, int max_chips);
|
extern int nand_scan(struct mtd_info *mtd, int max_chips);
|
||||||
/*
|
/*
|
||||||
|
@ -144,6 +146,14 @@ typedef enum {
|
||||||
/* Enable Hardware ECC before syndrome is read back from flash */
|
/* Enable Hardware ECC before syndrome is read back from flash */
|
||||||
#define NAND_ECC_READSYN 2
|
#define NAND_ECC_READSYN 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable generic NAND 'page erased' check. This check is only done when
|
||||||
|
* ecc.correct() returns -EBADMSG.
|
||||||
|
* Set this flag if your implementation does not fix bitflips in erased
|
||||||
|
* pages and you want to rely on the default implementation.
|
||||||
|
*/
|
||||||
|
#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0)
|
||||||
|
|
||||||
/* Bit mask for flags passed to do_nand_read_ecc */
|
/* Bit mask for flags passed to do_nand_read_ecc */
|
||||||
#define NAND_GET_DEVICE 0x80
|
#define NAND_GET_DEVICE 0x80
|
||||||
|
|
||||||
|
@ -179,6 +189,12 @@ typedef enum {
|
||||||
/* Device supports subpage reads */
|
/* Device supports subpage reads */
|
||||||
#define NAND_SUBPAGE_READ 0x00001000
|
#define NAND_SUBPAGE_READ 0x00001000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some MLC NANDs need data scrambling to limit bitflips caused by repeated
|
||||||
|
* patterns.
|
||||||
|
*/
|
||||||
|
#define NAND_NEED_SCRAMBLING 0x00002000
|
||||||
|
|
||||||
/* Options valid for Samsung large page devices */
|
/* Options valid for Samsung large page devices */
|
||||||
#define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
|
#define NAND_SAMSUNG_LP_OPTIONS NAND_CACHEPRG
|
||||||
|
|
||||||
|
@ -203,6 +219,11 @@ typedef enum {
|
||||||
* before calling nand_scan_tail.
|
* before calling nand_scan_tail.
|
||||||
*/
|
*/
|
||||||
#define NAND_BUSWIDTH_AUTO 0x00080000
|
#define NAND_BUSWIDTH_AUTO 0x00080000
|
||||||
|
/*
|
||||||
|
* This option could be defined by controller drivers to protect against
|
||||||
|
* kmap'ed, vmalloc'ed highmem buffers being passed from upper layers
|
||||||
|
*/
|
||||||
|
#define NAND_USE_BOUNCE_BUFFER 0x00100000
|
||||||
|
|
||||||
/* Options set by nand scan */
|
/* Options set by nand scan */
|
||||||
/* bbt has already been read */
|
/* bbt has already been read */
|
||||||
|
@ -292,15 +313,15 @@ struct nand_onfi_params {
|
||||||
__le16 t_r;
|
__le16 t_r;
|
||||||
__le16 t_ccs;
|
__le16 t_ccs;
|
||||||
__le16 src_sync_timing_mode;
|
__le16 src_sync_timing_mode;
|
||||||
__le16 src_ssync_features;
|
u8 src_ssync_features;
|
||||||
__le16 clk_pin_capacitance_typ;
|
__le16 clk_pin_capacitance_typ;
|
||||||
__le16 io_pin_capacitance_typ;
|
__le16 io_pin_capacitance_typ;
|
||||||
__le16 input_pin_capacitance_typ;
|
__le16 input_pin_capacitance_typ;
|
||||||
u8 input_pin_capacitance_max;
|
u8 input_pin_capacitance_max;
|
||||||
u8 driver_strength_support;
|
u8 driver_strength_support;
|
||||||
__le16 t_int_r;
|
__le16 t_int_r;
|
||||||
__le16 t_ald;
|
__le16 t_adl;
|
||||||
u8 reserved4[7];
|
u8 reserved4[8];
|
||||||
|
|
||||||
/* vendor */
|
/* vendor */
|
||||||
__le16 vendor_revision;
|
__le16 vendor_revision;
|
||||||
|
@ -423,7 +444,7 @@ struct nand_jedec_params {
|
||||||
__le16 input_pin_capacitance_typ;
|
__le16 input_pin_capacitance_typ;
|
||||||
__le16 clk_pin_capacitance_typ;
|
__le16 clk_pin_capacitance_typ;
|
||||||
u8 driver_strength_support;
|
u8 driver_strength_support;
|
||||||
__le16 t_ald;
|
__le16 t_adl;
|
||||||
u8 reserved4[36];
|
u8 reserved4[36];
|
||||||
|
|
||||||
/* ECC and endurance block */
|
/* ECC and endurance block */
|
||||||
|
@ -466,12 +487,19 @@ struct nand_hw_control {
|
||||||
* @total: total number of ECC bytes per page
|
* @total: total number of ECC bytes per page
|
||||||
* @prepad: padding information for syndrome based ECC generators
|
* @prepad: padding information for syndrome based ECC generators
|
||||||
* @postpad: padding information for syndrome based ECC generators
|
* @postpad: padding information for syndrome based ECC generators
|
||||||
|
* @options: ECC specific options (see NAND_ECC_XXX flags defined above)
|
||||||
* @layout: ECC layout control struct pointer
|
* @layout: ECC layout control struct pointer
|
||||||
* @priv: pointer to private ECC control data
|
* @priv: pointer to private ECC control data
|
||||||
* @hwctl: function to control hardware ECC generator. Must only
|
* @hwctl: function to control hardware ECC generator. Must only
|
||||||
* be provided if an hardware ECC is available
|
* be provided if an hardware ECC is available
|
||||||
* @calculate: function for ECC calculation or readback from ECC hardware
|
* @calculate: function for ECC calculation or readback from ECC hardware
|
||||||
* @correct: function for ECC correction, matching to ECC generator (sw/hw)
|
* @correct: function for ECC correction, matching to ECC generator (sw/hw).
|
||||||
|
* Should return a positive number representing the number of
|
||||||
|
* corrected bitflips, -EBADMSG if the number of bitflips exceed
|
||||||
|
* ECC strength, or any other error code if the error is not
|
||||||
|
* directly related to correction.
|
||||||
|
* If -EBADMSG is returned the input buffers should be left
|
||||||
|
* untouched.
|
||||||
* @read_page_raw: function to read a raw page without ECC. This function
|
* @read_page_raw: function to read a raw page without ECC. This function
|
||||||
* should hide the specific layout used by the ECC
|
* should hide the specific layout used by the ECC
|
||||||
* controller and always return contiguous in-band and
|
* controller and always return contiguous in-band and
|
||||||
|
@ -509,6 +537,7 @@ struct nand_ecc_ctrl {
|
||||||
int strength;
|
int strength;
|
||||||
int prepad;
|
int prepad;
|
||||||
int postpad;
|
int postpad;
|
||||||
|
unsigned int options;
|
||||||
struct nand_ecclayout *layout;
|
struct nand_ecclayout *layout;
|
||||||
void *priv;
|
void *priv;
|
||||||
void (*hwctl)(struct mtd_info *mtd, int mode);
|
void (*hwctl)(struct mtd_info *mtd, int mode);
|
||||||
|
@ -556,6 +585,7 @@ struct nand_buffers {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nand_chip - NAND Private Flash Chip Data
|
* struct nand_chip - NAND Private Flash Chip Data
|
||||||
|
* @mtd: MTD device registered to the MTD framework
|
||||||
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the
|
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the
|
||||||
* flash device
|
* flash device
|
||||||
* @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the
|
* @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the
|
||||||
|
@ -571,10 +601,6 @@ struct nand_buffers {
|
||||||
* @block_markbad: [REPLACEABLE] mark a block bad
|
* @block_markbad: [REPLACEABLE] mark a block bad
|
||||||
* @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific function for controlling
|
* @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific function for controlling
|
||||||
* ALE/CLE/nCE. Also used to write command and address
|
* ALE/CLE/nCE. Also used to write command and address
|
||||||
* @init_size: [BOARDSPECIFIC] hardwarespecific function for setting
|
|
||||||
* mtd->oobsize, mtd->writesize and so on.
|
|
||||||
* @id_data contains the 8 bytes values of NAND_CMD_READID.
|
|
||||||
* Return with the bus width.
|
|
||||||
* @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accessing
|
* @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accessing
|
||||||
* device ready/busy line. If set to NULL no access to
|
* device ready/busy line. If set to NULL no access to
|
||||||
* ready/busy is available and the ready/busy information
|
* ready/busy is available and the ready/busy information
|
||||||
|
@ -669,11 +695,9 @@ struct nand_chip {
|
||||||
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
|
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
|
||||||
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
|
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
|
||||||
void (*select_chip)(struct mtd_info *mtd, int chip);
|
void (*select_chip)(struct mtd_info *mtd, int chip);
|
||||||
int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
|
int (*block_bad)(struct mtd_info *mtd, loff_t ofs);
|
||||||
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
|
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
|
||||||
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
|
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
|
||||||
int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
|
|
||||||
u8 *id_data);
|
|
||||||
int (*dev_ready)(struct mtd_info *mtd);
|
int (*dev_ready)(struct mtd_info *mtd);
|
||||||
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
|
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
|
||||||
int page_addr);
|
int page_addr);
|
||||||
|
@ -873,7 +897,6 @@ struct nand_manufacturers {
|
||||||
extern struct nand_flash_dev nand_flash_ids[];
|
extern struct nand_flash_dev nand_flash_ids[];
|
||||||
extern struct nand_manufacturers nand_manuf_ids[];
|
extern struct nand_manufacturers nand_manuf_ids[];
|
||||||
|
|
||||||
extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
|
|
||||||
extern int nand_default_bbt(struct mtd_info *mtd);
|
extern int nand_default_bbt(struct mtd_info *mtd);
|
||||||
extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
|
extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
|
||||||
extern int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
|
extern int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
|
||||||
|
@ -898,7 +921,6 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
* @chip_delay: R/B delay value in us
|
* @chip_delay: R/B delay value in us
|
||||||
* @options: Option flags, e.g. 16bit buswidth
|
* @options: Option flags, e.g. 16bit buswidth
|
||||||
* @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH
|
* @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH
|
||||||
* @ecclayout: ECC layout info structure
|
|
||||||
* @part_probe_types: NULL-terminated array of probe types
|
* @part_probe_types: NULL-terminated array of probe types
|
||||||
*/
|
*/
|
||||||
struct platform_nand_chip {
|
struct platform_nand_chip {
|
||||||
|
@ -906,7 +928,6 @@ struct platform_nand_chip {
|
||||||
int chip_offset;
|
int chip_offset;
|
||||||
int nr_partitions;
|
int nr_partitions;
|
||||||
struct mtd_partition *partitions;
|
struct mtd_partition *partitions;
|
||||||
struct nand_ecclayout *ecclayout;
|
|
||||||
int chip_delay;
|
int chip_delay;
|
||||||
unsigned int options;
|
unsigned int options;
|
||||||
unsigned int bbt_options;
|
unsigned int bbt_options;
|
||||||
|
@ -955,15 +976,6 @@ struct platform_nand_data {
|
||||||
struct platform_nand_ctrl ctrl;
|
struct platform_nand_ctrl ctrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Some helpers to access the data structures */
|
|
||||||
static inline
|
|
||||||
struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
|
|
||||||
{
|
|
||||||
struct nand_chip *chip = mtd->priv;
|
|
||||||
|
|
||||||
return chip->priv;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
||||||
/* return the supported features. */
|
/* return the supported features. */
|
||||||
static inline int onfi_feature(struct nand_chip *chip)
|
static inline int onfi_feature(struct nand_chip *chip)
|
||||||
|
@ -1081,4 +1093,9 @@ struct nand_sdr_timings {
|
||||||
|
|
||||||
/* get timing characteristics from ONFI timing mode. */
|
/* get timing characteristics from ONFI timing mode. */
|
||||||
const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
|
const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
|
||||||
|
|
||||||
|
int nand_check_erased_ecc_chunk(void *data, int datalen,
|
||||||
|
void *ecc, int ecclen,
|
||||||
|
void *extraoob, int extraooblen,
|
||||||
|
int threshold);
|
||||||
#endif /* __LINUX_MTD_NAND_H */
|
#endif /* __LINUX_MTD_NAND_H */
|
||||||
|
|
|
@ -32,9 +32,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
|
||||||
/*
|
/*
|
||||||
* Initialize BCH encoder/decoder
|
* Initialize BCH encoder/decoder
|
||||||
*/
|
*/
|
||||||
struct nand_bch_control *
|
struct nand_bch_control *nand_bch_init(struct mtd_info *mtd);
|
||||||
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
|
|
||||||
unsigned int eccbytes, struct nand_ecclayout **ecclayout);
|
|
||||||
/*
|
/*
|
||||||
* Release BCH encoder/decoder resources
|
* Release BCH encoder/decoder resources
|
||||||
*/
|
*/
|
||||||
|
@ -55,12 +53,10 @@ static inline int
|
||||||
nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
|
||||||
unsigned char *read_ecc, unsigned char *calc_ecc)
|
unsigned char *read_ecc, unsigned char *calc_ecc)
|
||||||
{
|
{
|
||||||
return -1;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct nand_bch_control *
|
static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
|
||||||
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
|
|
||||||
unsigned int eccbytes, struct nand_ecclayout **ecclayout)
|
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue