mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-29 16:10:58 +00:00
nand: Merge changes from Linux nand driver
[backport from linux commit 02f8c6aee8df3cdc935e9bdd4f2d020306035dbe] This patch synchronizes the nand driver with the Linux 3.0 state. Signed-off-by: Christian Hitz <christian.hitz@aizo.com> Cc: Scott Wood <scottwood@freescale.com> [scottwood@freescale.com: minor fixes] Signed-off-by: Scott Wood <scottwood@freescale.com>
This commit is contained in:
parent
90e3f395bf
commit
2a8e0fc8b3
3 changed files with 538 additions and 312 deletions
|
@ -115,6 +115,35 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
|
||||||
|
|
||||||
static int nand_wait(struct mtd_info *mtd, struct nand_chip *this);
|
static int nand_wait(struct mtd_info *mtd, struct nand_chip *this);
|
||||||
|
|
||||||
|
static int check_offs_len(struct mtd_info *mtd,
|
||||||
|
loff_t ofs, uint64_t len)
|
||||||
|
{
|
||||||
|
struct nand_chip *chip = mtd->priv;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Start address must align on block boundary */
|
||||||
|
if (ofs & ((1 << chip->phys_erase_shift) - 1)) {
|
||||||
|
MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Unaligned address\n", __func__);
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Length must align on block boundary */
|
||||||
|
if (len & ((1 << chip->phys_erase_shift) - 1)) {
|
||||||
|
MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Length not block aligned\n",
|
||||||
|
__func__);
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do not allow past end of device */
|
||||||
|
if (ofs + len > mtd->size) {
|
||||||
|
MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Past end of device\n",
|
||||||
|
__func__);
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_release_device - [GENERIC] release chip
|
* nand_release_device - [GENERIC] release chip
|
||||||
* @mtd: MTD device structure
|
* @mtd: MTD device structure
|
||||||
|
@ -123,8 +152,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this);
|
||||||
*/
|
*/
|
||||||
static void nand_release_device(struct mtd_info *mtd)
|
static void nand_release_device(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct nand_chip *this = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
this->select_chip(mtd, -1); /* De-select the NAND device */
|
|
||||||
|
/* De-select the NAND device */
|
||||||
|
chip->select_chip(mtd, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -316,6 +347,9 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
u16 bad;
|
u16 bad;
|
||||||
|
|
||||||
|
if (chip->options & NAND_BBT_SCANLASTPAGE)
|
||||||
|
ofs += mtd->erasesize - mtd->writesize;
|
||||||
|
|
||||||
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
|
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
|
||||||
|
|
||||||
if (getchip) {
|
if (getchip) {
|
||||||
|
@ -333,14 +367,18 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
|
||||||
bad = cpu_to_le16(chip->read_word(mtd));
|
bad = cpu_to_le16(chip->read_word(mtd));
|
||||||
if (chip->badblockpos & 0x1)
|
if (chip->badblockpos & 0x1)
|
||||||
bad >>= 8;
|
bad >>= 8;
|
||||||
if ((bad & 0xFF) != 0xff)
|
else
|
||||||
res = 1;
|
bad &= 0xFF;
|
||||||
} else {
|
} else {
|
||||||
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
|
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
|
||||||
if (chip->read_byte(mtd) != 0xff)
|
bad = chip->read_byte(mtd);
|
||||||
res = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (likely(chip->badblockbits == 8))
|
||||||
|
res = bad != 0xFF;
|
||||||
|
else
|
||||||
|
res = hweight8(bad) < chip->badblockbits;
|
||||||
|
|
||||||
if (getchip)
|
if (getchip)
|
||||||
nand_release_device(mtd);
|
nand_release_device(mtd);
|
||||||
|
|
||||||
|
@ -359,7 +397,10 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
uint8_t buf[2] = { 0, 0 };
|
uint8_t buf[2] = { 0, 0 };
|
||||||
int block, ret;
|
int block, ret, i = 0;
|
||||||
|
|
||||||
|
if (chip->options & NAND_BBT_SCANLASTPAGE)
|
||||||
|
ofs += mtd->erasesize - mtd->writesize;
|
||||||
|
|
||||||
/* Get block number */
|
/* Get block number */
|
||||||
block = (int)(ofs >> chip->bbt_erase_shift);
|
block = (int)(ofs >> chip->bbt_erase_shift);
|
||||||
|
@ -370,17 +411,31 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
if (chip->options & NAND_USE_FLASH_BBT)
|
if (chip->options & NAND_USE_FLASH_BBT)
|
||||||
ret = nand_update_bbt(mtd, ofs);
|
ret = nand_update_bbt(mtd, ofs);
|
||||||
else {
|
else {
|
||||||
/* We write two bytes, so we dont have to mess with 16 bit
|
|
||||||
* access
|
|
||||||
*/
|
|
||||||
nand_get_device(chip, mtd, FL_WRITING);
|
nand_get_device(chip, mtd, FL_WRITING);
|
||||||
ofs += mtd->oobsize;
|
|
||||||
chip->ops.len = chip->ops.ooblen = 2;
|
|
||||||
chip->ops.datbuf = NULL;
|
|
||||||
chip->ops.oobbuf = buf;
|
|
||||||
chip->ops.ooboffs = chip->badblockpos & ~0x01;
|
|
||||||
|
|
||||||
ret = nand_do_write_oob(mtd, ofs, &chip->ops);
|
/* Write to first two pages and to byte 1 and 6 if necessary.
|
||||||
|
* If we write to more than one location, the first error
|
||||||
|
* encountered quits the procedure. We write two bytes per
|
||||||
|
* location, so we dont have to mess with 16 bit access.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
chip->ops.len = chip->ops.ooblen = 2;
|
||||||
|
chip->ops.datbuf = NULL;
|
||||||
|
chip->ops.oobbuf = buf;
|
||||||
|
chip->ops.ooboffs = chip->badblockpos & ~0x01;
|
||||||
|
|
||||||
|
ret = nand_do_write_oob(mtd, ofs, &chip->ops);
|
||||||
|
|
||||||
|
if (!ret && (chip->options & NAND_BBT_SCANBYTE1AND6)) {
|
||||||
|
chip->ops.ooboffs = NAND_SMALL_BADBLOCK_POS
|
||||||
|
& ~0x01;
|
||||||
|
ret = nand_do_write_oob(mtd, ofs, &chip->ops);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
ofs += mtd->writesize;
|
||||||
|
} while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) &&
|
||||||
|
i < 2);
|
||||||
|
|
||||||
nand_release_device(mtd);
|
nand_release_device(mtd);
|
||||||
}
|
}
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -399,6 +454,11 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
static int nand_check_wp(struct mtd_info *mtd)
|
static int nand_check_wp(struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
|
|
||||||
|
/* broken xD cards report WP despite being writable */
|
||||||
|
if (chip->options & NAND_BROKEN_XD)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Check the WP bit */
|
/* Check the WP bit */
|
||||||
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
||||||
return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
|
return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
|
||||||
|
@ -419,11 +479,6 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
|
||||||
{
|
{
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
|
|
||||||
if (!(chip->options & NAND_BBT_SCANNED)) {
|
|
||||||
chip->options |= NAND_BBT_SCANNED;
|
|
||||||
chip->scan_bbt(mtd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!chip->bbt)
|
if (!chip->bbt)
|
||||||
return chip->block_bad(mtd, ofs, getchip);
|
return chip->block_bad(mtd, ofs, getchip);
|
||||||
|
|
||||||
|
@ -686,9 +741,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
|
||||||
*
|
*
|
||||||
* Get the device and lock it for exclusive access
|
* Get the device and lock it for exclusive access
|
||||||
*/
|
*/
|
||||||
static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
|
static int
|
||||||
|
nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
|
||||||
{
|
{
|
||||||
this->state = new_state;
|
chip->state = new_state;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,10 +757,10 @@ static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int ne
|
||||||
* Erase can take up to 400ms and program up to 20ms according to
|
* Erase can take up to 400ms and program up to 20ms according to
|
||||||
* general NAND and SmartMedia specs
|
* general NAND and SmartMedia specs
|
||||||
*/
|
*/
|
||||||
static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
|
static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
|
||||||
{
|
{
|
||||||
unsigned long timeo;
|
unsigned long timeo;
|
||||||
int state = this->state;
|
int state = chip->state;
|
||||||
u32 time_start;
|
u32 time_start;
|
||||||
|
|
||||||
if (state == FL_ERASING)
|
if (state == FL_ERASING)
|
||||||
|
@ -712,10 +768,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
|
||||||
else
|
else
|
||||||
timeo = (CONFIG_SYS_HZ * 20) / 1000;
|
timeo = (CONFIG_SYS_HZ * 20) / 1000;
|
||||||
|
|
||||||
if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
|
if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))
|
||||||
this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
|
chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);
|
||||||
else
|
else
|
||||||
this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
|
||||||
|
|
||||||
time_start = get_timer(0);
|
time_start = get_timer(0);
|
||||||
|
|
||||||
|
@ -725,11 +781,11 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
|
||||||
return 0x01;
|
return 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->dev_ready) {
|
if (chip->dev_ready) {
|
||||||
if (this->dev_ready(mtd))
|
if (chip->dev_ready(mtd))
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (this->read_byte(mtd) & NAND_STATUS_READY)
|
if (chip->read_byte(mtd) & NAND_STATUS_READY)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -739,7 +795,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this)
|
||||||
;
|
;
|
||||||
#endif /* PPCHAMELON_NAND_TIMER_HACK */
|
#endif /* PPCHAMELON_NAND_TIMER_HACK */
|
||||||
|
|
||||||
return this->read_byte(mtd);
|
return (int)chip->read_byte(mtd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -860,6 +916,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
int data_col_addr, i, gaps = 0;
|
int data_col_addr, i, gaps = 0;
|
||||||
int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
|
int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
|
||||||
int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
|
int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
/* Column address wihin the page aligned to ECC size (256bytes). */
|
/* Column address wihin the page aligned to ECC size (256bytes). */
|
||||||
start_step = data_offs / chip->ecc.size;
|
start_step = data_offs / chip->ecc.size;
|
||||||
|
@ -898,26 +955,30 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
} else {
|
} else {
|
||||||
/* send the command to read the particular ecc bytes */
|
/* send the command to read the particular ecc bytes */
|
||||||
/* take care about buswidth alignment in read_buf */
|
/* take care about buswidth alignment in read_buf */
|
||||||
aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1);
|
index = start_step * chip->ecc.bytes;
|
||||||
|
|
||||||
|
aligned_pos = eccpos[index] & ~(busw - 1);
|
||||||
aligned_len = eccfrag_len;
|
aligned_len = eccfrag_len;
|
||||||
if (eccpos[start_step * chip->ecc.bytes] & (busw - 1))
|
if (eccpos[index] & (busw - 1))
|
||||||
aligned_len++;
|
aligned_len++;
|
||||||
if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1))
|
if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1))
|
||||||
aligned_len++;
|
aligned_len++;
|
||||||
|
|
||||||
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1);
|
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
|
||||||
|
mtd->writesize + aligned_pos, -1);
|
||||||
chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
|
chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < eccfrag_len; i++)
|
for (i = 0; i < eccfrag_len; i++)
|
||||||
chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]];
|
chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]];
|
||||||
|
|
||||||
p = bufpoi + data_col_addr;
|
p = bufpoi + data_col_addr;
|
||||||
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
|
for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {
|
||||||
int stat;
|
int stat;
|
||||||
|
|
||||||
stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
|
stat = chip->ecc.correct(mtd, p,
|
||||||
if (stat == -1)
|
&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);
|
||||||
|
if (stat < 0)
|
||||||
mtd->ecc_stats.failed++;
|
mtd->ecc_stats.failed++;
|
||||||
else
|
else
|
||||||
mtd->ecc_stats.corrected += stat;
|
mtd->ecc_stats.corrected += stat;
|
||||||
|
@ -1142,6 +1203,9 @@ 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_OOB_AUTO ?
|
||||||
|
mtd->oobavail : mtd->oobsize;
|
||||||
|
|
||||||
uint8_t *bufpoi, *oob, *buf;
|
uint8_t *bufpoi, *oob, *buf;
|
||||||
|
|
||||||
stats = mtd->ecc_stats;
|
stats = mtd->ecc_stats;
|
||||||
|
@ -1187,7 +1251,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||||
|
|
||||||
/* Transfer not aligned data */
|
/* Transfer not aligned data */
|
||||||
if (!aligned) {
|
if (!aligned) {
|
||||||
if (!NAND_SUBPAGE_READ(chip) && !oob)
|
if (!NAND_SUBPAGE_READ(chip) && !oob &&
|
||||||
|
!(mtd->ecc_stats.failed - stats.failed))
|
||||||
chip->pagebuf = realpage;
|
chip->pagebuf = realpage;
|
||||||
memcpy(buf, chip->buffers->databuf + col, bytes);
|
memcpy(buf, chip->buffers->databuf + col, bytes);
|
||||||
}
|
}
|
||||||
|
@ -1195,18 +1260,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
|
||||||
buf += bytes;
|
buf += bytes;
|
||||||
|
|
||||||
if (unlikely(oob)) {
|
if (unlikely(oob)) {
|
||||||
/* Raw mode does data:oob:data:oob */
|
|
||||||
if (ops->mode != MTD_OOB_RAW) {
|
int toread = min(oobreadlen, max_oobsize);
|
||||||
int toread = min(oobreadlen,
|
|
||||||
chip->ecc.layout->oobavail);
|
if (toread) {
|
||||||
if (toread) {
|
oob = nand_transfer_oob(chip,
|
||||||
oob = nand_transfer_oob(chip,
|
oob, ops, toread);
|
||||||
oob, ops, toread);
|
oobreadlen -= toread;
|
||||||
oobreadlen -= toread;
|
}
|
||||||
}
|
|
||||||
} else
|
|
||||||
buf = nand_transfer_oob(chip,
|
|
||||||
buf, ops, mtd->oobsize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(chip->options & NAND_NO_READRDY)) {
|
if (!(chip->options & NAND_NO_READRDY)) {
|
||||||
|
@ -1793,13 +1854,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
* nand_fill_oob - [Internal] Transfer client buffer to oob
|
* nand_fill_oob - [Internal] Transfer client buffer to oob
|
||||||
* @chip: nand chip structure
|
* @chip: nand chip structure
|
||||||
* @oob: oob data buffer
|
* @oob: oob data buffer
|
||||||
|
* @len: oob data write length
|
||||||
* @ops: oob ops structure
|
* @ops: oob ops structure
|
||||||
*/
|
*/
|
||||||
static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
|
static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len,
|
||||||
struct mtd_oob_ops *ops)
|
struct mtd_oob_ops *ops)
|
||||||
{
|
{
|
||||||
size_t len = ops->ooblen;
|
|
||||||
|
|
||||||
switch (ops->mode) {
|
switch (ops->mode) {
|
||||||
|
|
||||||
case MTD_OOB_PLACE:
|
case MTD_OOB_PLACE:
|
||||||
|
@ -1838,7 +1898,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0
|
#define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_do_write_ops - [Internal] NAND write with ECC
|
* nand_do_write_ops - [Internal] NAND write with ECC
|
||||||
|
@ -1854,6 +1914,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
|
||||||
int chipnr, realpage, page, blockmask, column;
|
int chipnr, realpage, page, blockmask, column;
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
uint32_t writelen = ops->len;
|
uint32_t writelen = ops->len;
|
||||||
|
|
||||||
|
uint32_t oobwritelen = ops->ooblen;
|
||||||
|
uint32_t oobmaxlen = ops->mode == MTD_OOB_AUTO ?
|
||||||
|
mtd->oobavail : mtd->oobsize;
|
||||||
|
|
||||||
uint8_t *oob = ops->oobbuf;
|
uint8_t *oob = ops->oobbuf;
|
||||||
uint8_t *buf = ops->datbuf;
|
uint8_t *buf = ops->datbuf;
|
||||||
int ret, subpage;
|
int ret, subpage;
|
||||||
|
@ -1890,6 +1955,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
|
||||||
if (likely(!oob))
|
if (likely(!oob))
|
||||||
memset(chip->oob_poi, 0xff, mtd->oobsize);
|
memset(chip->oob_poi, 0xff, mtd->oobsize);
|
||||||
|
|
||||||
|
/* Don't allow multipage oob writes with offset */
|
||||||
|
if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
WATCHDOG_RESET();
|
WATCHDOG_RESET();
|
||||||
|
|
||||||
|
@ -1907,8 +1976,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
|
||||||
wbuf = chip->buffers->databuf;
|
wbuf = chip->buffers->databuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(oob))
|
if (unlikely(oob)) {
|
||||||
oob = nand_fill_oob(chip, oob, ops);
|
size_t len = min(oobwritelen, oobmaxlen);
|
||||||
|
oob = nand_fill_oob(chip, oob, len, ops);
|
||||||
|
oobwritelen -= len;
|
||||||
|
}
|
||||||
|
|
||||||
ret = chip->write_page(mtd, chip, wbuf, page, cached,
|
ret = chip->write_page(mtd, chip, wbuf, page, cached,
|
||||||
(ops->mode == MTD_OOB_RAW));
|
(ops->mode == MTD_OOB_RAW));
|
||||||
|
@ -2043,7 +2115,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
|
||||||
chip->pagebuf = -1;
|
chip->pagebuf = -1;
|
||||||
|
|
||||||
memset(chip->oob_poi, 0xff, mtd->oobsize);
|
memset(chip->oob_poi, 0xff, mtd->oobsize);
|
||||||
nand_fill_oob(chip, ops->oobbuf, ops);
|
nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops);
|
||||||
status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
|
status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
|
||||||
memset(chip->oob_poi, 0xff, mtd->oobsize);
|
memset(chip->oob_poi, 0xff, mtd->oobsize);
|
||||||
|
|
||||||
|
@ -2166,27 +2238,10 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
|
||||||
__func__, (unsigned long long)instr->addr,
|
__func__, (unsigned long long)instr->addr,
|
||||||
(unsigned long long)instr->len);
|
(unsigned long long)instr->len);
|
||||||
|
|
||||||
/* Start address must align on block boundary */
|
if (check_offs_len(mtd, instr->addr, instr->len))
|
||||||
if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
|
|
||||||
MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
/* Length must align on block boundary */
|
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
|
||||||
if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {
|
|
||||||
MTDDEBUG (MTD_DEBUG_LEVEL0,
|
|
||||||
"nand_erase: Length not block aligned\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do not allow erase past end of device */
|
|
||||||
if ((instr->len + instr->addr) > mtd->size) {
|
|
||||||
MTDDEBUG (MTD_DEBUG_LEVEL0,
|
|
||||||
"nand_erase: Erase past end of device\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
instr->fail_addr = 0xffffffff;
|
|
||||||
|
|
||||||
/* Grab the lock and see if the device is available */
|
/* Grab the lock and see if the device is available */
|
||||||
nand_get_device(chip, mtd, FL_ERASING);
|
nand_get_device(chip, mtd, FL_ERASING);
|
||||||
|
@ -2371,7 +2426,8 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||||
struct nand_chip *chip = mtd->priv;
|
struct nand_chip *chip = mtd->priv;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((ret = nand_block_isbad(mtd, ofs))) {
|
ret = nand_block_isbad(mtd, ofs);
|
||||||
|
if (ret) {
|
||||||
/* If it was bad already, return success and do nothing. */
|
/* If it was bad already, return success and do nothing. */
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2444,6 +2500,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
int i;
|
int i;
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
|
/* try ONFI for unknow chip or LP */
|
||||||
chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1);
|
||||||
if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
|
if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' ||
|
||||||
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
|
chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
|
||||||
|
@ -2486,7 +2543,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
|
|
||||||
if (!mtd->name)
|
if (!mtd->name)
|
||||||
mtd->name = p->model;
|
mtd->name = p->model;
|
||||||
|
|
||||||
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
mtd->writesize = le32_to_cpu(p->byte_per_page);
|
||||||
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
|
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
|
||||||
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
|
||||||
|
@ -2495,6 +2551,10 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
if (le16_to_cpu(p->features) & 1)
|
if (le16_to_cpu(p->features) & 1)
|
||||||
*busw = NAND_BUSWIDTH_16;
|
*busw = NAND_BUSWIDTH_16;
|
||||||
|
|
||||||
|
chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
||||||
|
chip->options |= (NAND_NO_READRDY |
|
||||||
|
NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -2506,41 +2566,6 @@ static inline int nand_flash_detect_onfi(struct mtd_info *mtd,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void nand_flash_detect_non_onfi(struct mtd_info *mtd,
|
|
||||||
struct nand_chip *chip,
|
|
||||||
const struct nand_flash_dev *type,
|
|
||||||
int *busw)
|
|
||||||
{
|
|
||||||
/* Newer devices have all the information in additional id bytes */
|
|
||||||
if (!type->pagesize) {
|
|
||||||
int extid;
|
|
||||||
/* The 3rd id byte holds MLC / multichip data */
|
|
||||||
chip->cellinfo = chip->read_byte(mtd);
|
|
||||||
/* The 4th id byte is the important one */
|
|
||||||
extid = chip->read_byte(mtd);
|
|
||||||
/* Calc pagesize */
|
|
||||||
mtd->writesize = 1024 << (extid & 0x3);
|
|
||||||
extid >>= 2;
|
|
||||||
/* Calc oobsize */
|
|
||||||
mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
|
|
||||||
extid >>= 2;
|
|
||||||
/* Calc blocksize. Blocksize is multiples of 64KiB */
|
|
||||||
mtd->erasesize = (64 * 1024) << (extid & 0x03);
|
|
||||||
extid >>= 2;
|
|
||||||
/* Get buswidth information */
|
|
||||||
*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Old devices have chip data hardcoded in the device id table
|
|
||||||
*/
|
|
||||||
mtd->erasesize = type->erasesize;
|
|
||||||
mtd->writesize = type->pagesize;
|
|
||||||
mtd->oobsize = mtd->writesize / 32;
|
|
||||||
*busw = type->options & NAND_BUSWIDTH_16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the flash and manufacturer id and lookup if the type is supported
|
* Get the flash and manufacturer id and lookup if the type is supported
|
||||||
*/
|
*/
|
||||||
|
@ -2550,8 +2575,9 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
int *maf_id, int *dev_id,
|
int *maf_id, int *dev_id,
|
||||||
const struct nand_flash_dev *type)
|
const struct nand_flash_dev *type)
|
||||||
{
|
{
|
||||||
int ret, maf_idx;
|
int i, maf_idx;
|
||||||
int tmp_id, tmp_manf;
|
u8 id_data[8];
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Select the device */
|
/* Select the device */
|
||||||
chip->select_chip(mtd, 0);
|
chip->select_chip(mtd, 0);
|
||||||
|
@ -2577,15 +2603,13 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
|
|
||||||
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
||||||
|
|
||||||
/* Read manufacturer and device IDs */
|
for (i = 0; i < 2; i++)
|
||||||
|
id_data[i] = chip->read_byte(mtd);
|
||||||
|
|
||||||
tmp_manf = chip->read_byte(mtd);
|
if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
|
||||||
tmp_id = chip->read_byte(mtd);
|
|
||||||
|
|
||||||
if (tmp_manf != *maf_id || tmp_id != *dev_id) {
|
|
||||||
printk(KERN_INFO "%s: second ID read did not match "
|
printk(KERN_INFO "%s: second ID read did not match "
|
||||||
"%02x,%02x against %02x,%02x\n", __func__,
|
"%02x,%02x against %02x,%02x\n", __func__,
|
||||||
*maf_id, *dev_id, tmp_manf, tmp_id);
|
*maf_id, *dev_id, id_data[0], id_data[1]);
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2596,30 +2620,121 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
if (*dev_id == type->id)
|
if (*dev_id == type->id)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!type->name) {
|
chip->onfi_version = 0;
|
||||||
/* supress warning if there is no nand */
|
if (!type->name || !type->pagesize) {
|
||||||
if (*maf_id != 0x00 && *maf_id != 0xff &&
|
/* Check is chip is ONFI compliant */
|
||||||
*dev_id != 0x00 && *dev_id != 0xff)
|
ret = nand_flash_detect_onfi(mtd, chip, &busw);
|
||||||
printk(KERN_INFO "%s: unknown NAND device: "
|
if (ret)
|
||||||
"Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
|
goto ident_done;
|
||||||
__func__, *maf_id, *dev_id);
|
|
||||||
return ERR_PTR(-ENODEV);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
|
||||||
|
|
||||||
|
/* Read entire ID string */
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
id_data[i] = chip->read_byte(mtd);
|
||||||
|
|
||||||
|
if (!type->name)
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
if (!mtd->name)
|
if (!mtd->name)
|
||||||
mtd->name = type->name;
|
mtd->name = type->name;
|
||||||
|
|
||||||
chip->chipsize = (uint64_t)type->chipsize << 20;
|
chip->chipsize = (uint64_t)type->chipsize << 20;
|
||||||
chip->onfi_version = 0;
|
|
||||||
|
|
||||||
ret = nand_flash_detect_onfi(mtd, chip, &busw);
|
if (!type->pagesize && chip->init_size) {
|
||||||
if (!ret)
|
/* set the pagesize, oobsize, erasesize by the driver*/
|
||||||
nand_flash_detect_non_onfi(mtd, chip, type, &busw);
|
busw = chip->init_size(mtd, chip, id_data);
|
||||||
|
} else if (!type->pagesize) {
|
||||||
|
int extid;
|
||||||
|
/* The 3rd id byte holds MLC / multichip data */
|
||||||
|
chip->cellinfo = id_data[2];
|
||||||
|
/* The 4th id byte is the important one */
|
||||||
|
extid = id_data[3];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Field definitions are in the following datasheets:
|
||||||
|
* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
|
||||||
|
* New style (6 byte ID): Samsung K9GBG08U0M (p.40)
|
||||||
|
*
|
||||||
|
* Check for wraparound + Samsung ID + nonzero 6th byte
|
||||||
|
* to decide what to do.
|
||||||
|
*/
|
||||||
|
if (id_data[0] == id_data[6] && id_data[1] == id_data[7] &&
|
||||||
|
id_data[0] == NAND_MFR_SAMSUNG &&
|
||||||
|
(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
|
||||||
|
id_data[5] != 0x00) {
|
||||||
|
/* Calc pagesize */
|
||||||
|
mtd->writesize = 2048 << (extid & 0x03);
|
||||||
|
extid >>= 2;
|
||||||
|
/* Calc oobsize */
|
||||||
|
switch (extid & 0x03) {
|
||||||
|
case 1:
|
||||||
|
mtd->oobsize = 128;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mtd->oobsize = 218;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mtd->oobsize = 400;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mtd->oobsize = 436;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
extid >>= 2;
|
||||||
|
/* Calc blocksize */
|
||||||
|
mtd->erasesize = (128 * 1024) <<
|
||||||
|
(((extid >> 1) & 0x04) | (extid & 0x03));
|
||||||
|
busw = 0;
|
||||||
|
} else {
|
||||||
|
/* Calc pagesize */
|
||||||
|
mtd->writesize = 1024 << (extid & 0x03);
|
||||||
|
extid >>= 2;
|
||||||
|
/* Calc oobsize */
|
||||||
|
mtd->oobsize = (8 << (extid & 0x01)) *
|
||||||
|
(mtd->writesize >> 9);
|
||||||
|
extid >>= 2;
|
||||||
|
/* Calc blocksize. Blocksize is multiples of 64KiB */
|
||||||
|
mtd->erasesize = (64 * 1024) << (extid & 0x03);
|
||||||
|
extid >>= 2;
|
||||||
|
/* Get buswidth information */
|
||||||
|
busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Old devices have chip data hardcoded in the device id table
|
||||||
|
*/
|
||||||
|
mtd->erasesize = type->erasesize;
|
||||||
|
mtd->writesize = type->pagesize;
|
||||||
|
mtd->oobsize = mtd->writesize / 32;
|
||||||
|
busw = type->options & NAND_BUSWIDTH_16;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
|
||||||
|
* some Spansion chips have erasesize that conflicts with size
|
||||||
|
* listed in nand_ids table
|
||||||
|
* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
|
||||||
|
*/
|
||||||
|
if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 &&
|
||||||
|
id_data[5] == 0x00 && id_data[6] == 0x00 &&
|
||||||
|
id_data[7] == 0x00 && mtd->writesize == 512) {
|
||||||
|
mtd->erasesize = 128 * 1024;
|
||||||
|
mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
/* Get chip options, preserve non chip based options */
|
/* Get chip options, preserve non chip based options */
|
||||||
chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
chip->options &= ~NAND_CHIPOPTIONS_MSK;
|
||||||
chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
|
chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
|
||||||
|
|
||||||
|
/* Check if chip is a not a samsung device. Do not clear the
|
||||||
|
* options for chips which are not having an extended id.
|
||||||
|
*/
|
||||||
|
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
|
||||||
|
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
|
||||||
|
ident_done:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set chip as a default. Board drivers can override it, if necessary
|
* Set chip as a default. Board drivers can override it, if necessary
|
||||||
*/
|
*/
|
||||||
|
@ -2654,18 +2769,48 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
ffs(mtd->erasesize) - 1;
|
ffs(mtd->erasesize) - 1;
|
||||||
if (chip->chipsize & 0xffffffff)
|
if (chip->chipsize & 0xffffffff)
|
||||||
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
|
chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
|
||||||
else
|
else {
|
||||||
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31;
|
chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32));
|
||||||
|
chip->chip_shift += 32 - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip->badblockbits = 8;
|
||||||
|
|
||||||
/* Set the bad block position */
|
/* Set the bad block position */
|
||||||
chip->badblockpos = mtd->writesize > 512 ?
|
if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16))
|
||||||
NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
|
chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
|
||||||
|
else
|
||||||
|
chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
|
||||||
|
|
||||||
/* Check if chip is a not a samsung device. Do not clear the
|
/*
|
||||||
* options for chips which are not having an extended id.
|
* Bad block marker is stored in the last page of each block
|
||||||
|
* on Samsung and Hynix MLC devices; stored in first two pages
|
||||||
|
* of each block on Micron devices with 2KiB pages and on
|
||||||
|
* SLC Samsung, Hynix, Toshiba and AMD/Spansion. All others scan
|
||||||
|
* only the first page.
|
||||||
*/
|
*/
|
||||||
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
|
if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
|
||||||
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
|
(*maf_id == NAND_MFR_SAMSUNG ||
|
||||||
|
*maf_id == NAND_MFR_HYNIX))
|
||||||
|
chip->options |= NAND_BBT_SCANLASTPAGE;
|
||||||
|
else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
|
||||||
|
(*maf_id == NAND_MFR_SAMSUNG ||
|
||||||
|
*maf_id == NAND_MFR_HYNIX ||
|
||||||
|
*maf_id == NAND_MFR_TOSHIBA ||
|
||||||
|
*maf_id == NAND_MFR_AMD)) ||
|
||||||
|
(mtd->writesize == 2048 &&
|
||||||
|
*maf_id == NAND_MFR_MICRON))
|
||||||
|
chip->options |= NAND_BBT_SCAN2NDPAGE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6
|
||||||
|
*/
|
||||||
|
if (!(busw & NAND_BUSWIDTH_16) &&
|
||||||
|
*maf_id == NAND_MFR_STMICRO &&
|
||||||
|
mtd->writesize == 2048) {
|
||||||
|
chip->options |= NAND_BBT_SCANBYTE1AND6;
|
||||||
|
chip->badblockpos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for AND chips with 4 page planes */
|
/* Check for AND chips with 4 page planes */
|
||||||
if (chip->options & NAND_4PAGE_ARRAY)
|
if (chip->options & NAND_4PAGE_ARRAY)
|
||||||
|
@ -2677,9 +2822,15 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||||
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
||||||
chip->cmdfunc = nand_command_lp;
|
chip->cmdfunc = nand_command_lp;
|
||||||
|
|
||||||
|
/* TODO onfi flash name */
|
||||||
MTDDEBUG (MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:"
|
MTDDEBUG (MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:"
|
||||||
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id,
|
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id,
|
||||||
nand_manuf_ids[maf_idx].name, type->name);
|
nand_manuf_ids[maf_idx].name,
|
||||||
|
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
||||||
|
chip->onfi_version ? chip->onfi_params.model : type->name);
|
||||||
|
#else
|
||||||
|
type->name);
|
||||||
|
#endif
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
@ -2865,7 +3016,8 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||||
chip->ecc.write_page_raw = nand_write_page_raw;
|
chip->ecc.write_page_raw = nand_write_page_raw;
|
||||||
chip->ecc.read_oob = nand_read_oob_std;
|
chip->ecc.read_oob = nand_read_oob_std;
|
||||||
chip->ecc.write_oob = nand_write_oob_std;
|
chip->ecc.write_oob = nand_write_oob_std;
|
||||||
chip->ecc.size = 256;
|
if (!chip->ecc.size)
|
||||||
|
chip->ecc.size = 256;
|
||||||
chip->ecc.bytes = 3;
|
chip->ecc.bytes = 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2973,7 +3125,8 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||||
|
|
||||||
/* Fill in remaining MTD driver data */
|
/* Fill in remaining MTD driver data */
|
||||||
mtd->type = MTD_NANDFLASH;
|
mtd->type = MTD_NANDFLASH;
|
||||||
mtd->flags = MTD_CAP_NANDFLASH;
|
mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM :
|
||||||
|
MTD_CAP_NANDFLASH;
|
||||||
mtd->erase = nand_erase;
|
mtd->erase = nand_erase;
|
||||||
mtd->point = NULL;
|
mtd->point = NULL;
|
||||||
mtd->unpoint = NULL;
|
mtd->unpoint = NULL;
|
||||||
|
@ -2992,9 +3145,10 @@ int nand_scan_tail(struct mtd_info *mtd)
|
||||||
|
|
||||||
/* Check, if we should skip the bad block table scan */
|
/* Check, if we should skip the bad block table scan */
|
||||||
if (chip->options & NAND_SKIP_BBTSCAN)
|
if (chip->options & NAND_SKIP_BBTSCAN)
|
||||||
chip->options |= NAND_BBT_SCANNED;
|
return 0;
|
||||||
|
|
||||||
return 0;
|
/* Build bad block table */
|
||||||
|
return chip->scan_bbt(mtd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3039,4 +3193,9 @@ void nand_release(struct mtd_info *mtd)
|
||||||
kfree(chip->bbt);
|
kfree(chip->bbt);
|
||||||
if (!(chip->options & NAND_OWN_BUFFERS))
|
if (!(chip->options & NAND_OWN_BUFFERS))
|
||||||
kfree(chip->buffers);
|
kfree(chip->buffers);
|
||||||
|
|
||||||
|
/* Free bad block descriptor memory */
|
||||||
|
if (chip->badblock_pattern && chip->badblock_pattern->options
|
||||||
|
& NAND_BBT_DYNAMICSTRUCT)
|
||||||
|
kfree(chip->badblock_pattern);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,19 @@
|
||||||
* Thomas Gleixner <tglx@linuxtronix.de>
|
* Thomas Gleixner <tglx@linuxtronix.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
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
* it under the terms of the GNU General Public License as published by
|
||||||
* published by the Free Software Foundation.
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
#ifndef __LINUX_MTD_BBM_H
|
#ifndef __LINUX_MTD_BBM_H
|
||||||
#define __LINUX_MTD_BBM_H
|
#define __LINUX_MTD_BBM_H
|
||||||
|
@ -76,7 +87,7 @@ struct nand_bbt_descr {
|
||||||
#define NAND_BBT_PERCHIP 0x00000080
|
#define NAND_BBT_PERCHIP 0x00000080
|
||||||
/* bbt has a version counter at offset veroffs */
|
/* bbt has a version counter at offset veroffs */
|
||||||
#define NAND_BBT_VERSION 0x00000100
|
#define NAND_BBT_VERSION 0x00000100
|
||||||
/* Create a bbt if none axists */
|
/* Create a bbt if none exists */
|
||||||
#define NAND_BBT_CREATE 0x00000200
|
#define NAND_BBT_CREATE 0x00000200
|
||||||
/* Search good / bad pattern through all pages of a block */
|
/* Search good / bad pattern through all pages of a block */
|
||||||
#define NAND_BBT_SCANALLPAGES 0x00000400
|
#define NAND_BBT_SCANALLPAGES 0x00000400
|
||||||
|
@ -88,6 +99,12 @@ struct nand_bbt_descr {
|
||||||
#define NAND_BBT_SAVECONTENT 0x00002000
|
#define NAND_BBT_SAVECONTENT 0x00002000
|
||||||
/* Search good / bad pattern on the first and the second page */
|
/* Search good / bad pattern on the first and the second page */
|
||||||
#define NAND_BBT_SCAN2NDPAGE 0x00004000
|
#define NAND_BBT_SCAN2NDPAGE 0x00004000
|
||||||
|
/* Search good / bad pattern on the last page of the eraseblock */
|
||||||
|
#define NAND_BBT_SCANLASTPAGE 0x00008000
|
||||||
|
/* Chip stores bad block marker on BOTH 1st and 6th bytes of OOB */
|
||||||
|
#define NAND_BBT_SCANBYTE1AND6 0x00100000
|
||||||
|
/* The nand_bbt_descr was created dynamicaly and must be freed */
|
||||||
|
#define NAND_BBT_DYNAMICSTRUCT 0x00200000
|
||||||
|
|
||||||
/* The maximum number of blocks to scan for a bbt */
|
/* The maximum number of blocks to scan for a bbt */
|
||||||
#define NAND_BBT_SCAN_MAXBLOCKS 4
|
#define NAND_BBT_SCAN_MAXBLOCKS 4
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* linux/include/linux/mtd/nand.h
|
* linux/include/linux/mtd/nand.h
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000 David Woodhouse <dwmw2@infradead.org>
|
* Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org>
|
||||||
* Steven J. Hill <sjhill@realitydiluted.com>
|
* Steven J. Hill <sjhill@realitydiluted.com>
|
||||||
* Thomas Gleixner <tglx@linutronix.de>
|
* 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
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -36,17 +36,18 @@ extern int nand_scan_ident(struct mtd_info *mtd, int max_chips,
|
||||||
extern int nand_scan_tail(struct mtd_info *mtd);
|
extern int nand_scan_tail(struct mtd_info *mtd);
|
||||||
|
|
||||||
/* Free resources held by the NAND device */
|
/* Free resources held by the NAND device */
|
||||||
extern void nand_release (struct mtd_info *mtd);
|
extern void nand_release(struct mtd_info *mtd);
|
||||||
|
|
||||||
/* Internal helper for board drivers which need to override command function */
|
/* Internal helper for board drivers which need to override command function */
|
||||||
extern void nand_wait_ready(struct mtd_info *mtd);
|
extern void nand_wait_ready(struct mtd_info *mtd);
|
||||||
|
|
||||||
/* This constant declares the max. oobsize / page, which
|
/*
|
||||||
|
* This constant declares the max. oobsize / page, which
|
||||||
* is supported now. If you add a chip with bigger oobsize/page
|
* is supported now. If you add a chip with bigger oobsize/page
|
||||||
* adjust this accordingly.
|
* adjust this accordingly.
|
||||||
*/
|
*/
|
||||||
#define NAND_MAX_OOBSIZE 218
|
#define NAND_MAX_OOBSIZE 576
|
||||||
#define NAND_MAX_PAGESIZE 4096
|
#define NAND_MAX_PAGESIZE 8192
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constants for hardware specific CLE/ALE/NCE function
|
* Constants for hardware specific CLE/ALE/NCE function
|
||||||
|
@ -79,10 +80,14 @@ extern void nand_wait_ready(struct mtd_info *mtd);
|
||||||
#define NAND_CMD_SEQIN 0x80
|
#define NAND_CMD_SEQIN 0x80
|
||||||
#define NAND_CMD_RNDIN 0x85
|
#define NAND_CMD_RNDIN 0x85
|
||||||
#define NAND_CMD_READID 0x90
|
#define NAND_CMD_READID 0x90
|
||||||
#define NAND_CMD_PARAM 0xec
|
|
||||||
#define NAND_CMD_ERASE2 0xd0
|
#define NAND_CMD_ERASE2 0xd0
|
||||||
|
#define NAND_CMD_PARAM 0xec
|
||||||
#define NAND_CMD_RESET 0xff
|
#define NAND_CMD_RESET 0xff
|
||||||
|
|
||||||
|
#define NAND_CMD_LOCK 0x2a
|
||||||
|
#define NAND_CMD_UNLOCK1 0x23
|
||||||
|
#define NAND_CMD_UNLOCK2 0x24
|
||||||
|
|
||||||
/* Extended commands for large page devices */
|
/* Extended commands for large page devices */
|
||||||
#define NAND_CMD_READSTART 0x30
|
#define NAND_CMD_READSTART 0x30
|
||||||
#define NAND_CMD_RNDOUTSTART 0xE0
|
#define NAND_CMD_RNDOUTSTART 0xE0
|
||||||
|
@ -142,9 +147,10 @@ typedef enum {
|
||||||
#define NAND_GET_DEVICE 0x80
|
#define NAND_GET_DEVICE 0x80
|
||||||
|
|
||||||
|
|
||||||
/* Option constants for bizarre disfunctionality and real
|
/*
|
||||||
* features
|
* Option constants for bizarre disfunctionality and real
|
||||||
*/
|
* features.
|
||||||
|
*/
|
||||||
/* Chip can not auto increment pages */
|
/* Chip can not auto increment pages */
|
||||||
#define NAND_NO_AUTOINCR 0x00000001
|
#define NAND_NO_AUTOINCR 0x00000001
|
||||||
/* Buswitdh is 16 bit */
|
/* Buswitdh is 16 bit */
|
||||||
|
@ -155,23 +161,36 @@ typedef enum {
|
||||||
#define NAND_CACHEPRG 0x00000008
|
#define NAND_CACHEPRG 0x00000008
|
||||||
/* Chip has copy back function */
|
/* Chip has copy back function */
|
||||||
#define NAND_COPYBACK 0x00000010
|
#define NAND_COPYBACK 0x00000010
|
||||||
/* AND Chip which has 4 banks and a confusing page / block
|
/*
|
||||||
* assignment. See Renesas datasheet for further information */
|
* AND Chip which has 4 banks and a confusing page / block
|
||||||
|
* assignment. See Renesas datasheet for further information.
|
||||||
|
*/
|
||||||
#define NAND_IS_AND 0x00000020
|
#define NAND_IS_AND 0x00000020
|
||||||
/* Chip has a array of 4 pages which can be read without
|
/*
|
||||||
* additional ready /busy waits */
|
* Chip has a array of 4 pages which can be read without
|
||||||
|
* additional ready /busy waits.
|
||||||
|
*/
|
||||||
#define NAND_4PAGE_ARRAY 0x00000040
|
#define NAND_4PAGE_ARRAY 0x00000040
|
||||||
/* Chip requires that BBT is periodically rewritten to prevent
|
/*
|
||||||
|
* Chip requires that BBT is periodically rewritten to prevent
|
||||||
* bits from adjacent blocks from 'leaking' in altering data.
|
* bits from adjacent blocks from 'leaking' in altering data.
|
||||||
* This happens with the Renesas AG-AND chips, possibly others. */
|
* This happens with the Renesas AG-AND chips, possibly others.
|
||||||
|
*/
|
||||||
#define BBT_AUTO_REFRESH 0x00000080
|
#define BBT_AUTO_REFRESH 0x00000080
|
||||||
/* Chip does not require ready check on read. True
|
/*
|
||||||
|
* Chip does not require ready check on read. True
|
||||||
* for all large page devices, as they do not support
|
* for all large page devices, as they do not support
|
||||||
* autoincrement.*/
|
* autoincrement.
|
||||||
|
*/
|
||||||
#define NAND_NO_READRDY 0x00000100
|
#define NAND_NO_READRDY 0x00000100
|
||||||
/* Chip does not allow subpage writes */
|
/* Chip does not allow subpage writes */
|
||||||
#define NAND_NO_SUBPAGE_WRITE 0x00000200
|
#define NAND_NO_SUBPAGE_WRITE 0x00000200
|
||||||
|
|
||||||
|
/* Device is one of 'new' xD cards that expose fake nand command set */
|
||||||
|
#define NAND_BROKEN_XD 0x00000400
|
||||||
|
|
||||||
|
/* Device behaves just like nand, but is readonly */
|
||||||
|
#define NAND_ROM 0x00000800
|
||||||
|
|
||||||
/* Options valid for Samsung large page devices */
|
/* Options valid for Samsung large page devices */
|
||||||
#define NAND_SAMSUNG_LP_OPTIONS \
|
#define NAND_SAMSUNG_LP_OPTIONS \
|
||||||
|
@ -190,17 +209,29 @@ typedef enum {
|
||||||
#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR)
|
#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR)
|
||||||
|
|
||||||
/* Non chip related options */
|
/* Non chip related options */
|
||||||
/* Use a flash based bad block table. This option is passed to the
|
/*
|
||||||
* default bad block table function. */
|
* Use a flash based bad block table. OOB identifier is saved in OOB area.
|
||||||
|
* This option is passed to the default bad block table function.
|
||||||
|
*/
|
||||||
#define NAND_USE_FLASH_BBT 0x00010000
|
#define NAND_USE_FLASH_BBT 0x00010000
|
||||||
/* This option skips the bbt scan during initialization. */
|
/* This option skips the bbt scan during initialization. */
|
||||||
#define NAND_SKIP_BBTSCAN 0x00020000
|
#define NAND_SKIP_BBTSCAN 0x00020000
|
||||||
/* This option is defined if the board driver allocates its own buffers
|
/*
|
||||||
(e.g. because it needs them DMA-coherent */
|
* This option is defined if the board driver allocates its own buffers
|
||||||
|
* (e.g. because it needs them DMA-coherent).
|
||||||
|
*/
|
||||||
#define NAND_OWN_BUFFERS 0x00040000
|
#define NAND_OWN_BUFFERS 0x00040000
|
||||||
|
/* Chip may not exist, so silence any errors in scan */
|
||||||
|
#define NAND_SCAN_SILENT_NODEV 0x00080000
|
||||||
|
/*
|
||||||
|
* If passed additionally to NAND_USE_FLASH_BBT then BBT code will not touch
|
||||||
|
* the OOB area.
|
||||||
|
*/
|
||||||
|
#define NAND_USE_FLASH_BBT_NO_OOB 0x00800000
|
||||||
|
/* Create an empty BBT with no vendor information if the BBT is available */
|
||||||
|
#define NAND_CREATE_EMPTY_BBT 0x01000000
|
||||||
|
|
||||||
/* Options set by nand scan */
|
/* Options set by nand scan */
|
||||||
/* bbt has already been read */
|
|
||||||
#define NAND_BBT_SCANNED 0x40000000
|
|
||||||
/* Nand scan has allocated controller struct */
|
/* Nand scan has allocated controller struct */
|
||||||
#define NAND_CONTROLLER_ALLOC 0x80000000
|
#define NAND_CONTROLLER_ALLOC 0x80000000
|
||||||
|
|
||||||
|
@ -275,13 +306,13 @@ struct nand_onfi_params {
|
||||||
|
|
||||||
#define ONFI_CRC_BASE 0x4F4E
|
#define ONFI_CRC_BASE 0x4F4E
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
|
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
|
||||||
* @lock: protection lock
|
* @lock: protection lock
|
||||||
* @active: the mtd device which holds the controller currently
|
* @active: the mtd device which holds the controller currently
|
||||||
* @wq: wait queue to sleep on if a NAND operation is in progress
|
* @wq: wait queue to sleep on if a NAND operation is in
|
||||||
* used instead of the per chip wait queue when a hw controller is available
|
* progress used instead of the per chip wait queue
|
||||||
|
* when a hw controller is available.
|
||||||
*/
|
*/
|
||||||
struct nand_hw_control {
|
struct nand_hw_control {
|
||||||
/* XXX U-BOOT XXX */
|
/* XXX U-BOOT XXX */
|
||||||
|
@ -302,58 +333,50 @@ struct nand_hw_control {
|
||||||
* @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
|
||||||
* @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)
|
||||||
* @read_page_raw: function to read a raw page without ECC
|
* @read_page_raw: function to read a raw page without ECC
|
||||||
* @write_page_raw: function to write a raw page without ECC
|
* @write_page_raw: function to write a raw page without ECC
|
||||||
* @read_page: function to read a page according to the ecc generator requirements
|
* @read_page: function to read a page according to the ecc generator
|
||||||
* @write_page: function to write a page according to the ecc generator requirements
|
* requirements.
|
||||||
|
* @read_subpage: function to read parts of the page covered by ECC.
|
||||||
|
* @write_page: function to write a page according to the ecc generator
|
||||||
|
* requirements.
|
||||||
* @read_oob: function to read chip OOB data
|
* @read_oob: function to read chip OOB data
|
||||||
* @write_oob: function to write chip OOB data
|
* @write_oob: function to write chip OOB data
|
||||||
*/
|
*/
|
||||||
struct nand_ecc_ctrl {
|
struct nand_ecc_ctrl {
|
||||||
nand_ecc_modes_t mode;
|
nand_ecc_modes_t mode;
|
||||||
int steps;
|
int steps;
|
||||||
int size;
|
int size;
|
||||||
int bytes;
|
int bytes;
|
||||||
int total;
|
int total;
|
||||||
int prepad;
|
int prepad;
|
||||||
int postpad;
|
int postpad;
|
||||||
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);
|
||||||
int (*calculate)(struct mtd_info *mtd,
|
int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,
|
||||||
const uint8_t *dat,
|
uint8_t *ecc_code);
|
||||||
uint8_t *ecc_code);
|
int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,
|
||||||
int (*correct)(struct mtd_info *mtd, uint8_t *dat,
|
uint8_t *calc_ecc);
|
||||||
uint8_t *read_ecc,
|
int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
uint8_t *calc_ecc);
|
uint8_t *buf, int page);
|
||||||
int (*read_page_raw)(struct mtd_info *mtd,
|
void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
struct nand_chip *chip,
|
const uint8_t *buf);
|
||||||
uint8_t *buf, int page);
|
int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
void (*write_page_raw)(struct mtd_info *mtd,
|
uint8_t *buf, int page);
|
||||||
struct nand_chip *chip,
|
int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
const uint8_t *buf);
|
uint32_t offs, uint32_t len, uint8_t *buf);
|
||||||
int (*read_page)(struct mtd_info *mtd,
|
void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
struct nand_chip *chip,
|
const uint8_t *buf);
|
||||||
uint8_t *buf, int page);
|
int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page,
|
||||||
int (*read_subpage)(struct mtd_info *mtd,
|
int sndcmd);
|
||||||
struct nand_chip *chip,
|
int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
uint32_t offs, uint32_t len,
|
int page);
|
||||||
uint8_t *buf);
|
|
||||||
void (*write_page)(struct mtd_info *mtd,
|
|
||||||
struct nand_chip *chip,
|
|
||||||
const uint8_t *buf);
|
|
||||||
int (*read_oob)(struct mtd_info *mtd,
|
|
||||||
struct nand_chip *chip,
|
|
||||||
int page,
|
|
||||||
int sndcmd);
|
|
||||||
int (*write_oob)(struct mtd_info *mtd,
|
|
||||||
struct nand_chip *chip,
|
|
||||||
int page);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -373,125 +396,150 @@ struct nand_buffers {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nand_chip - NAND Private Flash Chip Data
|
* struct nand_chip - NAND Private Flash Chip Data
|
||||||
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device
|
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the
|
||||||
* @IO_ADDR_W: [BOARDSPECIFIC] address to write 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
|
||||||
|
* flash device.
|
||||||
* @read_byte: [REPLACEABLE] read one byte from the chip
|
* @read_byte: [REPLACEABLE] read one byte from the chip
|
||||||
* @read_word: [REPLACEABLE] read one word from the chip
|
* @read_word: [REPLACEABLE] read one word from the chip
|
||||||
* @write_buf: [REPLACEABLE] write data from the buffer to the chip
|
* @write_buf: [REPLACEABLE] write data from the buffer to the chip
|
||||||
* @read_buf: [REPLACEABLE] read data from the chip into the buffer
|
* @read_buf: [REPLACEABLE] read data from the chip into the buffer
|
||||||
* @verify_buf: [REPLACEABLE] verify buffer contents against the chip data
|
* @verify_buf: [REPLACEABLE] verify buffer contents against the chip
|
||||||
|
* data.
|
||||||
* @select_chip: [REPLACEABLE] select chip nr
|
* @select_chip: [REPLACEABLE] select chip nr
|
||||||
* @block_bad: [REPLACEABLE] check, if the block is bad
|
* @block_bad: [REPLACEABLE] check, if the block is bad
|
||||||
* @block_markbad: [REPLACEABLE] mark the block bad
|
* @block_markbad: [REPLACEABLE] mark the block bad
|
||||||
* @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific funtion 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
|
||||||
* @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line
|
* @init_size: [BOARDSPECIFIC] hardwarespecific function for setting
|
||||||
* If set to NULL no access to ready/busy is available and the ready/busy information
|
* mtd->oobsize, mtd->writesize and so on.
|
||||||
* is read from the chip status register
|
* @id_data contains the 8 bytes values of NAND_CMD_READID.
|
||||||
* @cmdfunc: [REPLACEABLE] hardwarespecific function for writing commands to the chip
|
* Return with the bus width.
|
||||||
* @waitfunc: [REPLACEABLE] hardwarespecific function for wait on ready
|
* @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing
|
||||||
|
* device ready/busy line. If set to NULL no access to
|
||||||
|
* ready/busy is available and the ready/busy information
|
||||||
|
* is read from the chip status register.
|
||||||
|
* @cmdfunc: [REPLACEABLE] hardwarespecific function for writing
|
||||||
|
* commands to the chip.
|
||||||
|
* @waitfunc: [REPLACEABLE] hardwarespecific function for wait on
|
||||||
|
* ready.
|
||||||
* @ecc: [BOARDSPECIFIC] ecc control ctructure
|
* @ecc: [BOARDSPECIFIC] ecc control ctructure
|
||||||
* @buffers: buffer structure for read/write
|
* @buffers: buffer structure for read/write
|
||||||
* @hwcontrol: platform-specific hardware control structure
|
* @hwcontrol: platform-specific hardware control structure
|
||||||
* @ops: oob operation operands
|
* @ops: oob operation operands
|
||||||
* @erase_cmd: [INTERN] erase command write function, selectable due to AND support
|
* @erase_cmd: [INTERN] erase command write function, selectable due
|
||||||
|
* to AND support.
|
||||||
* @scan_bbt: [REPLACEABLE] function to scan bad block table
|
* @scan_bbt: [REPLACEABLE] function to scan bad block table
|
||||||
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
|
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring
|
||||||
* @wq: [INTERN] wait queue to sleep on if a NAND operation is in progress
|
* data from array to read regs (tR).
|
||||||
* @state: [INTERN] the current state of the NAND device
|
* @state: [INTERN] the current state of the NAND device
|
||||||
* @oob_poi: poison value buffer
|
* @oob_poi: poison value buffer
|
||||||
* @page_shift: [INTERN] number of address bits in a page (column address bits)
|
* @page_shift: [INTERN] number of address bits in a page (column
|
||||||
|
* address bits).
|
||||||
* @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
|
* @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock
|
||||||
* @bbt_erase_shift: [INTERN] number of address bits in a bbt entry
|
* @bbt_erase_shift: [INTERN] number of address bits in a bbt entry
|
||||||
* @chip_shift: [INTERN] number of address bits in one chip
|
* @chip_shift: [INTERN] number of address bits in one chip
|
||||||
* @datbuf: [INTERN] internal buffer for one page + oob
|
* @options: [BOARDSPECIFIC] various chip options. They can partly
|
||||||
* @oobbuf: [INTERN] oob buffer for one eraseblock
|
* be set to inform nand_scan about special functionality.
|
||||||
* @oobdirty: [INTERN] indicates that oob_buf must be reinitialized
|
* See the defines for further explanation.
|
||||||
* @data_poi: [INTERN] pointer to a data buffer
|
* @badblockpos: [INTERN] position of the bad block marker in the oob
|
||||||
* @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about
|
* area.
|
||||||
* special functionality. See the defines for further explanation
|
* @badblockbits: [INTERN] number of bits to left-shift the bad block
|
||||||
* @badblockpos: [INTERN] position of the bad block marker in the oob area
|
* number
|
||||||
* @cellinfo: [INTERN] MLC/multichip data from chip ident
|
* @cellinfo: [INTERN] MLC/multichip data from chip ident
|
||||||
* @numchips: [INTERN] number of physical chips
|
* @numchips: [INTERN] number of physical chips
|
||||||
* @chipsize: [INTERN] the size of one chip for multichip arrays
|
* @chipsize: [INTERN] the size of one chip for multichip arrays
|
||||||
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
|
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
|
||||||
* @pagebuf: [INTERN] holds the pagenumber which is currently in data_buf
|
* @pagebuf: [INTERN] holds the pagenumber which is currently in
|
||||||
|
* data_buf.
|
||||||
* @subpagesize: [INTERN] holds the subpagesize
|
* @subpagesize: [INTERN] holds the subpagesize
|
||||||
|
* @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded),
|
||||||
|
* non 0 if ONFI supported.
|
||||||
|
* @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is
|
||||||
|
* supported, 0 otherwise.
|
||||||
* @ecclayout: [REPLACEABLE] the default ecc placement scheme
|
* @ecclayout: [REPLACEABLE] the default ecc placement scheme
|
||||||
* @bbt: [INTERN] bad block table pointer
|
* @bbt: [INTERN] bad block table pointer
|
||||||
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup
|
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
|
||||||
|
* lookup.
|
||||||
* @bbt_md: [REPLACEABLE] bad block table mirror descriptor
|
* @bbt_md: [REPLACEABLE] bad block table mirror descriptor
|
||||||
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan
|
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial
|
||||||
* @controller: [REPLACEABLE] a pointer to a hardware controller structure
|
* bad block scan.
|
||||||
* which is shared among multiple independend devices
|
* @controller: [REPLACEABLE] a pointer to a hardware controller
|
||||||
|
* structure which is shared among multiple independend
|
||||||
|
* devices.
|
||||||
* @priv: [OPTIONAL] pointer to private chip date
|
* @priv: [OPTIONAL] pointer to private chip date
|
||||||
* @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
|
* @errstat: [OPTIONAL] hardware specific function to perform
|
||||||
* (determine if errors are correctable)
|
* additional error status checks (determine if errors are
|
||||||
|
* correctable).
|
||||||
* @write_page: [REPLACEABLE] High-level page write function
|
* @write_page: [REPLACEABLE] High-level page write function
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct nand_chip {
|
struct nand_chip {
|
||||||
void __iomem *IO_ADDR_R;
|
void __iomem *IO_ADDR_R;
|
||||||
void __iomem *IO_ADDR_W;
|
void __iomem *IO_ADDR_W;
|
||||||
|
|
||||||
uint8_t (*read_byte)(struct mtd_info *mtd);
|
uint8_t (*read_byte)(struct mtd_info *mtd);
|
||||||
u16 (*read_word)(struct mtd_info *mtd);
|
u16 (*read_word)(struct mtd_info *mtd);
|
||||||
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);
|
||||||
int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
|
int (*verify_buf)(struct mtd_info *mtd, const 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 getchip);
|
||||||
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,
|
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
|
||||||
unsigned int ctrl);
|
int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
|
||||||
int (*dev_ready)(struct mtd_info *mtd);
|
u8 *id_data);
|
||||||
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
|
int (*dev_ready)(struct mtd_info *mtd);
|
||||||
int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
|
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column,
|
||||||
void (*erase_cmd)(struct mtd_info *mtd, int page);
|
int page_addr);
|
||||||
int (*scan_bbt)(struct mtd_info *mtd);
|
int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
|
||||||
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
|
void (*erase_cmd)(struct mtd_info *mtd, int page);
|
||||||
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
int (*scan_bbt)(struct mtd_info *mtd);
|
||||||
const uint8_t *buf, int page, int cached, int raw);
|
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
|
||||||
|
int status, int page);
|
||||||
|
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
|
||||||
|
const uint8_t *buf, int page, int cached, int raw);
|
||||||
|
|
||||||
int chip_delay;
|
int chip_delay;
|
||||||
unsigned int options;
|
unsigned int options;
|
||||||
|
|
||||||
int page_shift;
|
int page_shift;
|
||||||
int phys_erase_shift;
|
int phys_erase_shift;
|
||||||
int bbt_erase_shift;
|
int bbt_erase_shift;
|
||||||
int chip_shift;
|
int chip_shift;
|
||||||
int numchips;
|
int numchips;
|
||||||
uint64_t chipsize;
|
uint64_t chipsize;
|
||||||
int pagemask;
|
int pagemask;
|
||||||
int pagebuf;
|
int pagebuf;
|
||||||
int subpagesize;
|
int subpagesize;
|
||||||
uint8_t cellinfo;
|
uint8_t cellinfo;
|
||||||
int badblockpos;
|
int badblockpos;
|
||||||
int onfi_version;
|
int badblockbits;
|
||||||
|
|
||||||
|
int onfi_version;
|
||||||
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
||||||
struct nand_onfi_params onfi_params;
|
struct nand_onfi_params onfi_params;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int state;
|
int state;
|
||||||
|
|
||||||
uint8_t *oob_poi;
|
uint8_t *oob_poi;
|
||||||
struct nand_hw_control *controller;
|
struct nand_hw_control *controller;
|
||||||
struct nand_ecclayout *ecclayout;
|
struct nand_ecclayout *ecclayout;
|
||||||
|
|
||||||
struct nand_ecc_ctrl ecc;
|
struct nand_ecc_ctrl ecc;
|
||||||
struct nand_buffers *buffers;
|
struct nand_buffers *buffers;
|
||||||
|
|
||||||
struct nand_hw_control hwcontrol;
|
struct nand_hw_control hwcontrol;
|
||||||
|
|
||||||
struct mtd_oob_ops ops;
|
struct mtd_oob_ops ops;
|
||||||
|
|
||||||
uint8_t *bbt;
|
uint8_t *bbt;
|
||||||
struct nand_bbt_descr *bbt_td;
|
struct nand_bbt_descr *bbt_td;
|
||||||
struct nand_bbt_descr *bbt_md;
|
struct nand_bbt_descr *bbt_md;
|
||||||
|
|
||||||
struct nand_bbt_descr *badblock_pattern;
|
struct nand_bbt_descr *badblock_pattern;
|
||||||
|
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -535,7 +583,7 @@ struct nand_flash_dev {
|
||||||
*/
|
*/
|
||||||
struct nand_manufacturers {
|
struct nand_manufacturers {
|
||||||
int id;
|
int id;
|
||||||
char * name;
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct nand_flash_dev nand_flash_ids[];
|
extern const struct nand_flash_dev nand_flash_ids[];
|
||||||
|
@ -548,7 +596,7 @@ extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
|
||||||
extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
|
extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
|
||||||
int allowbbt);
|
int allowbbt);
|
||||||
extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
|
extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
size_t * retlen, uint8_t * buf);
|
size_t *retlen, uint8_t *buf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constants for oob configuration
|
* Constants for oob configuration
|
||||||
|
@ -569,17 +617,20 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
|
||||||
* @priv: hardware controller specific settings
|
* @priv: hardware controller specific settings
|
||||||
*/
|
*/
|
||||||
struct platform_nand_chip {
|
struct platform_nand_chip {
|
||||||
int nr_chips;
|
int nr_chips;
|
||||||
int chip_offset;
|
int chip_offset;
|
||||||
int nr_partitions;
|
int nr_partitions;
|
||||||
struct mtd_partition *partitions;
|
struct mtd_partition *partitions;
|
||||||
struct nand_ecclayout *ecclayout;
|
struct nand_ecclayout *ecclayout;
|
||||||
int chip_delay;
|
int chip_delay;
|
||||||
unsigned int options;
|
unsigned int options;
|
||||||
const char **part_probe_types;
|
const char **part_probe_types;
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Keep gcc happy */
|
||||||
|
struct platform_device;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct platform_nand_ctrl - controller level device structure
|
* struct platform_nand_ctrl - controller level device structure
|
||||||
* @hwcontrol: platform specific hardware control structure
|
* @hwcontrol: platform specific hardware control structure
|
||||||
|
@ -592,12 +643,11 @@ struct platform_nand_chip {
|
||||||
* All fields are optional and depend on the hardware driver requirements
|
* All fields are optional and depend on the hardware driver requirements
|
||||||
*/
|
*/
|
||||||
struct platform_nand_ctrl {
|
struct platform_nand_ctrl {
|
||||||
void (*hwcontrol)(struct mtd_info *mtd, int cmd);
|
void (*hwcontrol)(struct mtd_info *mtd, int cmd);
|
||||||
int (*dev_ready)(struct mtd_info *mtd);
|
int (*dev_ready)(struct mtd_info *mtd);
|
||||||
void (*select_chip)(struct mtd_info *mtd, int chip);
|
void (*select_chip)(struct mtd_info *mtd, int chip);
|
||||||
void (*cmd_ctrl)(struct mtd_info *mtd, int dat,
|
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
|
||||||
unsigned int ctrl);
|
void *priv;
|
||||||
void *priv;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -606,8 +656,8 @@ struct platform_nand_ctrl {
|
||||||
* @ctrl: controller level device structure
|
* @ctrl: controller level device structure
|
||||||
*/
|
*/
|
||||||
struct platform_nand_data {
|
struct platform_nand_data {
|
||||||
struct platform_nand_chip chip;
|
struct platform_nand_chip chip;
|
||||||
struct platform_nand_ctrl ctrl;
|
struct platform_nand_ctrl ctrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Some helpers to access the data structures */
|
/* Some helpers to access the data structures */
|
||||||
|
|
Loading…
Reference in a new issue