Commit 0305c865 authored by David Woodhouse's avatar David Woodhouse
parents 99988f7b d470a97c
...@@ -59,9 +59,6 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -59,9 +59,6 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t *retlen, u_char *buf); size_t *retlen, u_char *buf);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
...@@ -587,9 +584,6 @@ void DoC2k_init(struct mtd_info *mtd) ...@@ -587,9 +584,6 @@ void DoC2k_init(struct mtd_info *mtd)
mtd->unpoint = NULL; mtd->unpoint = NULL;
mtd->read = doc_read; mtd->read = doc_read;
mtd->write = doc_write; mtd->write = doc_write;
mtd->read_ecc = doc_read_ecc;
mtd->write_ecc = doc_write_ecc;
mtd->writev_ecc = doc_writev_ecc;
mtd->read_oob = doc_read_oob; mtd->read_oob = doc_read_oob;
mtd->write_oob = doc_write_oob; mtd->write_oob = doc_write_oob;
mtd->sync = NULL; mtd->sync = NULL;
...@@ -965,66 +959,6 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -965,66 +959,6 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
return 0; return 0;
} }
static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel)
{
static char static_buf[512];
static DEFINE_MUTEX(writev_buf_mutex);
size_t totretlen = 0;
size_t thisvecofs = 0;
int ret= 0;
mutex_lock(&writev_buf_mutex);
while(count) {
size_t thislen, thisretlen;
unsigned char *buf;
buf = vecs->iov_base + thisvecofs;
thislen = vecs->iov_len - thisvecofs;
if (thislen >= 512) {
thislen = thislen & ~(512-1);
thisvecofs += thislen;
} else {
/* Not enough to fill a page. Copy into buf */
memcpy(static_buf, buf, thislen);
buf = &static_buf[thislen];
while(count && thislen < 512) {
vecs++;
count--;
thisvecofs = min((512-thislen), vecs->iov_len);
memcpy(buf, vecs->iov_base, thisvecofs);
thislen += thisvecofs;
buf += thisvecofs;
}
buf = static_buf;
}
if (count && thisvecofs == vecs->iov_len) {
thisvecofs = 0;
vecs++;
count--;
}
ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel);
totretlen += thisretlen;
if (ret || thisretlen != thislen)
break;
to += thislen;
}
mutex_unlock(&writev_buf_mutex);
*retlen = totretlen;
return ret;
}
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
size_t * retlen, u_char * buf) size_t * retlen, u_char * buf)
{ {
......
...@@ -369,8 +369,6 @@ void DoCMil_init(struct mtd_info *mtd) ...@@ -369,8 +369,6 @@ void DoCMil_init(struct mtd_info *mtd)
mtd->unpoint = NULL; mtd->unpoint = NULL;
mtd->read = doc_read; mtd->read = doc_read;
mtd->write = doc_write; mtd->write = doc_write;
mtd->read_ecc = doc_read_ecc;
mtd->write_ecc = doc_write_ecc;
mtd->read_oob = doc_read_oob; mtd->read_oob = doc_read_oob;
mtd->write_oob = doc_write_oob; mtd->write_oob = doc_write_oob;
mtd->sync = NULL; mtd->sync = NULL;
......
...@@ -491,8 +491,6 @@ void DoCMilPlus_init(struct mtd_info *mtd) ...@@ -491,8 +491,6 @@ void DoCMilPlus_init(struct mtd_info *mtd)
mtd->unpoint = NULL; mtd->unpoint = NULL;
mtd->read = doc_read; mtd->read = doc_read;
mtd->write = doc_write; mtd->write = doc_write;
mtd->read_ecc = doc_read_ecc;
mtd->write_ecc = doc_write_ecc;
mtd->read_oob = doc_read_oob; mtd->read_oob = doc_read_oob;
mtd->write_oob = doc_write_oob; mtd->write_oob = doc_write_oob;
mtd->sync = NULL; mtd->sync = NULL;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/nftl.h> #include <linux/mtd/nftl.h>
#include <linux/mtd/inftl.h> #include <linux/mtd/inftl.h>
#include <linux/mtd/nand.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/errno.h> #include <asm/errno.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -79,14 +80,12 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -79,14 +80,12 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
inftl->mbd.devnum = -1; inftl->mbd.devnum = -1;
inftl->mbd.blksize = 512; inftl->mbd.blksize = 512;
inftl->mbd.tr = tr; inftl->mbd.tr = tr;
memcpy(&inftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
inftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
if (INFTL_mount(inftl) < 0) { if (INFTL_mount(inftl) < 0) {
printk(KERN_WARNING "INFTL: could not mount device\n"); printk(KERN_WARNING "INFTL: could not mount device\n");
kfree(inftl); kfree(inftl);
return; return;
} }
/* OK, it's a new one. Set up all the data structures. */ /* OK, it's a new one. Set up all the data structures. */
...@@ -221,7 +220,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned ...@@ -221,7 +220,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
* Scan to find the Erase Unit which holds the actual data for each * Scan to find the Erase Unit which holds the actual data for each
* 512-byte block within the Chain. * 512-byte block within the Chain.
*/ */
silly = MAX_LOOPS; silly = MAX_LOOPS;
while (thisEUN < inftl->nb_blocks) { while (thisEUN < inftl->nb_blocks) {
for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) { for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
if ((BlockMap[block] != 0xffff) || BlockDeleted[block]) if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
...@@ -232,7 +231,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned ...@@ -232,7 +231,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
(char *)&oob) < 0) (char *)&oob) < 0)
status = SECTOR_IGNORE; status = SECTOR_IGNORE;
else else
status = oob.b.Status | oob.b.Status1; status = oob.b.Status | oob.b.Status1;
switch(status) { switch(status) {
case SECTOR_FREE: case SECTOR_FREE:
...@@ -282,29 +281,30 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned ...@@ -282,29 +281,30 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
continue; continue;
} }
/* /*
* Copy only in non free block (free blocks can only * Copy only in non free block (free blocks can only
* happen in case of media errors or deleted blocks). * happen in case of media errors or deleted blocks).
*/ */
if (BlockMap[block] == BLOCK_NIL) if (BlockMap[block] == BLOCK_NIL)
continue; continue;
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
&retlen, movebuf); &retlen, movebuf);
if (ret < 0) { if (ret < 0) {
ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
BlockMap[block]) + (block * SECTORSIZE), BlockMap[block]) + (block * SECTORSIZE),
SECTORSIZE, &retlen, movebuf); SECTORSIZE, &retlen, movebuf);
if (ret != -EIO) if (ret != -EIO)
DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
"away on retry?\n"); "away on retry?\n");
} }
memset(&oob, 0xff, sizeof(struct inftl_oob)); memset(&oob, 0xff, sizeof(struct inftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED; oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
(block * SECTORSIZE), SECTORSIZE, &retlen, nand_write_raw(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
movebuf, (char *)&oob, &inftl->oobinfo); (block * SECTORSIZE), SECTORSIZE, &retlen,
movebuf, (char *)&oob);
} }
/* /*
...@@ -329,17 +329,17 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned ...@@ -329,17 +329,17 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
if (thisEUN == targetEUN) if (thisEUN == targetEUN)
break; break;
if (INFTL_formatblock(inftl, thisEUN) < 0) { if (INFTL_formatblock(inftl, thisEUN) < 0) {
/* /*
* Could not erase : mark block as reserved. * Could not erase : mark block as reserved.
*/ */
inftl->PUtable[thisEUN] = BLOCK_RESERVED; inftl->PUtable[thisEUN] = BLOCK_RESERVED;
} else { } else {
/* Correctly erased : mark it as free */ /* Correctly erased : mark it as free */
inftl->PUtable[thisEUN] = BLOCK_FREE; inftl->PUtable[thisEUN] = BLOCK_FREE;
inftl->PUtable[prevEUN] = BLOCK_NIL; inftl->PUtable[prevEUN] = BLOCK_NIL;
inftl->numfreeEUNs++; inftl->numfreeEUNs++;
} }
} }
return targetEUN; return targetEUN;
...@@ -437,7 +437,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) ...@@ -437,7 +437,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
blockofs, 8, &retlen, (char *)&bci); blockofs, 8, &retlen, (char *)&bci);
status = bci.Status | bci.Status1; status = bci.Status | bci.Status1;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in "
"EUN %d is %x\n", block , writeEUN, status); "EUN %d is %x\n", block , writeEUN, status);
...@@ -670,12 +670,12 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) ...@@ -670,12 +670,12 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n", DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n",
thisEUN, thisVUC); thisEUN, thisVUC);
if (INFTL_formatblock(inftl, thisEUN) < 0) { if (INFTL_formatblock(inftl, thisEUN) < 0) {
/* /*
* Could not erase : mark block as reserved. * Could not erase : mark block as reserved.
*/ */
inftl->PUtable[thisEUN] = BLOCK_RESERVED; inftl->PUtable[thisEUN] = BLOCK_RESERVED;
} else { } else {
/* Correctly erased : mark it as free */ /* Correctly erased : mark it as free */
inftl->PUtable[thisEUN] = BLOCK_FREE; inftl->PUtable[thisEUN] = BLOCK_FREE;
inftl->numfreeEUNs++; inftl->numfreeEUNs++;
...@@ -784,9 +784,10 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, ...@@ -784,9 +784,10 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
memset(&oob, 0xff, sizeof(struct inftl_oob)); memset(&oob, 0xff, sizeof(struct inftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED; oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
blockofs, SECTORSIZE, &retlen, (char *)buffer, nand_write_raw(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
(char *)&oob, &inftl->oobinfo); blockofs, SECTORSIZE, &retlen, (char *)buffer,
(char *)&oob);
/* /*
* need to write SECTOR_USED flags since they are not written * need to write SECTOR_USED flags since they are not written
* in mtd_writeecc * in mtd_writeecc
...@@ -804,9 +805,9 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, ...@@ -804,9 +805,9 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
struct INFTLrecord *inftl = (void *)mbd; struct INFTLrecord *inftl = (void *)mbd;
unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)];
unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
unsigned int status; unsigned int status;
int silly = MAX_LOOPS; int silly = MAX_LOOPS;
struct inftl_bci bci; struct inftl_bci bci;
size_t retlen; size_t retlen;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld," DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld,"
...@@ -850,7 +851,7 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, ...@@ -850,7 +851,7 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
/* The requested block is not on the media, return all 0x00 */ /* The requested block is not on the media, return all 0x00 */
memset(buffer, 0, SECTORSIZE); memset(buffer, 0, SECTORSIZE);
} else { } else {
size_t retlen; size_t retlen;
loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen, if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
buffer)) buffer))
......
...@@ -350,21 +350,21 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, ...@@ -350,21 +350,21 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
int len, int check_oob) int len, int check_oob)
{ {
u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize]; u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
struct mtd_info *mtd = inftl->mbd.mtd;
size_t retlen; size_t retlen;
int i; int i;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=%p,"
"address=0x%x,len=%d,check_oob=%d)\n", inftl,
address, len, check_oob);
for (i = 0; i < len; i += SECTORSIZE) { for (i = 0; i < len; i += SECTORSIZE) {
if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0) if (mtd->read(mtd, address, SECTORSIZE, &retlen, buf))
return -1; return -1;
if (memcmpb(buf, 0xff, SECTORSIZE) != 0) if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
return -1; return -1;
if (check_oob) { if (check_oob) {
if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0) if(mtd->read_oob(mtd, address, mtd->oobsize,
&retlen, &buf[SECTORSIZE]) < 0)
return -1;
if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
return -1; return -1;
} }
address += SECTORSIZE; address += SECTORSIZE;
......
...@@ -143,119 +143,8 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -143,119 +143,8 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len,
} }
static int static int
concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
size_t * retlen, u_char * buf, u_char * eccbuf, unsigned long count, loff_t to, size_t * retlen)
struct nand_oobinfo *oobsel)
{
struct mtd_concat *concat = CONCAT(mtd);
int err = -EINVAL;
int i;
*retlen = 0;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size, retsize;
if (from >= subdev->size) {
/* Not destined for this subdev */
size = 0;
from -= subdev->size;
continue;
}
if (from + len > subdev->size)
/* First part goes into this subdev */
size = subdev->size - from;
else
/* Entire transaction goes into this subdev */
size = len;
if (subdev->read_ecc)
err = subdev->read_ecc(subdev, from, size,
&retsize, buf, eccbuf, oobsel);
else
err = -EINVAL;
if (err)
break;
*retlen += retsize;
len -= size;
if (len == 0)
break;
err = -EINVAL;
buf += size;
if (eccbuf) {
eccbuf += subdev->oobsize;
/* in nand.c at least, eccbufs are
tagged with 2 (int)eccstatus'; we
must account for these */
eccbuf += 2 * (sizeof (int));
}
from = 0;
}
return err;
}
static int
concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf, u_char * eccbuf,
struct nand_oobinfo *oobsel)
{
struct mtd_concat *concat = CONCAT(mtd);
int err = -EINVAL;
int i;
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
*retlen = 0;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
size_t size, retsize;
if (to >= subdev->size) {
size = 0;
to -= subdev->size;
continue;
}
if (to + len > subdev->size)
size = subdev->size - to;
else
size = len;
if (!(subdev->flags & MTD_WRITEABLE))
err = -EROFS;
else if (subdev->write_ecc)
err = subdev->write_ecc(subdev, to, size,
&retsize, buf, eccbuf, oobsel);
else
err = -EINVAL;
if (err)
break;
*retlen += retsize;
len -= size;
if (len == 0)
break;
err = -EINVAL;
buf += size;
if (eccbuf)
eccbuf += subdev->oobsize;
to = 0;
}
return err;
}
static int
concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t * retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel)
{ {
struct mtd_concat *concat = CONCAT(mtd); struct mtd_concat *concat = CONCAT(mtd);
struct kvec *vecs_copy; struct kvec *vecs_copy;
...@@ -315,10 +204,6 @@ concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, ...@@ -315,10 +204,6 @@ concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
if (!(subdev->flags & MTD_WRITEABLE)) if (!(subdev->flags & MTD_WRITEABLE))
err = -EROFS; err = -EROFS;
else if (eccbuf)
err = subdev->writev_ecc(subdev, &vecs_copy[entry_low],
entry_high - entry_low + 1, to, &retsize,
eccbuf, oobsel);
else else
err = subdev->writev(subdev, &vecs_copy[entry_low], err = subdev->writev(subdev, &vecs_copy[entry_low],
entry_high - entry_low + 1, to, &retsize); entry_high - entry_low + 1, to, &retsize);
...@@ -333,8 +218,6 @@ concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, ...@@ -333,8 +218,6 @@ concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
*retlen += retsize; *retlen += retsize;
total_len -= wsize; total_len -= wsize;
if (concat->mtd.type == MTD_NANDFLASH && eccbuf)
eccbuf += mtd->oobavail * (wsize / mtd->writesize);
if (total_len == 0) if (total_len == 0)
break; break;
...@@ -347,13 +230,6 @@ concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, ...@@ -347,13 +230,6 @@ concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
return err; return err;
} }
static int
concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t * retlen)
{
return concat_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL);
}
static int static int
concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len, concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf) size_t * retlen, u_char * buf)
...@@ -837,14 +713,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c ...@@ -837,14 +713,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobsize = subdev[0]->oobsize;
concat->mtd.ecctype = subdev[0]->ecctype; concat->mtd.ecctype = subdev[0]->ecctype;
concat->mtd.eccsize = subdev[0]->eccsize; concat->mtd.eccsize = subdev[0]->eccsize;
if (subdev[0]->read_ecc)
concat->mtd.read_ecc = concat_read_ecc;
if (subdev[0]->write_ecc)
concat->mtd.write_ecc = concat_write_ecc;
if (subdev[0]->writev) if (subdev[0]->writev)
concat->mtd.writev = concat_writev; concat->mtd.writev = concat_writev;
if (subdev[0]->writev_ecc)
concat->mtd.writev_ecc = concat_writev_ecc;
if (subdev[0]->read_oob) if (subdev[0]->read_oob)
concat->mtd.read_oob = concat_read_oob; concat->mtd.read_oob = concat_read_oob;
if (subdev[0]->write_oob) if (subdev[0]->write_oob)
...@@ -885,8 +755,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c ...@@ -885,8 +755,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.oobsize != subdev[i]->oobsize || concat->mtd.oobsize != subdev[i]->oobsize ||
concat->mtd.ecctype != subdev[i]->ecctype || concat->mtd.ecctype != subdev[i]->ecctype ||
concat->mtd.eccsize != subdev[i]->eccsize || concat->mtd.eccsize != subdev[i]->eccsize ||
!concat->mtd.read_ecc != !subdev[i]->read_ecc ||
!concat->mtd.write_ecc != !subdev[i]->write_ecc ||
!concat->mtd.read_oob != !subdev[i]->read_oob || !concat->mtd.read_oob != !subdev[i]->read_oob ||
!concat->mtd.write_oob != !subdev[i]->write_oob) { !concat->mtd.write_oob != !subdev[i]->write_oob) {
kfree(concat); kfree(concat);
......
...@@ -55,12 +55,8 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, ...@@ -55,12 +55,8 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
len = 0; len = 0;
else if (from + len > mtd->size) else if (from + len > mtd->size)
len = mtd->size - from; len = mtd->size - from;
if (part->master->read_ecc == NULL) return part->master->read (part->master, from + part->offset,
return part->master->read (part->master, from + part->offset, len, retlen, buf);
len, retlen, buf);
else
return part->master->read_ecc (part->master, from + part->offset,
len, retlen, buf, NULL, &mtd->oobinfo);
} }
static int part_point (struct mtd_info *mtd, loff_t from, size_t len, static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
...@@ -74,6 +70,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len, ...@@ -74,6 +70,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
return part->master->point (part->master, from + part->offset, return part->master->point (part->master, from + part->offset,
len, retlen, buf); len, retlen, buf);
} }
static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
{ {
struct mtd_part *part = PART(mtd); struct mtd_part *part = PART(mtd);
...@@ -81,21 +78,6 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_ ...@@ -81,21 +78,6 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_
part->master->unpoint (part->master, addr, from + part->offset, len); part->master->unpoint (part->master, addr, from + part->offset, len);
} }
static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
{
struct mtd_part *part = PART(mtd);
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
if (from >= mtd->size)
len = 0;
else if (from + len > mtd->size)
len = mtd->size - from;
return part->master->read_ecc (part->master, from + part->offset,
len, retlen, buf, eccbuf, oobsel);
}
static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf) size_t *retlen, u_char *buf)
{ {
...@@ -148,30 +130,8 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len, ...@@ -148,30 +130,8 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
len = 0; len = 0;
else if (to + len > mtd->size) else if (to + len > mtd->size)
len = mtd->size - to; len = mtd->size - to;
if (part->master->write_ecc == NULL) return part->master->write (part->master, to + part->offset,
return part->master->write (part->master, to + part->offset, len, retlen, buf);
len, retlen, buf);
else
return part->master->write_ecc (part->master, to + part->offset,
len, retlen, buf, NULL, &mtd->oobinfo);
}
static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf,
u_char *eccbuf, struct nand_oobinfo *oobsel)
{
struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
if (to >= mtd->size)
len = 0;
else if (to + len > mtd->size)
len = mtd->size - to;
return part->master->write_ecc (part->master, to + part->offset,
len, retlen, buf, eccbuf, oobsel);
} }
static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
...@@ -208,52 +168,8 @@ static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, ...@@ -208,52 +168,8 @@ static int part_writev (struct mtd_info *mtd, const struct kvec *vecs,
struct mtd_part *part = PART(mtd); struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE)) if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS; return -EROFS;
if (part->master->writev_ecc == NULL) return part->master->writev (part->master, vecs, count,
return part->master->writev (part->master, vecs, count,
to + part->offset, retlen); to + part->offset, retlen);
else
return part->master->writev_ecc (part->master, vecs, count,
to + part->offset, retlen,
NULL, &mtd->oobinfo);
}
static int part_readv (struct mtd_info *mtd, struct kvec *vecs,
unsigned long count, loff_t from, size_t *retlen)
{
struct mtd_part *part = PART(mtd);
if (part->master->readv_ecc == NULL)
return part->master->readv (part->master, vecs, count,
from + part->offset, retlen);
else
return part->master->readv_ecc (part->master, vecs, count,
from + part->offset, retlen,
NULL, &mtd->oobinfo);
}
static int part_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel)
{
struct mtd_part *part = PART(mtd);
if (!(mtd->flags & MTD_WRITEABLE))
return -EROFS;
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
return part->master->writev_ecc (part->master, vecs, count,
to + part->offset, retlen,
eccbuf, oobsel);
}
static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs,
unsigned long count, loff_t from, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel)
{
struct mtd_part *part = PART(mtd);
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
return part->master->readv_ecc (part->master, vecs, count,
from + part->offset, retlen,
eccbuf, oobsel);
} }
static int part_erase (struct mtd_info *mtd, struct erase_info *instr) static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
...@@ -416,10 +332,6 @@ int add_mtd_partitions(struct mtd_info *master, ...@@ -416,10 +332,6 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.unpoint = part_unpoint; slave->mtd.unpoint = part_unpoint;
} }
if (master->read_ecc)
slave->mtd.read_ecc = part_read_ecc;
if (master->write_ecc)
slave->mtd.write_ecc = part_write_ecc;
if (master->read_oob) if (master->read_oob)
slave->mtd.read_oob = part_read_oob; slave->mtd.read_oob = part_read_oob;
if (master->write_oob) if (master->write_oob)
...@@ -444,12 +356,6 @@ int add_mtd_partitions(struct mtd_info *master, ...@@ -444,12 +356,6 @@ int add_mtd_partitions(struct mtd_info *master,
} }
if (master->writev) if (master->writev)
slave->mtd.writev = part_writev; slave->mtd.writev = part_writev;
if (master->readv)
slave->mtd.readv = part_readv;
if (master->writev_ecc)
slave->mtd.writev_ecc = part_writev_ecc;
if (master->readv_ecc)
slave->mtd.readv_ecc = part_readv_ecc;
if (master->lock) if (master->lock)
slave->mtd.lock = part_lock; slave->mtd.lock = part_lock;
if (master->unlock) if (master->unlock)
......
...@@ -65,7 +65,7 @@ config MTD_NAND_AMS_DELTA ...@@ -65,7 +65,7 @@ config MTD_NAND_AMS_DELTA
config MTD_NAND_TOTO config MTD_NAND_TOTO
tristate "NAND Flash device on TOTO board" tristate "NAND Flash device on TOTO board"
depends on ARCH_OMAP && MTD_NAND depends on ARCH_OMAP && MTD_NAND && BROKEN
help help
Support for NAND flash on Texas Instruments Toto platform. Support for NAND flash on Texas Instruments Toto platform.
...@@ -96,7 +96,7 @@ config MTD_NAND_RTC_FROM4 ...@@ -96,7 +96,7 @@ config MTD_NAND_RTC_FROM4
config MTD_NAND_PPCHAMELEONEVB config MTD_NAND_PPCHAMELEONEVB
tristate "NAND Flash device on PPChameleonEVB board" tristate "NAND Flash device on PPChameleonEVB board"
depends on PPCHAMELEONEVB && MTD_NAND depends on PPCHAMELEONEVB && MTD_NAND && BROKEN
help help
This enables the NAND flash driver on the PPChameleon EVB Board. This enables the NAND flash driver on the PPChameleon EVB Board.
......
...@@ -34,13 +34,6 @@ static struct mtd_info *ams_delta_mtd = NULL; ...@@ -34,13 +34,6 @@ static struct mtd_info *ams_delta_mtd = NULL;
#define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP) #define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP)
#define T_NAND_CTL_CLRALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, 0)
#define T_NAND_CTL_SETALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, AMS_DELTA_LATCH2_NAND_ALE)
#define T_NAND_CTL_CLRCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, 0)
#define T_NAND_CTL_SETCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, AMS_DELTA_LATCH2_NAND_CLE)
#define T_NAND_CTL_SETNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, 0)
#define T_NAND_CTL_CLRNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, AMS_DELTA_LATCH2_NAND_NCE)
/* /*
* Define partitions for flash devices * Define partitions for flash devices
*/ */
...@@ -66,25 +59,6 @@ static struct mtd_partition partition_info[] = { ...@@ -66,25 +59,6 @@ static struct mtd_partition partition_info[] = {
.size = 3 * SZ_256K }, .size = 3 * SZ_256K },
}; };
/*
* hardware specific access to control-lines
*/
static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd)
{
switch (cmd) {
case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break;
case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break;
case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break;
case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break;
case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break;
case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break;
}
}
static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
{ {
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
...@@ -141,6 +115,32 @@ static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf, ...@@ -141,6 +115,32 @@ static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf,
return 0; return 0;
} }
/*
* Command control function
*
* ctrl:
* NAND_NCE: bit 0 -> bit 2
* NAND_CLE: bit 1 -> bit 7
* NAND_ALE: bit 2 -> bit 6
*/
static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
if (ctrl & NAND_CTRL_CHANGE) {
unsigned long bits;
bits = (~ctrl & NAND_NCE) << 2;
bits |= (ctrl & NAND_CLE) << 7;
bits |= (ctrl & NAND_ALE) << 6;
ams_delta_latch2_write(0xC2, bits);
}
if (cmd != NAND_CMD_NONE)
ams_delta_write_byte(mtd, cmd);
}
static int ams_delta_nand_ready(struct mtd_info *mtd) static int ams_delta_nand_ready(struct mtd_info *mtd)
{ {
return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB); return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB);
...@@ -179,11 +179,10 @@ static int __init ams_delta_init(void) ...@@ -179,11 +179,10 @@ static int __init ams_delta_init(void)
this->IO_ADDR_R = (OMAP_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH); this->IO_ADDR_R = (OMAP_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH);
this->IO_ADDR_W = (OMAP_MPUIO_BASE + OMAP_MPUIO_OUTPUT); this->IO_ADDR_W = (OMAP_MPUIO_BASE + OMAP_MPUIO_OUTPUT);
this->read_byte = ams_delta_read_byte; this->read_byte = ams_delta_read_byte;
this->write_byte = ams_delta_write_byte;
this->write_buf = ams_delta_write_buf; this->write_buf = ams_delta_write_buf;
this->read_buf = ams_delta_read_buf; this->read_buf = ams_delta_read_buf;
this->verify_buf = ams_delta_verify_buf; this->verify_buf = ams_delta_verify_buf;
this->hwcontrol = ams_delta_hwcontrol; this->cmd_ctrl = ams_delta_hwcontrol;
if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) { if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) {
this->dev_ready = ams_delta_nand_ready; this->dev_ready = ams_delta_nand_ready;
} else { } else {
...@@ -200,7 +199,7 @@ static int __init ams_delta_init(void) ...@@ -200,7 +199,7 @@ static int __init ams_delta_init(void)
AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NCE |
AMS_DELTA_LATCH2_NAND_NWP); AMS_DELTA_LATCH2_NAND_NWP);
/* Scan to find existance of the device */ /* Scan to find existance of the device */
if (nand_scan(ams_delta_mtd, 1)) { if (nand_scan(ams_delta_mtd, 1)) {
err = -ENXIO; err = -ENXIO;
goto out_mtd; goto out_mtd;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
static struct mtd_info *au1550_mtd = NULL; static struct mtd_info *au1550_mtd = NULL;
static void __iomem *p_nand; static void __iomem *p_nand;
static int nand_width = 1; /* default x8 */ static int nand_width = 1; /* default x8 */
static void (*au1550_write_byte)(struct mtd_info *, u_char);
/* /*
* Define partitions for flash device * Define partitions for flash device
...@@ -128,21 +129,6 @@ static u16 au_read_word(struct mtd_info *mtd) ...@@ -128,21 +129,6 @@ static u16 au_read_word(struct mtd_info *mtd)
return ret; return ret;
} }
/**
* au_write_word - write one word to the chip
* @mtd: MTD device structure
* @word: data word to write
*
* write function for 16bit buswith without
* endianess conversion
*/
static void au_write_word(struct mtd_info *mtd, u16 word)
{
struct nand_chip *this = mtd->priv;
writew(word, this->IO_ADDR_W);
au_sync();
}
/** /**
* au_write_buf - write buffer to chip * au_write_buf - write buffer to chip
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -269,6 +255,18 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) ...@@ -269,6 +255,18 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
return 0; return 0;
} }
/* Select the chip by setting nCE to low */
#define NAND_CTL_SETNCE 1
/* Deselect the chip by setting nCE to high */
#define NAND_CTL_CLRNCE 2
/* Select the command latch by setting CLE to high */
#define NAND_CTL_SETCLE 3
/* Deselect the command latch by setting CLE to low */
#define NAND_CTL_CLRCLE 4
/* Select the address latch by setting ALE to high */
#define NAND_CTL_SETALE 5
/* Deselect the address latch by setting ALE to low */
#define NAND_CTL_CLRALE 6
static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
{ {
...@@ -349,7 +347,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i ...@@ -349,7 +347,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
ulong flags; ulong flags;
/* Begin command latch cycle */ /* Begin command latch cycle */
this->hwcontrol(mtd, NAND_CTL_SETCLE); au1550_hwcontrol(mtd, NAND_CTL_SETCLE);
/* /*
* Write out the command to the device. * Write out the command to the device.
*/ */
...@@ -367,25 +365,25 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i ...@@ -367,25 +365,25 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
column -= 256; column -= 256;
readcmd = NAND_CMD_READ1; readcmd = NAND_CMD_READ1;
} }
this->write_byte(mtd, readcmd); au1550_write_byte(mtd, readcmd);
} }
this->write_byte(mtd, command); au1550_write_byte(mtd, command);
/* Set ALE and clear CLE to start address cycle */ /* Set ALE and clear CLE to start address cycle */
this->hwcontrol(mtd, NAND_CTL_CLRCLE); au1550_hwcontrol(mtd, NAND_CTL_CLRCLE);
if (column != -1 || page_addr != -1) { if (column != -1 || page_addr != -1) {
this->hwcontrol(mtd, NAND_CTL_SETALE); au1550_hwcontrol(mtd, NAND_CTL_SETALE);
/* Serially input address */ /* Serially input address */
if (column != -1) { if (column != -1) {
/* Adjust columns for 16 bit buswidth */ /* Adjust columns for 16 bit buswidth */
if (this->options & NAND_BUSWIDTH_16) if (this->options & NAND_BUSWIDTH_16)
column >>= 1; column >>= 1;
this->write_byte(mtd, column); au1550_write_byte(mtd, column);
} }
if (page_addr != -1) { if (page_addr != -1) {
this->write_byte(mtd, (u8)(page_addr & 0xff)); au1550_write_byte(mtd, (u8)(page_addr & 0xff));
if (command == NAND_CMD_READ0 || if (command == NAND_CMD_READ0 ||
command == NAND_CMD_READ1 || command == NAND_CMD_READ1 ||
...@@ -400,17 +398,17 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i ...@@ -400,17 +398,17 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
*/ */
ce_override = 1; ce_override = 1;
local_irq_save(flags); local_irq_save(flags);
this->hwcontrol(mtd, NAND_CTL_SETNCE); au1550_hwcontrol(mtd, NAND_CTL_SETNCE);
} }
this->write_byte(mtd, (u8)(page_addr >> 8)); au1550_write_byte(mtd, (u8)(page_addr >> 8));
/* One more address cycle for devices > 32MiB */ /* One more address cycle for devices > 32MiB */
if (this->chipsize > (32 << 20)) if (this->chipsize > (32 << 20))
this->write_byte(mtd, (u8)((page_addr >> 16) & 0x0f)); au1550_write_byte(mtd, (u8)((page_addr >> 16) & 0x0f));
} }
/* Latch in address */ /* Latch in address */
this->hwcontrol(mtd, NAND_CTL_CLRALE); au1550_hwcontrol(mtd, NAND_CTL_CLRALE);
} }
/* /*
...@@ -443,7 +441,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i ...@@ -443,7 +441,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
udelay(1); udelay(1);
/* Release -CE and re-enable interrupts. */ /* Release -CE and re-enable interrupts. */
this->hwcontrol(mtd, NAND_CTL_CLRNCE); au1550_hwcontrol(mtd, NAND_CTL_CLRNCE);
local_irq_restore(flags); local_irq_restore(flags);
return; return;
} }
...@@ -571,7 +569,6 @@ static int __init au1xxx_nand_init(void) ...@@ -571,7 +569,6 @@ static int __init au1xxx_nand_init(void)
nand_width = au_readl(MEM_STCFG3) & (1 << 22); nand_width = au_readl(MEM_STCFG3) & (1 << 22);
/* Set address of hardware control function */ /* Set address of hardware control function */
this->hwcontrol = au1550_hwcontrol;
this->dev_ready = au1550_device_ready; this->dev_ready = au1550_device_ready;
this->select_chip = au1550_select_chip; this->select_chip = au1550_select_chip;
this->cmdfunc = au1550_command; this->cmdfunc = au1550_command;
...@@ -586,8 +583,7 @@ static int __init au1xxx_nand_init(void) ...@@ -586,8 +583,7 @@ static int __init au1xxx_nand_init(void)
this->options |= NAND_BUSWIDTH_16; this->options |= NAND_BUSWIDTH_16;
this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte; this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte;
this->write_byte = (!nand_width) ? au_write_byte16 : au_write_byte; au1550_write_byte = (!nand_width) ? au_write_byte16 : au_write_byte;
this->write_word = au_write_word;
this->read_word = au_read_word; this->read_word = au_read_word;
this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf; this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf;
this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf; this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de> * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
* *
* Derived from drivers/mtd/spia.c * Derived from drivers/mtd/spia.c
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
* *
* $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $ * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $
* *
...@@ -42,11 +42,6 @@ ...@@ -42,11 +42,6 @@
* MTD structure for AUTCPU12 board * MTD structure for AUTCPU12 board
*/ */
static struct mtd_info *autcpu12_mtd = NULL; static struct mtd_info *autcpu12_mtd = NULL;
static int autcpu12_io_base = CS89712_VIRT_BASE;
static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC;
static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET;
static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET;
static void __iomem *autcpu12_fio_base; static void __iomem *autcpu12_fio_base;
/* /*
...@@ -94,31 +89,42 @@ static struct mtd_partition partition_info128k[] = { ...@@ -94,31 +89,42 @@ static struct mtd_partition partition_info128k[] = {
#define NUM_PARTITIONS128K 2 #define NUM_PARTITIONS128K 2
/* /*
* hardware specific access to control-lines * hardware specific access to control-lines
*/ *
* ALE bit 4 autcpu12_pedr
static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) * CLE bit 5 autcpu12_pedr
* NCE bit 0 fio_ctrl
*
*/
static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{ {
switch (cmd) { struct nand_chip *chip = mtd->priv;
case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_CLE; break; if (ctrl & NAND_CTRL_CHANGE) {
case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break; void __iomem *addr
unsigned char bits;
case NAND_CTL_SETALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_ALE; break; addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
case NAND_CTL_CLRALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_ALE; break; bits = (ctrl & NAND_CLE) << 4;
bits |= (ctrl & NAND_ALE) << 2;
writeb((readb(addr) & ~0x30) | bits, addr);
case NAND_CTL_SETNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x01; break; addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET;
case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x00; break; writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr);
} }
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
} }
/* /*
* read device ready pin * read device ready pin
*/ */
int autcpu12_device_ready(struct mtd_info *mtd) int autcpu12_device_ready(struct mtd_info *mtd)
{ {
void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
return ((*(volatile unsigned char *)(autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0; return readb(addr) & AUTCPU12_SMC_RDY;
} }
/* /*
...@@ -130,7 +136,8 @@ static int __init autcpu12_init(void) ...@@ -130,7 +136,8 @@ static int __init autcpu12_init(void)
int err = 0; int err = 0;
/* Allocate memory for MTD device structure and private data */ /* Allocate memory for MTD device structure and private data */
autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
GFP_KERNEL);
if (!autcpu12_mtd) { if (!autcpu12_mtd) {
printk("Unable to allocate AUTCPU12 NAND MTD device structure.\n"); printk("Unable to allocate AUTCPU12 NAND MTD device structure.\n");
err = -ENOMEM; err = -ENOMEM;
...@@ -138,7 +145,7 @@ static int __init autcpu12_init(void) ...@@ -138,7 +145,7 @@ static int __init autcpu12_init(void)
} }
/* map physical adress */ /* map physical adress */
autcpu12_fio_base = ioremap(autcpu12_fio_pbase, SZ_1K); autcpu12_fio_base = ioremap(AUTCPU12_PHYS_SMC, SZ_1K);
if (!autcpu12_fio_base) { if (!autcpu12_fio_base) {
printk("Ioremap autcpu12 SmartMedia Card failed\n"); printk("Ioremap autcpu12 SmartMedia Card failed\n");
err = -EIO; err = -EIO;
...@@ -159,7 +166,7 @@ static int __init autcpu12_init(void) ...@@ -159,7 +166,7 @@ static int __init autcpu12_init(void)
/* Set address of NAND IO lines */ /* Set address of NAND IO lines */
this->IO_ADDR_R = autcpu12_fio_base; this->IO_ADDR_R = autcpu12_fio_base;
this->IO_ADDR_W = autcpu12_fio_base; this->IO_ADDR_W = autcpu12_fio_base;
this->hwcontrol = autcpu12_hwcontrol; this->cmd_ctrl = autcpu12_hwcontrol;
this->dev_ready = autcpu12_device_ready; this->dev_ready = autcpu12_device_ready;
/* 20 us command delay time */ /* 20 us command delay time */
this->chip_delay = 20; this->chip_delay = 20;
...@@ -179,10 +186,22 @@ static int __init autcpu12_init(void) ...@@ -179,10 +186,22 @@ static int __init autcpu12_init(void)
/* Register the partitions */ /* Register the partitions */
switch (autcpu12_mtd->size) { switch (autcpu12_mtd->size) {
case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; case SZ_16M:
case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break; add_mtd_partitions(autcpu12_mtd, partition_info16k,
case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; NUM_PARTITIONS16K);
case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; break;
case SZ_32M:
add_mtd_partitions(autcpu12_mtd, partition_info32k,
NUM_PARTITIONS32K);
break;
case SZ_64M:
add_mtd_partitions(autcpu12_mtd, partition_info64k,
NUM_PARTITIONS64K);
break;
case SZ_128M:
add_mtd_partitions(autcpu12_mtd, partition_info128k,
NUM_PARTITIONS128K);
break;
default: default:
printk("Unsupported SmartMedia device\n"); printk("Unsupported SmartMedia device\n");
err = -ENXIO; err = -ENXIO;
...@@ -191,7 +210,7 @@ static int __init autcpu12_init(void) ...@@ -191,7 +210,7 @@ static int __init autcpu12_init(void)
goto out; goto out;
out_ior: out_ior:
iounmap((void *)autcpu12_fio_base); iounmap(autcpu12_fio_base);
out_mtd: out_mtd:
kfree(autcpu12_mtd); kfree(autcpu12_mtd);
out: out:
...@@ -209,7 +228,7 @@ static void __exit autcpu12_cleanup(void) ...@@ -209,7 +228,7 @@ static void __exit autcpu12_cleanup(void)
nand_release(autcpu12_mtd); nand_release(autcpu12_mtd);
/* unmap physical adress */ /* unmap physical adress */
iounmap((void *)autcpu12_fio_base); iounmap(autcpu12_fio_base);
/* Free the MTD device structure */ /* Free the MTD device structure */
kfree(autcpu12_mtd); kfree(autcpu12_mtd);
......
...@@ -131,33 +131,17 @@ static void cs553x_write_byte(struct mtd_info *mtd, u_char byte) ...@@ -131,33 +131,17 @@ static void cs553x_write_byte(struct mtd_info *mtd, u_char byte)
writeb(byte, this->IO_ADDR_W + 0x801); writeb(byte, this->IO_ADDR_W + 0x801);
} }
static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd) static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{ {
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
void __iomem *mmio_base = this->IO_ADDR_R; void __iomem *mmio_base = this->IO_ADDR_R;
unsigned char ctl; if (ctrl & NAND_CTRL_CHANGE) {
unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01;
switch (cmd) { writeb(ctl, mmio_base + MM_NAND_CTL);
case NAND_CTL_SETCLE:
ctl = CS_NAND_CTL_CLE;
break;
case NAND_CTL_CLRCLE:
case NAND_CTL_CLRALE:
case NAND_CTL_SETNCE:
ctl = 0;
break;
case NAND_CTL_SETALE:
ctl = CS_NAND_CTL_ALE;
break;
default:
case NAND_CTL_CLRNCE:
ctl = CS_NAND_CTL_CE;
break;
} }
writeb(ctl, mmio_base + MM_NAND_CTL); if (cmd != NAND_CMD_NONE)
cs553x_write_byte(mtd, cmd);
} }
static int cs553x_device_ready(struct mtd_info *mtd) static int cs553x_device_ready(struct mtd_info *mtd)
...@@ -233,10 +217,9 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) ...@@ -233,10 +217,9 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
goto out_mtd; goto out_mtd;
} }
this->hwcontrol = cs553x_hwcontrol; this->cmd_ctrl = cs553x_hwcontrol;
this->dev_ready = cs553x_device_ready; this->dev_ready = cs553x_device_ready;
this->read_byte = cs553x_read_byte; this->read_byte = cs553x_read_byte;
this->write_byte = cs553x_write_byte;
this->read_buf = cs553x_read_buf; this->read_buf = cs553x_read_buf;
this->write_buf = cs553x_write_buf; this->write_buf = cs553x_write_buf;
......
...@@ -95,7 +95,8 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 }; ...@@ -95,7 +95,8 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil) #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k) #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd); static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int bitmask);
static void doc200x_select_chip(struct mtd_info *mtd, int chip); static void doc200x_select_chip(struct mtd_info *mtd, int chip);
static int debug = 0; static int debug = 0;
...@@ -402,12 +403,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) ...@@ -402,12 +403,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
uint16_t ret; uint16_t ret;
doc200x_select_chip(mtd, nr); doc200x_select_chip(mtd, nr);
doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); doc200x_hwcontrol(mtd, NAND_CMD_READID,
this->write_byte(mtd, NAND_CMD_READID); NAND_CTRL_CLE | NAND_CTRL_CHANGE);
doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
doc200x_hwcontrol(mtd, NAND_CTL_SETALE); doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
this->write_byte(mtd, 0);
doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
/* We cant' use dev_ready here, but at least we wait for the /* We cant' use dev_ready here, but at least we wait for the
* command to complete * command to complete
...@@ -425,12 +424,11 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) ...@@ -425,12 +424,11 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
} ident; } ident;
void __iomem *docptr = doc->virtadr; void __iomem *docptr = doc->virtadr;
doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); doc200x_hwcontrol(mtd, NAND_CMD_READID,
doc2000_write_byte(mtd, NAND_CMD_READID); NAND_CTRL_CLE | NAND_CTRL_CHANGE);
doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE);
doc200x_hwcontrol(mtd, NAND_CTL_SETALE); doc200x_hwcontrol(mtd, NAND_CMD_NONE,
doc2000_write_byte(mtd, 0); NAND_NCE | NAND_CTRL_CHANGE);
doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
udelay(50); udelay(50);
...@@ -690,54 +688,41 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip) ...@@ -690,54 +688,41 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
chip -= (floor * doc->chips_per_floor); chip -= (floor * doc->chips_per_floor);
/* 11.4.4 -- deassert CE before changing chip */ /* 11.4.4 -- deassert CE before changing chip */
doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE); doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
WriteDOC(floor, docptr, FloorSelect); WriteDOC(floor, docptr, FloorSelect);
WriteDOC(chip, docptr, CDSNDeviceSelect); WriteDOC(chip, docptr, CDSNDeviceSelect);
doc200x_hwcontrol(mtd, NAND_CTL_SETNCE); doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
doc->curchip = chip; doc->curchip = chip;
doc->curfloor = floor; doc->curfloor = floor;
} }
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) #define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE)
static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{ {
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv; struct doc_priv *doc = this->priv;
void __iomem *docptr = doc->virtadr; void __iomem *docptr = doc->virtadr;
switch (cmd) { if (ctrl & NAND_CTRL_CHANGE) {
case NAND_CTL_SETNCE: doc->CDSNControl &= ~CDSN_CTRL_MSK;
doc->CDSNControl |= CDSN_CTRL_CE; doc->CDSNControl |= ctrl & CDSN_CTRL_MSK;
break; if (debug)
case NAND_CTL_CLRNCE: printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
doc->CDSNControl &= ~CDSN_CTRL_CE; WriteDOC(doc->CDSNControl, docptr, CDSNControl);
break; /* 11.4.3 -- 4 NOPs after CSDNControl write */
case NAND_CTL_SETCLE: DoC_Delay(doc, 4);
doc->CDSNControl |= CDSN_CTRL_CLE; }
break; if (cmd != NAND_CMD_NONE) {
case NAND_CTL_CLRCLE: if (DoC_is_2000(doc))
doc->CDSNControl &= ~CDSN_CTRL_CLE; doc2000_write_byte(mtd, cmd);
break; else
case NAND_CTL_SETALE: doc2001_write_byte(mtd, cmd);
doc->CDSNControl |= CDSN_CTRL_ALE;
break;
case NAND_CTL_CLRALE:
doc->CDSNControl &= ~CDSN_CTRL_ALE;
break;
case NAND_CTL_SETWP:
doc->CDSNControl |= CDSN_CTRL_WP;
break;
case NAND_CTL_CLRWP:
doc->CDSNControl &= ~CDSN_CTRL_WP;
break;
} }
if (debug)
printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
WriteDOC(doc->CDSNControl, docptr, CDSNControl);
/* 11.4.3 -- 4 NOPs after CSDNControl write */
DoC_Delay(doc, 4);
} }
static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr)
...@@ -1454,7 +1439,6 @@ static inline int __init doc2000_init(struct mtd_info *mtd) ...@@ -1454,7 +1439,6 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv; struct doc_priv *doc = this->priv;
this->write_byte = doc2000_write_byte;
this->read_byte = doc2000_read_byte; this->read_byte = doc2000_read_byte;
this->write_buf = doc2000_writebuf; this->write_buf = doc2000_writebuf;
this->read_buf = doc2000_readbuf; this->read_buf = doc2000_readbuf;
...@@ -1472,7 +1456,6 @@ static inline int __init doc2001_init(struct mtd_info *mtd) ...@@ -1472,7 +1456,6 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv; struct doc_priv *doc = this->priv;
this->write_byte = doc2001_write_byte;
this->read_byte = doc2001_read_byte; this->read_byte = doc2001_read_byte;
this->write_buf = doc2001_writebuf; this->write_buf = doc2001_writebuf;
this->read_buf = doc2001_readbuf; this->read_buf = doc2001_readbuf;
...@@ -1504,16 +1487,15 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd) ...@@ -1504,16 +1487,15 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv; struct doc_priv *doc = this->priv;
this->write_byte = NULL;
this->read_byte = doc2001plus_read_byte; this->read_byte = doc2001plus_read_byte;
this->write_buf = doc2001plus_writebuf; this->write_buf = doc2001plus_writebuf;
this->read_buf = doc2001plus_readbuf; this->read_buf = doc2001plus_readbuf;
this->verify_buf = doc2001plus_verifybuf; this->verify_buf = doc2001plus_verifybuf;
this->scan_bbt = inftl_scan_bbt; this->scan_bbt = inftl_scan_bbt;
this->hwcontrol = NULL; this->cmd_ctrl = NULL;
this->select_chip = doc2001plus_select_chip; this->select_chip = doc2001plus_select_chip;
this->cmdfunc = doc2001plus_command; this->cmdfunc = doc2001plus_command;
this->enable_hwecc = doc2001plus_enable_hwecc; this->ecc.hwctl = doc2001plus_enable_hwecc;
doc->chips_per_floor = 1; doc->chips_per_floor = 1;
mtd->name = "DiskOnChip Millennium Plus"; mtd->name = "DiskOnChip Millennium Plus";
...@@ -1670,7 +1652,7 @@ static int __init doc_probe(unsigned long physadr) ...@@ -1670,7 +1652,7 @@ static int __init doc_probe(unsigned long physadr)
nand->priv = doc; nand->priv = doc;
nand->select_chip = doc200x_select_chip; nand->select_chip = doc200x_select_chip;
nand->hwcontrol = doc200x_hwcontrol; nand->cmd_ctrl = doc200x_hwcontrol;
nand->dev_ready = doc200x_dev_ready; nand->dev_ready = doc200x_dev_ready;
nand->waitfunc = doc200x_wait; nand->waitfunc = doc200x_wait;
nand->block_bad = doc200x_block_bad; nand->block_bad = doc200x_block_bad;
......
...@@ -73,32 +73,26 @@ static struct mtd_partition partition_info[] = { ...@@ -73,32 +73,26 @@ static struct mtd_partition partition_info[] = {
/* /*
* hardware specific access to control-lines * hardware specific access to control-lines
*
* NAND_NCE: bit 0 -> bit 7
* NAND_CLE: bit 1 -> bit 4
* NAND_ALE: bit 2 -> bit 5
*/ */
static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{ {
switch (cmd) { struct nand_chip *chip = mtd->priv;
case NAND_CTL_SETCLE: if (ctrl & NAND_CTRL_CHANGE) {
clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); unsigned char bits;
break;
case NAND_CTL_CLRCLE: bits = (ctrl & (NAND_CLE | NAND_ALE)) << 3;
clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr); bits = (ctrl & NAND_NCE) << 7;
break;
clps_writeb((clps_readb(ep7312_pxdr) & 0xB0) | 0x10,
case NAND_CTL_SETALE: ep7312_pxdr);
clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr);
break;
case NAND_CTL_CLRALE:
clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr);
break;
case NAND_CTL_SETNCE:
clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr);
break;
case NAND_CTL_CLRNCE:
clps_writeb((clps_readb(ep7312_pxdr) | 0x80) | 0x40, ep7312_pxdr);
break;
} }
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
} }
/* /*
...@@ -159,7 +153,7 @@ static int __init ep7312_init(void) ...@@ -159,7 +153,7 @@ static int __init ep7312_init(void)
/* insert callbacks */ /* insert callbacks */
this->IO_ADDR_R = ep7312_fio_base; this->IO_ADDR_R = ep7312_fio_base;
this->IO_ADDR_W = ep7312_fio_base; this->IO_ADDR_W = ep7312_fio_base;
this->hwcontrol = ep7312_hwcontrol; this->cmd_ctrl = ep7312_hwcontrol;
this->dev_ready = ep7312_device_ready; this->dev_ready = ep7312_device_ready;
/* 15 us command delay time */ /* 15 us command delay time */
this->chip_delay = 15; this->chip_delay = 15;
......
...@@ -56,36 +56,18 @@ static struct mtd_partition partition_info[] = { ...@@ -56,36 +56,18 @@ static struct mtd_partition partition_info[] = {
/* /*
* hardware specific access to control-lines * hardware specific access to control-lines
*
* NAND_NCE: bit 0 - don't care
* NAND_CLE: bit 1 - address bit 2
* NAND_ALE: bit 2 - address bit 3
*/ */
static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) static void h1910_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{ {
struct nand_chip *this = (struct nand_chip *)(mtd->priv); struct nand_chip *chip = mtd->priv;
switch (cmd) { if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W | ((ctrl & 0x6) << 1));
case NAND_CTL_SETCLE:
this->IO_ADDR_R |= (1 << 2);
this->IO_ADDR_W |= (1 << 2);
break;
case NAND_CTL_CLRCLE:
this->IO_ADDR_R &= ~(1 << 2);
this->IO_ADDR_W &= ~(1 << 2);
break;
case NAND_CTL_SETALE:
this->IO_ADDR_R |= (1 << 3);
this->IO_ADDR_W |= (1 << 3);
break;
case NAND_CTL_CLRALE:
this->IO_ADDR_R &= ~(1 << 3);
this->IO_ADDR_W &= ~(1 << 3);
break;
case NAND_CTL_SETNCE:
break;
case NAND_CTL_CLRNCE:
break;
}
} }
/* /*
...@@ -145,7 +127,7 @@ static int __init h1910_init(void) ...@@ -145,7 +127,7 @@ static int __init h1910_init(void)
/* insert callbacks */ /* insert callbacks */
this->IO_ADDR_R = nandaddr; this->IO_ADDR_R = nandaddr;
this->IO_ADDR_W = nandaddr; this->IO_ADDR_W = nandaddr;
this->hwcontrol = h1910_hwcontrol; this->cmd_ctrl = h1910_hwcontrol;
this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */ this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */
/* 15 us command delay time */ /* 15 us command delay time */
this->chip_delay = 50; this->chip_delay = 50;
......
...@@ -139,23 +139,12 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len); ...@@ -139,23 +139,12 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf); size_t *retlen, uint8_t *buf);
static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf, uint8_t *eccbuf,
struct nand_oobinfo *oobsel);
static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf); size_t *retlen, uint8_t *buf);
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf); size_t *retlen, const uint8_t *buf);
static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf, uint8_t *eccbuf,
struct nand_oobinfo *oobsel);
static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf); size_t *retlen, const uint8_t *buf);
static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen);
static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen,
uint8_t *eccbuf, struct nand_oobinfo *oobsel);
static int nand_erase(struct mtd_info *mtd, struct erase_info *instr); static int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
static void nand_sync(struct mtd_info *mtd); static void nand_sync(struct mtd_info *mtd);
...@@ -175,6 +164,12 @@ static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, ...@@ -175,6 +164,12 @@ static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this,
static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd,
int new_state); int new_state);
/*
* For devices which display every fart in the system on a seperate LED. Is
* compiled away when LED support is disabled.
*/
DEFINE_LED_TRIGGER(nand_led_trigger);
/** /**
* nand_release_device - [GENERIC] release chip * nand_release_device - [GENERIC] release chip
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -208,19 +203,6 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) ...@@ -208,19 +203,6 @@ static uint8_t nand_read_byte(struct mtd_info *mtd)
return readb(this->IO_ADDR_R); return readb(this->IO_ADDR_R);
} }
/**
* nand_write_byte - [DEFAULT] write one byte to the chip
* @mtd: MTD device structure
* @byte: pointer to data byte to write
*
* Default write function for 8it buswith
*/
static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
{
struct nand_chip *this = mtd->priv;
writeb(byte, this->IO_ADDR_W);
}
/** /**
* nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -234,20 +216,6 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd) ...@@ -234,20 +216,6 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd)
return (uint8_t) cpu_to_le16(readw(this->IO_ADDR_R)); return (uint8_t) cpu_to_le16(readw(this->IO_ADDR_R));
} }
/**
* nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip
* @mtd: MTD device structure
* @byte: pointer to data byte to write
*
* Default write function for 16bit buswith with
* endianess conversion
*/
static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
{
struct nand_chip *this = mtd->priv;
writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
}
/** /**
* nand_read_word - [DEFAULT] read one word from the chip * nand_read_word - [DEFAULT] read one word from the chip
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -261,20 +229,6 @@ static u16 nand_read_word(struct mtd_info *mtd) ...@@ -261,20 +229,6 @@ static u16 nand_read_word(struct mtd_info *mtd)
return readw(this->IO_ADDR_R); return readw(this->IO_ADDR_R);
} }
/**
* nand_write_word - [DEFAULT] write one word to the chip
* @mtd: MTD device structure
* @word: data word to write
*
* Default write function for 16bit buswith without
* endianess conversion
*/
static void nand_write_word(struct mtd_info *mtd, u16 word)
{
struct nand_chip *this = mtd->priv;
writew(word, this->IO_ADDR_W);
}
/** /**
* nand_select_chip - [DEFAULT] control CE line * nand_select_chip - [DEFAULT] control CE line
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -287,10 +241,10 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) ...@@ -287,10 +241,10 @@ static void nand_select_chip(struct mtd_info *mtd, int chip)
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
switch (chip) { switch (chip) {
case -1: case -1:
this->hwcontrol(mtd, NAND_CTL_CLRNCE); this->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
break; break;
case 0: case 0:
this->hwcontrol(mtd, NAND_CTL_SETNCE); this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
break; break;
default: default:
...@@ -528,8 +482,6 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, ...@@ -528,8 +482,6 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
return nand_isbad_bbt(mtd, ofs, allowbbt); return nand_isbad_bbt(mtd, ofs, allowbbt);
} }
DEFINE_LED_TRIGGER(nand_led_trigger);
/* /*
* Wait for the ready pin, after a command * Wait for the ready pin, after a command
* The timeout is catched later. * The timeout is catched later.
...@@ -559,13 +511,12 @@ static void nand_wait_ready(struct mtd_info *mtd) ...@@ -559,13 +511,12 @@ static void nand_wait_ready(struct mtd_info *mtd)
* Send command to NAND device. This function is used for small page * Send command to NAND device. This function is used for small page
* devices (256/512 Bytes per page) * devices (256/512 Bytes per page)
*/ */
static void nand_command(struct mtd_info *mtd, unsigned command, int column, static void nand_command(struct mtd_info *mtd, unsigned int command,
int page_addr) int column, int page_addr)
{ {
register struct nand_chip *this = mtd->priv; register struct nand_chip *this = mtd->priv;
int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;
/* Begin command latch cycle */
this->hwcontrol(mtd, NAND_CTL_SETCLE);
/* /*
* Write out the command to the device. * Write out the command to the device.
*/ */
...@@ -583,33 +534,32 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, ...@@ -583,33 +534,32 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column,
column -= 256; column -= 256;
readcmd = NAND_CMD_READ1; readcmd = NAND_CMD_READ1;
} }
this->write_byte(mtd, readcmd); this->cmd_ctrl(mtd, readcmd, ctrl);
ctrl &= ~NAND_CTRL_CHANGE;
} }
this->write_byte(mtd, command); this->cmd_ctrl(mtd, command, ctrl);
/* Set ALE and clear CLE to start address cycle */
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
if (column != -1 || page_addr != -1) {
this->hwcontrol(mtd, NAND_CTL_SETALE);
/* Serially input address */ /*
if (column != -1) { * Address cycle, when necessary
/* Adjust columns for 16 bit buswidth */ */
if (this->options & NAND_BUSWIDTH_16) ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;
column >>= 1; /* Serially input address */
this->write_byte(mtd, column); if (column != -1) {
} /* Adjust columns for 16 bit buswidth */
if (page_addr != -1) { if (this->options & NAND_BUSWIDTH_16)
this->write_byte(mtd, (uint8_t)(page_addr & 0xff)); column >>= 1;
this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff)); this->cmd_ctrl(mtd, column, ctrl);
/* One more address cycle for devices > 32MiB */ ctrl &= ~NAND_CTRL_CHANGE;
if (this->chipsize > (32 << 20)) }
this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0x0f)); if (page_addr != -1) {
} this->cmd_ctrl(mtd, page_addr, ctrl);
/* Latch in address */ ctrl &= ~NAND_CTRL_CHANGE;
this->hwcontrol(mtd, NAND_CTL_CLRALE); this->cmd_ctrl(mtd, page_addr >> 8, ctrl);
/* One more address cycle for devices > 32MiB */
if (this->chipsize > (32 << 20))
this->cmd_ctrl(mtd, page_addr >> 16, ctrl);
} }
this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/* /*
* program and erase have their own busy handlers * program and erase have their own busy handlers
...@@ -622,15 +572,16 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, ...@@ -622,15 +572,16 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column,
case NAND_CMD_ERASE2: case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN: case NAND_CMD_SEQIN:
case NAND_CMD_STATUS: case NAND_CMD_STATUS:
this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
return; return;
case NAND_CMD_RESET: case NAND_CMD_RESET:
if (this->dev_ready) if (this->dev_ready)
break; break;
udelay(this->chip_delay); udelay(this->chip_delay);
this->hwcontrol(mtd, NAND_CTL_SETCLE); this->cmd_ctrl(mtd, NAND_CMD_STATUS,
this->write_byte(mtd, NAND_CMD_STATUS); NAND_CTRL_CLE | NAND_CTRL_CHANGE);
this->hwcontrol(mtd, NAND_CTL_CLRCLE); this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
return; return;
...@@ -659,12 +610,13 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, ...@@ -659,12 +610,13 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column,
* @column: the column address for this command, -1 if none * @column: the column address for this command, -1 if none
* @page_addr: the page address for this command, -1 if none * @page_addr: the page address for this command, -1 if none
* *
* Send command to NAND device. This is the version for the new large page devices * Send command to NAND device. This is the version for the new large page
* We dont have the separate regions as we have in the small page devices. * devices We dont have the separate regions as we have in the small page
* We must emulate NAND_CMD_READOOB to keep the code compatible. * devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
* *
*/ */
static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr) static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
{ {
register struct nand_chip *this = mtd->priv; register struct nand_chip *this = mtd->priv;
...@@ -674,34 +626,33 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, ...@@ -674,34 +626,33 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column,
command = NAND_CMD_READ0; command = NAND_CMD_READ0;
} }
/* Begin command latch cycle */ /* Command latch cycle */
this->hwcontrol(mtd, NAND_CTL_SETCLE); this->cmd_ctrl(mtd, command & 0xff,
/* Write out the command to the device. */ NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
this->write_byte(mtd, (command & 0xff));
/* End command latch cycle */
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
if (column != -1 || page_addr != -1) { if (column != -1 || page_addr != -1) {
this->hwcontrol(mtd, NAND_CTL_SETALE); int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
/* Serially input address */ /* Serially input address */
if (column != -1) { if (column != -1) {
/* Adjust columns for 16 bit buswidth */ /* Adjust columns for 16 bit buswidth */
if (this->options & NAND_BUSWIDTH_16) if (this->options & NAND_BUSWIDTH_16)
column >>= 1; column >>= 1;
this->write_byte(mtd, column & 0xff); this->cmd_ctrl(mtd, column, ctrl);
this->write_byte(mtd, column >> 8); ctrl &= ~NAND_CTRL_CHANGE;
this->cmd_ctrl(mtd, column >> 8, ctrl);
} }
if (page_addr != -1) { if (page_addr != -1) {
this->write_byte(mtd, (uint8_t)(page_addr & 0xff)); this->cmd_ctrl(mtd, page_addr, ctrl);
this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff)); this->cmd_ctrl(mtd, page_addr >> 8,
NAND_NCE | NAND_ALE);
/* One more address cycle for devices > 128MiB */ /* One more address cycle for devices > 128MiB */
if (this->chipsize > (128 << 20)) if (this->chipsize > (128 << 20))
this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0xff)); this->cmd_ctrl(mtd, page_addr >> 16,
NAND_NCE | NAND_ALE);
} }
/* Latch in address */
this->hwcontrol(mtd, NAND_CTL_CLRALE);
} }
this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
/* /*
* program and erase have their own busy handlers * program and erase have their own busy handlers
...@@ -733,20 +684,14 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, ...@@ -733,20 +684,14 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column,
if (this->dev_ready) if (this->dev_ready)
break; break;
udelay(this->chip_delay); udelay(this->chip_delay);
this->hwcontrol(mtd, NAND_CTL_SETCLE); this->cmd_ctrl(mtd, NAND_CMD_STATUS, NAND_NCE | NAND_CLE);
this->write_byte(mtd, NAND_CMD_STATUS); this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ;
return; return;
case NAND_CMD_READ0: case NAND_CMD_READ0:
/* Begin command latch cycle */ this->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_NCE | NAND_CLE);
this->hwcontrol(mtd, NAND_CTL_SETCLE); this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE);
/* Write out the start read command */
this->write_byte(mtd, NAND_CMD_READSTART);
/* End command latch cycle */
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
/* Fall through into ready check */
/* This applies to read commands */ /* This applies to read commands */
default: default:
...@@ -1084,27 +1029,6 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retl ...@@ -1084,27 +1029,6 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retl
return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff); return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
} }
/**
* nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
* @oob_buf: filesystem supplied oob data buffer
* @oobsel: oob selection structure
*
* This function simply calls nand_do_read_ecc with flags = 0xff
*/
static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel)
{
/* use userspace supplied oobinfo, if zero */
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
}
/** /**
* nand_do_read_ecc - [MTD Interface] Read data with ECC * nand_do_read_ecc - [MTD Interface] Read data with ECC
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -1528,6 +1452,56 @@ int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, s ...@@ -1528,6 +1452,56 @@ int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, s
return 0; return 0;
} }
/**
* nand_write_raw - [GENERIC] Write raw data including oob
* @mtd: MTD device structure
* @buf: source buffer
* @to: offset to write to
* @len: number of bytes to write
* @buf: source buffer
* @oob: oob buffer
*
* Write raw data including oob
*/
int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
uint8_t *buf, uint8_t *oob)
{
struct nand_chip *this = mtd->priv;
int page = (int)(to >> this->page_shift);
int chip = (int)(to >> this->chip_shift);
int ret;
*retlen = 0;
/* Do not allow writes past end of device */
if ((to + len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write "
"beyond end of device\n");
return -EINVAL;
}
/* Grab the lock and see if the device is available */
nand_get_device(this, mtd, FL_WRITING);
this->select_chip(mtd, chip);
this->data_poi = buf;
while (len != *retlen) {
ret = nand_write_page(mtd, this, page, oob, &mtd->oobinfo, 0);
if (ret)
return ret;
page++;
*retlen += mtd->writesize;
this->data_poi += mtd->writesize;
oob += mtd->oobsize;
}
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
return 0;
}
EXPORT_SYMBOL_GPL(nand_write_raw);
/** /**
* nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -1590,57 +1564,39 @@ static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct ...@@ -1590,57 +1564,39 @@ static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct
#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0 #define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
/** /**
* nand_write - [MTD Interface] compability function for nand_write_ecc * nand_write - [MTD Interface] NAND write with ECC
* @mtd: MTD device structure * @mtd: MTD device structure
* @to: offset to write to * @to: offset to write to
* @len: number of bytes to write * @len: number of bytes to write
* @retlen: pointer to variable to store the number of written bytes * @retlen: pointer to variable to store the number of written bytes
* @buf: the data to write * @buf: the data to write
* *
* This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
*
*/
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf)
{
return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL));
}
/**
* nand_write_ecc - [MTD Interface] NAND write with ECC
* @mtd: MTD device structure
* @to: offset to write to
* @len: number of bytes to write
* @retlen: pointer to variable to store the number of written bytes
* @buf: the data to write
* @eccbuf: filesystem supplied oob data buffer
* @oobsel: oob selection structure
*
* NAND write with ECC * NAND write with ECC
*/ */
static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf, uint8_t *eccbuf, size_t *retlen, const uint8_t *buf)
struct nand_oobinfo *oobsel)
{ {
int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr; int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
int autoplace = 0, numpages, totalpages; int autoplace = 0, numpages, totalpages;
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
uint8_t *oobbuf, *bufstart; uint8_t *oobbuf, *bufstart, *eccbuf = NULL;
int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
struct nand_oobinfo *oobsel = &mtd->oobinfo;
DEBUG(MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); DEBUG(MTD_DEBUG_LEVEL3, "nand_write: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len);
/* Initialize retlen, in case of early exit */ /* Initialize retlen, in case of early exit */
*retlen = 0; *retlen = 0;
/* Do not allow write past end of device */ /* Do not allow write past end of device */
if ((to + len) > mtd->size) { if ((to + len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); DEBUG(MTD_DEBUG_LEVEL0, "nand_write: Attempt to write past end of page\n");
return -EINVAL; return -EINVAL;
} }
/* reject writes, which are not page aligned */ /* reject writes, which are not page aligned */
if (NOTALIGNED(to) || NOTALIGNED(len)) { if (NOTALIGNED(to) || NOTALIGNED(len)) {
printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); printk(KERN_NOTICE "nand_write: Attempt to write not page aligned data\n");
return -EINVAL; return -EINVAL;
} }
...@@ -1656,10 +1612,6 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -1656,10 +1612,6 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
if (nand_check_wp(mtd)) if (nand_check_wp(mtd))
goto out; goto out;
/* if oobsel is NULL, use chip defaults */
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
/* Autoplace of oob data ? Use the default placement scheme */ /* Autoplace of oob data ? Use the default placement scheme */
if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
oobsel = this->autooob; oobsel = this->autooob;
...@@ -1694,7 +1646,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -1694,7 +1646,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
*/ */
ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0)); ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
if (ret) { if (ret) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); DEBUG(MTD_DEBUG_LEVEL0, "nand_write: write_page failed %d\n", ret);
goto out; goto out;
} }
/* Next oob page */ /* Next oob page */
...@@ -1717,7 +1669,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -1717,7 +1669,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
ret = nand_verify_pages(mtd, this, startpage, page - startpage, ret = nand_verify_pages(mtd, this, startpage, page - startpage,
oobbuf, oobsel, chipnr, (eccbuf != NULL)); oobbuf, oobsel, chipnr, (eccbuf != NULL));
if (ret) { if (ret) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
goto out; goto out;
} }
*retlen = written; *retlen = written;
...@@ -1746,7 +1698,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -1746,7 +1698,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
if (!ret) if (!ret)
*retlen = written; *retlen = written;
else else
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret);
out: out:
/* Deselect and wake up anyone waiting on the device */ /* Deselect and wake up anyone waiting on the device */
...@@ -1856,187 +1808,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *r ...@@ -1856,187 +1808,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *r
return ret; return ret;
} }
/**
* nand_writev - [MTD Interface] compabilty function for nand_writev_ecc
* @mtd: MTD device structure
* @vecs: the iovectors to write
* @count: number of vectors
* @to: offset to write to
* @retlen: pointer to variable to store the number of written bytes
*
* NAND write with kvec. This just calls the ecc function
*/
static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
loff_t to, size_t *retlen)
{
return (nand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL));
}
/**
* nand_writev_ecc - [MTD Interface] write with iovec with ecc
* @mtd: MTD device structure
* @vecs: the iovectors to write
* @count: number of vectors
* @to: offset to write to
* @retlen: pointer to variable to store the number of written bytes
* @eccbuf: filesystem supplied oob data buffer
* @oobsel: oob selection structure
*
* NAND write with iovec with ecc
*/
static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
loff_t to, size_t *retlen, uint8_t *eccbuf, struct nand_oobinfo *oobsel)
{
int i, page, len, total_len, ret = -EIO, written = 0, chipnr;
int oob, numpages, autoplace = 0, startpage;
struct nand_chip *this = mtd->priv;
int ppblock = (1 << (this->phys_erase_shift - this->page_shift));
uint8_t *oobbuf, *bufstart;
/* Preset written len for early exit */
*retlen = 0;
/* Calculate total length of data */
total_len = 0;
for (i = 0; i < count; i++)
total_len += (int)vecs[i].iov_len;
DEBUG(MTD_DEBUG_LEVEL3, "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int)to, (unsigned int)total_len, count);
/* Do not allow write past end of page */
if ((to + total_len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
return -EINVAL;
}
/* reject writes, which are not page aligned */
if (NOTALIGNED(to) || NOTALIGNED(total_len)) {
printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
return -EINVAL;
}
/* Grab the lock and see if the device is available */
nand_get_device(this, mtd, FL_WRITING);
/* Get the current chip-nr */
chipnr = (int)(to >> this->chip_shift);
/* Select the NAND device */
this->select_chip(mtd, chipnr);
/* Check, if it is write protected */
if (nand_check_wp(mtd))
goto out;
/* if oobsel is NULL, use chip defaults */
if (oobsel == NULL)
oobsel = &mtd->oobinfo;
/* Autoplace of oob data ? Use the default placement scheme */
if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
oobsel = this->autooob;
autoplace = 1;
}
if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
autoplace = 1;
/* Setup start page */
page = (int)(to >> this->page_shift);
/* Invalidate the page cache, if we write to the cached page */
if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))
this->pagebuf = -1;
startpage = page & this->pagemask;
/* Loop until all kvec' data has been written */
len = 0;
while (count) {
/* If the given tuple is >= pagesize then
* write it out from the iov
*/
if ((vecs->iov_len - len) >= mtd->writesize) {
/* Calc number of pages we can write
* out of this iov in one go */
numpages = (vecs->iov_len - len) >> this->page_shift;
/* Do not cross block boundaries */
numpages = min(ppblock - (startpage & (ppblock - 1)), numpages);
oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
bufstart = (uint8_t *) vecs->iov_base;
bufstart += len;
this->data_poi = bufstart;
oob = 0;
for (i = 1; i <= numpages; i++) {
/* Write one page. If this is the last page to write
* then use the real pageprogram command, else select
* cached programming if supported by the chip.
*/
ret = nand_write_page(mtd, this, page & this->pagemask,
&oobbuf[oob], oobsel, i != numpages);
if (ret)
goto out;
this->data_poi += mtd->writesize;
len += mtd->writesize;
oob += mtd->oobsize;
page++;
}
/* Check, if we have to switch to the next tuple */
if (len >= (int)vecs->iov_len) {
vecs++;
len = 0;
count--;
}
} else {
/* We must use the internal buffer, read data out of each
* tuple until we have a full page to write
*/
int cnt = 0;
while (cnt < mtd->writesize) {
if (vecs->iov_base != NULL && vecs->iov_len)
this->data_buf[cnt++] = ((uint8_t *) vecs->iov_base)[len++];
/* Check, if we have to switch to the next tuple */
if (len >= (int)vecs->iov_len) {
vecs++;
len = 0;
count--;
}
}
this->pagebuf = page;
this->data_poi = this->data_buf;
bufstart = this->data_poi;
numpages = 1;
oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages);
ret = nand_write_page(mtd, this, page & this->pagemask, oobbuf, oobsel, 0);
if (ret)
goto out;
page++;
}
this->data_poi = bufstart;
ret = nand_verify_pages(mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0);
if (ret)
goto out;
written += mtd->writesize * numpages;
/* All done ? */
if (!count)
break;
startpage = page & this->pagemask;
/* Check, if we cross a chip boundary */
if (!startpage) {
chipnr++;
this->select_chip(mtd, -1);
this->select_chip(mtd, chipnr);
}
}
ret = 0;
out:
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
*retlen = written;
return ret;
}
/** /**
* single_erease_cmd - [GENERIC] NAND standard block erase command function * single_erease_cmd - [GENERIC] NAND standard block erase command function
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -2392,12 +2163,8 @@ static void nand_set_defaults(struct nand_chip *this, int busw) ...@@ -2392,12 +2163,8 @@ static void nand_set_defaults(struct nand_chip *this, int busw)
if (!this->select_chip) if (!this->select_chip)
this->select_chip = nand_select_chip; this->select_chip = nand_select_chip;
if (!this->write_byte)
this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
if (!this->read_byte) if (!this->read_byte)
this->read_byte = busw ? nand_read_byte16 : nand_read_byte; this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
if (!this->write_word)
this->write_word = nand_write_word;
if (!this->read_word) if (!this->read_word)
this->read_word = nand_read_word; this->read_word = nand_read_word;
if (!this->block_bad) if (!this->block_bad)
...@@ -2713,13 +2480,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips) ...@@ -2713,13 +2480,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
mtd->unpoint = NULL; mtd->unpoint = NULL;
mtd->read = nand_read; mtd->read = nand_read;
mtd->write = nand_write; mtd->write = nand_write;
mtd->read_ecc = nand_read_ecc;
mtd->write_ecc = nand_write_ecc;
mtd->read_oob = nand_read_oob; mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob; mtd->write_oob = nand_write_oob;
mtd->readv = NULL;
mtd->writev = nand_writev;
mtd->writev_ecc = nand_writev_ecc;
mtd->sync = nand_sync; mtd->sync = nand_sync;
mtd->lock = NULL; mtd->lock = NULL;
mtd->unlock = NULL; mtd->unlock = NULL;
......
...@@ -156,7 +156,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, ...@@ -156,7 +156,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
while (totlen) { while (totlen) {
len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); len = min(totlen, (size_t) (1 << this->bbt_erase_shift));
res = mtd->read_ecc(mtd, from, len, &retlen, buf, NULL, this->autooob); res = mtd->read(mtd, from, len, &retlen, buf);
if (res < 0) { if (res < 0) {
if (retlen != len) { if (retlen != len) {
printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); printk(KERN_INFO "nand_bbt: Error reading bad block table\n");
...@@ -471,17 +471,17 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt ...@@ -471,17 +471,17 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt
* *
*/ */
static int write_bbt(struct mtd_info *mtd, uint8_t *buf, static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) struct nand_bbt_descr *td, struct nand_bbt_descr *md,
int chipsel)
{ {
struct nand_chip *this = mtd->priv; struct nand_chip *this = mtd->priv;
struct nand_oobinfo oobinfo;
struct erase_info einfo; struct erase_info einfo;
int i, j, res, chip = 0; int i, j, res, chip = 0;
int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
int nrchips, bbtoffs, pageoffs; int nrchips, bbtoffs, pageoffs, ooboffs;
uint8_t msk[4]; uint8_t msk[4];
uint8_t rcode = td->reserved_block_code; uint8_t rcode = td->reserved_block_code;
size_t retlen, len = 0; size_t retlen, len = 0, ooblen;
loff_t to; loff_t to;
if (!rcode) if (!rcode)
...@@ -526,12 +526,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ...@@ -526,12 +526,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
for (i = 0; i < td->maxblocks; i++) { for (i = 0; i < td->maxblocks; i++) {
int block = startblock + dir * i; int block = startblock + dir * i;
/* Check, if the block is bad */ /* Check, if the block is bad */
switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) { switch ((this->bbt[block >> 2] >>
(2 * (block & 0x03))) & 0x03) {
case 0x01: case 0x01:
case 0x03: case 0x03:
continue; continue;
} }
page = block << (this->bbt_erase_shift - this->page_shift); page = block <<
(this->bbt_erase_shift - this->page_shift);
/* Check, if the block is used by the mirror table */ /* Check, if the block is used by the mirror table */
if (!md || md->pages[chip] != page) if (!md || md->pages[chip] != page)
goto write; goto write;
...@@ -542,11 +544,20 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ...@@ -542,11 +544,20 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
/* Set up shift count and masks for the flash table */ /* Set up shift count and masks for the flash table */
bits = td->options & NAND_BBT_NRBITS_MSK; bits = td->options & NAND_BBT_NRBITS_MSK;
msk[2] = ~rcode;
switch (bits) { switch (bits) {
case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break; case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break; msk[3] = 0x01;
case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break; break;
case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break; case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
msk[3] = 0x03;
break;
case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
msk[3] = 0x0f;
break;
case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
msk[3] = 0xff;
break;
default: return -EINVAL; default: return -EINVAL;
} }
...@@ -554,49 +565,55 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ...@@ -554,49 +565,55 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
to = ((loff_t) page) << this->page_shift; to = ((loff_t) page) << this->page_shift;
memcpy(&oobinfo, this->autooob, sizeof(oobinfo));
oobinfo.useecc = MTD_NANDECC_PLACEONLY;
/* 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_ecc(mtd, to, len, &retlen, buf, &buf[len], &oobinfo); res = mtd->read(mtd, to, len, &retlen, buf);
if (res < 0) { if (res < 0) {
if (retlen != len) { if (retlen != len) {
printk(KERN_INFO printk(KERN_INFO "nand_bbt: Error "
"nand_bbt: Error reading block for writing the bad block table\n"); "reading block for writing "
"the bad block table\n");
return res; return res;
} }
printk(KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n"); printk(KERN_WARNING "nand_bbt: ECC error "
"while reading block for writing "
"bad block table\n");
} }
/* Read oob data */
ooblen = (len >> this->page_shift) * mtd->oobsize;
res = mtd->read_oob(mtd, to + mtd->writesize, ooblen,
&retlen, &buf[len]);
if (res < 0 || retlen != ooblen)
goto outerr;
/* Calc the byte offset in the buffer */ /* Calc the byte offset in the buffer */
pageoffs = page - (int)(to >> this->page_shift); pageoffs = page - (int)(to >> this->page_shift);
offs = pageoffs << this->page_shift; offs = pageoffs << this->page_shift;
/* Preset the bbt area with 0xff */ /* Preset the bbt area with 0xff */
memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));
/* Preset the bbt's oob area with 0xff */ ooboffs = len + (pageoffs * mtd->oobsize);
memset(&buf[len + pageoffs * mtd->oobsize], 0xff,
((len >> this->page_shift) - pageoffs) * mtd->oobsize);
if (td->options & NAND_BBT_VERSION) {
buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip];
}
} else { } else {
/* Calc length */ /* Calc length */
len = (size_t) (numblocks >> sft); len = (size_t) (numblocks >> sft);
/* Make it page aligned ! */ /* Make it page aligned ! */
len = (len + (mtd->writesize - 1)) & ~(mtd->writesize - 1); len = (len + (mtd->writesize - 1)) &
~(mtd->writesize - 1);
/* Preset the buffer with 0xff */ /* Preset the buffer with 0xff */
memset(buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize); memset(buf, 0xff, len +
(len >> this->page_shift)* mtd->oobsize);
offs = 0; offs = 0;
ooboffs = len;
/* Pattern is located in oob area of first page */ /* Pattern is located in oob area of first page */
memcpy(&buf[len + td->offs], td->pattern, td->len); memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
if (td->options & NAND_BBT_VERSION) {
buf[len + td->veroffs] = td->version[chip];
}
} }
if (td->options & NAND_BBT_VERSION)
buf[ooboffs + td->veroffs] = td->version[chip];
/* walk through the memory table */ /* walk through the memory table */
for (i = 0; i < numblocks;) { for (i = 0; i < numblocks;) {
uint8_t dat; uint8_t dat;
...@@ -604,7 +621,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ...@@ -604,7 +621,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
for (j = 0; j < 4; j++, i++) { for (j = 0; j < 4; j++, i++) {
int sftcnt = (i << (3 - sft)) & sftmsk; int sftcnt = (i << (3 - sft)) & sftmsk;
/* Do not store the reserved bbt blocks ! */ /* Do not store the reserved bbt blocks ! */
buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); buf[offs + (i >> sft)] &=
~(msk[dat & 0x03] << sftcnt);
dat >>= 2; dat >>= 2;
} }
} }
...@@ -614,23 +632,25 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ...@@ -614,23 +632,25 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
einfo.addr = (unsigned long)to; einfo.addr = (unsigned long)to;
einfo.len = 1 << this->bbt_erase_shift; einfo.len = 1 << this->bbt_erase_shift;
res = nand_erase_nand(mtd, &einfo, 1); res = nand_erase_nand(mtd, &einfo, 1);
if (res < 0) { if (res < 0)
printk(KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); goto outerr;
return res;
}
res = mtd->write_ecc(mtd, to, len, &retlen, buf, &buf[len], &oobinfo); res = nand_write_raw(mtd, to, len, &retlen, buf, &buf[len]);
if (res < 0) { if (res < 0)
printk(KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); goto outerr;
return res;
} printk(KERN_DEBUG "Bad block table written to 0x%08x, version "
printk(KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", "0x%02X\n", (unsigned int)to, td->version[chip]);
(unsigned int)to, td->version[chip]);
/* Mark it as used */ /* Mark it as used */
td->pages[chip] = page; td->pages[chip] = page;
} }
return 0; return 0;
outerr:
printk(KERN_WARNING
"nand_bbt: Error while writing bad block table %d\n", res);
return res;
} }
/** /**
......
...@@ -1071,68 +1071,6 @@ switch_state(struct nandsim *ns) ...@@ -1071,68 +1071,6 @@ switch_state(struct nandsim *ns)
} }
} }
static void
ns_hwcontrol(struct mtd_info *mtd, int cmd)
{
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
switch (cmd) {
/* set CLE line high */
case NAND_CTL_SETCLE:
NS_DBG("ns_hwcontrol: start command latch cycles\n");
ns->lines.cle = 1;
break;
/* set CLE line low */
case NAND_CTL_CLRCLE:
NS_DBG("ns_hwcontrol: stop command latch cycles\n");
ns->lines.cle = 0;
break;
/* set ALE line high */
case NAND_CTL_SETALE:
NS_DBG("ns_hwcontrol: start address latch cycles\n");
ns->lines.ale = 1;
break;
/* set ALE line low */
case NAND_CTL_CLRALE:
NS_DBG("ns_hwcontrol: stop address latch cycles\n");
ns->lines.ale = 0;
break;
/* set WP line high */
case NAND_CTL_SETWP:
NS_DBG("ns_hwcontrol: enable write protection\n");
ns->lines.wp = 1;
break;
/* set WP line low */
case NAND_CTL_CLRWP:
NS_DBG("ns_hwcontrol: disable write protection\n");
ns->lines.wp = 0;
break;
/* set CE line low */
case NAND_CTL_SETNCE:
NS_DBG("ns_hwcontrol: enable chip\n");
ns->lines.ce = 1;
break;
/* set CE line high */
case NAND_CTL_CLRNCE:
NS_DBG("ns_hwcontrol: disable chip\n");
ns->lines.ce = 0;
break;
default:
NS_ERR("hwcontrol: unknown command\n");
}
return;
}
static u_char static u_char
ns_nand_read_byte(struct mtd_info *mtd) ns_nand_read_byte(struct mtd_info *mtd)
{ {
...@@ -1359,6 +1297,18 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) ...@@ -1359,6 +1297,18 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
return; return;
} }
static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
{
struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv;
ns->lines.cle = bitmask & NAND_CLE ? 1 : 0;
ns->lines.ale = bitmask & NAND_ALE ? 1 : 0;
ns->lines.ce = bitmask & NAND_NCE ? 1 : 0;
if (cmd != NAND_CMD_NONE)
ns_nand_write_byte(mtd, cmd);
}
static int static int
ns_device_ready(struct mtd_info *mtd) ns_device_ready(struct mtd_info *mtd)
{ {
...@@ -1376,17 +1326,6 @@ ns_nand_read_word(struct mtd_info *mtd) ...@@ -1376,17 +1326,6 @@ ns_nand_read_word(struct mtd_info *mtd)
return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8); return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
} }
static void
ns_nand_write_word(struct mtd_info *mtd, uint16_t word)
{
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
NS_DBG("write_word\n");
chip->write_byte(mtd, word & 0xFF);
chip->write_byte(mtd, word >> 8);
}
static void static void
ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{ {
...@@ -1514,14 +1453,12 @@ static int __init ns_init_module(void) ...@@ -1514,14 +1453,12 @@ static int __init ns_init_module(void)
/* /*
* Register simulator's callbacks. * Register simulator's callbacks.
*/ */
chip->hwcontrol = ns_hwcontrol; chip->cmd_ctrl = ns_hwcontrol;
chip->read_byte = ns_nand_read_byte; chip->read_byte = ns_nand_read_byte;
chip->dev_ready = ns_device_ready; chip->dev_ready = ns_device_ready;
chip->write_byte = ns_nand_write_byte;
chip->write_buf = ns_nand_write_buf; chip->write_buf = ns_nand_write_buf;
chip->read_buf = ns_nand_read_buf; chip->read_buf = ns_nand_read_buf;
chip->verify_buf = ns_nand_verify_buf; chip->verify_buf = ns_nand_verify_buf;
chip->write_word = ns_nand_write_word;
chip->read_word = ns_nand_read_word; chip->read_word = ns_nand_read_word;
chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.mode = NAND_ECC_SOFT;
chip->options |= NAND_SKIP_BBTSCAN; chip->options |= NAND_SKIP_BBTSCAN;
......
...@@ -60,22 +60,17 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) ...@@ -60,22 +60,17 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
writel(ccr, ndfc->ndfcbase + NDFC_CCR); writel(ccr, ndfc->ndfcbase + NDFC_CCR);
} }
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd) static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{ {
struct ndfc_controller *ndfc = &ndfc_ctrl;
struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd->priv;
switch (cmd) { if (cmd == NAND_CMD_NONE)
case NAND_CTL_SETCLE: return;
chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_CMD;
break; if (ctrl & NAND_CLE)
case NAND_CTL_SETALE: writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD);
chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_ALE; else
break; writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE);
default:
chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
break;
}
} }
static int ndfc_ready(struct mtd_info *mtd) static int ndfc_ready(struct mtd_info *mtd)
...@@ -158,7 +153,7 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) ...@@ -158,7 +153,7 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
chip->hwcontrol = ndfc_hwcontrol; chip->cmd_ctrl = ndfc_hwcontrol;
chip->dev_ready = ndfc_ready; chip->dev_ready = ndfc_ready;
chip->select_chip = ndfc_select_chip; chip->select_chip = ndfc_select_chip;
chip->chip_delay = 50; chip->chip_delay = 50;
......
...@@ -108,54 +108,68 @@ extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio ...@@ -108,54 +108,68 @@ extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio
/* /*
* hardware specific access to control-lines * hardware specific access to control-lines
*/ */
static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd) static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd,
unsigned int ctrl)
{ {
switch (cmd) { struct nand_chip *chip = mtd->priv;
case NAND_CTL_SETCLE: if (ctrl & NAND_CTRL_CHANGE) {
MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR); #error Missing headerfiles. No way to fix this. -tglx
break; switch (cmd) {
case NAND_CTL_CLRCLE: case NAND_CTL_SETCLE:
MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR); MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR);
break; break;
case NAND_CTL_SETALE: case NAND_CTL_CLRCLE:
MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR); MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR);
break; break;
case NAND_CTL_CLRALE: case NAND_CTL_SETALE:
MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR); MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR);
break; break;
case NAND_CTL_SETNCE: case NAND_CTL_CLRALE:
MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR); MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR);
break; break;
case NAND_CTL_CLRNCE: case NAND_CTL_SETNCE:
MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR); MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR);
break; break;
case NAND_CTL_CLRNCE:
MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR);
break;
}
} }
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
} }
static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd) static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd,
unsigned int ctrl)
{ {
switch (cmd) { struct nand_chip *chip = mtd->priv;
case NAND_CTL_SETCLE: if (ctrl & NAND_CTRL_CHANGE) {
MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR); #error Missing headerfiles. No way to fix this. -tglx
break; switch (cmd) {
case NAND_CTL_CLRCLE: case NAND_CTL_SETCLE:
MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR); MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR);
break; break;
case NAND_CTL_SETALE: case NAND_CTL_CLRCLE:
MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR); MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR);
break; break;
case NAND_CTL_CLRALE: case NAND_CTL_SETALE:
MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR); MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR);
break; break;
case NAND_CTL_SETNCE: case NAND_CTL_CLRALE:
MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR); MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR);
break; break;
case NAND_CTL_CLRNCE: case NAND_CTL_SETNCE:
MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR); MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR);
break; break;
case NAND_CTL_CLRNCE:
MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR);
break;
}
} }
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
} }
#ifdef USE_READY_BUSY_PIN #ifdef USE_READY_BUSY_PIN
...@@ -251,7 +265,7 @@ static int __init ppchameleonevb_init(void) ...@@ -251,7 +265,7 @@ static int __init ppchameleonevb_init(void)
/* insert callbacks */ /* insert callbacks */
this->IO_ADDR_R = ppchameleon_fio_base; this->IO_ADDR_R = ppchameleon_fio_base;
this->IO_ADDR_W = ppchameleon_fio_base; this->IO_ADDR_W = ppchameleon_fio_base;
this->hwcontrol = ppchameleon_hwcontrol; this->cmd_ctrl = ppchameleon_hwcontrol;
#ifdef USE_READY_BUSY_PIN #ifdef USE_READY_BUSY_PIN
this->dev_ready = ppchameleon_device_ready; this->dev_ready = ppchameleon_device_ready;
#endif #endif
...@@ -351,7 +365,7 @@ static int __init ppchameleonevb_init(void) ...@@ -351,7 +365,7 @@ static int __init ppchameleonevb_init(void)
/* insert callbacks */ /* insert callbacks */
this->IO_ADDR_R = ppchameleonevb_fio_base; this->IO_ADDR_R = ppchameleonevb_fio_base;
this->IO_ADDR_W = ppchameleonevb_fio_base; this->IO_ADDR_W = ppchameleonevb_fio_base;
this->hwcontrol = ppchameleonevb_hwcontrol; this->cmd_ctrl = ppchameleonevb_hwcontrol;
#ifdef USE_READY_BUSY_PIN #ifdef USE_READY_BUSY_PIN
this->dev_ready = ppchameleonevb_device_ready; this->dev_ready = ppchameleonevb_device_ready;
#endif #endif
......
...@@ -208,32 +208,18 @@ static uint8_t revbits[256] = { ...@@ -208,32 +208,18 @@ static uint8_t revbits[256] = {
* Address lines (A24-A22), so no action is required here. * Address lines (A24-A22), so no action is required here.
* *
*/ */
static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{ {
struct nand_chip *this = (struct nand_chip *)(mtd->priv); struct nand_chip *chip = (mtd->priv);
switch (cmd) { if (cmd == NAND_CMD_NONE)
return;
case NAND_CTL_SETCLE: if (ctrl & NAND_CLE)
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE); writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_CLE);
break; else
case NAND_CTL_CLRCLE: writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_ALE);
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE);
break;
case NAND_CTL_SETALE:
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE);
break;
case NAND_CTL_CLRALE:
this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE);
break;
case NAND_CTL_SETNCE:
break;
case NAND_CTL_CLRNCE:
break;
}
} }
/* /*
...@@ -559,7 +545,7 @@ static int __init rtc_from4_init(void) ...@@ -559,7 +545,7 @@ static int __init rtc_from4_init(void)
this->IO_ADDR_R = rtc_from4_fio_base; this->IO_ADDR_R = rtc_from4_fio_base;
this->IO_ADDR_W = rtc_from4_fio_base; this->IO_ADDR_W = rtc_from4_fio_base;
/* Set address of hardware control function */ /* Set address of hardware control function */
this->hwcontrol = rtc_from4_hwcontrol; this->cmd_ctrl = rtc_from4_hwcontrol;
/* Set address of chip select function */ /* Set address of chip select function */
this->select_chip = rtc_from4_nand_select_chip; this->select_chip = rtc_from4_nand_select_chip;
/* command delay time (in us) */ /* command delay time (in us) */
......
...@@ -256,60 +256,36 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) ...@@ -256,60 +256,36 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
* *
*/ */
static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigend int ctrl)
{ {
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd->priv;
switch (cmd) { if (cmd == NAND_CMD_NONE)
case NAND_CTL_SETNCE: return;
case NAND_CTL_CLRNCE:
printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); if (cmd & NAND_CLE)
break; writeb(cmd, info->regs + S3C2410_NFCMD);
else
case NAND_CTL_SETCLE: writeb(cmd, info->regs + S3C2410_NFADDR);
chip->IO_ADDR_W = info->regs + S3C2410_NFCMD;
break;
case NAND_CTL_SETALE:
chip->IO_ADDR_W = info->regs + S3C2410_NFADDR;
break;
/* NAND_CTL_CLRCLE: */
/* NAND_CTL_CLRALE: */
default:
chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
break;
}
} }
/* command and control functions */ /* command and control functions */
static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd) static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigend int ctrl)
{ {
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd->priv;
switch (cmd) { if (cmd == NAND_CMD_NONE)
case NAND_CTL_SETNCE: return;
case NAND_CTL_CLRNCE:
printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); if (cmd & NAND_CLE)
break; writeb(cmd, info->regs + S3C2440_NFCMD);
else
case NAND_CTL_SETCLE: writeb(cmd, info->regs + S3C2440_NFADDR);
chip->IO_ADDR_W = info->regs + S3C2440_NFCMD;
break;
case NAND_CTL_SETALE:
chip->IO_ADDR_W = info->regs + S3C2440_NFADDR;
break;
/* NAND_CTL_CLRCLE: */
/* NAND_CTL_CLRALE: */
default:
chip->IO_ADDR_W = info->regs + S3C2440_NFDATA;
break;
}
} }
/* s3c2410_nand_devready() /* s3c2410_nand_devready()
...@@ -498,7 +474,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, ...@@ -498,7 +474,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->IO_ADDR_R = info->regs + S3C2410_NFDATA; chip->IO_ADDR_R = info->regs + S3C2410_NFDATA;
chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
chip->hwcontrol = s3c2410_nand_hwcontrol; chip->cmd_ctrl = s3c2410_nand_hwcontrol;
chip->dev_ready = s3c2410_nand_devready; chip->dev_ready = s3c2410_nand_devready;
chip->write_buf = s3c2410_nand_write_buf; chip->write_buf = s3c2410_nand_write_buf;
chip->read_buf = s3c2410_nand_read_buf; chip->read_buf = s3c2410_nand_read_buf;
...@@ -511,7 +487,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, ...@@ -511,7 +487,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
if (info->is_s3c2440) { if (info->is_s3c2440) {
chip->IO_ADDR_R = info->regs + S3C2440_NFDATA; chip->IO_ADDR_R = info->regs + S3C2440_NFDATA;
chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; chip->IO_ADDR_W = info->regs + S3C2440_NFDATA;
chip->hwcontrol = s3c2440_nand_hwcontrol; chip->cmd_ctrl = s3c2440_nand_hwcontrol;
} }
nmtd->info = info; nmtd->info = info;
......
...@@ -77,31 +77,26 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = { ...@@ -77,31 +77,26 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = {
/* /*
* hardware specific access to control-lines * hardware specific access to control-lines
* ctrl:
* NAND_CNE: bit 0 -> bit 0 & 4
* NAND_CLE: bit 1 -> bit 1
* NAND_ALE: bit 2 -> bit 2
*
*/ */
static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd) static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{ {
switch (cmd) { struct nand_chip *chip = mtd->priv;
case NAND_CTL_SETCLE:
writeb(readb(FLASHCTL) | FLCLE, FLASHCTL); if (ctrl & NAND_CTRL_CHANGE) {
break; unsigned char bits = ctrl & 0x07;
case NAND_CTL_CLRCLE:
writeb(readb(FLASHCTL) & ~FLCLE, FLASHCTL); bits |= (ctrl & 0x01) << 4;
break; writeb((readb(FLASHCTL) & 0x17) | bits, FLASHCTL);
case NAND_CTL_SETALE:
writeb(readb(FLASHCTL) | FLALE, FLASHCTL);
break;
case NAND_CTL_CLRALE:
writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL);
break;
case NAND_CTL_SETNCE:
writeb(readb(FLASHCTL) & ~(FLCE0 | FLCE1), FLASHCTL);
break;
case NAND_CTL_CLRNCE:
writeb(readb(FLASHCTL) | (FLCE0 | FLCE1), FLASHCTL);
break;
} }
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
} }
static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
...@@ -196,7 +191,7 @@ static int __init sharpsl_nand_init(void) ...@@ -196,7 +191,7 @@ static int __init sharpsl_nand_init(void)
this->IO_ADDR_R = FLASHIO; this->IO_ADDR_R = FLASHIO;
this->IO_ADDR_W = FLASHIO; this->IO_ADDR_W = FLASHIO;
/* Set address of hardware control function */ /* Set address of hardware control function */
this->hwcontrol = sharpsl_nand_hwcontrol; this->cmd_ctrl = sharpsl_nand_hwcontrol;
this->dev_ready = sharpsl_nand_dev_ready; this->dev_ready = sharpsl_nand_dev_ready;
/* 15 us command delay time */ /* 15 us command delay time */
this->chip_delay = 15; this->chip_delay = 15;
......
...@@ -82,20 +82,27 @@ static const struct mtd_partition partition_info[] = { ...@@ -82,20 +82,27 @@ static const struct mtd_partition partition_info[] = {
/* /*
* hardware specific access to control-lines * hardware specific access to control-lines
*/ *
* ctrl:
* NAND_CNE: bit 0 -> bit 2
* NAND_CLE: bit 1 -> bit 0
* NAND_ALE: bit 2 -> bit 1
*/
static void spia_hwcontrol(struct mtd_info *mtd, int cmd) static void spia_hwcontrol(struct mtd_info *mtd, int cmd)
{ {
switch (cmd) { struct nand_chip *chip = mtd->priv;
case NAND_CTL_SETCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x01; break; if (ctrl & NAND_CTRL_CHANGE) {
case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x01; break; void __iomem *addr = spia_io_base + spia_pedr;
unsigned char bits;
case NAND_CTL_SETALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x02; break; bits = (ctrl & NAND_CNE) << 2;
case NAND_CTL_CLRALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x02; break; bits |= (ctrl & NAND_CLE | NAND_ALE) >> 1;
writeb((readb(addr) & ~0x7) | bits, addr);
case NAND_CTL_SETNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x04; break;
case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x04; break;
} }
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
} }
/* /*
...@@ -133,7 +140,7 @@ static int __init spia_init(void) ...@@ -133,7 +140,7 @@ static int __init spia_init(void)
this->IO_ADDR_R = (void __iomem *)spia_fio_base; this->IO_ADDR_R = (void __iomem *)spia_fio_base;
this->IO_ADDR_W = (void __iomem *)spia_fio_base; this->IO_ADDR_W = (void __iomem *)spia_fio_base;
/* Set address of hardware control function */ /* Set address of hardware control function */
this->hwcontrol = spia_hwcontrol; this->cmd_ctrl = spia_hwcontrol;
/* 15 us command delay time */ /* 15 us command delay time */
this->chip_delay = 15; this->chip_delay = 15;
......
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <asm/arch-omap1510/hardware.h> #include <asm/arch-omap1510/hardware.h>
#include <asm/arch/gpio.h> #include <asm/arch/gpio.h>
#define CONFIG_NAND_WORKAROUND 1
/* /*
* MTD structure for TOTO board * MTD structure for TOTO board
*/ */
...@@ -39,25 +41,6 @@ static struct mtd_info *toto_mtd = NULL; ...@@ -39,25 +41,6 @@ static struct mtd_info *toto_mtd = NULL;
static unsigned long toto_io_base = OMAP_FLASH_1_BASE; static unsigned long toto_io_base = OMAP_FLASH_1_BASE;
#define CONFIG_NAND_WORKAROUND 1
#define NAND_NCE 0x4000
#define NAND_CLE 0x1000
#define NAND_ALE 0x0002
#define NAND_MASK (NAND_CLE | NAND_ALE | NAND_NCE)
#define T_NAND_CTL_CLRALE(iob) gpiosetout(NAND_ALE, 0)
#define T_NAND_CTL_SETALE(iob) gpiosetout(NAND_ALE, NAND_ALE)
#ifdef CONFIG_NAND_WORKAROUND /* "some" dev boards busted, blue wired to rts2 :( */
#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0); rts2setout(2, 2)
#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE); rts2setout(2, 0)
#else
#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0)
#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE)
#endif
#define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0)
#define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE)
/* /*
* Define partitions for flash devices * Define partitions for flash devices
*/ */
...@@ -91,25 +74,43 @@ static struct mtd_partition partition_info32M[] = { ...@@ -91,25 +74,43 @@ static struct mtd_partition partition_info32M[] = {
#define NUM_PARTITIONS32M 3 #define NUM_PARTITIONS32M 3
#define NUM_PARTITIONS64M 4 #define NUM_PARTITIONS64M 4
/* /*
* hardware specific access to control-lines * hardware specific access to control-lines
*/ *
* ctrl:
static void toto_hwcontrol(struct mtd_info *mtd, int cmd) * NAND_NCE: bit 0 -> bit 14 (0x4000)
* NAND_CLE: bit 1 -> bit 12 (0x1000)
* NAND_ALE: bit 2 -> bit 1 (0x0002)
*/
static void toto_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{ {
struct nand_chip *chip = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
unsigned long bits;
udelay(1); /* hopefully enough time for tc make proceding write to clear */ /* hopefully enough time for tc make proceding write to clear */
switch (cmd) { udelay(1);
case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break;
case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break;
case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break; bits = (~ctrl & NAND_NCE) << 14;
case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break; bits |= (ctrl & NAND_CLE) << 12;
bits |= (ctrl & NAND_ALE) >> 1;
case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break; #warning Wild guess as gpiosetout() is nowhere defined in the kernel source - tglx
case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break; gpiosetout(0x5002, bits);
#ifdef CONFIG_NAND_WORKAROUND
/* "some" dev boards busted, blue wired to rts2 :( */
rts2setout(2, (ctrl & NAND_CLE) << 1);
#endif
/* allow time to ensure gpio state to over take memory write */
udelay(1);
} }
udelay(1); /* allow time to ensure gpio state to over take memory write */
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
} }
/* /*
...@@ -142,7 +143,7 @@ static int __init toto_init(void) ...@@ -142,7 +143,7 @@ static int __init toto_init(void)
/* Set address of NAND IO lines */ /* Set address of NAND IO lines */
this->IO_ADDR_R = toto_io_base; this->IO_ADDR_R = toto_io_base;
this->IO_ADDR_W = toto_io_base; this->IO_ADDR_W = toto_io_base;
this->hwcontrol = toto_hwcontrol; this->cmd_ctrl = toto_hwcontrol;
this->dev_ready = NULL; this->dev_ready = NULL;
/* 25 us command delay time */ /* 25 us command delay time */
this->chip_delay = 30; this->chip_delay = 30;
......
...@@ -83,31 +83,29 @@ static struct mtd_partition partition_info128[] = { ...@@ -83,31 +83,29 @@ static struct mtd_partition partition_info128[] = {
/* /*
* hardware specific access to control-lines * hardware specific access to control-lines
*
* ctrl:
* NAND_NCE: bit 0 -> bit 2
* NAND_CLE: bit 1 -> bit 1
* NAND_ALE: bit 2 -> bit 0
*/ */
static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd) static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{ {
unsigned long ctrl = TS72XX_NAND_CONTROL_VIRT_BASE; struct nand_chip *chip = mtd->priv;
switch (cmd) { if (ctrl & NAND_CTRL_CHANGE) {
case NAND_CTL_SETCLE: unsigned long addr = TS72XX_NAND_CONTROL_VIRT_BASE;
__raw_writeb(__raw_readb(ctrl) | 0x2, ctrl); unsigned char bits;
break;
case NAND_CTL_CLRCLE: bits = (ctrl & NAND_CNE) << 2;
__raw_writeb(__raw_readb(ctrl) & ~0x2, ctrl); bits |= ctrl & NAND_CLE;
break; bits |= (ctrl & NAND_ALE) >> 2;
case NAND_CTL_SETALE:
__raw_writeb(__raw_readb(ctrl) | 0x1, ctrl); __raw_writeb((__raw_readb(addr) & ~0x7) | bits, addr);
break;
case NAND_CTL_CLRALE:
__raw_writeb(__raw_readb(ctrl) & ~0x1, ctrl);
break;
case NAND_CTL_SETNCE:
__raw_writeb(__raw_readb(ctrl) | 0x4, ctrl);
break;
case NAND_CTL_CLRNCE:
__raw_writeb(__raw_readb(ctrl) & ~0x4, ctrl);
break;
} }
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
} }
/* /*
...@@ -152,7 +150,7 @@ static int __init ts7250_init(void) ...@@ -152,7 +150,7 @@ static int __init ts7250_init(void)
/* insert callbacks */ /* insert callbacks */
this->IO_ADDR_R = (void *)TS72XX_NAND_DATA_VIRT_BASE; this->IO_ADDR_R = (void *)TS72XX_NAND_DATA_VIRT_BASE;
this->IO_ADDR_W = (void *)TS72XX_NAND_DATA_VIRT_BASE; this->IO_ADDR_W = (void *)TS72XX_NAND_DATA_VIRT_BASE;
this->hwcontrol = ts7250_hwcontrol; this->cmd_ctrl = ts7250_hwcontrol;
this->dev_ready = ts7250_device_ready; this->dev_ready = ts7250_device_ready;
this->chip_delay = 15; this->chip_delay = 15;
this->ecc.mode = NAND_ECC_SOFT; this->ecc.mode = NAND_ECC_SOFT;
......
...@@ -70,8 +70,6 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -70,8 +70,6 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
nftl->mbd.devnum = -1; nftl->mbd.devnum = -1;
nftl->mbd.blksize = 512; nftl->mbd.blksize = 512;
nftl->mbd.tr = tr; nftl->mbd.tr = tr;
memcpy(&nftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
nftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
if (NFTL_mount(nftl) < 0) { if (NFTL_mount(nftl) < 0) {
printk(KERN_WARNING "NFTL: could not mount device\n"); printk(KERN_WARNING "NFTL: could not mount device\n");
...@@ -369,8 +367,11 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p ...@@ -369,8 +367,11 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
} }
memset(&oob, 0xff, sizeof(struct nftl_oob)); memset(&oob, 0xff, sizeof(struct nftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED; oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo); nand_write_raw(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
(block * 512), 512, &retlen, movebuf,
(char *)&oob);
} }
/* add the header so that it is now a valid chain */ /* add the header so that it is now a valid chain */
...@@ -639,10 +640,10 @@ static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, ...@@ -639,10 +640,10 @@ static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
memset(&oob, 0xff, sizeof(struct nftl_oob)); memset(&oob, 0xff, sizeof(struct nftl_oob));
oob.b.Status = oob.b.Status1 = SECTOR_USED; oob.b.Status = oob.b.Status1 = SECTOR_USED;
MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
512, &retlen, (char *)buffer, (char *)&oob, &nftl->oobinfo);
/* need to write SECTOR_USED flags since they are not written in mtd_writeecc */
nand_write_raw(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) +
blockofs, 512, &retlen, (char *)buffer,
(char *)&oob);
return 0; return 0;
} }
#endif /* CONFIG_NFTL_RW */ #endif /* CONFIG_NFTL_RW */
......
...@@ -268,18 +268,22 @@ static int memcmpb(void *a, int c, int n) ...@@ -268,18 +268,22 @@ static int memcmpb(void *a, int c, int n)
static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
int check_oob) int check_oob)
{ {
int i;
size_t retlen;
u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize]; u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize];
struct mtd_info *mtd = nftl->mbd.mtd;
size_t retlen;
int i;
for (i = 0; i < len; i += SECTORSIZE) { for (i = 0; i < len; i += SECTORSIZE) {
if (MTD_READECC(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &nftl->oobinfo) < 0) if (mtd->read(mtd, address, SECTORSIZE, &retlen, buf))
return -1; return -1;
if (memcmpb(buf, 0xff, SECTORSIZE) != 0) if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
return -1; return -1;
if (check_oob) { if (check_oob) {
if (memcmpb(buf + SECTORSIZE, 0xff, nftl->mbd.mtd->oobsize) != 0) if(mtd->read_oob(mtd, address, mtd->oobsize,
&retlen, &buf[SECTORSIZE]) < 0)
return -1;
if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
return -1; return -1;
} }
address += SECTORSIZE; address += SECTORSIZE;
......
...@@ -597,31 +597,28 @@ static void onenand_release_device(struct mtd_info *mtd) ...@@ -597,31 +597,28 @@ static void onenand_release_device(struct mtd_info *mtd)
} }
/** /**
* onenand_read_ecc - [MTD Interface] Read data with ECC * onenand_read - [MTD Interface] Read data from flash
* @param mtd MTD device structure * @param mtd MTD device structure
* @param from offset to read from * @param from offset to read from
* @param len number of bytes to read * @param len number of bytes to read
* @param retlen pointer to variable to store the number of read bytes * @param retlen pointer to variable to store the number of read bytes
* @param buf the databuffer to put data * @param buf the databuffer to put data
* @param oob_buf filesystem supplied oob data buffer
* @param oobsel oob selection structure
* *
* OneNAND read with ECC * Read with ecc
*/ */
static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf, size_t *retlen, u_char *buf)
u_char *oob_buf, struct nand_oobinfo *oobsel)
{ {
struct onenand_chip *this = mtd->priv; struct onenand_chip *this = mtd->priv;
int read = 0, column; int read = 0, column;
int thislen; int thislen;
int ret = 0; int ret = 0;
DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
/* Do not allow reads past end of device */ /* Do not allow reads past end of device */
if ((from + len) > mtd->size) { if ((from + len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n"); DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end of device\n");
*retlen = 0; *retlen = 0;
return -EINVAL; return -EINVAL;
} }
...@@ -654,7 +651,7 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -654,7 +651,7 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
break; break;
if (ret) { if (ret) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret); DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret);
goto out; goto out;
} }
...@@ -675,22 +672,6 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -675,22 +672,6 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
return ret; return ret;
} }
/**
* onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc
* @param mtd MTD device structure
* @param from offset to read from
* @param len number of bytes to read
* @param retlen pointer to variable to store the number of read bytes
* @param buf the databuffer to put data
*
* This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL
*/
static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
}
/** /**
* onenand_read_oob - [MTD Interface] OneNAND read out-of-band * onenand_read_oob - [MTD Interface] OneNAND read out-of-band
* @param mtd MTD device structure * @param mtd MTD device structure
...@@ -834,39 +815,36 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) ...@@ -834,39 +815,36 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) #define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0)
/** /**
* onenand_write_ecc - [MTD Interface] OneNAND write with ECC * onenand_write - [MTD Interface] write buffer to FLASH
* @param mtd MTD device structure * @param mtd MTD device structure
* @param to offset to write to * @param to offset to write to
* @param len number of bytes to write * @param len number of bytes to write
* @param retlen pointer to variable to store the number of written bytes * @param retlen pointer to variable to store the number of written bytes
* @param buf the data to write * @param buf the data to write
* @param eccbuf filesystem supplied oob data buffer
* @param oobsel oob selection structure
* *
* OneNAND write with ECC * Write with ECC
*/ */
static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf, size_t *retlen, const u_char *buf)
u_char *eccbuf, struct nand_oobinfo *oobsel)
{ {
struct onenand_chip *this = mtd->priv; struct onenand_chip *this = mtd->priv;
int written = 0; int written = 0;
int ret = 0; int ret = 0;
DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
/* Initialize retlen, in case of early exit */ /* Initialize retlen, in case of early exit */
*retlen = 0; *retlen = 0;
/* Do not allow writes past end of device */ /* Do not allow writes past end of device */
if (unlikely((to + len) > mtd->size)) { if (unlikely((to + len) > mtd->size)) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n"); DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past end of device\n");
return -EINVAL; return -EINVAL;
} }
/* Reject writes, which are not page aligned */ /* Reject writes, which are not page aligned */
if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n"); DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not page aligned data\n");
return -EINVAL; return -EINVAL;
} }
...@@ -888,7 +866,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -888,7 +866,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
ret = this->wait(mtd, FL_WRITING); ret = this->wait(mtd, FL_WRITING);
if (ret) { if (ret) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret); DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret);
goto out; goto out;
} }
...@@ -897,7 +875,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -897,7 +875,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
/* Only check verify write turn on */ /* Only check verify write turn on */
ret = onenand_verify_page(mtd, (u_char *) buf, to); ret = onenand_verify_page(mtd, (u_char *) buf, to);
if (ret) { if (ret) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret); DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret);
goto out; goto out;
} }
...@@ -917,23 +895,6 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -917,23 +895,6 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
return ret; return ret;
} }
/**
* onenand_write - [MTD Interface] compability function for onenand_write_ecc
* @param mtd MTD device structure
* @param to offset to write to
* @param len number of bytes to write
* @param retlen pointer to variable to store the number of written bytes
* @param buf the data to write
*
* This function simply calls onenand_write_ecc
* with oob buffer and oobsel = NULL
*/
static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL);
}
/** /**
* onenand_write_oob - [MTD Interface] OneNAND write out-of-band * onenand_write_oob - [MTD Interface] OneNAND write out-of-band
* @param mtd MTD device structure * @param mtd MTD device structure
...@@ -1013,144 +974,6 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -1013,144 +974,6 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
return ret; return ret;
} }
/**
* onenand_writev_ecc - [MTD Interface] write with iovec with ecc
* @param mtd MTD device structure
* @param vecs the iovectors to write
* @param count number of vectors
* @param to offset to write to
* @param retlen pointer to variable to store the number of written bytes
* @param eccbuf filesystem supplied oob data buffer
* @param oobsel oob selection structure
*
* OneNAND write with iovec with ecc
*/
static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen,
u_char *eccbuf, struct nand_oobinfo *oobsel)
{
struct onenand_chip *this = mtd->priv;
unsigned char *pbuf;
size_t total_len, len;
int i, written = 0;
int ret = 0;
/* Preset written len for early exit */
*retlen = 0;
/* Calculate total length of data */
total_len = 0;
for (i = 0; i < count; i++)
total_len += vecs[i].iov_len;
DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
/* Do not allow write past end of the device */
if (unlikely((to + total_len) > mtd->size)) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n");
return -EINVAL;
}
/* Reject writes, which are not page aligned */
if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempt to write not page aligned data\n");
return -EINVAL;
}
/* Grab the lock and see if the device is available */
onenand_get_device(mtd, FL_WRITING);
/* TODO handling oob */
/* Loop until all keve's data has been written */
len = 0;
while (count) {
pbuf = this->page_buf;
/*
* If the given tuple is >= pagesize then
* write it out from the iov
*/
if ((vecs->iov_len - len) >= mtd->writesize) {
pbuf = vecs->iov_base + len;
len += mtd->writesize;
/* Check, if we have to switch to the next tuple */
if (len >= (int) vecs->iov_len) {
vecs++;
len = 0;
count--;
}
} else {
int cnt = 0, thislen;
while (cnt < mtd->writesize) {
thislen = min_t(int, mtd->writesize - cnt, vecs->iov_len - len);
memcpy(this->page_buf + cnt, vecs->iov_base + len, thislen);
cnt += thislen;
len += thislen;
/* Check, if we have to switch to the next tuple */
if (len >= (int) vecs->iov_len) {
vecs++;
len = 0;
count--;
}
}
}
this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize);
this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->writesize);
this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
onenand_update_bufferram(mtd, to, 1);
ret = this->wait(mtd, FL_WRITING);
if (ret) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: write failed %d\n", ret);
goto out;
}
/* Only check verify write turn on */
ret = onenand_verify_page(mtd, (u_char *) pbuf, to);
if (ret) {
DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: verify failed %d\n", ret);
goto out;
}
written += mtd->writesize;
to += mtd->writesize;
}
out:
/* Deselect and wakt up anyone waiting on the device */
onenand_release_device(mtd);
*retlen = written;
return 0;
}
/**
* onenand_writev - [MTD Interface] compabilty function for onenand_writev_ecc
* @param mtd MTD device structure
* @param vecs the iovectors to write
* @param count number of vectors
* @param to offset to write to
* @param retlen pointer to variable to store the number of written bytes
*
* OneNAND write with kvec. This just calls the ecc function
*/
static int onenand_writev(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen)
{
return onenand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL);
}
/** /**
* onenand_block_checkbad - [GENERIC] Check if a block is marked bad * onenand_block_checkbad - [GENERIC] Check if a block is marked bad
* @param mtd MTD device structure * @param mtd MTD device structure
...@@ -1950,8 +1773,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) ...@@ -1950,8 +1773,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd->unpoint = NULL; mtd->unpoint = NULL;
mtd->read = onenand_read; mtd->read = onenand_read;
mtd->write = onenand_write; mtd->write = onenand_write;
mtd->read_ecc = onenand_read_ecc;
mtd->write_ecc = onenand_write_ecc;
mtd->read_oob = onenand_read_oob; mtd->read_oob = onenand_read_oob;
mtd->write_oob = onenand_write_oob; mtd->write_oob = onenand_write_oob;
#ifdef CONFIG_MTD_ONENAND_OTP #ifdef CONFIG_MTD_ONENAND_OTP
...@@ -1962,10 +1783,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) ...@@ -1962,10 +1783,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd->write_user_prot_reg = onenand_write_user_prot_reg; mtd->write_user_prot_reg = onenand_write_user_prot_reg;
mtd->lock_user_prot_reg = onenand_lock_user_prot_reg; mtd->lock_user_prot_reg = onenand_lock_user_prot_reg;
#endif #endif
mtd->readv = NULL;
mtd->readv_ecc = NULL;
mtd->writev = onenand_writev;
mtd->writev_ecc = onenand_writev_ecc;
mtd->sync = onenand_sync; mtd->sync = onenand_sync;
mtd->lock = NULL; mtd->lock = NULL;
mtd->unlock = onenand_unlock; mtd->unlock = onenand_unlock;
......
...@@ -236,10 +236,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -236,10 +236,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
} }
/* Do the read... */ /* Do the read... */
if (jffs2_cleanmarker_oob(c)) ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
else
ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) {
/* ECC recovered */ /* ECC recovered */
...@@ -293,16 +290,13 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -293,16 +290,13 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
if (breakme++ == 20) { if (breakme++ == 20) {
printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs); printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs);
breakme = 0; breakme = 0;
c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, c->mtd->write(c->mtd, ofs, towrite, &retlen,
brokenbuf, NULL, c->oobinfo); brokenbuf);
ret = -EIO; ret = -EIO;
} else } else
#endif #endif
if (jffs2_cleanmarker_oob(c)) ret = c->mtd->write(c->mtd, ofs, towrite, &retlen,
ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, rewrite_buf);
rewrite_buf, NULL, c->oobinfo);
else
ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf);
if (ret || retlen != towrite) { if (ret || retlen != towrite) {
/* Argh. We tried. Really we did. */ /* Argh. We tried. Really we did. */
...@@ -455,15 +449,12 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) ...@@ -455,15 +449,12 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
if (breakme++ == 20) { if (breakme++ == 20) {
printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs); printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
breakme = 0; breakme = 0;
c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen,
&retlen, brokenbuf, NULL, c->oobinfo); brokenbuf);
ret = -EIO; ret = -EIO;
} else } else
#endif #endif
if (jffs2_cleanmarker_oob(c))
ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
else
ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
if (ret || retlen != c->wbuf_pagesize) { if (ret || retlen != c->wbuf_pagesize) {
...@@ -792,10 +783,7 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re ...@@ -792,10 +783,7 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
/* Read flash */ /* Read flash */
down_read(&c->wbuf_sem); down_read(&c->wbuf_sem);
if (jffs2_cleanmarker_oob(c)) ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
else
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
if ( (ret == -EBADMSG) && (*retlen == len) ) { if ( (ret == -EBADMSG) && (*retlen == len) ) {
printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
......
...@@ -115,9 +115,6 @@ struct mtd_info { ...@@ -115,9 +115,6 @@ struct mtd_info {
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
...@@ -133,17 +130,11 @@ struct mtd_info { ...@@ -133,17 +130,11 @@ struct mtd_info {
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
/* kvec-based read/write methods. We need these especially for NAND flash, /* kvec-based read/write methods.
with its limited number of write cycles per erase.
NB: The 'count' parameter is the number of _vectors_, each of NB: The 'count' parameter is the number of _vectors_, each of
which contains an (ofs, len) tuple. which contains an (ofs, len) tuple.
*/ */
int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen);
int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from,
size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to,
size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
/* Sync */ /* Sync */
void (*sync) (struct mtd_info *mtd); void (*sync) (struct mtd_info *mtd);
......
...@@ -36,6 +36,9 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, ...@@ -36,6 +36,9 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from,
size_t len, size_t ooblen); size_t len, size_t ooblen);
extern int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, uint8_t *buf, uint8_t *oob);
/* The maximum number of NAND chips in an array */ /* The maximum number of NAND chips in an array */
#define NAND_MAX_CHIPS 8 #define NAND_MAX_CHIPS 8
...@@ -47,23 +50,20 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, ...@@ -47,23 +50,20 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from,
/* /*
* Constants for hardware specific CLE/ALE/NCE function * Constants for hardware specific CLE/ALE/NCE function
*/ *
* These are bits which can be or'ed to set/clear multiple
* bits in one go.
*/
/* Select the chip by setting nCE to low */ /* Select the chip by setting nCE to low */
#define NAND_CTL_SETNCE 1 #define NAND_NCE 0x01
/* Deselect the chip by setting nCE to high */
#define NAND_CTL_CLRNCE 2
/* Select the command latch by setting CLE to high */ /* Select the command latch by setting CLE to high */
#define NAND_CTL_SETCLE 3 #define NAND_CLE 0x02
/* Deselect the command latch by setting CLE to low */
#define NAND_CTL_CLRCLE 4
/* Select the address latch by setting ALE to high */ /* Select the address latch by setting ALE to high */
#define NAND_CTL_SETALE 5 #define NAND_ALE 0x04
/* Deselect the address latch by setting ALE to low */
#define NAND_CTL_CLRALE 6 #define NAND_CTRL_CLE (NAND_NCE | NAND_CLE)
/* Set write protection by setting WP to high. Not used! */ #define NAND_CTRL_ALE (NAND_NCE | NAND_ALE)
#define NAND_CTL_SETWP 7 #define NAND_CTRL_CHANGE 0x80
/* Clear write protection by setting WP to low. Not used! */
#define NAND_CTL_CLRWP 8
/* /*
* Standard NAND flash commands * Standard NAND flash commands
...@@ -103,6 +103,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, ...@@ -103,6 +103,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from,
#define NAND_CMD_STATUS_RESET 0x7f #define NAND_CMD_STATUS_RESET 0x7f
#define NAND_CMD_STATUS_CLEAR 0xff #define NAND_CMD_STATUS_CLEAR 0xff
#define NAND_CMD_NONE -1
/* Status bits */ /* Status bits */
#define NAND_STATUS_FAIL 0x01 #define NAND_STATUS_FAIL 0x01
#define NAND_STATUS_FAIL_N1 0x02 #define NAND_STATUS_FAIL_N1 0x02
...@@ -237,7 +239,7 @@ struct nand_ecc_ctrl { ...@@ -237,7 +239,7 @@ struct nand_ecc_ctrl {
int steps; int steps;
int size; int size;
int bytes; int bytes;
int (*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);
...@@ -251,16 +253,15 @@ struct nand_ecc_ctrl { ...@@ -251,16 +253,15 @@ struct nand_ecc_ctrl {
* @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 flash device
* @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the 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
* @write_byte: [REPLACEABLE] write one byte to the chip
* @read_word: [REPLACEABLE] read one word from the chip * @read_word: [REPLACEABLE] read one word from the chip
* @write_word: [REPLACEABLE] write one word to 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
* @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines * @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific funtion for controlling
* ALE/CLE/nCE. Also used to write command and address
* @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line * @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 * If set to NULL no access to ready/busy is available and the ready/busy information
* is read from the chip status register * is read from the chip status register
...@@ -304,17 +305,15 @@ struct nand_chip { ...@@ -304,17 +305,15 @@ struct nand_chip {
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);
void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
u16 (*read_word)(struct mtd_info *mtd); u16 (*read_word)(struct mtd_info *mtd);
void (*write_word)(struct mtd_info *mtd, u16 word);
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 (*hwcontrol)(struct mtd_info *mtd, int cmd); void (*cmd_ctrl)(struct mtd_info *mtd, int dat,
unsigned int ctrl);
int (*dev_ready)(struct mtd_info *mtd); int (*dev_ready)(struct mtd_info *mtd);
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment