diff options
author | David Woodhouse <dwmw2@infradead.org> | 2006-05-24 05:01:43 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-05-24 05:01:43 -0400 |
commit | 0305c8659ff9cebabf469d5cd0ab8dc384857e10 (patch) | |
tree | 1784b2bb078a58e50ca75dfccd1e9fc5f8b211b8 | |
parent | 99988f7bbd16b861590dda4631c4db6cb17b5091 (diff) | |
parent | d470a97c70a43ffafd6e728c913254b6d6fd1219 (diff) |
Merge branch 'master' of git://git.infradead.org/~gleixner/mtd-nand-2.6.git
32 files changed, 666 insertions, 1515 deletions
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 423a34f4638c..d9ba1ee658f6 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c | |||
@@ -59,9 +59,6 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
59 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); | 59 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); |
60 | static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | 60 | static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, |
61 | size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); | 61 | size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); |
62 | static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | ||
63 | unsigned long count, loff_t to, size_t *retlen, | ||
64 | u_char *eccbuf, struct nand_oobinfo *oobsel); | ||
65 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, | 62 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, |
66 | size_t *retlen, u_char *buf); | 63 | size_t *retlen, u_char *buf); |
67 | static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, | 64 | 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 | mtd->unpoint = NULL; | 584 | mtd->unpoint = NULL; |
588 | mtd->read = doc_read; | 585 | mtd->read = doc_read; |
589 | mtd->write = doc_write; | 586 | mtd->write = doc_write; |
590 | mtd->read_ecc = doc_read_ecc; | ||
591 | mtd->write_ecc = doc_write_ecc; | ||
592 | mtd->writev_ecc = doc_writev_ecc; | ||
593 | mtd->read_oob = doc_read_oob; | 587 | mtd->read_oob = doc_read_oob; |
594 | mtd->write_oob = doc_write_oob; | 588 | mtd->write_oob = doc_write_oob; |
595 | mtd->sync = NULL; | 589 | mtd->sync = NULL; |
@@ -965,66 +959,6 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
965 | return 0; | 959 | return 0; |
966 | } | 960 | } |
967 | 961 | ||
968 | static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | ||
969 | unsigned long count, loff_t to, size_t *retlen, | ||
970 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
971 | { | ||
972 | static char static_buf[512]; | ||
973 | static DEFINE_MUTEX(writev_buf_mutex); | ||
974 | |||
975 | size_t totretlen = 0; | ||
976 | size_t thisvecofs = 0; | ||
977 | int ret= 0; | ||
978 | |||
979 | mutex_lock(&writev_buf_mutex); | ||
980 | |||
981 | while(count) { | ||
982 | size_t thislen, thisretlen; | ||
983 | unsigned char *buf; | ||
984 | |||
985 | buf = vecs->iov_base + thisvecofs; | ||
986 | thislen = vecs->iov_len - thisvecofs; | ||
987 | |||
988 | |||
989 | if (thislen >= 512) { | ||
990 | thislen = thislen & ~(512-1); | ||
991 | thisvecofs += thislen; | ||
992 | } else { | ||
993 | /* Not enough to fill a page. Copy into buf */ | ||
994 | memcpy(static_buf, buf, thislen); | ||
995 | buf = &static_buf[thislen]; | ||
996 | |||
997 | while(count && thislen < 512) { | ||
998 | vecs++; | ||
999 | count--; | ||
1000 | thisvecofs = min((512-thislen), vecs->iov_len); | ||
1001 | memcpy(buf, vecs->iov_base, thisvecofs); | ||
1002 | thislen += thisvecofs; | ||
1003 | buf += thisvecofs; | ||
1004 | } | ||
1005 | buf = static_buf; | ||
1006 | } | ||
1007 | if (count && thisvecofs == vecs->iov_len) { | ||
1008 | thisvecofs = 0; | ||
1009 | vecs++; | ||
1010 | count--; | ||
1011 | } | ||
1012 | ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel); | ||
1013 | |||
1014 | totretlen += thisretlen; | ||
1015 | |||
1016 | if (ret || thisretlen != thislen) | ||
1017 | break; | ||
1018 | |||
1019 | to += thislen; | ||
1020 | } | ||
1021 | |||
1022 | mutex_unlock(&writev_buf_mutex); | ||
1023 | *retlen = totretlen; | ||
1024 | return ret; | ||
1025 | } | ||
1026 | |||
1027 | |||
1028 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, | 962 | static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, |
1029 | size_t * retlen, u_char * buf) | 963 | size_t * retlen, u_char * buf) |
1030 | { | 964 | { |
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index e6eaef28a2b0..579c0b570ae5 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c | |||
@@ -369,8 +369,6 @@ void DoCMil_init(struct mtd_info *mtd) | |||
369 | mtd->unpoint = NULL; | 369 | mtd->unpoint = NULL; |
370 | mtd->read = doc_read; | 370 | mtd->read = doc_read; |
371 | mtd->write = doc_write; | 371 | mtd->write = doc_write; |
372 | mtd->read_ecc = doc_read_ecc; | ||
373 | mtd->write_ecc = doc_write_ecc; | ||
374 | mtd->read_oob = doc_read_oob; | 372 | mtd->read_oob = doc_read_oob; |
375 | mtd->write_oob = doc_write_oob; | 373 | mtd->write_oob = doc_write_oob; |
376 | mtd->sync = NULL; | 374 | mtd->sync = NULL; |
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 8422c5e92d27..1ee0c0dcb53b 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c | |||
@@ -491,8 +491,6 @@ void DoCMilPlus_init(struct mtd_info *mtd) | |||
491 | mtd->unpoint = NULL; | 491 | mtd->unpoint = NULL; |
492 | mtd->read = doc_read; | 492 | mtd->read = doc_read; |
493 | mtd->write = doc_write; | 493 | mtd->write = doc_write; |
494 | mtd->read_ecc = doc_read_ecc; | ||
495 | mtd->write_ecc = doc_write_ecc; | ||
496 | mtd->read_oob = doc_read_oob; | 494 | mtd->read_oob = doc_read_oob; |
497 | mtd->write_oob = doc_write_oob; | 495 | mtd->write_oob = doc_write_oob; |
498 | mtd->sync = NULL; | 496 | mtd->sync = NULL; |
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index a3b92479719d..ddd12993780d 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/mtd/mtd.h> | 36 | #include <linux/mtd/mtd.h> |
37 | #include <linux/mtd/nftl.h> | 37 | #include <linux/mtd/nftl.h> |
38 | #include <linux/mtd/inftl.h> | 38 | #include <linux/mtd/inftl.h> |
39 | #include <linux/mtd/nand.h> | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | #include <asm/errno.h> | 41 | #include <asm/errno.h> |
41 | #include <asm/io.h> | 42 | #include <asm/io.h> |
@@ -79,14 +80,12 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
79 | inftl->mbd.devnum = -1; | 80 | inftl->mbd.devnum = -1; |
80 | inftl->mbd.blksize = 512; | 81 | inftl->mbd.blksize = 512; |
81 | inftl->mbd.tr = tr; | 82 | inftl->mbd.tr = tr; |
82 | memcpy(&inftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo)); | ||
83 | inftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY; | ||
84 | 83 | ||
85 | if (INFTL_mount(inftl) < 0) { | 84 | if (INFTL_mount(inftl) < 0) { |
86 | printk(KERN_WARNING "INFTL: could not mount device\n"); | 85 | printk(KERN_WARNING "INFTL: could not mount device\n"); |
87 | kfree(inftl); | 86 | kfree(inftl); |
88 | return; | 87 | return; |
89 | } | 88 | } |
90 | 89 | ||
91 | /* OK, it's a new one. Set up all the data structures. */ | 90 | /* OK, it's a new one. Set up all the data structures. */ |
92 | 91 | ||
@@ -221,7 +220,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
221 | * Scan to find the Erase Unit which holds the actual data for each | 220 | * Scan to find the Erase Unit which holds the actual data for each |
222 | * 512-byte block within the Chain. | 221 | * 512-byte block within the Chain. |
223 | */ | 222 | */ |
224 | silly = MAX_LOOPS; | 223 | silly = MAX_LOOPS; |
225 | while (thisEUN < inftl->nb_blocks) { | 224 | while (thisEUN < inftl->nb_blocks) { |
226 | for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) { | 225 | for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) { |
227 | if ((BlockMap[block] != 0xffff) || BlockDeleted[block]) | 226 | if ((BlockMap[block] != 0xffff) || BlockDeleted[block]) |
@@ -232,7 +231,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
232 | (char *)&oob) < 0) | 231 | (char *)&oob) < 0) |
233 | status = SECTOR_IGNORE; | 232 | status = SECTOR_IGNORE; |
234 | else | 233 | else |
235 | status = oob.b.Status | oob.b.Status1; | 234 | status = oob.b.Status | oob.b.Status1; |
236 | 235 | ||
237 | switch(status) { | 236 | switch(status) { |
238 | case SECTOR_FREE: | 237 | case SECTOR_FREE: |
@@ -282,29 +281,30 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
282 | continue; | 281 | continue; |
283 | } | 282 | } |
284 | 283 | ||
285 | /* | 284 | /* |
286 | * Copy only in non free block (free blocks can only | 285 | * Copy only in non free block (free blocks can only |
287 | * happen in case of media errors or deleted blocks). | 286 | * happen in case of media errors or deleted blocks). |
288 | */ | 287 | */ |
289 | if (BlockMap[block] == BLOCK_NIL) | 288 | if (BlockMap[block] == BLOCK_NIL) |
290 | continue; | 289 | continue; |
291 | 290 | ||
292 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * | 291 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * |
293 | BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, | 292 | BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, |
294 | &retlen, movebuf); | 293 | &retlen, movebuf); |
295 | if (ret < 0) { | 294 | if (ret < 0) { |
296 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * | 295 | ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize * |
297 | BlockMap[block]) + (block * SECTORSIZE), | 296 | BlockMap[block]) + (block * SECTORSIZE), |
298 | SECTORSIZE, &retlen, movebuf); | 297 | SECTORSIZE, &retlen, movebuf); |
299 | if (ret != -EIO) | 298 | if (ret != -EIO) |
300 | DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " | 299 | DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " |
301 | "away on retry?\n"); | 300 | "away on retry?\n"); |
302 | } | 301 | } |
303 | memset(&oob, 0xff, sizeof(struct inftl_oob)); | 302 | memset(&oob, 0xff, sizeof(struct inftl_oob)); |
304 | oob.b.Status = oob.b.Status1 = SECTOR_USED; | 303 | oob.b.Status = oob.b.Status1 = SECTOR_USED; |
305 | MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) + | 304 | |
306 | (block * SECTORSIZE), SECTORSIZE, &retlen, | 305 | nand_write_raw(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) + |
307 | movebuf, (char *)&oob, &inftl->oobinfo); | 306 | (block * SECTORSIZE), SECTORSIZE, &retlen, |
307 | movebuf, (char *)&oob); | ||
308 | } | 308 | } |
309 | 309 | ||
310 | /* | 310 | /* |
@@ -329,17 +329,17 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned | |||
329 | if (thisEUN == targetEUN) | 329 | if (thisEUN == targetEUN) |
330 | break; | 330 | break; |
331 | 331 | ||
332 | if (INFTL_formatblock(inftl, thisEUN) < 0) { | 332 | if (INFTL_formatblock(inftl, thisEUN) < 0) { |
333 | /* | 333 | /* |
334 | * Could not erase : mark block as reserved. | 334 | * Could not erase : mark block as reserved. |
335 | */ | 335 | */ |
336 | inftl->PUtable[thisEUN] = BLOCK_RESERVED; | 336 | inftl->PUtable[thisEUN] = BLOCK_RESERVED; |
337 | } else { | 337 | } else { |
338 | /* Correctly erased : mark it as free */ | 338 | /* Correctly erased : mark it as free */ |
339 | inftl->PUtable[thisEUN] = BLOCK_FREE; | 339 | inftl->PUtable[thisEUN] = BLOCK_FREE; |
340 | inftl->PUtable[prevEUN] = BLOCK_NIL; | 340 | inftl->PUtable[prevEUN] = BLOCK_NIL; |
341 | inftl->numfreeEUNs++; | 341 | inftl->numfreeEUNs++; |
342 | } | 342 | } |
343 | } | 343 | } |
344 | 344 | ||
345 | return targetEUN; | 345 | return targetEUN; |
@@ -437,7 +437,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) | |||
437 | MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + | 437 | MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + |
438 | blockofs, 8, &retlen, (char *)&bci); | 438 | blockofs, 8, &retlen, (char *)&bci); |
439 | 439 | ||
440 | status = bci.Status | bci.Status1; | 440 | status = bci.Status | bci.Status1; |
441 | DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " | 441 | DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " |
442 | "EUN %d is %x\n", block , writeEUN, status); | 442 | "EUN %d is %x\n", block , writeEUN, status); |
443 | 443 | ||
@@ -670,12 +670,12 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) | |||
670 | DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n", | 670 | DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n", |
671 | thisEUN, thisVUC); | 671 | thisEUN, thisVUC); |
672 | 672 | ||
673 | if (INFTL_formatblock(inftl, thisEUN) < 0) { | 673 | if (INFTL_formatblock(inftl, thisEUN) < 0) { |
674 | /* | 674 | /* |
675 | * Could not erase : mark block as reserved. | 675 | * Could not erase : mark block as reserved. |
676 | */ | 676 | */ |
677 | inftl->PUtable[thisEUN] = BLOCK_RESERVED; | 677 | inftl->PUtable[thisEUN] = BLOCK_RESERVED; |
678 | } else { | 678 | } else { |
679 | /* Correctly erased : mark it as free */ | 679 | /* Correctly erased : mark it as free */ |
680 | inftl->PUtable[thisEUN] = BLOCK_FREE; | 680 | inftl->PUtable[thisEUN] = BLOCK_FREE; |
681 | inftl->numfreeEUNs++; | 681 | inftl->numfreeEUNs++; |
@@ -784,9 +784,10 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, | |||
784 | 784 | ||
785 | memset(&oob, 0xff, sizeof(struct inftl_oob)); | 785 | memset(&oob, 0xff, sizeof(struct inftl_oob)); |
786 | oob.b.Status = oob.b.Status1 = SECTOR_USED; | 786 | oob.b.Status = oob.b.Status1 = SECTOR_USED; |
787 | MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) + | 787 | |
788 | blockofs, SECTORSIZE, &retlen, (char *)buffer, | 788 | nand_write_raw(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) + |
789 | (char *)&oob, &inftl->oobinfo); | 789 | blockofs, SECTORSIZE, &retlen, (char *)buffer, |
790 | (char *)&oob); | ||
790 | /* | 791 | /* |
791 | * need to write SECTOR_USED flags since they are not written | 792 | * need to write SECTOR_USED flags since they are not written |
792 | * in mtd_writeecc | 793 | * in mtd_writeecc |
@@ -804,9 +805,9 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, | |||
804 | struct INFTLrecord *inftl = (void *)mbd; | 805 | struct INFTLrecord *inftl = (void *)mbd; |
805 | unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; | 806 | unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; |
806 | unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); | 807 | unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); |
807 | unsigned int status; | 808 | unsigned int status; |
808 | int silly = MAX_LOOPS; | 809 | int silly = MAX_LOOPS; |
809 | struct inftl_bci bci; | 810 | struct inftl_bci bci; |
810 | size_t retlen; | 811 | size_t retlen; |
811 | 812 | ||
812 | DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld," | 813 | DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld," |
@@ -850,7 +851,7 @@ foundit: | |||
850 | /* The requested block is not on the media, return all 0x00 */ | 851 | /* The requested block is not on the media, return all 0x00 */ |
851 | memset(buffer, 0, SECTORSIZE); | 852 | memset(buffer, 0, SECTORSIZE); |
852 | } else { | 853 | } else { |
853 | size_t retlen; | 854 | size_t retlen; |
854 | loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; | 855 | loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; |
855 | if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen, | 856 | if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen, |
856 | buffer)) | 857 | buffer)) |
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 43fdc9433882..f89a03795e76 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c | |||
@@ -350,21 +350,21 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, | |||
350 | int len, int check_oob) | 350 | int len, int check_oob) |
351 | { | 351 | { |
352 | u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize]; | 352 | u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize]; |
353 | struct mtd_info *mtd = inftl->mbd.mtd; | ||
353 | size_t retlen; | 354 | size_t retlen; |
354 | int i; | 355 | int i; |
355 | 356 | ||
356 | DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=%p," | ||
357 | "address=0x%x,len=%d,check_oob=%d)\n", inftl, | ||
358 | address, len, check_oob); | ||
359 | |||
360 | for (i = 0; i < len; i += SECTORSIZE) { | 357 | for (i = 0; i < len; i += SECTORSIZE) { |
361 | if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0) | 358 | if (mtd->read(mtd, address, SECTORSIZE, &retlen, buf)) |
362 | return -1; | 359 | return -1; |
363 | if (memcmpb(buf, 0xff, SECTORSIZE) != 0) | 360 | if (memcmpb(buf, 0xff, SECTORSIZE) != 0) |
364 | return -1; | 361 | return -1; |
365 | 362 | ||
366 | if (check_oob) { | 363 | if (check_oob) { |
367 | if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0) | 364 | if(mtd->read_oob(mtd, address, mtd->oobsize, |
365 | &retlen, &buf[SECTORSIZE]) < 0) | ||
366 | return -1; | ||
367 | if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0) | ||
368 | return -1; | 368 | return -1; |
369 | } | 369 | } |
370 | address += SECTORSIZE; | 370 | address += SECTORSIZE; |
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index a5e8373349a5..6d52137988fa 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c | |||
@@ -143,119 +143,8 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
143 | } | 143 | } |
144 | 144 | ||
145 | static int | 145 | static int |
146 | concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | 146 | concat_writev(struct mtd_info *mtd, const struct kvec *vecs, |
147 | size_t * retlen, u_char * buf, u_char * eccbuf, | 147 | unsigned long count, loff_t to, size_t * retlen) |
148 | struct nand_oobinfo *oobsel) | ||
149 | { | ||
150 | struct mtd_concat *concat = CONCAT(mtd); | ||
151 | int err = -EINVAL; | ||
152 | int i; | ||
153 | |||
154 | *retlen = 0; | ||
155 | |||
156 | for (i = 0; i < concat->num_subdev; i++) { | ||
157 | struct mtd_info *subdev = concat->subdev[i]; | ||
158 | size_t size, retsize; | ||
159 | |||
160 | if (from >= subdev->size) { | ||
161 | /* Not destined for this subdev */ | ||
162 | size = 0; | ||
163 | from -= subdev->size; | ||
164 | continue; | ||
165 | } | ||
166 | |||
167 | if (from + len > subdev->size) | ||
168 | /* First part goes into this subdev */ | ||
169 | size = subdev->size - from; | ||
170 | else | ||
171 | /* Entire transaction goes into this subdev */ | ||
172 | size = len; | ||
173 | |||
174 | if (subdev->read_ecc) | ||
175 | err = subdev->read_ecc(subdev, from, size, | ||
176 | &retsize, buf, eccbuf, oobsel); | ||
177 | else | ||
178 | err = -EINVAL; | ||
179 | |||
180 | if (err) | ||
181 | break; | ||
182 | |||
183 | *retlen += retsize; | ||
184 | len -= size; | ||
185 | if (len == 0) | ||
186 | break; | ||
187 | |||
188 | err = -EINVAL; | ||
189 | buf += size; | ||
190 | if (eccbuf) { | ||
191 | eccbuf += subdev->oobsize; | ||
192 | /* in nand.c at least, eccbufs are | ||
193 | tagged with 2 (int)eccstatus'; we | ||
194 | must account for these */ | ||
195 | eccbuf += 2 * (sizeof (int)); | ||
196 | } | ||
197 | from = 0; | ||
198 | } | ||
199 | return err; | ||
200 | } | ||
201 | |||
202 | static int | ||
203 | concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | ||
204 | size_t * retlen, const u_char * buf, u_char * eccbuf, | ||
205 | struct nand_oobinfo *oobsel) | ||
206 | { | ||
207 | struct mtd_concat *concat = CONCAT(mtd); | ||
208 | int err = -EINVAL; | ||
209 | int i; | ||
210 | |||
211 | if (!(mtd->flags & MTD_WRITEABLE)) | ||
212 | return -EROFS; | ||
213 | |||
214 | *retlen = 0; | ||
215 | |||
216 | for (i = 0; i < concat->num_subdev; i++) { | ||
217 | struct mtd_info *subdev = concat->subdev[i]; | ||
218 | size_t size, retsize; | ||
219 | |||
220 | if (to >= subdev->size) { | ||
221 | size = 0; | ||
222 | to -= subdev->size; | ||
223 | continue; | ||
224 | } | ||
225 | if (to + len > subdev->size) | ||
226 | size = subdev->size - to; | ||
227 | else | ||
228 | size = len; | ||
229 | |||
230 | if (!(subdev->flags & MTD_WRITEABLE)) | ||
231 | err = -EROFS; | ||
232 | else if (subdev->write_ecc) | ||
233 | err = subdev->write_ecc(subdev, to, size, | ||
234 | &retsize, buf, eccbuf, oobsel); | ||
235 | else | ||
236 | err = -EINVAL; | ||
237 | |||
238 | if (err) | ||
239 | break; | ||
240 | |||
241 | *retlen += retsize; | ||
242 | len -= size; | ||
243 | if (len == 0) | ||
244 | break; | ||
245 | |||
246 | err = -EINVAL; | ||
247 | buf += size; | ||
248 | if (eccbuf) | ||
249 | eccbuf += subdev->oobsize; | ||
250 | to = 0; | ||
251 | } | ||
252 | return err; | ||
253 | } | ||
254 | |||
255 | static int | ||
256 | concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | ||
257 | unsigned long count, loff_t to, size_t * retlen, | ||
258 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
259 | { | 148 | { |
260 | struct mtd_concat *concat = CONCAT(mtd); | 149 | struct mtd_concat *concat = CONCAT(mtd); |
261 | struct kvec *vecs_copy; | 150 | struct kvec *vecs_copy; |
@@ -315,10 +204,6 @@ concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | |||
315 | 204 | ||
316 | if (!(subdev->flags & MTD_WRITEABLE)) | 205 | if (!(subdev->flags & MTD_WRITEABLE)) |
317 | err = -EROFS; | 206 | err = -EROFS; |
318 | else if (eccbuf) | ||
319 | err = subdev->writev_ecc(subdev, &vecs_copy[entry_low], | ||
320 | entry_high - entry_low + 1, to, &retsize, | ||
321 | eccbuf, oobsel); | ||
322 | else | 207 | else |
323 | err = subdev->writev(subdev, &vecs_copy[entry_low], | 208 | err = subdev->writev(subdev, &vecs_copy[entry_low], |
324 | entry_high - entry_low + 1, to, &retsize); | 209 | entry_high - entry_low + 1, to, &retsize); |
@@ -333,8 +218,6 @@ concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | |||
333 | 218 | ||
334 | *retlen += retsize; | 219 | *retlen += retsize; |
335 | total_len -= wsize; | 220 | total_len -= wsize; |
336 | if (concat->mtd.type == MTD_NANDFLASH && eccbuf) | ||
337 | eccbuf += mtd->oobavail * (wsize / mtd->writesize); | ||
338 | 221 | ||
339 | if (total_len == 0) | 222 | if (total_len == 0) |
340 | break; | 223 | break; |
@@ -348,13 +231,6 @@ concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | |||
348 | } | 231 | } |
349 | 232 | ||
350 | static int | 233 | static int |
351 | concat_writev(struct mtd_info *mtd, const struct kvec *vecs, | ||
352 | unsigned long count, loff_t to, size_t * retlen) | ||
353 | { | ||
354 | return concat_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL); | ||
355 | } | ||
356 | |||
357 | static int | ||
358 | concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | 234 | concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len, |
359 | size_t * retlen, u_char * buf) | 235 | size_t * retlen, u_char * buf) |
360 | { | 236 | { |
@@ -837,14 +713,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c | |||
837 | concat->mtd.oobsize = subdev[0]->oobsize; | 713 | concat->mtd.oobsize = subdev[0]->oobsize; |
838 | concat->mtd.ecctype = subdev[0]->ecctype; | 714 | concat->mtd.ecctype = subdev[0]->ecctype; |
839 | concat->mtd.eccsize = subdev[0]->eccsize; | 715 | concat->mtd.eccsize = subdev[0]->eccsize; |
840 | if (subdev[0]->read_ecc) | ||
841 | concat->mtd.read_ecc = concat_read_ecc; | ||
842 | if (subdev[0]->write_ecc) | ||
843 | concat->mtd.write_ecc = concat_write_ecc; | ||
844 | if (subdev[0]->writev) | 716 | if (subdev[0]->writev) |
845 | concat->mtd.writev = concat_writev; | 717 | concat->mtd.writev = concat_writev; |
846 | if (subdev[0]->writev_ecc) | ||
847 | concat->mtd.writev_ecc = concat_writev_ecc; | ||
848 | if (subdev[0]->read_oob) | 718 | if (subdev[0]->read_oob) |
849 | concat->mtd.read_oob = concat_read_oob; | 719 | concat->mtd.read_oob = concat_read_oob; |
850 | if (subdev[0]->write_oob) | 720 | if (subdev[0]->write_oob) |
@@ -885,8 +755,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c | |||
885 | concat->mtd.oobsize != subdev[i]->oobsize || | 755 | concat->mtd.oobsize != subdev[i]->oobsize || |
886 | concat->mtd.ecctype != subdev[i]->ecctype || | 756 | concat->mtd.ecctype != subdev[i]->ecctype || |
887 | concat->mtd.eccsize != subdev[i]->eccsize || | 757 | concat->mtd.eccsize != subdev[i]->eccsize || |
888 | !concat->mtd.read_ecc != !subdev[i]->read_ecc || | ||
889 | !concat->mtd.write_ecc != !subdev[i]->write_ecc || | ||
890 | !concat->mtd.read_oob != !subdev[i]->read_oob || | 758 | !concat->mtd.read_oob != !subdev[i]->read_oob || |
891 | !concat->mtd.write_oob != !subdev[i]->write_oob) { | 759 | !concat->mtd.write_oob != !subdev[i]->write_oob) { |
892 | kfree(concat); | 760 | kfree(concat); |
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 082662f90481..a93550ce7978 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
@@ -55,12 +55,8 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len, | |||
55 | len = 0; | 55 | len = 0; |
56 | else if (from + len > mtd->size) | 56 | else if (from + len > mtd->size) |
57 | len = mtd->size - from; | 57 | len = mtd->size - from; |
58 | if (part->master->read_ecc == NULL) | 58 | return part->master->read (part->master, from + part->offset, |
59 | return part->master->read (part->master, from + part->offset, | 59 | len, retlen, buf); |
60 | len, retlen, buf); | ||
61 | else | ||
62 | return part->master->read_ecc (part->master, from + part->offset, | ||
63 | len, retlen, buf, NULL, &mtd->oobinfo); | ||
64 | } | 60 | } |
65 | 61 | ||
66 | static int part_point (struct mtd_info *mtd, loff_t from, size_t len, | 62 | 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 | return part->master->point (part->master, from + part->offset, | 70 | return part->master->point (part->master, from + part->offset, |
75 | len, retlen, buf); | 71 | len, retlen, buf); |
76 | } | 72 | } |
73 | |||
77 | static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) | 74 | static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) |
78 | { | 75 | { |
79 | struct mtd_part *part = PART(mtd); | 76 | 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 | part->master->unpoint (part->master, addr, from + part->offset, len); | 78 | part->master->unpoint (part->master, addr, from + part->offset, len); |
82 | } | 79 | } |
83 | 80 | ||
84 | |||
85 | static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | ||
86 | size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
87 | { | ||
88 | struct mtd_part *part = PART(mtd); | ||
89 | if (oobsel == NULL) | ||
90 | oobsel = &mtd->oobinfo; | ||
91 | if (from >= mtd->size) | ||
92 | len = 0; | ||
93 | else if (from + len > mtd->size) | ||
94 | len = mtd->size - from; | ||
95 | return part->master->read_ecc (part->master, from + part->offset, | ||
96 | len, retlen, buf, eccbuf, oobsel); | ||
97 | } | ||
98 | |||
99 | static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, | 81 | static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, |
100 | size_t *retlen, u_char *buf) | 82 | size_t *retlen, u_char *buf) |
101 | { | 83 | { |
@@ -148,30 +130,8 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len, | |||
148 | len = 0; | 130 | len = 0; |
149 | else if (to + len > mtd->size) | 131 | else if (to + len > mtd->size) |
150 | len = mtd->size - to; | 132 | len = mtd->size - to; |
151 | if (part->master->write_ecc == NULL) | 133 | return part->master->write (part->master, to + part->offset, |
152 | return part->master->write (part->master, to + part->offset, | 134 | len, retlen, buf); |
153 | len, retlen, buf); | ||
154 | else | ||
155 | return part->master->write_ecc (part->master, to + part->offset, | ||
156 | len, retlen, buf, NULL, &mtd->oobinfo); | ||
157 | |||
158 | } | ||
159 | |||
160 | static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, | ||
161 | size_t *retlen, const u_char *buf, | ||
162 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
163 | { | ||
164 | struct mtd_part *part = PART(mtd); | ||
165 | if (!(mtd->flags & MTD_WRITEABLE)) | ||
166 | return -EROFS; | ||
167 | if (oobsel == NULL) | ||
168 | oobsel = &mtd->oobinfo; | ||
169 | if (to >= mtd->size) | ||
170 | len = 0; | ||
171 | else if (to + len > mtd->size) | ||
172 | len = mtd->size - to; | ||
173 | return part->master->write_ecc (part->master, to + part->offset, | ||
174 | len, retlen, buf, eccbuf, oobsel); | ||
175 | } | 135 | } |
176 | 136 | ||
177 | static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, | 137 | 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 | struct mtd_part *part = PART(mtd); | 168 | struct mtd_part *part = PART(mtd); |
209 | if (!(mtd->flags & MTD_WRITEABLE)) | 169 | if (!(mtd->flags & MTD_WRITEABLE)) |
210 | return -EROFS; | 170 | return -EROFS; |
211 | if (part->master->writev_ecc == NULL) | 171 | return part->master->writev (part->master, vecs, count, |
212 | return part->master->writev (part->master, vecs, count, | ||
213 | to + part->offset, retlen); | 172 | to + part->offset, retlen); |
214 | else | ||
215 | return part->master->writev_ecc (part->master, vecs, count, | ||
216 | to + part->offset, retlen, | ||
217 | NULL, &mtd->oobinfo); | ||
218 | } | ||
219 | |||
220 | static int part_readv (struct mtd_info *mtd, struct kvec *vecs, | ||
221 | unsigned long count, loff_t from, size_t *retlen) | ||
222 | { | ||
223 | struct mtd_part *part = PART(mtd); | ||
224 | if (part->master->readv_ecc == NULL) | ||
225 | return part->master->readv (part->master, vecs, count, | ||
226 | from + part->offset, retlen); | ||
227 | else | ||
228 | return part->master->readv_ecc (part->master, vecs, count, | ||
229 | from + part->offset, retlen, | ||
230 | NULL, &mtd->oobinfo); | ||
231 | } | ||
232 | |||
233 | static int part_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, | ||
234 | unsigned long count, loff_t to, size_t *retlen, | ||
235 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
236 | { | ||
237 | struct mtd_part *part = PART(mtd); | ||
238 | if (!(mtd->flags & MTD_WRITEABLE)) | ||
239 | return -EROFS; | ||
240 | if (oobsel == NULL) | ||
241 | oobsel = &mtd->oobinfo; | ||
242 | return part->master->writev_ecc (part->master, vecs, count, | ||
243 | to + part->offset, retlen, | ||
244 | eccbuf, oobsel); | ||
245 | } | ||
246 | |||
247 | static int part_readv_ecc (struct mtd_info *mtd, struct kvec *vecs, | ||
248 | unsigned long count, loff_t from, size_t *retlen, | ||
249 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
250 | { | ||
251 | struct mtd_part *part = PART(mtd); | ||
252 | if (oobsel == NULL) | ||
253 | oobsel = &mtd->oobinfo; | ||
254 | return part->master->readv_ecc (part->master, vecs, count, | ||
255 | from + part->offset, retlen, | ||
256 | eccbuf, oobsel); | ||
257 | } | 173 | } |
258 | 174 | ||
259 | static int part_erase (struct mtd_info *mtd, struct erase_info *instr) | 175 | 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 | slave->mtd.unpoint = part_unpoint; | 332 | slave->mtd.unpoint = part_unpoint; |
417 | } | 333 | } |
418 | 334 | ||
419 | if (master->read_ecc) | ||
420 | slave->mtd.read_ecc = part_read_ecc; | ||
421 | if (master->write_ecc) | ||
422 | slave->mtd.write_ecc = part_write_ecc; | ||
423 | if (master->read_oob) | 335 | if (master->read_oob) |
424 | slave->mtd.read_oob = part_read_oob; | 336 | slave->mtd.read_oob = part_read_oob; |
425 | if (master->write_oob) | 337 | if (master->write_oob) |
@@ -444,12 +356,6 @@ int add_mtd_partitions(struct mtd_info *master, | |||
444 | } | 356 | } |
445 | if (master->writev) | 357 | if (master->writev) |
446 | slave->mtd.writev = part_writev; | 358 | slave->mtd.writev = part_writev; |
447 | if (master->readv) | ||
448 | slave->mtd.readv = part_readv; | ||
449 | if (master->writev_ecc) | ||
450 | slave->mtd.writev_ecc = part_writev_ecc; | ||
451 | if (master->readv_ecc) | ||
452 | slave->mtd.readv_ecc = part_readv_ecc; | ||
453 | if (master->lock) | 359 | if (master->lock) |
454 | slave->mtd.lock = part_lock; | 360 | slave->mtd.lock = part_lock; |
455 | if (master->unlock) | 361 | if (master->unlock) |
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index c2cb87fc4cb8..f24408d92688 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -65,7 +65,7 @@ config MTD_NAND_AMS_DELTA | |||
65 | 65 | ||
66 | config MTD_NAND_TOTO | 66 | config MTD_NAND_TOTO |
67 | tristate "NAND Flash device on TOTO board" | 67 | tristate "NAND Flash device on TOTO board" |
68 | depends on ARCH_OMAP && MTD_NAND | 68 | depends on ARCH_OMAP && MTD_NAND && BROKEN |
69 | help | 69 | help |
70 | Support for NAND flash on Texas Instruments Toto platform. | 70 | Support for NAND flash on Texas Instruments Toto platform. |
71 | 71 | ||
@@ -96,7 +96,7 @@ config MTD_NAND_RTC_FROM4 | |||
96 | 96 | ||
97 | config MTD_NAND_PPCHAMELEONEVB | 97 | config MTD_NAND_PPCHAMELEONEVB |
98 | tristate "NAND Flash device on PPChameleonEVB board" | 98 | tristate "NAND Flash device on PPChameleonEVB board" |
99 | depends on PPCHAMELEONEVB && MTD_NAND | 99 | depends on PPCHAMELEONEVB && MTD_NAND && BROKEN |
100 | help | 100 | help |
101 | This enables the NAND flash driver on the PPChameleon EVB Board. | 101 | This enables the NAND flash driver on the PPChameleon EVB Board. |
102 | 102 | ||
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index aeaf2dece095..d7897dc6b3c8 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c | |||
@@ -34,13 +34,6 @@ static struct mtd_info *ams_delta_mtd = NULL; | |||
34 | 34 | ||
35 | #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) | 35 | #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) |
36 | 36 | ||
37 | #define T_NAND_CTL_CLRALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, 0) | ||
38 | #define T_NAND_CTL_SETALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, AMS_DELTA_LATCH2_NAND_ALE) | ||
39 | #define T_NAND_CTL_CLRCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, 0) | ||
40 | #define T_NAND_CTL_SETCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, AMS_DELTA_LATCH2_NAND_CLE) | ||
41 | #define T_NAND_CTL_SETNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, 0) | ||
42 | #define T_NAND_CTL_CLRNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, AMS_DELTA_LATCH2_NAND_NCE) | ||
43 | |||
44 | /* | 37 | /* |
45 | * Define partitions for flash devices | 38 | * Define partitions for flash devices |
46 | */ | 39 | */ |
@@ -66,25 +59,6 @@ static struct mtd_partition partition_info[] = { | |||
66 | .size = 3 * SZ_256K }, | 59 | .size = 3 * SZ_256K }, |
67 | }; | 60 | }; |
68 | 61 | ||
69 | /* | ||
70 | * hardware specific access to control-lines | ||
71 | */ | ||
72 | |||
73 | static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd) | ||
74 | { | ||
75 | switch (cmd) { | ||
76 | |||
77 | case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break; | ||
78 | case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break; | ||
79 | |||
80 | case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break; | ||
81 | case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break; | ||
82 | |||
83 | case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break; | ||
84 | case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) | 62 | static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) |
89 | { | 63 | { |
90 | struct nand_chip *this = mtd->priv; | 64 | 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 | return 0; | 115 | return 0; |
142 | } | 116 | } |
143 | 117 | ||
118 | /* | ||
119 | * Command control function | ||
120 | * | ||
121 | * ctrl: | ||
122 | * NAND_NCE: bit 0 -> bit 2 | ||
123 | * NAND_CLE: bit 1 -> bit 7 | ||
124 | * NAND_ALE: bit 2 -> bit 6 | ||
125 | */ | ||
126 | static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd, | ||
127 | unsigned int ctrl) | ||
128 | { | ||
129 | |||
130 | if (ctrl & NAND_CTRL_CHANGE) { | ||
131 | unsigned long bits; | ||
132 | |||
133 | bits = (~ctrl & NAND_NCE) << 2; | ||
134 | bits |= (ctrl & NAND_CLE) << 7; | ||
135 | bits |= (ctrl & NAND_ALE) << 6; | ||
136 | |||
137 | ams_delta_latch2_write(0xC2, bits); | ||
138 | } | ||
139 | |||
140 | if (cmd != NAND_CMD_NONE) | ||
141 | ams_delta_write_byte(mtd, cmd); | ||
142 | } | ||
143 | |||
144 | static int ams_delta_nand_ready(struct mtd_info *mtd) | 144 | static int ams_delta_nand_ready(struct mtd_info *mtd) |
145 | { | 145 | { |
146 | return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB); | 146 | return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB); |
@@ -179,11 +179,10 @@ static int __init ams_delta_init(void) | |||
179 | this->IO_ADDR_R = (OMAP_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH); | 179 | this->IO_ADDR_R = (OMAP_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH); |
180 | this->IO_ADDR_W = (OMAP_MPUIO_BASE + OMAP_MPUIO_OUTPUT); | 180 | this->IO_ADDR_W = (OMAP_MPUIO_BASE + OMAP_MPUIO_OUTPUT); |
181 | this->read_byte = ams_delta_read_byte; | 181 | this->read_byte = ams_delta_read_byte; |
182 | this->write_byte = ams_delta_write_byte; | ||
183 | this->write_buf = ams_delta_write_buf; | 182 | this->write_buf = ams_delta_write_buf; |
184 | this->read_buf = ams_delta_read_buf; | 183 | this->read_buf = ams_delta_read_buf; |
185 | this->verify_buf = ams_delta_verify_buf; | 184 | this->verify_buf = ams_delta_verify_buf; |
186 | this->hwcontrol = ams_delta_hwcontrol; | 185 | this->cmd_ctrl = ams_delta_hwcontrol; |
187 | if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) { | 186 | if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) { |
188 | this->dev_ready = ams_delta_nand_ready; | 187 | this->dev_ready = ams_delta_nand_ready; |
189 | } else { | 188 | } else { |
@@ -200,7 +199,7 @@ static int __init ams_delta_init(void) | |||
200 | AMS_DELTA_LATCH2_NAND_NCE | | 199 | AMS_DELTA_LATCH2_NAND_NCE | |
201 | AMS_DELTA_LATCH2_NAND_NWP); | 200 | AMS_DELTA_LATCH2_NAND_NWP); |
202 | 201 | ||
203 | /* Scan to find existance of the device */ | 202 | /* Scan to find existance of the device */ |
204 | if (nand_scan(ams_delta_mtd, 1)) { | 203 | if (nand_scan(ams_delta_mtd, 1)) { |
205 | err = -ENXIO; | 204 | err = -ENXIO; |
206 | goto out_mtd; | 205 | goto out_mtd; |
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 29dde7dcafa1..31228334da12 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c | |||
@@ -40,6 +40,7 @@ | |||
40 | static struct mtd_info *au1550_mtd = NULL; | 40 | static struct mtd_info *au1550_mtd = NULL; |
41 | static void __iomem *p_nand; | 41 | static void __iomem *p_nand; |
42 | static int nand_width = 1; /* default x8 */ | 42 | static int nand_width = 1; /* default x8 */ |
43 | static void (*au1550_write_byte)(struct mtd_info *, u_char); | ||
43 | 44 | ||
44 | /* | 45 | /* |
45 | * Define partitions for flash device | 46 | * Define partitions for flash device |
@@ -129,21 +130,6 @@ static u16 au_read_word(struct mtd_info *mtd) | |||
129 | } | 130 | } |
130 | 131 | ||
131 | /** | 132 | /** |
132 | * au_write_word - write one word to the chip | ||
133 | * @mtd: MTD device structure | ||
134 | * @word: data word to write | ||
135 | * | ||
136 | * write function for 16bit buswith without | ||
137 | * endianess conversion | ||
138 | */ | ||
139 | static void au_write_word(struct mtd_info *mtd, u16 word) | ||
140 | { | ||
141 | struct nand_chip *this = mtd->priv; | ||
142 | writew(word, this->IO_ADDR_W); | ||
143 | au_sync(); | ||
144 | } | ||
145 | |||
146 | /** | ||
147 | * au_write_buf - write buffer to chip | 133 | * au_write_buf - write buffer to chip |
148 | * @mtd: MTD device structure | 134 | * @mtd: MTD device structure |
149 | * @buf: data buffer | 135 | * @buf: data buffer |
@@ -269,6 +255,18 @@ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) | |||
269 | return 0; | 255 | return 0; |
270 | } | 256 | } |
271 | 257 | ||
258 | /* Select the chip by setting nCE to low */ | ||
259 | #define NAND_CTL_SETNCE 1 | ||
260 | /* Deselect the chip by setting nCE to high */ | ||
261 | #define NAND_CTL_CLRNCE 2 | ||
262 | /* Select the command latch by setting CLE to high */ | ||
263 | #define NAND_CTL_SETCLE 3 | ||
264 | /* Deselect the command latch by setting CLE to low */ | ||
265 | #define NAND_CTL_CLRCLE 4 | ||
266 | /* Select the address latch by setting ALE to high */ | ||
267 | #define NAND_CTL_SETALE 5 | ||
268 | /* Deselect the address latch by setting ALE to low */ | ||
269 | #define NAND_CTL_CLRALE 6 | ||
272 | 270 | ||
273 | static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) | 271 | static void au1550_hwcontrol(struct mtd_info *mtd, int cmd) |
274 | { | 272 | { |
@@ -349,7 +347,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i | |||
349 | ulong flags; | 347 | ulong flags; |
350 | 348 | ||
351 | /* Begin command latch cycle */ | 349 | /* Begin command latch cycle */ |
352 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 350 | au1550_hwcontrol(mtd, NAND_CTL_SETCLE); |
353 | /* | 351 | /* |
354 | * Write out the command to the device. | 352 | * Write out the command to the device. |
355 | */ | 353 | */ |
@@ -367,25 +365,25 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i | |||
367 | column -= 256; | 365 | column -= 256; |
368 | readcmd = NAND_CMD_READ1; | 366 | readcmd = NAND_CMD_READ1; |
369 | } | 367 | } |
370 | this->write_byte(mtd, readcmd); | 368 | au1550_write_byte(mtd, readcmd); |
371 | } | 369 | } |
372 | this->write_byte(mtd, command); | 370 | au1550_write_byte(mtd, command); |
373 | 371 | ||
374 | /* Set ALE and clear CLE to start address cycle */ | 372 | /* Set ALE and clear CLE to start address cycle */ |
375 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | 373 | au1550_hwcontrol(mtd, NAND_CTL_CLRCLE); |
376 | 374 | ||
377 | if (column != -1 || page_addr != -1) { | 375 | if (column != -1 || page_addr != -1) { |
378 | this->hwcontrol(mtd, NAND_CTL_SETALE); | 376 | au1550_hwcontrol(mtd, NAND_CTL_SETALE); |
379 | 377 | ||
380 | /* Serially input address */ | 378 | /* Serially input address */ |
381 | if (column != -1) { | 379 | if (column != -1) { |
382 | /* Adjust columns for 16 bit buswidth */ | 380 | /* Adjust columns for 16 bit buswidth */ |
383 | if (this->options & NAND_BUSWIDTH_16) | 381 | if (this->options & NAND_BUSWIDTH_16) |
384 | column >>= 1; | 382 | column >>= 1; |
385 | this->write_byte(mtd, column); | 383 | au1550_write_byte(mtd, column); |
386 | } | 384 | } |
387 | if (page_addr != -1) { | 385 | if (page_addr != -1) { |
388 | this->write_byte(mtd, (u8)(page_addr & 0xff)); | 386 | au1550_write_byte(mtd, (u8)(page_addr & 0xff)); |
389 | 387 | ||
390 | if (command == NAND_CMD_READ0 || | 388 | if (command == NAND_CMD_READ0 || |
391 | command == NAND_CMD_READ1 || | 389 | command == NAND_CMD_READ1 || |
@@ -400,17 +398,17 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i | |||
400 | */ | 398 | */ |
401 | ce_override = 1; | 399 | ce_override = 1; |
402 | local_irq_save(flags); | 400 | local_irq_save(flags); |
403 | this->hwcontrol(mtd, NAND_CTL_SETNCE); | 401 | au1550_hwcontrol(mtd, NAND_CTL_SETNCE); |
404 | } | 402 | } |
405 | 403 | ||
406 | this->write_byte(mtd, (u8)(page_addr >> 8)); | 404 | au1550_write_byte(mtd, (u8)(page_addr >> 8)); |
407 | 405 | ||
408 | /* One more address cycle for devices > 32MiB */ | 406 | /* One more address cycle for devices > 32MiB */ |
409 | if (this->chipsize > (32 << 20)) | 407 | if (this->chipsize > (32 << 20)) |
410 | this->write_byte(mtd, (u8)((page_addr >> 16) & 0x0f)); | 408 | au1550_write_byte(mtd, (u8)((page_addr >> 16) & 0x0f)); |
411 | } | 409 | } |
412 | /* Latch in address */ | 410 | /* Latch in address */ |
413 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | 411 | au1550_hwcontrol(mtd, NAND_CTL_CLRALE); |
414 | } | 412 | } |
415 | 413 | ||
416 | /* | 414 | /* |
@@ -443,7 +441,7 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i | |||
443 | udelay(1); | 441 | udelay(1); |
444 | 442 | ||
445 | /* Release -CE and re-enable interrupts. */ | 443 | /* Release -CE and re-enable interrupts. */ |
446 | this->hwcontrol(mtd, NAND_CTL_CLRNCE); | 444 | au1550_hwcontrol(mtd, NAND_CTL_CLRNCE); |
447 | local_irq_restore(flags); | 445 | local_irq_restore(flags); |
448 | return; | 446 | return; |
449 | } | 447 | } |
@@ -571,7 +569,6 @@ static int __init au1xxx_nand_init(void) | |||
571 | nand_width = au_readl(MEM_STCFG3) & (1 << 22); | 569 | nand_width = au_readl(MEM_STCFG3) & (1 << 22); |
572 | 570 | ||
573 | /* Set address of hardware control function */ | 571 | /* Set address of hardware control function */ |
574 | this->hwcontrol = au1550_hwcontrol; | ||
575 | this->dev_ready = au1550_device_ready; | 572 | this->dev_ready = au1550_device_ready; |
576 | this->select_chip = au1550_select_chip; | 573 | this->select_chip = au1550_select_chip; |
577 | this->cmdfunc = au1550_command; | 574 | this->cmdfunc = au1550_command; |
@@ -586,8 +583,7 @@ static int __init au1xxx_nand_init(void) | |||
586 | this->options |= NAND_BUSWIDTH_16; | 583 | this->options |= NAND_BUSWIDTH_16; |
587 | 584 | ||
588 | this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte; | 585 | this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte; |
589 | this->write_byte = (!nand_width) ? au_write_byte16 : au_write_byte; | 586 | au1550_write_byte = (!nand_width) ? au_write_byte16 : au_write_byte; |
590 | this->write_word = au_write_word; | ||
591 | this->read_word = au_read_word; | 587 | this->read_word = au_read_word; |
592 | this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf; | 588 | this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf; |
593 | this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf; | 589 | this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf; |
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index dbb1b6267ade..fe94ae9ae1f2 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de> | 4 | * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de> |
5 | * | 5 | * |
6 | * Derived from drivers/mtd/spia.c | 6 | * Derived from drivers/mtd/spia.c |
7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) | 7 | * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) |
8 | * | 8 | * |
9 | * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $ | 9 | * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 gleixner Exp $ |
10 | * | 10 | * |
@@ -42,11 +42,6 @@ | |||
42 | * MTD structure for AUTCPU12 board | 42 | * MTD structure for AUTCPU12 board |
43 | */ | 43 | */ |
44 | static struct mtd_info *autcpu12_mtd = NULL; | 44 | static struct mtd_info *autcpu12_mtd = NULL; |
45 | |||
46 | static int autcpu12_io_base = CS89712_VIRT_BASE; | ||
47 | static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC; | ||
48 | static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET; | ||
49 | static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET; | ||
50 | static void __iomem *autcpu12_fio_base; | 45 | static void __iomem *autcpu12_fio_base; |
51 | 46 | ||
52 | /* | 47 | /* |
@@ -94,31 +89,42 @@ static struct mtd_partition partition_info128k[] = { | |||
94 | #define NUM_PARTITIONS128K 2 | 89 | #define NUM_PARTITIONS128K 2 |
95 | /* | 90 | /* |
96 | * hardware specific access to control-lines | 91 | * hardware specific access to control-lines |
97 | */ | 92 | * |
98 | 93 | * ALE bit 4 autcpu12_pedr | |
99 | static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) | 94 | * CLE bit 5 autcpu12_pedr |
95 | * NCE bit 0 fio_ctrl | ||
96 | * | ||
97 | */ | ||
98 | static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd, | ||
99 | unsigned int ctrl) | ||
100 | { | 100 | { |
101 | switch (cmd) { | 101 | struct nand_chip *chip = mtd->priv; |
102 | 102 | ||
103 | case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_CLE; break; | 103 | if (ctrl & NAND_CTRL_CHANGE) { |
104 | case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break; | 104 | void __iomem *addr |
105 | unsigned char bits; | ||
105 | 106 | ||
106 | case NAND_CTL_SETALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_ALE; break; | 107 | addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET; |
107 | case NAND_CTL_CLRALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_ALE; break; | 108 | bits = (ctrl & NAND_CLE) << 4; |
109 | bits |= (ctrl & NAND_ALE) << 2; | ||
110 | writeb((readb(addr) & ~0x30) | bits, addr); | ||
108 | 111 | ||
109 | case NAND_CTL_SETNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x01; break; | 112 | addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET; |
110 | case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x00; break; | 113 | writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr); |
111 | } | 114 | } |
115 | |||
116 | if (cmd != NAND_CMD_NONE) | ||
117 | writeb(cmd, chip->IO_ADDR_W); | ||
112 | } | 118 | } |
113 | 119 | ||
114 | /* | 120 | /* |
115 | * read device ready pin | 121 | * read device ready pin |
116 | */ | 122 | */ |
117 | int autcpu12_device_ready(struct mtd_info *mtd) | 123 | int autcpu12_device_ready(struct mtd_info *mtd) |
118 | { | 124 | { |
125 | void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET; | ||
119 | 126 | ||
120 | return ((*(volatile unsigned char *)(autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0; | 127 | return readb(addr) & AUTCPU12_SMC_RDY; |
121 | |||
122 | } | 128 | } |
123 | 129 | ||
124 | /* | 130 | /* |
@@ -130,7 +136,8 @@ static int __init autcpu12_init(void) | |||
130 | int err = 0; | 136 | int err = 0; |
131 | 137 | ||
132 | /* Allocate memory for MTD device structure and private data */ | 138 | /* Allocate memory for MTD device structure and private data */ |
133 | autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); | 139 | autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), |
140 | GFP_KERNEL); | ||
134 | if (!autcpu12_mtd) { | 141 | if (!autcpu12_mtd) { |
135 | printk("Unable to allocate AUTCPU12 NAND MTD device structure.\n"); | 142 | printk("Unable to allocate AUTCPU12 NAND MTD device structure.\n"); |
136 | err = -ENOMEM; | 143 | err = -ENOMEM; |
@@ -138,7 +145,7 @@ static int __init autcpu12_init(void) | |||
138 | } | 145 | } |
139 | 146 | ||
140 | /* map physical adress */ | 147 | /* map physical adress */ |
141 | autcpu12_fio_base = ioremap(autcpu12_fio_pbase, SZ_1K); | 148 | autcpu12_fio_base = ioremap(AUTCPU12_PHYS_SMC, SZ_1K); |
142 | if (!autcpu12_fio_base) { | 149 | if (!autcpu12_fio_base) { |
143 | printk("Ioremap autcpu12 SmartMedia Card failed\n"); | 150 | printk("Ioremap autcpu12 SmartMedia Card failed\n"); |
144 | err = -EIO; | 151 | err = -EIO; |
@@ -159,7 +166,7 @@ static int __init autcpu12_init(void) | |||
159 | /* Set address of NAND IO lines */ | 166 | /* Set address of NAND IO lines */ |
160 | this->IO_ADDR_R = autcpu12_fio_base; | 167 | this->IO_ADDR_R = autcpu12_fio_base; |
161 | this->IO_ADDR_W = autcpu12_fio_base; | 168 | this->IO_ADDR_W = autcpu12_fio_base; |
162 | this->hwcontrol = autcpu12_hwcontrol; | 169 | this->cmd_ctrl = autcpu12_hwcontrol; |
163 | this->dev_ready = autcpu12_device_ready; | 170 | this->dev_ready = autcpu12_device_ready; |
164 | /* 20 us command delay time */ | 171 | /* 20 us command delay time */ |
165 | this->chip_delay = 20; | 172 | this->chip_delay = 20; |
@@ -179,10 +186,22 @@ static int __init autcpu12_init(void) | |||
179 | 186 | ||
180 | /* Register the partitions */ | 187 | /* Register the partitions */ |
181 | switch (autcpu12_mtd->size) { | 188 | switch (autcpu12_mtd->size) { |
182 | case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; | 189 | case SZ_16M: |
183 | case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break; | 190 | add_mtd_partitions(autcpu12_mtd, partition_info16k, |
184 | case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; | 191 | NUM_PARTITIONS16K); |
185 | case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; | 192 | break; |
193 | case SZ_32M: | ||
194 | add_mtd_partitions(autcpu12_mtd, partition_info32k, | ||
195 | NUM_PARTITIONS32K); | ||
196 | break; | ||
197 | case SZ_64M: | ||
198 | add_mtd_partitions(autcpu12_mtd, partition_info64k, | ||
199 | NUM_PARTITIONS64K); | ||
200 | break; | ||
201 | case SZ_128M: | ||
202 | add_mtd_partitions(autcpu12_mtd, partition_info128k, | ||
203 | NUM_PARTITIONS128K); | ||
204 | break; | ||
186 | default: | 205 | default: |
187 | printk("Unsupported SmartMedia device\n"); | 206 | printk("Unsupported SmartMedia device\n"); |
188 | err = -ENXIO; | 207 | err = -ENXIO; |
@@ -191,7 +210,7 @@ static int __init autcpu12_init(void) | |||
191 | goto out; | 210 | goto out; |
192 | 211 | ||
193 | out_ior: | 212 | out_ior: |
194 | iounmap((void *)autcpu12_fio_base); | 213 | iounmap(autcpu12_fio_base); |
195 | out_mtd: | 214 | out_mtd: |
196 | kfree(autcpu12_mtd); | 215 | kfree(autcpu12_mtd); |
197 | out: | 216 | out: |
@@ -209,7 +228,7 @@ static void __exit autcpu12_cleanup(void) | |||
209 | nand_release(autcpu12_mtd); | 228 | nand_release(autcpu12_mtd); |
210 | 229 | ||
211 | /* unmap physical adress */ | 230 | /* unmap physical adress */ |
212 | iounmap((void *)autcpu12_fio_base); | 231 | iounmap(autcpu12_fio_base); |
213 | 232 | ||
214 | /* Free the MTD device structure */ | 233 | /* Free the MTD device structure */ |
215 | kfree(autcpu12_mtd); | 234 | kfree(autcpu12_mtd); |
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 064f3feadf53..1e0348ae325f 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c | |||
@@ -131,33 +131,17 @@ static void cs553x_write_byte(struct mtd_info *mtd, u_char byte) | |||
131 | writeb(byte, this->IO_ADDR_W + 0x801); | 131 | writeb(byte, this->IO_ADDR_W + 0x801); |
132 | } | 132 | } |
133 | 133 | ||
134 | static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd) | 134 | static void cs553x_hwcontrol(struct mtd_info *mtd, int cmd, |
135 | unsigned int ctrl) | ||
135 | { | 136 | { |
136 | struct nand_chip *this = mtd->priv; | 137 | struct nand_chip *this = mtd->priv; |
137 | void __iomem *mmio_base = this->IO_ADDR_R; | 138 | void __iomem *mmio_base = this->IO_ADDR_R; |
138 | unsigned char ctl; | 139 | if (ctrl & NAND_CTRL_CHANGE) { |
139 | 140 | unsigned char ctl = (ctrl & ~NAND_CTRL_CHANGE ) ^ 0x01; | |
140 | switch (cmd) { | 141 | writeb(ctl, mmio_base + MM_NAND_CTL); |
141 | case NAND_CTL_SETCLE: | ||
142 | ctl = CS_NAND_CTL_CLE; | ||
143 | break; | ||
144 | |||
145 | case NAND_CTL_CLRCLE: | ||
146 | case NAND_CTL_CLRALE: | ||
147 | case NAND_CTL_SETNCE: | ||
148 | ctl = 0; | ||
149 | break; | ||
150 | |||
151 | case NAND_CTL_SETALE: | ||
152 | ctl = CS_NAND_CTL_ALE; | ||
153 | break; | ||
154 | |||
155 | default: | ||
156 | case NAND_CTL_CLRNCE: | ||
157 | ctl = CS_NAND_CTL_CE; | ||
158 | break; | ||
159 | } | 142 | } |
160 | writeb(ctl, mmio_base + MM_NAND_CTL); | 143 | if (cmd != NAND_CMD_NONE) |
144 | cs553x_write_byte(mtd, cmd); | ||
161 | } | 145 | } |
162 | 146 | ||
163 | static int cs553x_device_ready(struct mtd_info *mtd) | 147 | 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 | goto out_mtd; | 217 | goto out_mtd; |
234 | } | 218 | } |
235 | 219 | ||
236 | this->hwcontrol = cs553x_hwcontrol; | 220 | this->cmd_ctrl = cs553x_hwcontrol; |
237 | this->dev_ready = cs553x_device_ready; | 221 | this->dev_ready = cs553x_device_ready; |
238 | this->read_byte = cs553x_read_byte; | 222 | this->read_byte = cs553x_read_byte; |
239 | this->write_byte = cs553x_write_byte; | ||
240 | this->read_buf = cs553x_read_buf; | 223 | this->read_buf = cs553x_read_buf; |
241 | this->write_buf = cs553x_write_buf; | 224 | this->write_buf = cs553x_write_buf; |
242 | 225 | ||
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index b771608ef84e..2ec9080e2b14 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c | |||
@@ -95,7 +95,8 @@ static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 }; | |||
95 | #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil) | 95 | #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil) |
96 | #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k) | 96 | #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k) |
97 | 97 | ||
98 | static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd); | 98 | static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd, |
99 | unsigned int bitmask); | ||
99 | static void doc200x_select_chip(struct mtd_info *mtd, int chip); | 100 | static void doc200x_select_chip(struct mtd_info *mtd, int chip); |
100 | 101 | ||
101 | static int debug = 0; | 102 | static int debug = 0; |
@@ -402,12 +403,10 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) | |||
402 | uint16_t ret; | 403 | uint16_t ret; |
403 | 404 | ||
404 | doc200x_select_chip(mtd, nr); | 405 | doc200x_select_chip(mtd, nr); |
405 | doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); | 406 | doc200x_hwcontrol(mtd, NAND_CMD_READID, |
406 | this->write_byte(mtd, NAND_CMD_READID); | 407 | NAND_CTRL_CLE | NAND_CTRL_CHANGE); |
407 | doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); | 408 | doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); |
408 | doc200x_hwcontrol(mtd, NAND_CTL_SETALE); | 409 | doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); |
409 | this->write_byte(mtd, 0); | ||
410 | doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); | ||
411 | 410 | ||
412 | /* We cant' use dev_ready here, but at least we wait for the | 411 | /* We cant' use dev_ready here, but at least we wait for the |
413 | * command to complete | 412 | * command to complete |
@@ -425,12 +424,11 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) | |||
425 | } ident; | 424 | } ident; |
426 | void __iomem *docptr = doc->virtadr; | 425 | void __iomem *docptr = doc->virtadr; |
427 | 426 | ||
428 | doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); | 427 | doc200x_hwcontrol(mtd, NAND_CMD_READID, |
429 | doc2000_write_byte(mtd, NAND_CMD_READID); | 428 | NAND_CTRL_CLE | NAND_CTRL_CHANGE); |
430 | doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); | 429 | doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); |
431 | doc200x_hwcontrol(mtd, NAND_CTL_SETALE); | 430 | doc200x_hwcontrol(mtd, NAND_CMD_NONE, |
432 | doc2000_write_byte(mtd, 0); | 431 | NAND_NCE | NAND_CTRL_CHANGE); |
433 | doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); | ||
434 | 432 | ||
435 | udelay(50); | 433 | udelay(50); |
436 | 434 | ||
@@ -690,54 +688,41 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip) | |||
690 | chip -= (floor * doc->chips_per_floor); | 688 | chip -= (floor * doc->chips_per_floor); |
691 | 689 | ||
692 | /* 11.4.4 -- deassert CE before changing chip */ | 690 | /* 11.4.4 -- deassert CE before changing chip */ |
693 | doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE); | 691 | doc200x_hwcontrol(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); |
694 | 692 | ||
695 | WriteDOC(floor, docptr, FloorSelect); | 693 | WriteDOC(floor, docptr, FloorSelect); |
696 | WriteDOC(chip, docptr, CDSNDeviceSelect); | 694 | WriteDOC(chip, docptr, CDSNDeviceSelect); |
697 | 695 | ||
698 | doc200x_hwcontrol(mtd, NAND_CTL_SETNCE); | 696 | doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); |
699 | 697 | ||
700 | doc->curchip = chip; | 698 | doc->curchip = chip; |
701 | doc->curfloor = floor; | 699 | doc->curfloor = floor; |
702 | } | 700 | } |
703 | 701 | ||
704 | static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) | 702 | #define CDSN_CTRL_MSK (CDSN_CTRL_CE | CDSN_CTRL_CLE | CDSN_CTRL_ALE) |
703 | |||
704 | static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd, | ||
705 | unsigned int ctrl) | ||
705 | { | 706 | { |
706 | struct nand_chip *this = mtd->priv; | 707 | struct nand_chip *this = mtd->priv; |
707 | struct doc_priv *doc = this->priv; | 708 | struct doc_priv *doc = this->priv; |
708 | void __iomem *docptr = doc->virtadr; | 709 | void __iomem *docptr = doc->virtadr; |
709 | 710 | ||
710 | switch (cmd) { | 711 | if (ctrl & NAND_CTRL_CHANGE) { |
711 | case NAND_CTL_SETNCE: | 712 | doc->CDSNControl &= ~CDSN_CTRL_MSK; |
712 | doc->CDSNControl |= CDSN_CTRL_CE; | 713 | doc->CDSNControl |= ctrl & CDSN_CTRL_MSK; |
713 | break; | 714 | if (debug) |
714 | case NAND_CTL_CLRNCE: | 715 | printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); |
715 | doc->CDSNControl &= ~CDSN_CTRL_CE; | 716 | WriteDOC(doc->CDSNControl, docptr, CDSNControl); |
716 | break; | 717 | /* 11.4.3 -- 4 NOPs after CSDNControl write */ |
717 | case NAND_CTL_SETCLE: | 718 | DoC_Delay(doc, 4); |
718 | doc->CDSNControl |= CDSN_CTRL_CLE; | 719 | } |
719 | break; | 720 | if (cmd != NAND_CMD_NONE) { |
720 | case NAND_CTL_CLRCLE: | 721 | if (DoC_is_2000(doc)) |
721 | doc->CDSNControl &= ~CDSN_CTRL_CLE; | 722 | doc2000_write_byte(mtd, cmd); |
722 | break; | 723 | else |
723 | case NAND_CTL_SETALE: | 724 | doc2001_write_byte(mtd, cmd); |
724 | doc->CDSNControl |= CDSN_CTRL_ALE; | ||
725 | break; | ||
726 | case NAND_CTL_CLRALE: | ||
727 | doc->CDSNControl &= ~CDSN_CTRL_ALE; | ||
728 | break; | ||
729 | case NAND_CTL_SETWP: | ||
730 | doc->CDSNControl |= CDSN_CTRL_WP; | ||
731 | break; | ||
732 | case NAND_CTL_CLRWP: | ||
733 | doc->CDSNControl &= ~CDSN_CTRL_WP; | ||
734 | break; | ||
735 | } | 725 | } |
736 | if (debug) | ||
737 | printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); | ||
738 | WriteDOC(doc->CDSNControl, docptr, CDSNControl); | ||
739 | /* 11.4.3 -- 4 NOPs after CSDNControl write */ | ||
740 | DoC_Delay(doc, 4); | ||
741 | } | 726 | } |
742 | 727 | ||
743 | static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) | 728 | 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 | struct nand_chip *this = mtd->priv; | 1439 | struct nand_chip *this = mtd->priv; |
1455 | struct doc_priv *doc = this->priv; | 1440 | struct doc_priv *doc = this->priv; |
1456 | 1441 | ||
1457 | this->write_byte = doc2000_write_byte; | ||
1458 | this->read_byte = doc2000_read_byte; | 1442 | this->read_byte = doc2000_read_byte; |
1459 | this->write_buf = doc2000_writebuf; | 1443 | this->write_buf = doc2000_writebuf; |
1460 | this->read_buf = doc2000_readbuf; | 1444 | this->read_buf = doc2000_readbuf; |
@@ -1472,7 +1456,6 @@ static inline int __init doc2001_init(struct mtd_info *mtd) | |||
1472 | struct nand_chip *this = mtd->priv; | 1456 | struct nand_chip *this = mtd->priv; |
1473 | struct doc_priv *doc = this->priv; | 1457 | struct doc_priv *doc = this->priv; |
1474 | 1458 | ||
1475 | this->write_byte = doc2001_write_byte; | ||
1476 | this->read_byte = doc2001_read_byte; | 1459 | this->read_byte = doc2001_read_byte; |
1477 | this->write_buf = doc2001_writebuf; | 1460 | this->write_buf = doc2001_writebuf; |
1478 | this->read_buf = doc2001_readbuf; | 1461 | this->read_buf = doc2001_readbuf; |
@@ -1504,16 +1487,15 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd) | |||
1504 | struct nand_chip *this = mtd->priv; | 1487 | struct nand_chip *this = mtd->priv; |
1505 | struct doc_priv *doc = this->priv; | 1488 | struct doc_priv *doc = this->priv; |
1506 | 1489 | ||
1507 | this->write_byte = NULL; | ||
1508 | this->read_byte = doc2001plus_read_byte; | 1490 | this->read_byte = doc2001plus_read_byte; |
1509 | this->write_buf = doc2001plus_writebuf; | 1491 | this->write_buf = doc2001plus_writebuf; |
1510 | this->read_buf = doc2001plus_readbuf; | 1492 | this->read_buf = doc2001plus_readbuf; |
1511 | this->verify_buf = doc2001plus_verifybuf; | 1493 | this->verify_buf = doc2001plus_verifybuf; |
1512 | this->scan_bbt = inftl_scan_bbt; | 1494 | this->scan_bbt = inftl_scan_bbt; |
1513 | this->hwcontrol = NULL; | 1495 | this->cmd_ctrl = NULL; |
1514 | this->select_chip = doc2001plus_select_chip; | 1496 | this->select_chip = doc2001plus_select_chip; |
1515 | this->cmdfunc = doc2001plus_command; | 1497 | this->cmdfunc = doc2001plus_command; |
1516 | this->enable_hwecc = doc2001plus_enable_hwecc; | 1498 | this->ecc.hwctl = doc2001plus_enable_hwecc; |
1517 | 1499 | ||
1518 | doc->chips_per_floor = 1; | 1500 | doc->chips_per_floor = 1; |
1519 | mtd->name = "DiskOnChip Millennium Plus"; | 1501 | mtd->name = "DiskOnChip Millennium Plus"; |
@@ -1670,7 +1652,7 @@ static int __init doc_probe(unsigned long physadr) | |||
1670 | 1652 | ||
1671 | nand->priv = doc; | 1653 | nand->priv = doc; |
1672 | nand->select_chip = doc200x_select_chip; | 1654 | nand->select_chip = doc200x_select_chip; |
1673 | nand->hwcontrol = doc200x_hwcontrol; | 1655 | nand->cmd_ctrl = doc200x_hwcontrol; |
1674 | nand->dev_ready = doc200x_dev_ready; | 1656 | nand->dev_ready = doc200x_dev_ready; |
1675 | nand->waitfunc = doc200x_wait; | 1657 | nand->waitfunc = doc200x_wait; |
1676 | nand->block_bad = doc200x_block_bad; | 1658 | nand->block_bad = doc200x_block_bad; |
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c index 8e56570af91f..ba5a2174a408 100644 --- a/drivers/mtd/nand/edb7312.c +++ b/drivers/mtd/nand/edb7312.c | |||
@@ -73,32 +73,26 @@ static struct mtd_partition partition_info[] = { | |||
73 | 73 | ||
74 | /* | 74 | /* |
75 | * hardware specific access to control-lines | 75 | * hardware specific access to control-lines |
76 | * | ||
77 | * NAND_NCE: bit 0 -> bit 7 | ||
78 | * NAND_CLE: bit 1 -> bit 4 | ||
79 | * NAND_ALE: bit 2 -> bit 5 | ||
76 | */ | 80 | */ |
77 | static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) | 81 | static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
78 | { | 82 | { |
79 | switch (cmd) { | 83 | struct nand_chip *chip = mtd->priv; |
80 | 84 | ||
81 | case NAND_CTL_SETCLE: | 85 | if (ctrl & NAND_CTRL_CHANGE) { |
82 | clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); | 86 | unsigned char bits; |
83 | break; | 87 | |
84 | case NAND_CTL_CLRCLE: | 88 | bits = (ctrl & (NAND_CLE | NAND_ALE)) << 3; |
85 | clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr); | 89 | bits = (ctrl & NAND_NCE) << 7; |
86 | break; | 90 | |
87 | 91 | clps_writeb((clps_readb(ep7312_pxdr) & 0xB0) | 0x10, | |
88 | case NAND_CTL_SETALE: | 92 | ep7312_pxdr); |
89 | clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr); | ||
90 | break; | ||
91 | case NAND_CTL_CLRALE: | ||
92 | clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr); | ||
93 | break; | ||
94 | |||
95 | case NAND_CTL_SETNCE: | ||
96 | clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr); | ||
97 | break; | ||
98 | case NAND_CTL_CLRNCE: | ||
99 | clps_writeb((clps_readb(ep7312_pxdr) | 0x80) | 0x40, ep7312_pxdr); | ||
100 | break; | ||
101 | } | 93 | } |
94 | if (cmd != NAND_CMD_NONE) | ||
95 | writeb(cmd, chip->IO_ADDR_W); | ||
102 | } | 96 | } |
103 | 97 | ||
104 | /* | 98 | /* |
@@ -159,7 +153,7 @@ static int __init ep7312_init(void) | |||
159 | /* insert callbacks */ | 153 | /* insert callbacks */ |
160 | this->IO_ADDR_R = ep7312_fio_base; | 154 | this->IO_ADDR_R = ep7312_fio_base; |
161 | this->IO_ADDR_W = ep7312_fio_base; | 155 | this->IO_ADDR_W = ep7312_fio_base; |
162 | this->hwcontrol = ep7312_hwcontrol; | 156 | this->cmd_ctrl = ep7312_hwcontrol; |
163 | this->dev_ready = ep7312_device_ready; | 157 | this->dev_ready = ep7312_device_ready; |
164 | /* 15 us command delay time */ | 158 | /* 15 us command delay time */ |
165 | this->chip_delay = 15; | 159 | this->chip_delay = 15; |
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 06e91fa11b34..2d585d2d090c 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c | |||
@@ -56,36 +56,18 @@ static struct mtd_partition partition_info[] = { | |||
56 | 56 | ||
57 | /* | 57 | /* |
58 | * hardware specific access to control-lines | 58 | * hardware specific access to control-lines |
59 | * | ||
60 | * NAND_NCE: bit 0 - don't care | ||
61 | * NAND_CLE: bit 1 - address bit 2 | ||
62 | * NAND_ALE: bit 2 - address bit 3 | ||
59 | */ | 63 | */ |
60 | static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) | 64 | static void h1910_hwcontrol(struct mtd_info *mtd, int cmd, |
65 | unsigned int ctrl) | ||
61 | { | 66 | { |
62 | struct nand_chip *this = (struct nand_chip *)(mtd->priv); | 67 | struct nand_chip *chip = mtd->priv; |
63 | 68 | ||
64 | switch (cmd) { | 69 | if (cmd != NAND_CMD_NONE) |
65 | 70 | writeb(cmd, chip->IO_ADDR_W | ((ctrl & 0x6) << 1)); | |
66 | case NAND_CTL_SETCLE: | ||
67 | this->IO_ADDR_R |= (1 << 2); | ||
68 | this->IO_ADDR_W |= (1 << 2); | ||
69 | break; | ||
70 | case NAND_CTL_CLRCLE: | ||
71 | this->IO_ADDR_R &= ~(1 << 2); | ||
72 | this->IO_ADDR_W &= ~(1 << 2); | ||
73 | break; | ||
74 | |||
75 | case NAND_CTL_SETALE: | ||
76 | this->IO_ADDR_R |= (1 << 3); | ||
77 | this->IO_ADDR_W |= (1 << 3); | ||
78 | break; | ||
79 | case NAND_CTL_CLRALE: | ||
80 | this->IO_ADDR_R &= ~(1 << 3); | ||
81 | this->IO_ADDR_W &= ~(1 << 3); | ||
82 | break; | ||
83 | |||
84 | case NAND_CTL_SETNCE: | ||
85 | break; | ||
86 | case NAND_CTL_CLRNCE: | ||
87 | break; | ||
88 | } | ||
89 | } | 71 | } |
90 | 72 | ||
91 | /* | 73 | /* |
@@ -145,7 +127,7 @@ static int __init h1910_init(void) | |||
145 | /* insert callbacks */ | 127 | /* insert callbacks */ |
146 | this->IO_ADDR_R = nandaddr; | 128 | this->IO_ADDR_R = nandaddr; |
147 | this->IO_ADDR_W = nandaddr; | 129 | this->IO_ADDR_W = nandaddr; |
148 | this->hwcontrol = h1910_hwcontrol; | 130 | this->cmd_ctrl = h1910_hwcontrol; |
149 | this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */ | 131 | this->dev_ready = NULL; /* unknown whether that was correct or not so we will just do it like this */ |
150 | /* 15 us command delay time */ | 132 | /* 15 us command delay time */ |
151 | this->chip_delay = 50; | 133 | this->chip_delay = 50; |
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 778535006c83..649c238837bb 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -139,23 +139,12 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len); | |||
139 | 139 | ||
140 | static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, | 140 | static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, |
141 | size_t *retlen, uint8_t *buf); | 141 | size_t *retlen, uint8_t *buf); |
142 | static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | ||
143 | size_t *retlen, uint8_t *buf, uint8_t *eccbuf, | ||
144 | struct nand_oobinfo *oobsel); | ||
145 | static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | 142 | static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, |
146 | size_t *retlen, uint8_t *buf); | 143 | size_t *retlen, uint8_t *buf); |
147 | static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, | 144 | static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, |
148 | size_t *retlen, const uint8_t *buf); | 145 | size_t *retlen, const uint8_t *buf); |
149 | static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | ||
150 | size_t *retlen, const uint8_t *buf, uint8_t *eccbuf, | ||
151 | struct nand_oobinfo *oobsel); | ||
152 | static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | 146 | static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, |
153 | size_t *retlen, const uint8_t *buf); | 147 | size_t *retlen, const uint8_t *buf); |
154 | static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, | ||
155 | unsigned long count, loff_t to, size_t *retlen); | ||
156 | static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | ||
157 | unsigned long count, loff_t to, size_t *retlen, | ||
158 | uint8_t *eccbuf, struct nand_oobinfo *oobsel); | ||
159 | static int nand_erase(struct mtd_info *mtd, struct erase_info *instr); | 148 | static int nand_erase(struct mtd_info *mtd, struct erase_info *instr); |
160 | static void nand_sync(struct mtd_info *mtd); | 149 | static void nand_sync(struct mtd_info *mtd); |
161 | 150 | ||
@@ -175,6 +164,12 @@ static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *this, | |||
175 | static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, | 164 | static int nand_get_device(struct nand_chip *this, struct mtd_info *mtd, |
176 | int new_state); | 165 | int new_state); |
177 | 166 | ||
167 | /* | ||
168 | * For devices which display every fart in the system on a seperate LED. Is | ||
169 | * compiled away when LED support is disabled. | ||
170 | */ | ||
171 | DEFINE_LED_TRIGGER(nand_led_trigger); | ||
172 | |||
178 | /** | 173 | /** |
179 | * nand_release_device - [GENERIC] release chip | 174 | * nand_release_device - [GENERIC] release chip |
180 | * @mtd: MTD device structure | 175 | * @mtd: MTD device structure |
@@ -209,19 +204,6 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) | |||
209 | } | 204 | } |
210 | 205 | ||
211 | /** | 206 | /** |
212 | * nand_write_byte - [DEFAULT] write one byte to the chip | ||
213 | * @mtd: MTD device structure | ||
214 | * @byte: pointer to data byte to write | ||
215 | * | ||
216 | * Default write function for 8it buswith | ||
217 | */ | ||
218 | static void nand_write_byte(struct mtd_info *mtd, uint8_t byte) | ||
219 | { | ||
220 | struct nand_chip *this = mtd->priv; | ||
221 | writeb(byte, this->IO_ADDR_W); | ||
222 | } | ||
223 | |||
224 | /** | ||
225 | * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip | 207 | * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip |
226 | * @mtd: MTD device structure | 208 | * @mtd: MTD device structure |
227 | * | 209 | * |
@@ -235,20 +217,6 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd) | |||
235 | } | 217 | } |
236 | 218 | ||
237 | /** | 219 | /** |
238 | * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip | ||
239 | * @mtd: MTD device structure | ||
240 | * @byte: pointer to data byte to write | ||
241 | * | ||
242 | * Default write function for 16bit buswith with | ||
243 | * endianess conversion | ||
244 | */ | ||
245 | static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte) | ||
246 | { | ||
247 | struct nand_chip *this = mtd->priv; | ||
248 | writew(le16_to_cpu((u16) byte), this->IO_ADDR_W); | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * nand_read_word - [DEFAULT] read one word from the chip | 220 | * nand_read_word - [DEFAULT] read one word from the chip |
253 | * @mtd: MTD device structure | 221 | * @mtd: MTD device structure |
254 | * | 222 | * |
@@ -262,20 +230,6 @@ static u16 nand_read_word(struct mtd_info *mtd) | |||
262 | } | 230 | } |
263 | 231 | ||
264 | /** | 232 | /** |
265 | * nand_write_word - [DEFAULT] write one word to the chip | ||
266 | * @mtd: MTD device structure | ||
267 | * @word: data word to write | ||
268 | * | ||
269 | * Default write function for 16bit buswith without | ||
270 | * endianess conversion | ||
271 | */ | ||
272 | static void nand_write_word(struct mtd_info *mtd, u16 word) | ||
273 | { | ||
274 | struct nand_chip *this = mtd->priv; | ||
275 | writew(word, this->IO_ADDR_W); | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * nand_select_chip - [DEFAULT] control CE line | 233 | * nand_select_chip - [DEFAULT] control CE line |
280 | * @mtd: MTD device structure | 234 | * @mtd: MTD device structure |
281 | * @chip: chipnumber to select, -1 for deselect | 235 | * @chip: chipnumber to select, -1 for deselect |
@@ -287,10 +241,10 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) | |||
287 | struct nand_chip *this = mtd->priv; | 241 | struct nand_chip *this = mtd->priv; |
288 | switch (chip) { | 242 | switch (chip) { |
289 | case -1: | 243 | case -1: |
290 | this->hwcontrol(mtd, NAND_CTL_CLRNCE); | 244 | this->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); |
291 | break; | 245 | break; |
292 | case 0: | 246 | case 0: |
293 | this->hwcontrol(mtd, NAND_CTL_SETNCE); | 247 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); |
294 | break; | 248 | break; |
295 | 249 | ||
296 | default: | 250 | default: |
@@ -528,8 +482,6 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, | |||
528 | return nand_isbad_bbt(mtd, ofs, allowbbt); | 482 | return nand_isbad_bbt(mtd, ofs, allowbbt); |
529 | } | 483 | } |
530 | 484 | ||
531 | DEFINE_LED_TRIGGER(nand_led_trigger); | ||
532 | |||
533 | /* | 485 | /* |
534 | * Wait for the ready pin, after a command | 486 | * Wait for the ready pin, after a command |
535 | * The timeout is catched later. | 487 | * The timeout is catched later. |
@@ -559,13 +511,12 @@ static void nand_wait_ready(struct mtd_info *mtd) | |||
559 | * Send command to NAND device. This function is used for small page | 511 | * Send command to NAND device. This function is used for small page |
560 | * devices (256/512 Bytes per page) | 512 | * devices (256/512 Bytes per page) |
561 | */ | 513 | */ |
562 | static void nand_command(struct mtd_info *mtd, unsigned command, int column, | 514 | static void nand_command(struct mtd_info *mtd, unsigned int command, |
563 | int page_addr) | 515 | int column, int page_addr) |
564 | { | 516 | { |
565 | register struct nand_chip *this = mtd->priv; | 517 | register struct nand_chip *this = mtd->priv; |
518 | int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; | ||
566 | 519 | ||
567 | /* Begin command latch cycle */ | ||
568 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | ||
569 | /* | 520 | /* |
570 | * Write out the command to the device. | 521 | * Write out the command to the device. |
571 | */ | 522 | */ |
@@ -583,33 +534,32 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, | |||
583 | column -= 256; | 534 | column -= 256; |
584 | readcmd = NAND_CMD_READ1; | 535 | readcmd = NAND_CMD_READ1; |
585 | } | 536 | } |
586 | this->write_byte(mtd, readcmd); | 537 | this->cmd_ctrl(mtd, readcmd, ctrl); |
538 | ctrl &= ~NAND_CTRL_CHANGE; | ||
587 | } | 539 | } |
588 | this->write_byte(mtd, command); | 540 | this->cmd_ctrl(mtd, command, ctrl); |
589 | |||
590 | /* Set ALE and clear CLE to start address cycle */ | ||
591 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
592 | |||
593 | if (column != -1 || page_addr != -1) { | ||
594 | this->hwcontrol(mtd, NAND_CTL_SETALE); | ||
595 | 541 | ||
596 | /* Serially input address */ | 542 | /* |
597 | if (column != -1) { | 543 | * Address cycle, when necessary |
598 | /* Adjust columns for 16 bit buswidth */ | 544 | */ |
599 | if (this->options & NAND_BUSWIDTH_16) | 545 | ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; |
600 | column >>= 1; | 546 | /* Serially input address */ |
601 | this->write_byte(mtd, column); | 547 | if (column != -1) { |
602 | } | 548 | /* Adjust columns for 16 bit buswidth */ |
603 | if (page_addr != -1) { | 549 | if (this->options & NAND_BUSWIDTH_16) |
604 | this->write_byte(mtd, (uint8_t)(page_addr & 0xff)); | 550 | column >>= 1; |
605 | this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff)); | 551 | this->cmd_ctrl(mtd, column, ctrl); |
606 | /* One more address cycle for devices > 32MiB */ | 552 | ctrl &= ~NAND_CTRL_CHANGE; |
607 | if (this->chipsize > (32 << 20)) | 553 | } |
608 | this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0x0f)); | 554 | if (page_addr != -1) { |
609 | } | 555 | this->cmd_ctrl(mtd, page_addr, ctrl); |
610 | /* Latch in address */ | 556 | ctrl &= ~NAND_CTRL_CHANGE; |
611 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | 557 | this->cmd_ctrl(mtd, page_addr >> 8, ctrl); |
558 | /* One more address cycle for devices > 32MiB */ | ||
559 | if (this->chipsize > (32 << 20)) | ||
560 | this->cmd_ctrl(mtd, page_addr >> 16, ctrl); | ||
612 | } | 561 | } |
562 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); | ||
613 | 563 | ||
614 | /* | 564 | /* |
615 | * program and erase have their own busy handlers | 565 | * 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 | case NAND_CMD_ERASE2: | 572 | case NAND_CMD_ERASE2: |
623 | case NAND_CMD_SEQIN: | 573 | case NAND_CMD_SEQIN: |
624 | case NAND_CMD_STATUS: | 574 | case NAND_CMD_STATUS: |
575 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); | ||
625 | return; | 576 | return; |
626 | 577 | ||
627 | case NAND_CMD_RESET: | 578 | case NAND_CMD_RESET: |
628 | if (this->dev_ready) | 579 | if (this->dev_ready) |
629 | break; | 580 | break; |
630 | udelay(this->chip_delay); | 581 | udelay(this->chip_delay); |
631 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 582 | this->cmd_ctrl(mtd, NAND_CMD_STATUS, |
632 | this->write_byte(mtd, NAND_CMD_STATUS); | 583 | NAND_CTRL_CLE | NAND_CTRL_CHANGE); |
633 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | 584 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); |
634 | while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; | 585 | while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; |
635 | return; | 586 | return; |
636 | 587 | ||
@@ -659,12 +610,13 @@ static void nand_command(struct mtd_info *mtd, unsigned command, int column, | |||
659 | * @column: the column address for this command, -1 if none | 610 | * @column: the column address for this command, -1 if none |
660 | * @page_addr: the page address for this command, -1 if none | 611 | * @page_addr: the page address for this command, -1 if none |
661 | * | 612 | * |
662 | * Send command to NAND device. This is the version for the new large page devices | 613 | * Send command to NAND device. This is the version for the new large page |
663 | * We dont have the separate regions as we have in the small page devices. | 614 | * devices We dont have the separate regions as we have in the small page |
664 | * We must emulate NAND_CMD_READOOB to keep the code compatible. | 615 | * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. |
665 | * | 616 | * |
666 | */ | 617 | */ |
667 | static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr) | 618 | static void nand_command_lp(struct mtd_info *mtd, unsigned int command, |
619 | int column, int page_addr) | ||
668 | { | 620 | { |
669 | register struct nand_chip *this = mtd->priv; | 621 | register struct nand_chip *this = mtd->priv; |
670 | 622 | ||
@@ -674,34 +626,33 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned command, int column, | |||
674 | command = NAND_CMD_READ0; | 626 | command = NAND_CMD_READ0; |
675 | } | 627 | } |
676 | 628 | ||
677 | /* Begin command latch cycle */ | 629 | /* Command latch cycle */ |
678 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 630 | this->cmd_ctrl(mtd, command & 0xff, |
679 | /* Write out the command to the device. */ | 631 | NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); |
680 | this->write_byte(mtd, (command & 0xff)); | ||
681 | /* End command latch cycle */ | ||
682 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
683 | 632 | ||
684 | if (column != -1 || page_addr != -1) { | 633 | if (column != -1 || page_addr != -1) { |
685 | this->hwcontrol(mtd, NAND_CTL_SETALE); | 634 | int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; |
686 | 635 | ||
687 | /* Serially input address */ | 636 | /* Serially input address */ |
688 | if (column != -1) { | 637 | if (column != -1) { |
689 | /* Adjust columns for 16 bit buswidth */ | 638 | /* Adjust columns for 16 bit buswidth */ |
690 | if (this->options & NAND_BUSWIDTH_16) | 639 | if (this->options & NAND_BUSWIDTH_16) |
691 | column >>= 1; | 640 | column >>= 1; |
692 | this->write_byte(mtd, column & 0xff); | 641 | this->cmd_ctrl(mtd, column, ctrl); |
693 | this->write_byte(mtd, column >> 8); | 642 | ctrl &= ~NAND_CTRL_CHANGE; |
643 | this->cmd_ctrl(mtd, column >> 8, ctrl); | ||
694 | } | 644 | } |
695 | if (page_addr != -1) { | 645 | if (page_addr != -1) { |
696 | this->write_byte(mtd, (uint8_t)(page_addr & 0xff)); | 646 | this->cmd_ctrl(mtd, page_addr, ctrl); |
697 | this->write_byte(mtd, (uint8_t)((page_addr >> 8) & 0xff)); | 647 | this->cmd_ctrl(mtd, page_addr >> 8, |
648 | NAND_NCE | NAND_ALE); | ||
698 | /* One more address cycle for devices > 128MiB */ | 649 | /* One more address cycle for devices > 128MiB */ |
699 | if (this->chipsize > (128 << 20)) | 650 | if (this->chipsize > (128 << 20)) |
700 | this->write_byte(mtd, (uint8_t)((page_addr >> 16) & 0xff)); | 651 | this->cmd_ctrl(mtd, page_addr >> 16, |
652 | NAND_NCE | NAND_ALE); | ||
701 | } | 653 | } |
702 | /* Latch in address */ | ||
703 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | ||
704 | } | 654 | } |
655 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); | ||
705 | 656 | ||
706 | /* | 657 | /* |
707 | * program and erase have their own busy handlers | 658 | * 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 | if (this->dev_ready) | 684 | if (this->dev_ready) |
734 | break; | 685 | break; |
735 | udelay(this->chip_delay); | 686 | udelay(this->chip_delay); |
736 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 687 | this->cmd_ctrl(mtd, NAND_CMD_STATUS, NAND_NCE | NAND_CLE); |
737 | this->write_byte(mtd, NAND_CMD_STATUS); | 688 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); |
738 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
739 | while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; | 689 | while (!(this->read_byte(mtd) & NAND_STATUS_READY)) ; |
740 | return; | 690 | return; |
741 | 691 | ||
742 | case NAND_CMD_READ0: | 692 | case NAND_CMD_READ0: |
743 | /* Begin command latch cycle */ | 693 | this->cmd_ctrl(mtd, NAND_CMD_READSTART, NAND_NCE | NAND_CLE); |
744 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | 694 | this->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); |
745 | /* Write out the start read command */ | ||
746 | this->write_byte(mtd, NAND_CMD_READSTART); | ||
747 | /* End command latch cycle */ | ||
748 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
749 | /* Fall through into ready check */ | ||
750 | 695 | ||
751 | /* This applies to read commands */ | 696 | /* This applies to read commands */ |
752 | default: | 697 | default: |
@@ -1085,27 +1030,6 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retl | |||
1085 | } | 1030 | } |
1086 | 1031 | ||
1087 | /** | 1032 | /** |
1088 | * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc | ||
1089 | * @mtd: MTD device structure | ||
1090 | * @from: offset to read from | ||
1091 | * @len: number of bytes to read | ||
1092 | * @retlen: pointer to variable to store the number of read bytes | ||
1093 | * @buf: the databuffer to put data | ||
1094 | * @oob_buf: filesystem supplied oob data buffer | ||
1095 | * @oobsel: oob selection structure | ||
1096 | * | ||
1097 | * This function simply calls nand_do_read_ecc with flags = 0xff | ||
1098 | */ | ||
1099 | static int nand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | ||
1100 | size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel) | ||
1101 | { | ||
1102 | /* use userspace supplied oobinfo, if zero */ | ||
1103 | if (oobsel == NULL) | ||
1104 | oobsel = &mtd->oobinfo; | ||
1105 | return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff); | ||
1106 | } | ||
1107 | |||
1108 | /** | ||
1109 | * nand_do_read_ecc - [MTD Interface] Read data with ECC | 1033 | * nand_do_read_ecc - [MTD Interface] Read data with ECC |
1110 | * @mtd: MTD device structure | 1034 | * @mtd: MTD device structure |
1111 | * @from: offset to read from | 1035 | * @from: offset to read from |
@@ -1529,6 +1453,56 @@ int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, s | |||
1529 | } | 1453 | } |
1530 | 1454 | ||
1531 | /** | 1455 | /** |
1456 | * nand_write_raw - [GENERIC] Write raw data including oob | ||
1457 | * @mtd: MTD device structure | ||
1458 | * @buf: source buffer | ||
1459 | * @to: offset to write to | ||
1460 | * @len: number of bytes to write | ||
1461 | * @buf: source buffer | ||
1462 | * @oob: oob buffer | ||
1463 | * | ||
1464 | * Write raw data including oob | ||
1465 | */ | ||
1466 | int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, | ||
1467 | uint8_t *buf, uint8_t *oob) | ||
1468 | { | ||
1469 | struct nand_chip *this = mtd->priv; | ||
1470 | int page = (int)(to >> this->page_shift); | ||
1471 | int chip = (int)(to >> this->chip_shift); | ||
1472 | int ret; | ||
1473 | |||
1474 | *retlen = 0; | ||
1475 | |||
1476 | /* Do not allow writes past end of device */ | ||
1477 | if ((to + len) > mtd->size) { | ||
1478 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write " | ||
1479 | "beyond end of device\n"); | ||
1480 | return -EINVAL; | ||
1481 | } | ||
1482 | |||
1483 | /* Grab the lock and see if the device is available */ | ||
1484 | nand_get_device(this, mtd, FL_WRITING); | ||
1485 | |||
1486 | this->select_chip(mtd, chip); | ||
1487 | this->data_poi = buf; | ||
1488 | |||
1489 | while (len != *retlen) { | ||
1490 | ret = nand_write_page(mtd, this, page, oob, &mtd->oobinfo, 0); | ||
1491 | if (ret) | ||
1492 | return ret; | ||
1493 | page++; | ||
1494 | *retlen += mtd->writesize; | ||
1495 | this->data_poi += mtd->writesize; | ||
1496 | oob += mtd->oobsize; | ||
1497 | } | ||
1498 | |||
1499 | /* Deselect and wake up anyone waiting on the device */ | ||
1500 | nand_release_device(mtd); | ||
1501 | return 0; | ||
1502 | } | ||
1503 | EXPORT_SYMBOL_GPL(nand_write_raw); | ||
1504 | |||
1505 | /** | ||
1532 | * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer | 1506 | * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer |
1533 | * @mtd: MTD device structure | 1507 | * @mtd: MTD device structure |
1534 | * @fsbuf: buffer given by fs driver | 1508 | * @fsbuf: buffer given by fs driver |
@@ -1590,57 +1564,39 @@ static uint8_t *nand_prepare_oobbuf(struct mtd_info *mtd, uint8_t *fsbuf, struct | |||
1590 | #define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0 | 1564 | #define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0 |
1591 | 1565 | ||
1592 | /** | 1566 | /** |
1593 | * nand_write - [MTD Interface] compability function for nand_write_ecc | 1567 | * nand_write - [MTD Interface] NAND write with ECC |
1594 | * @mtd: MTD device structure | 1568 | * @mtd: MTD device structure |
1595 | * @to: offset to write to | 1569 | * @to: offset to write to |
1596 | * @len: number of bytes to write | 1570 | * @len: number of bytes to write |
1597 | * @retlen: pointer to variable to store the number of written bytes | 1571 | * @retlen: pointer to variable to store the number of written bytes |
1598 | * @buf: the data to write | 1572 | * @buf: the data to write |
1599 | * | 1573 | * |
1600 | * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL | ||
1601 | * | ||
1602 | */ | ||
1603 | static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) | ||
1604 | { | ||
1605 | return (nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL)); | ||
1606 | } | ||
1607 | |||
1608 | /** | ||
1609 | * nand_write_ecc - [MTD Interface] NAND write with ECC | ||
1610 | * @mtd: MTD device structure | ||
1611 | * @to: offset to write to | ||
1612 | * @len: number of bytes to write | ||
1613 | * @retlen: pointer to variable to store the number of written bytes | ||
1614 | * @buf: the data to write | ||
1615 | * @eccbuf: filesystem supplied oob data buffer | ||
1616 | * @oobsel: oob selection structure | ||
1617 | * | ||
1618 | * NAND write with ECC | 1574 | * NAND write with ECC |
1619 | */ | 1575 | */ |
1620 | static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | 1576 | static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, |
1621 | size_t *retlen, const uint8_t *buf, uint8_t *eccbuf, | 1577 | size_t *retlen, const uint8_t *buf) |
1622 | struct nand_oobinfo *oobsel) | ||
1623 | { | 1578 | { |
1624 | int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr; | 1579 | int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr; |
1625 | int autoplace = 0, numpages, totalpages; | 1580 | int autoplace = 0, numpages, totalpages; |
1626 | struct nand_chip *this = mtd->priv; | 1581 | struct nand_chip *this = mtd->priv; |
1627 | uint8_t *oobbuf, *bufstart; | 1582 | uint8_t *oobbuf, *bufstart, *eccbuf = NULL; |
1628 | int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); | 1583 | int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); |
1584 | struct nand_oobinfo *oobsel = &mtd->oobinfo; | ||
1629 | 1585 | ||
1630 | DEBUG(MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); | 1586 | DEBUG(MTD_DEBUG_LEVEL3, "nand_write: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); |
1631 | 1587 | ||
1632 | /* Initialize retlen, in case of early exit */ | 1588 | /* Initialize retlen, in case of early exit */ |
1633 | *retlen = 0; | 1589 | *retlen = 0; |
1634 | 1590 | ||
1635 | /* Do not allow write past end of device */ | 1591 | /* Do not allow write past end of device */ |
1636 | if ((to + len) > mtd->size) { | 1592 | if ((to + len) > mtd->size) { |
1637 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); | 1593 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write: Attempt to write past end of page\n"); |
1638 | return -EINVAL; | 1594 | return -EINVAL; |
1639 | } | 1595 | } |
1640 | 1596 | ||
1641 | /* reject writes, which are not page aligned */ | 1597 | /* reject writes, which are not page aligned */ |
1642 | if (NOTALIGNED(to) || NOTALIGNED(len)) { | 1598 | if (NOTALIGNED(to) || NOTALIGNED(len)) { |
1643 | printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); | 1599 | printk(KERN_NOTICE "nand_write: Attempt to write not page aligned data\n"); |
1644 | return -EINVAL; | 1600 | return -EINVAL; |
1645 | } | 1601 | } |
1646 | 1602 | ||
@@ -1656,10 +1612,6 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
1656 | if (nand_check_wp(mtd)) | 1612 | if (nand_check_wp(mtd)) |
1657 | goto out; | 1613 | goto out; |
1658 | 1614 | ||
1659 | /* if oobsel is NULL, use chip defaults */ | ||
1660 | if (oobsel == NULL) | ||
1661 | oobsel = &mtd->oobinfo; | ||
1662 | |||
1663 | /* Autoplace of oob data ? Use the default placement scheme */ | 1615 | /* Autoplace of oob data ? Use the default placement scheme */ |
1664 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { | 1616 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { |
1665 | oobsel = this->autooob; | 1617 | oobsel = this->autooob; |
@@ -1694,7 +1646,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
1694 | */ | 1646 | */ |
1695 | ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0)); | 1647 | ret = nand_write_page(mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0)); |
1696 | if (ret) { | 1648 | if (ret) { |
1697 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); | 1649 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write: write_page failed %d\n", ret); |
1698 | goto out; | 1650 | goto out; |
1699 | } | 1651 | } |
1700 | /* Next oob page */ | 1652 | /* Next oob page */ |
@@ -1717,7 +1669,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
1717 | ret = nand_verify_pages(mtd, this, startpage, page - startpage, | 1669 | ret = nand_verify_pages(mtd, this, startpage, page - startpage, |
1718 | oobbuf, oobsel, chipnr, (eccbuf != NULL)); | 1670 | oobbuf, oobsel, chipnr, (eccbuf != NULL)); |
1719 | if (ret) { | 1671 | if (ret) { |
1720 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); | 1672 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret); |
1721 | goto out; | 1673 | goto out; |
1722 | } | 1674 | } |
1723 | *retlen = written; | 1675 | *retlen = written; |
@@ -1746,7 +1698,7 @@ static int nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
1746 | if (!ret) | 1698 | if (!ret) |
1747 | *retlen = written; | 1699 | *retlen = written; |
1748 | else | 1700 | else |
1749 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); | 1701 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write: verify_pages failed %d\n", ret); |
1750 | 1702 | ||
1751 | out: | 1703 | out: |
1752 | /* Deselect and wake up anyone waiting on the device */ | 1704 | /* Deselect and wake up anyone waiting on the device */ |
@@ -1857,187 +1809,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t *r | |||
1857 | } | 1809 | } |
1858 | 1810 | ||
1859 | /** | 1811 | /** |
1860 | * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc | ||
1861 | * @mtd: MTD device structure | ||
1862 | * @vecs: the iovectors to write | ||
1863 | * @count: number of vectors | ||
1864 | * @to: offset to write to | ||
1865 | * @retlen: pointer to variable to store the number of written bytes | ||
1866 | * | ||
1867 | * NAND write with kvec. This just calls the ecc function | ||
1868 | */ | ||
1869 | static int nand_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, | ||
1870 | loff_t to, size_t *retlen) | ||
1871 | { | ||
1872 | return (nand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL)); | ||
1873 | } | ||
1874 | |||
1875 | /** | ||
1876 | * nand_writev_ecc - [MTD Interface] write with iovec with ecc | ||
1877 | * @mtd: MTD device structure | ||
1878 | * @vecs: the iovectors to write | ||
1879 | * @count: number of vectors | ||
1880 | * @to: offset to write to | ||
1881 | * @retlen: pointer to variable to store the number of written bytes | ||
1882 | * @eccbuf: filesystem supplied oob data buffer | ||
1883 | * @oobsel: oob selection structure | ||
1884 | * | ||
1885 | * NAND write with iovec with ecc | ||
1886 | */ | ||
1887 | static int nand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, | ||
1888 | loff_t to, size_t *retlen, uint8_t *eccbuf, struct nand_oobinfo *oobsel) | ||
1889 | { | ||
1890 | int i, page, len, total_len, ret = -EIO, written = 0, chipnr; | ||
1891 | int oob, numpages, autoplace = 0, startpage; | ||
1892 | struct nand_chip *this = mtd->priv; | ||
1893 | int ppblock = (1 << (this->phys_erase_shift - this->page_shift)); | ||
1894 | uint8_t *oobbuf, *bufstart; | ||
1895 | |||
1896 | /* Preset written len for early exit */ | ||
1897 | *retlen = 0; | ||
1898 | |||
1899 | /* Calculate total length of data */ | ||
1900 | total_len = 0; | ||
1901 | for (i = 0; i < count; i++) | ||
1902 | total_len += (int)vecs[i].iov_len; | ||
1903 | |||
1904 | DEBUG(MTD_DEBUG_LEVEL3, "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int)to, (unsigned int)total_len, count); | ||
1905 | |||
1906 | /* Do not allow write past end of page */ | ||
1907 | if ((to + total_len) > mtd->size) { | ||
1908 | DEBUG(MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n"); | ||
1909 | return -EINVAL; | ||
1910 | } | ||
1911 | |||
1912 | /* reject writes, which are not page aligned */ | ||
1913 | if (NOTALIGNED(to) || NOTALIGNED(total_len)) { | ||
1914 | printk(KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); | ||
1915 | return -EINVAL; | ||
1916 | } | ||
1917 | |||
1918 | /* Grab the lock and see if the device is available */ | ||
1919 | nand_get_device(this, mtd, FL_WRITING); | ||
1920 | |||
1921 | /* Get the current chip-nr */ | ||
1922 | chipnr = (int)(to >> this->chip_shift); | ||
1923 | /* Select the NAND device */ | ||
1924 | this->select_chip(mtd, chipnr); | ||
1925 | |||
1926 | /* Check, if it is write protected */ | ||
1927 | if (nand_check_wp(mtd)) | ||
1928 | goto out; | ||
1929 | |||
1930 | /* if oobsel is NULL, use chip defaults */ | ||
1931 | if (oobsel == NULL) | ||
1932 | oobsel = &mtd->oobinfo; | ||
1933 | |||
1934 | /* Autoplace of oob data ? Use the default placement scheme */ | ||
1935 | if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { | ||
1936 | oobsel = this->autooob; | ||
1937 | autoplace = 1; | ||
1938 | } | ||
1939 | if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) | ||
1940 | autoplace = 1; | ||
1941 | |||
1942 | /* Setup start page */ | ||
1943 | page = (int)(to >> this->page_shift); | ||
1944 | /* Invalidate the page cache, if we write to the cached page */ | ||
1945 | if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) | ||
1946 | this->pagebuf = -1; | ||
1947 | |||
1948 | startpage = page & this->pagemask; | ||
1949 | |||
1950 | /* Loop until all kvec' data has been written */ | ||
1951 | len = 0; | ||
1952 | while (count) { | ||
1953 | /* If the given tuple is >= pagesize then | ||
1954 | * write it out from the iov | ||
1955 | */ | ||
1956 | if ((vecs->iov_len - len) >= mtd->writesize) { | ||
1957 | /* Calc number of pages we can write | ||
1958 | * out of this iov in one go */ | ||
1959 | numpages = (vecs->iov_len - len) >> this->page_shift; | ||
1960 | /* Do not cross block boundaries */ | ||
1961 | numpages = min(ppblock - (startpage & (ppblock - 1)), numpages); | ||
1962 | oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages); | ||
1963 | bufstart = (uint8_t *) vecs->iov_base; | ||
1964 | bufstart += len; | ||
1965 | this->data_poi = bufstart; | ||
1966 | oob = 0; | ||
1967 | for (i = 1; i <= numpages; i++) { | ||
1968 | /* Write one page. If this is the last page to write | ||
1969 | * then use the real pageprogram command, else select | ||
1970 | * cached programming if supported by the chip. | ||
1971 | */ | ||
1972 | ret = nand_write_page(mtd, this, page & this->pagemask, | ||
1973 | &oobbuf[oob], oobsel, i != numpages); | ||
1974 | if (ret) | ||
1975 | goto out; | ||
1976 | this->data_poi += mtd->writesize; | ||
1977 | len += mtd->writesize; | ||
1978 | oob += mtd->oobsize; | ||
1979 | page++; | ||
1980 | } | ||
1981 | /* Check, if we have to switch to the next tuple */ | ||
1982 | if (len >= (int)vecs->iov_len) { | ||
1983 | vecs++; | ||
1984 | len = 0; | ||
1985 | count--; | ||
1986 | } | ||
1987 | } else { | ||
1988 | /* We must use the internal buffer, read data out of each | ||
1989 | * tuple until we have a full page to write | ||
1990 | */ | ||
1991 | int cnt = 0; | ||
1992 | while (cnt < mtd->writesize) { | ||
1993 | if (vecs->iov_base != NULL && vecs->iov_len) | ||
1994 | this->data_buf[cnt++] = ((uint8_t *) vecs->iov_base)[len++]; | ||
1995 | /* Check, if we have to switch to the next tuple */ | ||
1996 | if (len >= (int)vecs->iov_len) { | ||
1997 | vecs++; | ||
1998 | len = 0; | ||
1999 | count--; | ||
2000 | } | ||
2001 | } | ||
2002 | this->pagebuf = page; | ||
2003 | this->data_poi = this->data_buf; | ||
2004 | bufstart = this->data_poi; | ||
2005 | numpages = 1; | ||
2006 | oobbuf = nand_prepare_oobbuf(mtd, NULL, oobsel, autoplace, numpages); | ||
2007 | ret = nand_write_page(mtd, this, page & this->pagemask, oobbuf, oobsel, 0); | ||
2008 | if (ret) | ||
2009 | goto out; | ||
2010 | page++; | ||
2011 | } | ||
2012 | |||
2013 | this->data_poi = bufstart; | ||
2014 | ret = nand_verify_pages(mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); | ||
2015 | if (ret) | ||
2016 | goto out; | ||
2017 | |||
2018 | written += mtd->writesize * numpages; | ||
2019 | /* All done ? */ | ||
2020 | if (!count) | ||
2021 | break; | ||
2022 | |||
2023 | startpage = page & this->pagemask; | ||
2024 | /* Check, if we cross a chip boundary */ | ||
2025 | if (!startpage) { | ||
2026 | chipnr++; | ||
2027 | this->select_chip(mtd, -1); | ||
2028 | this->select_chip(mtd, chipnr); | ||
2029 | } | ||
2030 | } | ||
2031 | ret = 0; | ||
2032 | out: | ||
2033 | /* Deselect and wake up anyone waiting on the device */ | ||
2034 | nand_release_device(mtd); | ||
2035 | |||
2036 | *retlen = written; | ||
2037 | return ret; | ||
2038 | } | ||
2039 | |||
2040 | /** | ||
2041 | * single_erease_cmd - [GENERIC] NAND standard block erase command function | 1812 | * single_erease_cmd - [GENERIC] NAND standard block erase command function |
2042 | * @mtd: MTD device structure | 1813 | * @mtd: MTD device structure |
2043 | * @page: the page address of the block which will be erased | 1814 | * @page: the page address of the block which will be erased |
@@ -2392,12 +2163,8 @@ static void nand_set_defaults(struct nand_chip *this, int busw) | |||
2392 | 2163 | ||
2393 | if (!this->select_chip) | 2164 | if (!this->select_chip) |
2394 | this->select_chip = nand_select_chip; | 2165 | this->select_chip = nand_select_chip; |
2395 | if (!this->write_byte) | ||
2396 | this->write_byte = busw ? nand_write_byte16 : nand_write_byte; | ||
2397 | if (!this->read_byte) | 2166 | if (!this->read_byte) |
2398 | this->read_byte = busw ? nand_read_byte16 : nand_read_byte; | 2167 | this->read_byte = busw ? nand_read_byte16 : nand_read_byte; |
2399 | if (!this->write_word) | ||
2400 | this->write_word = nand_write_word; | ||
2401 | if (!this->read_word) | 2168 | if (!this->read_word) |
2402 | this->read_word = nand_read_word; | 2169 | this->read_word = nand_read_word; |
2403 | if (!this->block_bad) | 2170 | if (!this->block_bad) |
@@ -2713,13 +2480,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips) | |||
2713 | mtd->unpoint = NULL; | 2480 | mtd->unpoint = NULL; |
2714 | mtd->read = nand_read; | 2481 | mtd->read = nand_read; |
2715 | mtd->write = nand_write; | 2482 | mtd->write = nand_write; |
2716 | mtd->read_ecc = nand_read_ecc; | ||
2717 | mtd->write_ecc = nand_write_ecc; | ||
2718 | mtd->read_oob = nand_read_oob; | 2483 | mtd->read_oob = nand_read_oob; |
2719 | mtd->write_oob = nand_write_oob; | 2484 | mtd->write_oob = nand_write_oob; |
2720 | mtd->readv = NULL; | ||
2721 | mtd->writev = nand_writev; | ||
2722 | mtd->writev_ecc = nand_writev_ecc; | ||
2723 | mtd->sync = nand_sync; | 2485 | mtd->sync = nand_sync; |
2724 | mtd->lock = NULL; | 2486 | mtd->lock = NULL; |
2725 | mtd->unlock = NULL; | 2487 | mtd->unlock = NULL; |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index fbccb2a25186..ecaaca18d1e0 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -156,7 +156,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
156 | 156 | ||
157 | while (totlen) { | 157 | while (totlen) { |
158 | len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); | 158 | len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); |
159 | res = mtd->read_ecc(mtd, from, len, &retlen, buf, NULL, this->autooob); | 159 | res = mtd->read(mtd, from, len, &retlen, buf); |
160 | if (res < 0) { | 160 | if (res < 0) { |
161 | if (retlen != len) { | 161 | if (retlen != len) { |
162 | printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); | 162 | 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 | * | 471 | * |
472 | */ | 472 | */ |
473 | static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | 473 | static int write_bbt(struct mtd_info *mtd, uint8_t *buf, |
474 | struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) | 474 | struct nand_bbt_descr *td, struct nand_bbt_descr *md, |
475 | int chipsel) | ||
475 | { | 476 | { |
476 | struct nand_chip *this = mtd->priv; | 477 | struct nand_chip *this = mtd->priv; |
477 | struct nand_oobinfo oobinfo; | ||
478 | struct erase_info einfo; | 478 | struct erase_info einfo; |
479 | int i, j, res, chip = 0; | 479 | int i, j, res, chip = 0; |
480 | int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; | 480 | int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; |
481 | int nrchips, bbtoffs, pageoffs; | 481 | int nrchips, bbtoffs, pageoffs, ooboffs; |
482 | uint8_t msk[4]; | 482 | uint8_t msk[4]; |
483 | uint8_t rcode = td->reserved_block_code; | 483 | uint8_t rcode = td->reserved_block_code; |
484 | size_t retlen, len = 0; | 484 | size_t retlen, len = 0, ooblen; |
485 | loff_t to; | 485 | loff_t to; |
486 | 486 | ||
487 | if (!rcode) | 487 | if (!rcode) |
@@ -526,12 +526,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
526 | for (i = 0; i < td->maxblocks; i++) { | 526 | for (i = 0; i < td->maxblocks; i++) { |
527 | int block = startblock + dir * i; | 527 | int block = startblock + dir * i; |
528 | /* Check, if the block is bad */ | 528 | /* Check, if the block is bad */ |
529 | switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) { | 529 | switch ((this->bbt[block >> 2] >> |
530 | (2 * (block & 0x03))) & 0x03) { | ||
530 | case 0x01: | 531 | case 0x01: |
531 | case 0x03: | 532 | case 0x03: |
532 | continue; | 533 | continue; |
533 | } | 534 | } |
534 | page = block << (this->bbt_erase_shift - this->page_shift); | 535 | page = block << |
536 | (this->bbt_erase_shift - this->page_shift); | ||
535 | /* Check, if the block is used by the mirror table */ | 537 | /* Check, if the block is used by the mirror table */ |
536 | if (!md || md->pages[chip] != page) | 538 | if (!md || md->pages[chip] != page) |
537 | goto write; | 539 | goto write; |
@@ -542,11 +544,20 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
542 | 544 | ||
543 | /* Set up shift count and masks for the flash table */ | 545 | /* Set up shift count and masks for the flash table */ |
544 | bits = td->options & NAND_BBT_NRBITS_MSK; | 546 | bits = td->options & NAND_BBT_NRBITS_MSK; |
547 | msk[2] = ~rcode; | ||
545 | switch (bits) { | 548 | switch (bits) { |
546 | case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break; | 549 | case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; |
547 | case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break; | 550 | msk[3] = 0x01; |
548 | case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break; | 551 | break; |
549 | case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break; | 552 | case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; |
553 | msk[3] = 0x03; | ||
554 | break; | ||
555 | case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; | ||
556 | msk[3] = 0x0f; | ||
557 | break; | ||
558 | case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; | ||
559 | msk[3] = 0xff; | ||
560 | break; | ||
550 | default: return -EINVAL; | 561 | default: return -EINVAL; |
551 | } | 562 | } |
552 | 563 | ||
@@ -554,49 +565,55 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
554 | 565 | ||
555 | to = ((loff_t) page) << this->page_shift; | 566 | to = ((loff_t) page) << this->page_shift; |
556 | 567 | ||
557 | memcpy(&oobinfo, this->autooob, sizeof(oobinfo)); | ||
558 | oobinfo.useecc = MTD_NANDECC_PLACEONLY; | ||
559 | |||
560 | /* Must we save the block contents ? */ | 568 | /* Must we save the block contents ? */ |
561 | if (td->options & NAND_BBT_SAVECONTENT) { | 569 | if (td->options & NAND_BBT_SAVECONTENT) { |
562 | /* Make it block aligned */ | 570 | /* Make it block aligned */ |
563 | to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); | 571 | to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); |
564 | len = 1 << this->bbt_erase_shift; | 572 | len = 1 << this->bbt_erase_shift; |
565 | res = mtd->read_ecc(mtd, to, len, &retlen, buf, &buf[len], &oobinfo); | 573 | res = mtd->read(mtd, to, len, &retlen, buf); |
566 | if (res < 0) { | 574 | if (res < 0) { |
567 | if (retlen != len) { | 575 | if (retlen != len) { |
568 | printk(KERN_INFO | 576 | printk(KERN_INFO "nand_bbt: Error " |
569 | "nand_bbt: Error reading block for writing the bad block table\n"); | 577 | "reading block for writing " |
578 | "the bad block table\n"); | ||
570 | return res; | 579 | return res; |
571 | } | 580 | } |
572 | printk(KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n"); | 581 | printk(KERN_WARNING "nand_bbt: ECC error " |
582 | "while reading block for writing " | ||
583 | "bad block table\n"); | ||
573 | } | 584 | } |
585 | /* Read oob data */ | ||
586 | ooblen = (len >> this->page_shift) * mtd->oobsize; | ||
587 | res = mtd->read_oob(mtd, to + mtd->writesize, ooblen, | ||
588 | &retlen, &buf[len]); | ||
589 | if (res < 0 || retlen != ooblen) | ||
590 | goto outerr; | ||
591 | |||
574 | /* Calc the byte offset in the buffer */ | 592 | /* Calc the byte offset in the buffer */ |
575 | pageoffs = page - (int)(to >> this->page_shift); | 593 | pageoffs = page - (int)(to >> this->page_shift); |
576 | offs = pageoffs << this->page_shift; | 594 | offs = pageoffs << this->page_shift; |
577 | /* Preset the bbt area with 0xff */ | 595 | /* Preset the bbt area with 0xff */ |
578 | memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); | 596 | memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); |
579 | /* Preset the bbt's oob area with 0xff */ | 597 | ooboffs = len + (pageoffs * mtd->oobsize); |
580 | memset(&buf[len + pageoffs * mtd->oobsize], 0xff, | 598 | |
581 | ((len >> this->page_shift) - pageoffs) * mtd->oobsize); | ||
582 | if (td->options & NAND_BBT_VERSION) { | ||
583 | buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip]; | ||
584 | } | ||
585 | } else { | 599 | } else { |
586 | /* Calc length */ | 600 | /* Calc length */ |
587 | len = (size_t) (numblocks >> sft); | 601 | len = (size_t) (numblocks >> sft); |
588 | /* Make it page aligned ! */ | 602 | /* Make it page aligned ! */ |
589 | len = (len + (mtd->writesize - 1)) & ~(mtd->writesize - 1); | 603 | len = (len + (mtd->writesize - 1)) & |
604 | ~(mtd->writesize - 1); | ||
590 | /* Preset the buffer with 0xff */ | 605 | /* Preset the buffer with 0xff */ |
591 | memset(buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize); | 606 | memset(buf, 0xff, len + |
607 | (len >> this->page_shift)* mtd->oobsize); | ||
592 | offs = 0; | 608 | offs = 0; |
609 | ooboffs = len; | ||
593 | /* Pattern is located in oob area of first page */ | 610 | /* Pattern is located in oob area of first page */ |
594 | memcpy(&buf[len + td->offs], td->pattern, td->len); | 611 | memcpy(&buf[ooboffs + td->offs], td->pattern, td->len); |
595 | if (td->options & NAND_BBT_VERSION) { | ||
596 | buf[len + td->veroffs] = td->version[chip]; | ||
597 | } | ||
598 | } | 612 | } |
599 | 613 | ||
614 | if (td->options & NAND_BBT_VERSION) | ||
615 | buf[ooboffs + td->veroffs] = td->version[chip]; | ||
616 | |||
600 | /* walk through the memory table */ | 617 | /* walk through the memory table */ |
601 | for (i = 0; i < numblocks;) { | 618 | for (i = 0; i < numblocks;) { |
602 | uint8_t dat; | 619 | uint8_t dat; |
@@ -604,7 +621,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
604 | for (j = 0; j < 4; j++, i++) { | 621 | for (j = 0; j < 4; j++, i++) { |
605 | int sftcnt = (i << (3 - sft)) & sftmsk; | 622 | int sftcnt = (i << (3 - sft)) & sftmsk; |
606 | /* Do not store the reserved bbt blocks ! */ | 623 | /* Do not store the reserved bbt blocks ! */ |
607 | buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); | 624 | buf[offs + (i >> sft)] &= |
625 | ~(msk[dat & 0x03] << sftcnt); | ||
608 | dat >>= 2; | 626 | dat >>= 2; |
609 | } | 627 | } |
610 | } | 628 | } |
@@ -614,23 +632,25 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
614 | einfo.addr = (unsigned long)to; | 632 | einfo.addr = (unsigned long)to; |
615 | einfo.len = 1 << this->bbt_erase_shift; | 633 | einfo.len = 1 << this->bbt_erase_shift; |
616 | res = nand_erase_nand(mtd, &einfo, 1); | 634 | res = nand_erase_nand(mtd, &einfo, 1); |
617 | if (res < 0) { | 635 | if (res < 0) |
618 | printk(KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); | 636 | goto outerr; |
619 | return res; | ||
620 | } | ||
621 | 637 | ||
622 | res = mtd->write_ecc(mtd, to, len, &retlen, buf, &buf[len], &oobinfo); | 638 | res = nand_write_raw(mtd, to, len, &retlen, buf, &buf[len]); |
623 | if (res < 0) { | 639 | if (res < 0) |
624 | printk(KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); | 640 | goto outerr; |
625 | return res; | 641 | |
626 | } | 642 | printk(KERN_DEBUG "Bad block table written to 0x%08x, version " |
627 | printk(KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", | 643 | "0x%02X\n", (unsigned int)to, td->version[chip]); |
628 | (unsigned int)to, td->version[chip]); | ||
629 | 644 | ||
630 | /* Mark it as used */ | 645 | /* Mark it as used */ |
631 | td->pages[chip] = page; | 646 | td->pages[chip] = page; |
632 | } | 647 | } |
633 | return 0; | 648 | return 0; |
649 | |||
650 | outerr: | ||
651 | printk(KERN_WARNING | ||
652 | "nand_bbt: Error while writing bad block table %d\n", res); | ||
653 | return res; | ||
634 | } | 654 | } |
635 | 655 | ||
636 | /** | 656 | /** |
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 22af9b29d2bf..ebd64abc8be8 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -1071,68 +1071,6 @@ switch_state(struct nandsim *ns) | |||
1071 | } | 1071 | } |
1072 | } | 1072 | } |
1073 | 1073 | ||
1074 | static void | ||
1075 | ns_hwcontrol(struct mtd_info *mtd, int cmd) | ||
1076 | { | ||
1077 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; | ||
1078 | |||
1079 | switch (cmd) { | ||
1080 | |||
1081 | /* set CLE line high */ | ||
1082 | case NAND_CTL_SETCLE: | ||
1083 | NS_DBG("ns_hwcontrol: start command latch cycles\n"); | ||
1084 | ns->lines.cle = 1; | ||
1085 | break; | ||
1086 | |||
1087 | /* set CLE line low */ | ||
1088 | case NAND_CTL_CLRCLE: | ||
1089 | NS_DBG("ns_hwcontrol: stop command latch cycles\n"); | ||
1090 | ns->lines.cle = 0; | ||
1091 | break; | ||
1092 | |||
1093 | /* set ALE line high */ | ||
1094 | case NAND_CTL_SETALE: | ||
1095 | NS_DBG("ns_hwcontrol: start address latch cycles\n"); | ||
1096 | ns->lines.ale = 1; | ||
1097 | break; | ||
1098 | |||
1099 | /* set ALE line low */ | ||
1100 | case NAND_CTL_CLRALE: | ||
1101 | NS_DBG("ns_hwcontrol: stop address latch cycles\n"); | ||
1102 | ns->lines.ale = 0; | ||
1103 | break; | ||
1104 | |||
1105 | /* set WP line high */ | ||
1106 | case NAND_CTL_SETWP: | ||
1107 | NS_DBG("ns_hwcontrol: enable write protection\n"); | ||
1108 | ns->lines.wp = 1; | ||
1109 | break; | ||
1110 | |||
1111 | /* set WP line low */ | ||
1112 | case NAND_CTL_CLRWP: | ||
1113 | NS_DBG("ns_hwcontrol: disable write protection\n"); | ||
1114 | ns->lines.wp = 0; | ||
1115 | break; | ||
1116 | |||
1117 | /* set CE line low */ | ||
1118 | case NAND_CTL_SETNCE: | ||
1119 | NS_DBG("ns_hwcontrol: enable chip\n"); | ||
1120 | ns->lines.ce = 1; | ||
1121 | break; | ||
1122 | |||
1123 | /* set CE line high */ | ||
1124 | case NAND_CTL_CLRNCE: | ||
1125 | NS_DBG("ns_hwcontrol: disable chip\n"); | ||
1126 | ns->lines.ce = 0; | ||
1127 | break; | ||
1128 | |||
1129 | default: | ||
1130 | NS_ERR("hwcontrol: unknown command\n"); | ||
1131 | } | ||
1132 | |||
1133 | return; | ||
1134 | } | ||
1135 | |||
1136 | static u_char | 1074 | static u_char |
1137 | ns_nand_read_byte(struct mtd_info *mtd) | 1075 | ns_nand_read_byte(struct mtd_info *mtd) |
1138 | { | 1076 | { |
@@ -1359,6 +1297,18 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte) | |||
1359 | return; | 1297 | return; |
1360 | } | 1298 | } |
1361 | 1299 | ||
1300 | static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask) | ||
1301 | { | ||
1302 | struct nandsim *ns = ((struct nand_chip *)mtd->priv)->priv; | ||
1303 | |||
1304 | ns->lines.cle = bitmask & NAND_CLE ? 1 : 0; | ||
1305 | ns->lines.ale = bitmask & NAND_ALE ? 1 : 0; | ||
1306 | ns->lines.ce = bitmask & NAND_NCE ? 1 : 0; | ||
1307 | |||
1308 | if (cmd != NAND_CMD_NONE) | ||
1309 | ns_nand_write_byte(mtd, cmd); | ||
1310 | } | ||
1311 | |||
1362 | static int | 1312 | static int |
1363 | ns_device_ready(struct mtd_info *mtd) | 1313 | ns_device_ready(struct mtd_info *mtd) |
1364 | { | 1314 | { |
@@ -1377,17 +1327,6 @@ ns_nand_read_word(struct mtd_info *mtd) | |||
1377 | } | 1327 | } |
1378 | 1328 | ||
1379 | static void | 1329 | static void |
1380 | ns_nand_write_word(struct mtd_info *mtd, uint16_t word) | ||
1381 | { | ||
1382 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | ||
1383 | |||
1384 | NS_DBG("write_word\n"); | ||
1385 | |||
1386 | chip->write_byte(mtd, word & 0xFF); | ||
1387 | chip->write_byte(mtd, word >> 8); | ||
1388 | } | ||
1389 | |||
1390 | static void | ||
1391 | ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | 1330 | ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) |
1392 | { | 1331 | { |
1393 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; | 1332 | struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; |
@@ -1514,14 +1453,12 @@ static int __init ns_init_module(void) | |||
1514 | /* | 1453 | /* |
1515 | * Register simulator's callbacks. | 1454 | * Register simulator's callbacks. |
1516 | */ | 1455 | */ |
1517 | chip->hwcontrol = ns_hwcontrol; | 1456 | chip->cmd_ctrl = ns_hwcontrol; |
1518 | chip->read_byte = ns_nand_read_byte; | 1457 | chip->read_byte = ns_nand_read_byte; |
1519 | chip->dev_ready = ns_device_ready; | 1458 | chip->dev_ready = ns_device_ready; |
1520 | chip->write_byte = ns_nand_write_byte; | ||
1521 | chip->write_buf = ns_nand_write_buf; | 1459 | chip->write_buf = ns_nand_write_buf; |
1522 | chip->read_buf = ns_nand_read_buf; | 1460 | chip->read_buf = ns_nand_read_buf; |
1523 | chip->verify_buf = ns_nand_verify_buf; | 1461 | chip->verify_buf = ns_nand_verify_buf; |
1524 | chip->write_word = ns_nand_write_word; | ||
1525 | chip->read_word = ns_nand_read_word; | 1462 | chip->read_word = ns_nand_read_word; |
1526 | chip->ecc.mode = NAND_ECC_SOFT; | 1463 | chip->ecc.mode = NAND_ECC_SOFT; |
1527 | chip->options |= NAND_SKIP_BBTSCAN; | 1464 | chip->options |= NAND_SKIP_BBTSCAN; |
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index e2dc81de106a..481541a683ca 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c | |||
@@ -60,22 +60,17 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) | |||
60 | writel(ccr, ndfc->ndfcbase + NDFC_CCR); | 60 | writel(ccr, ndfc->ndfcbase + NDFC_CCR); |
61 | } | 61 | } |
62 | 62 | ||
63 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd) | 63 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
64 | { | 64 | { |
65 | struct ndfc_controller *ndfc = &ndfc_ctrl; | ||
66 | struct nand_chip *chip = mtd->priv; | 65 | struct nand_chip *chip = mtd->priv; |
67 | 66 | ||
68 | switch (cmd) { | 67 | if (cmd == NAND_CMD_NONE) |
69 | case NAND_CTL_SETCLE: | 68 | return; |
70 | chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_CMD; | 69 | |
71 | break; | 70 | if (ctrl & NAND_CLE) |
72 | case NAND_CTL_SETALE: | 71 | writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD); |
73 | chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_ALE; | 72 | else |
74 | break; | 73 | writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE); |
75 | default: | ||
76 | chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; | ||
77 | break; | ||
78 | } | ||
79 | } | 74 | } |
80 | 75 | ||
81 | static int ndfc_ready(struct mtd_info *mtd) | 76 | static int ndfc_ready(struct mtd_info *mtd) |
@@ -158,7 +153,7 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) | |||
158 | 153 | ||
159 | chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; | 154 | chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; |
160 | chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; | 155 | chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; |
161 | chip->hwcontrol = ndfc_hwcontrol; | 156 | chip->cmd_ctrl = ndfc_hwcontrol; |
162 | chip->dev_ready = ndfc_ready; | 157 | chip->dev_ready = ndfc_ready; |
163 | chip->select_chip = ndfc_select_chip; | 158 | chip->select_chip = ndfc_select_chip; |
164 | chip->chip_delay = 50; | 159 | chip->chip_delay = 50; |
diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 9fab0998524d..22fa65c12ab9 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c | |||
@@ -108,54 +108,68 @@ extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio | |||
108 | /* | 108 | /* |
109 | * hardware specific access to control-lines | 109 | * hardware specific access to control-lines |
110 | */ | 110 | */ |
111 | static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd) | 111 | static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd, |
112 | unsigned int ctrl) | ||
112 | { | 113 | { |
113 | switch (cmd) { | 114 | struct nand_chip *chip = mtd->priv; |
114 | 115 | ||
115 | case NAND_CTL_SETCLE: | 116 | if (ctrl & NAND_CTRL_CHANGE) { |
116 | MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR); | 117 | #error Missing headerfiles. No way to fix this. -tglx |
117 | break; | 118 | switch (cmd) { |
118 | case NAND_CTL_CLRCLE: | 119 | case NAND_CTL_SETCLE: |
119 | MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR); | 120 | MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR); |
120 | break; | 121 | break; |
121 | case NAND_CTL_SETALE: | 122 | case NAND_CTL_CLRCLE: |
122 | MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR); | 123 | MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR); |
123 | break; | 124 | break; |
124 | case NAND_CTL_CLRALE: | 125 | case NAND_CTL_SETALE: |
125 | MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR); | 126 | MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR); |
126 | break; | 127 | break; |
127 | case NAND_CTL_SETNCE: | 128 | case NAND_CTL_CLRALE: |
128 | MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR); | 129 | MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR); |
129 | break; | 130 | break; |
130 | case NAND_CTL_CLRNCE: | 131 | case NAND_CTL_SETNCE: |
131 | MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR); | 132 | MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR); |
132 | break; | 133 | break; |
134 | case NAND_CTL_CLRNCE: | ||
135 | MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR); | ||
136 | break; | ||
137 | } | ||
133 | } | 138 | } |
139 | if (cmd != NAND_CMD_NONE) | ||
140 | writeb(cmd, chip->IO_ADDR_W); | ||
134 | } | 141 | } |
135 | 142 | ||
136 | static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd) | 143 | static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd, |
144 | unsigned int ctrl) | ||
137 | { | 145 | { |
138 | switch (cmd) { | 146 | struct nand_chip *chip = mtd->priv; |
139 | 147 | ||
140 | case NAND_CTL_SETCLE: | 148 | if (ctrl & NAND_CTRL_CHANGE) { |
141 | MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR); | 149 | #error Missing headerfiles. No way to fix this. -tglx |
142 | break; | 150 | switch (cmd) { |
143 | case NAND_CTL_CLRCLE: | 151 | case NAND_CTL_SETCLE: |
144 | MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR); | 152 | MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR); |
145 | break; | 153 | break; |
146 | case NAND_CTL_SETALE: | 154 | case NAND_CTL_CLRCLE: |
147 | MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR); | 155 | MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR); |
148 | break; | 156 | break; |
149 | case NAND_CTL_CLRALE: | 157 | case NAND_CTL_SETALE: |
150 | MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR); | 158 | MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR); |
151 | break; | 159 | break; |
152 | case NAND_CTL_SETNCE: | 160 | case NAND_CTL_CLRALE: |
153 | MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR); | 161 | MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR); |
154 | break; | 162 | break; |
155 | case NAND_CTL_CLRNCE: | 163 | case NAND_CTL_SETNCE: |
156 | MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR); | 164 | MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR); |
157 | break; | 165 | break; |
166 | case NAND_CTL_CLRNCE: | ||
167 | MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR); | ||
168 | break; | ||
169 | } | ||
158 | } | 170 | } |
171 | if (cmd != NAND_CMD_NONE) | ||
172 | writeb(cmd, chip->IO_ADDR_W); | ||
159 | } | 173 | } |
160 | 174 | ||
161 | #ifdef USE_READY_BUSY_PIN | 175 | #ifdef USE_READY_BUSY_PIN |
@@ -251,7 +265,7 @@ static int __init ppchameleonevb_init(void) | |||
251 | /* insert callbacks */ | 265 | /* insert callbacks */ |
252 | this->IO_ADDR_R = ppchameleon_fio_base; | 266 | this->IO_ADDR_R = ppchameleon_fio_base; |
253 | this->IO_ADDR_W = ppchameleon_fio_base; | 267 | this->IO_ADDR_W = ppchameleon_fio_base; |
254 | this->hwcontrol = ppchameleon_hwcontrol; | 268 | this->cmd_ctrl = ppchameleon_hwcontrol; |
255 | #ifdef USE_READY_BUSY_PIN | 269 | #ifdef USE_READY_BUSY_PIN |
256 | this->dev_ready = ppchameleon_device_ready; | 270 | this->dev_ready = ppchameleon_device_ready; |
257 | #endif | 271 | #endif |
@@ -351,7 +365,7 @@ static int __init ppchameleonevb_init(void) | |||
351 | /* insert callbacks */ | 365 | /* insert callbacks */ |
352 | this->IO_ADDR_R = ppchameleonevb_fio_base; | 366 | this->IO_ADDR_R = ppchameleonevb_fio_base; |
353 | this->IO_ADDR_W = ppchameleonevb_fio_base; | 367 | this->IO_ADDR_W = ppchameleonevb_fio_base; |
354 | this->hwcontrol = ppchameleonevb_hwcontrol; | 368 | this->cmd_ctrl = ppchameleonevb_hwcontrol; |
355 | #ifdef USE_READY_BUSY_PIN | 369 | #ifdef USE_READY_BUSY_PIN |
356 | this->dev_ready = ppchameleonevb_device_ready; | 370 | this->dev_ready = ppchameleonevb_device_ready; |
357 | #endif | 371 | #endif |
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index f8e631c89a60..6c97bfaea19a 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c | |||
@@ -208,32 +208,18 @@ static uint8_t revbits[256] = { | |||
208 | * Address lines (A24-A22), so no action is required here. | 208 | * Address lines (A24-A22), so no action is required here. |
209 | * | 209 | * |
210 | */ | 210 | */ |
211 | static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd) | 211 | static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd, |
212 | unsigned int ctrl) | ||
212 | { | 213 | { |
213 | struct nand_chip *this = (struct nand_chip *)(mtd->priv); | 214 | struct nand_chip *chip = (mtd->priv); |
214 | 215 | ||
215 | switch (cmd) { | 216 | if (cmd == NAND_CMD_NONE) |
217 | return; | ||
216 | 218 | ||
217 | case NAND_CTL_SETCLE: | 219 | if (ctrl & NAND_CLE) |
218 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE); | 220 | writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_CLE); |
219 | break; | 221 | else |
220 | case NAND_CTL_CLRCLE: | 222 | writeb(cmd, chip->IO_ADDR_W | RTC_FROM4_ALE); |
221 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE); | ||
222 | break; | ||
223 | |||
224 | case NAND_CTL_SETALE: | ||
225 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE); | ||
226 | break; | ||
227 | case NAND_CTL_CLRALE: | ||
228 | this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE); | ||
229 | break; | ||
230 | |||
231 | case NAND_CTL_SETNCE: | ||
232 | break; | ||
233 | case NAND_CTL_CLRNCE: | ||
234 | break; | ||
235 | |||
236 | } | ||
237 | } | 223 | } |
238 | 224 | ||
239 | /* | 225 | /* |
@@ -559,7 +545,7 @@ static int __init rtc_from4_init(void) | |||
559 | this->IO_ADDR_R = rtc_from4_fio_base; | 545 | this->IO_ADDR_R = rtc_from4_fio_base; |
560 | this->IO_ADDR_W = rtc_from4_fio_base; | 546 | this->IO_ADDR_W = rtc_from4_fio_base; |
561 | /* Set address of hardware control function */ | 547 | /* Set address of hardware control function */ |
562 | this->hwcontrol = rtc_from4_hwcontrol; | 548 | this->cmd_ctrl = rtc_from4_hwcontrol; |
563 | /* Set address of chip select function */ | 549 | /* Set address of chip select function */ |
564 | this->select_chip = rtc_from4_nand_select_chip; | 550 | this->select_chip = rtc_from4_nand_select_chip; |
565 | /* command delay time (in us) */ | 551 | /* command delay time (in us) */ |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 608340a25278..215227d1a65c 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -256,60 +256,36 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
256 | * | 256 | * |
257 | */ | 257 | */ |
258 | 258 | ||
259 | static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) | 259 | static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd, |
260 | unsigend int ctrl) | ||
260 | { | 261 | { |
261 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 262 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
262 | struct nand_chip *chip = mtd->priv; | 263 | struct nand_chip *chip = mtd->priv; |
263 | 264 | ||
264 | switch (cmd) { | 265 | if (cmd == NAND_CMD_NONE) |
265 | case NAND_CTL_SETNCE: | 266 | return; |
266 | case NAND_CTL_CLRNCE: | 267 | |
267 | printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); | 268 | if (cmd & NAND_CLE) |
268 | break; | 269 | writeb(cmd, info->regs + S3C2410_NFCMD); |
269 | 270 | else | |
270 | case NAND_CTL_SETCLE: | 271 | writeb(cmd, info->regs + S3C2410_NFADDR); |
271 | chip->IO_ADDR_W = info->regs + S3C2410_NFCMD; | ||
272 | break; | ||
273 | |||
274 | case NAND_CTL_SETALE: | ||
275 | chip->IO_ADDR_W = info->regs + S3C2410_NFADDR; | ||
276 | break; | ||
277 | |||
278 | /* NAND_CTL_CLRCLE: */ | ||
279 | /* NAND_CTL_CLRALE: */ | ||
280 | default: | ||
281 | chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; | ||
282 | break; | ||
283 | } | ||
284 | } | 272 | } |
285 | 273 | ||
286 | /* command and control functions */ | 274 | /* command and control functions */ |
287 | 275 | ||
288 | static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd) | 276 | static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd, |
277 | unsigend int ctrl) | ||
289 | { | 278 | { |
290 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); | 279 | struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); |
291 | struct nand_chip *chip = mtd->priv; | 280 | struct nand_chip *chip = mtd->priv; |
292 | 281 | ||
293 | switch (cmd) { | 282 | if (cmd == NAND_CMD_NONE) |
294 | case NAND_CTL_SETNCE: | 283 | return; |
295 | case NAND_CTL_CLRNCE: | 284 | |
296 | printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__); | 285 | if (cmd & NAND_CLE) |
297 | break; | 286 | writeb(cmd, info->regs + S3C2440_NFCMD); |
298 | 287 | else | |
299 | case NAND_CTL_SETCLE: | 288 | writeb(cmd, info->regs + S3C2440_NFADDR); |
300 | chip->IO_ADDR_W = info->regs + S3C2440_NFCMD; | ||
301 | break; | ||
302 | |||
303 | case NAND_CTL_SETALE: | ||
304 | chip->IO_ADDR_W = info->regs + S3C2440_NFADDR; | ||
305 | break; | ||
306 | |||
307 | /* NAND_CTL_CLRCLE: */ | ||
308 | /* NAND_CTL_CLRALE: */ | ||
309 | default: | ||
310 | chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; | ||
311 | break; | ||
312 | } | ||
313 | } | 289 | } |
314 | 290 | ||
315 | /* s3c2410_nand_devready() | 291 | /* s3c2410_nand_devready() |
@@ -498,7 +474,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
498 | 474 | ||
499 | chip->IO_ADDR_R = info->regs + S3C2410_NFDATA; | 475 | chip->IO_ADDR_R = info->regs + S3C2410_NFDATA; |
500 | chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; | 476 | chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; |
501 | chip->hwcontrol = s3c2410_nand_hwcontrol; | 477 | chip->cmd_ctrl = s3c2410_nand_hwcontrol; |
502 | chip->dev_ready = s3c2410_nand_devready; | 478 | chip->dev_ready = s3c2410_nand_devready; |
503 | chip->write_buf = s3c2410_nand_write_buf; | 479 | chip->write_buf = s3c2410_nand_write_buf; |
504 | chip->read_buf = s3c2410_nand_read_buf; | 480 | chip->read_buf = s3c2410_nand_read_buf; |
@@ -511,7 +487,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, | |||
511 | if (info->is_s3c2440) { | 487 | if (info->is_s3c2440) { |
512 | chip->IO_ADDR_R = info->regs + S3C2440_NFDATA; | 488 | chip->IO_ADDR_R = info->regs + S3C2440_NFDATA; |
513 | chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; | 489 | chip->IO_ADDR_W = info->regs + S3C2440_NFDATA; |
514 | chip->hwcontrol = s3c2440_nand_hwcontrol; | 490 | chip->cmd_ctrl = s3c2440_nand_hwcontrol; |
515 | } | 491 | } |
516 | 492 | ||
517 | nmtd->info = info; | 493 | nmtd->info = info; |
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 5554d0b97c8c..45a1da724bff 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c | |||
@@ -77,31 +77,26 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = { | |||
77 | 77 | ||
78 | /* | 78 | /* |
79 | * hardware specific access to control-lines | 79 | * hardware specific access to control-lines |
80 | * ctrl: | ||
81 | * NAND_CNE: bit 0 -> bit 0 & 4 | ||
82 | * NAND_CLE: bit 1 -> bit 1 | ||
83 | * NAND_ALE: bit 2 -> bit 2 | ||
84 | * | ||
80 | */ | 85 | */ |
81 | static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd) | 86 | static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, |
87 | unsigned int ctrl) | ||
82 | { | 88 | { |
83 | switch (cmd) { | 89 | struct nand_chip *chip = mtd->priv; |
84 | case NAND_CTL_SETCLE: | 90 | |
85 | writeb(readb(FLASHCTL) | FLCLE, FLASHCTL); | 91 | if (ctrl & NAND_CTRL_CHANGE) { |
86 | break; | 92 | unsigned char bits = ctrl & 0x07; |
87 | case NAND_CTL_CLRCLE: | 93 | |
88 | writeb(readb(FLASHCTL) & ~FLCLE, FLASHCTL); | 94 | bits |= (ctrl & 0x01) << 4; |
89 | break; | 95 | writeb((readb(FLASHCTL) & 0x17) | bits, FLASHCTL); |
90 | |||
91 | case NAND_CTL_SETALE: | ||
92 | writeb(readb(FLASHCTL) | FLALE, FLASHCTL); | ||
93 | break; | ||
94 | case NAND_CTL_CLRALE: | ||
95 | writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL); | ||
96 | break; | ||
97 | |||
98 | case NAND_CTL_SETNCE: | ||
99 | writeb(readb(FLASHCTL) & ~(FLCE0 | FLCE1), FLASHCTL); | ||
100 | break; | ||
101 | case NAND_CTL_CLRNCE: | ||
102 | writeb(readb(FLASHCTL) | (FLCE0 | FLCE1), FLASHCTL); | ||
103 | break; | ||
104 | } | 96 | } |
97 | |||
98 | if (cmd != NAND_CMD_NONE) | ||
99 | writeb(cmd, chip->IO_ADDR_W); | ||
105 | } | 100 | } |
106 | 101 | ||
107 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | 102 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; |
@@ -196,7 +191,7 @@ static int __init sharpsl_nand_init(void) | |||
196 | this->IO_ADDR_R = FLASHIO; | 191 | this->IO_ADDR_R = FLASHIO; |
197 | this->IO_ADDR_W = FLASHIO; | 192 | this->IO_ADDR_W = FLASHIO; |
198 | /* Set address of hardware control function */ | 193 | /* Set address of hardware control function */ |
199 | this->hwcontrol = sharpsl_nand_hwcontrol; | 194 | this->cmd_ctrl = sharpsl_nand_hwcontrol; |
200 | this->dev_ready = sharpsl_nand_dev_ready; | 195 | this->dev_ready = sharpsl_nand_dev_ready; |
201 | /* 15 us command delay time */ | 196 | /* 15 us command delay time */ |
202 | this->chip_delay = 15; | 197 | this->chip_delay = 15; |
diff --git a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c index 9737f1d67c3c..1f6d429b1583 100644 --- a/drivers/mtd/nand/spia.c +++ b/drivers/mtd/nand/spia.c | |||
@@ -82,20 +82,27 @@ static const struct mtd_partition partition_info[] = { | |||
82 | 82 | ||
83 | /* | 83 | /* |
84 | * hardware specific access to control-lines | 84 | * hardware specific access to control-lines |
85 | */ | 85 | * |
86 | * ctrl: | ||
87 | * NAND_CNE: bit 0 -> bit 2 | ||
88 | * NAND_CLE: bit 1 -> bit 0 | ||
89 | * NAND_ALE: bit 2 -> bit 1 | ||
90 | */ | ||
86 | static void spia_hwcontrol(struct mtd_info *mtd, int cmd) | 91 | static void spia_hwcontrol(struct mtd_info *mtd, int cmd) |
87 | { | 92 | { |
88 | switch (cmd) { | 93 | struct nand_chip *chip = mtd->priv; |
89 | 94 | ||
90 | case NAND_CTL_SETCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x01; break; | 95 | if (ctrl & NAND_CTRL_CHANGE) { |
91 | case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x01; break; | 96 | void __iomem *addr = spia_io_base + spia_pedr; |
97 | unsigned char bits; | ||
92 | 98 | ||
93 | case NAND_CTL_SETALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x02; break; | 99 | bits = (ctrl & NAND_CNE) << 2; |
94 | case NAND_CTL_CLRALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x02; break; | 100 | bits |= (ctrl & NAND_CLE | NAND_ALE) >> 1; |
95 | 101 | writeb((readb(addr) & ~0x7) | bits, addr); | |
96 | case NAND_CTL_SETNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x04; break; | ||
97 | case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x04; break; | ||
98 | } | 102 | } |
103 | |||
104 | if (cmd != NAND_CMD_NONE) | ||
105 | writeb(cmd, chip->IO_ADDR_W); | ||
99 | } | 106 | } |
100 | 107 | ||
101 | /* | 108 | /* |
@@ -133,7 +140,7 @@ static int __init spia_init(void) | |||
133 | this->IO_ADDR_R = (void __iomem *)spia_fio_base; | 140 | this->IO_ADDR_R = (void __iomem *)spia_fio_base; |
134 | this->IO_ADDR_W = (void __iomem *)spia_fio_base; | 141 | this->IO_ADDR_W = (void __iomem *)spia_fio_base; |
135 | /* Set address of hardware control function */ | 142 | /* Set address of hardware control function */ |
136 | this->hwcontrol = spia_hwcontrol; | 143 | this->cmd_ctrl = spia_hwcontrol; |
137 | /* 15 us command delay time */ | 144 | /* 15 us command delay time */ |
138 | this->chip_delay = 15; | 145 | this->chip_delay = 15; |
139 | 146 | ||
diff --git a/drivers/mtd/nand/toto.c b/drivers/mtd/nand/toto.c index 50aa6a46911f..a9cf0190c27a 100644 --- a/drivers/mtd/nand/toto.c +++ b/drivers/mtd/nand/toto.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <asm/arch-omap1510/hardware.h> | 32 | #include <asm/arch-omap1510/hardware.h> |
33 | #include <asm/arch/gpio.h> | 33 | #include <asm/arch/gpio.h> |
34 | 34 | ||
35 | #define CONFIG_NAND_WORKAROUND 1 | ||
36 | |||
35 | /* | 37 | /* |
36 | * MTD structure for TOTO board | 38 | * MTD structure for TOTO board |
37 | */ | 39 | */ |
@@ -39,25 +41,6 @@ static struct mtd_info *toto_mtd = NULL; | |||
39 | 41 | ||
40 | static unsigned long toto_io_base = OMAP_FLASH_1_BASE; | 42 | static unsigned long toto_io_base = OMAP_FLASH_1_BASE; |
41 | 43 | ||
42 | #define CONFIG_NAND_WORKAROUND 1 | ||
43 | |||
44 | #define NAND_NCE 0x4000 | ||
45 | #define NAND_CLE 0x1000 | ||
46 | #define NAND_ALE 0x0002 | ||
47 | #define NAND_MASK (NAND_CLE | NAND_ALE | NAND_NCE) | ||
48 | |||
49 | #define T_NAND_CTL_CLRALE(iob) gpiosetout(NAND_ALE, 0) | ||
50 | #define T_NAND_CTL_SETALE(iob) gpiosetout(NAND_ALE, NAND_ALE) | ||
51 | #ifdef CONFIG_NAND_WORKAROUND /* "some" dev boards busted, blue wired to rts2 :( */ | ||
52 | #define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0); rts2setout(2, 2) | ||
53 | #define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE); rts2setout(2, 0) | ||
54 | #else | ||
55 | #define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0) | ||
56 | #define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE) | ||
57 | #endif | ||
58 | #define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0) | ||
59 | #define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE) | ||
60 | |||
61 | /* | 44 | /* |
62 | * Define partitions for flash devices | 45 | * Define partitions for flash devices |
63 | */ | 46 | */ |
@@ -91,25 +74,43 @@ static struct mtd_partition partition_info32M[] = { | |||
91 | 74 | ||
92 | #define NUM_PARTITIONS32M 3 | 75 | #define NUM_PARTITIONS32M 3 |
93 | #define NUM_PARTITIONS64M 4 | 76 | #define NUM_PARTITIONS64M 4 |
77 | |||
94 | /* | 78 | /* |
95 | * hardware specific access to control-lines | 79 | * hardware specific access to control-lines |
96 | */ | 80 | * |
97 | 81 | * ctrl: | |
98 | static void toto_hwcontrol(struct mtd_info *mtd, int cmd) | 82 | * NAND_NCE: bit 0 -> bit 14 (0x4000) |
83 | * NAND_CLE: bit 1 -> bit 12 (0x1000) | ||
84 | * NAND_ALE: bit 2 -> bit 1 (0x0002) | ||
85 | */ | ||
86 | static void toto_hwcontrol(struct mtd_info *mtd, int cmd, | ||
87 | unsigned int ctrl) | ||
99 | { | 88 | { |
89 | struct nand_chip *chip = mtd->priv; | ||
90 | |||
91 | if (ctrl & NAND_CTRL_CHANGE) { | ||
92 | unsigned long bits; | ||
100 | 93 | ||
101 | udelay(1); /* hopefully enough time for tc make proceding write to clear */ | 94 | /* hopefully enough time for tc make proceding write to clear */ |
102 | switch (cmd) { | 95 | udelay(1); |
103 | case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break; | ||
104 | case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break; | ||
105 | 96 | ||
106 | case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break; | 97 | bits = (~ctrl & NAND_NCE) << 14; |
107 | case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break; | 98 | bits |= (ctrl & NAND_CLE) << 12; |
99 | bits |= (ctrl & NAND_ALE) >> 1; | ||
108 | 100 | ||
109 | case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break; | 101 | #warning Wild guess as gpiosetout() is nowhere defined in the kernel source - tglx |
110 | case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break; | 102 | gpiosetout(0x5002, bits); |
103 | |||
104 | #ifdef CONFIG_NAND_WORKAROUND | ||
105 | /* "some" dev boards busted, blue wired to rts2 :( */ | ||
106 | rts2setout(2, (ctrl & NAND_CLE) << 1); | ||
107 | #endif | ||
108 | /* allow time to ensure gpio state to over take memory write */ | ||
109 | udelay(1); | ||
111 | } | 110 | } |
112 | udelay(1); /* allow time to ensure gpio state to over take memory write */ | 111 | |
112 | if (cmd != NAND_CMD_NONE) | ||
113 | writeb(cmd, chip->IO_ADDR_W); | ||
113 | } | 114 | } |
114 | 115 | ||
115 | /* | 116 | /* |
@@ -142,7 +143,7 @@ static int __init toto_init(void) | |||
142 | /* Set address of NAND IO lines */ | 143 | /* Set address of NAND IO lines */ |
143 | this->IO_ADDR_R = toto_io_base; | 144 | this->IO_ADDR_R = toto_io_base; |
144 | this->IO_ADDR_W = toto_io_base; | 145 | this->IO_ADDR_W = toto_io_base; |
145 | this->hwcontrol = toto_hwcontrol; | 146 | this->cmd_ctrl = toto_hwcontrol; |
146 | this->dev_ready = NULL; | 147 | this->dev_ready = NULL; |
147 | /* 25 us command delay time */ | 148 | /* 25 us command delay time */ |
148 | this->chip_delay = 30; | 149 | this->chip_delay = 30; |
diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c index 70bce1b0326c..a0b4b1edcb0d 100644 --- a/drivers/mtd/nand/ts7250.c +++ b/drivers/mtd/nand/ts7250.c | |||
@@ -83,31 +83,29 @@ static struct mtd_partition partition_info128[] = { | |||
83 | 83 | ||
84 | /* | 84 | /* |
85 | * hardware specific access to control-lines | 85 | * hardware specific access to control-lines |
86 | * | ||
87 | * ctrl: | ||
88 | * NAND_NCE: bit 0 -> bit 2 | ||
89 | * NAND_CLE: bit 1 -> bit 1 | ||
90 | * NAND_ALE: bit 2 -> bit 0 | ||
86 | */ | 91 | */ |
87 | static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd) | 92 | static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
88 | { | 93 | { |
89 | unsigned long ctrl = TS72XX_NAND_CONTROL_VIRT_BASE; | 94 | struct nand_chip *chip = mtd->priv; |
90 | 95 | ||
91 | switch (cmd) { | 96 | if (ctrl & NAND_CTRL_CHANGE) { |
92 | case NAND_CTL_SETCLE: | 97 | unsigned long addr = TS72XX_NAND_CONTROL_VIRT_BASE; |
93 | __raw_writeb(__raw_readb(ctrl) | 0x2, ctrl); | 98 | unsigned char bits; |
94 | break; | 99 | |
95 | case NAND_CTL_CLRCLE: | 100 | bits = (ctrl & NAND_CNE) << 2; |
96 | __raw_writeb(__raw_readb(ctrl) & ~0x2, ctrl); | 101 | bits |= ctrl & NAND_CLE; |
97 | break; | 102 | bits |= (ctrl & NAND_ALE) >> 2; |
98 | case NAND_CTL_SETALE: | 103 | |
99 | __raw_writeb(__raw_readb(ctrl) | 0x1, ctrl); | 104 | __raw_writeb((__raw_readb(addr) & ~0x7) | bits, addr); |
100 | break; | ||
101 | case NAND_CTL_CLRALE: | ||
102 | __raw_writeb(__raw_readb(ctrl) & ~0x1, ctrl); | ||
103 | break; | ||
104 | case NAND_CTL_SETNCE: | ||
105 | __raw_writeb(__raw_readb(ctrl) | 0x4, ctrl); | ||
106 | break; | ||
107 | case NAND_CTL_CLRNCE: | ||
108 | __raw_writeb(__raw_readb(ctrl) & ~0x4, ctrl); | ||
109 | break; | ||
110 | } | 105 | } |
106 | |||
107 | if (cmd != NAND_CMD_NONE) | ||
108 | writeb(cmd, chip->IO_ADDR_W); | ||
111 | } | 109 | } |
112 | 110 | ||
113 | /* | 111 | /* |
@@ -152,7 +150,7 @@ static int __init ts7250_init(void) | |||
152 | /* insert callbacks */ | 150 | /* insert callbacks */ |
153 | this->IO_ADDR_R = (void *)TS72XX_NAND_DATA_VIRT_BASE; | 151 | this->IO_ADDR_R = (void *)TS72XX_NAND_DATA_VIRT_BASE; |
154 | this->IO_ADDR_W = (void *)TS72XX_NAND_DATA_VIRT_BASE; | 152 | this->IO_ADDR_W = (void *)TS72XX_NAND_DATA_VIRT_BASE; |
155 | this->hwcontrol = ts7250_hwcontrol; | 153 | this->cmd_ctrl = ts7250_hwcontrol; |
156 | this->dev_ready = ts7250_device_ready; | 154 | this->dev_ready = ts7250_device_ready; |
157 | this->chip_delay = 15; | 155 | this->chip_delay = 15; |
158 | this->ecc.mode = NAND_ECC_SOFT; | 156 | this->ecc.mode = NAND_ECC_SOFT; |
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index d7cd5fa16ba4..dd03349946c2 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c | |||
@@ -70,8 +70,6 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) | |||
70 | nftl->mbd.devnum = -1; | 70 | nftl->mbd.devnum = -1; |
71 | nftl->mbd.blksize = 512; | 71 | nftl->mbd.blksize = 512; |
72 | nftl->mbd.tr = tr; | 72 | nftl->mbd.tr = tr; |
73 | memcpy(&nftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo)); | ||
74 | nftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY; | ||
75 | 73 | ||
76 | if (NFTL_mount(nftl) < 0) { | 74 | if (NFTL_mount(nftl) < 0) { |
77 | printk(KERN_WARNING "NFTL: could not mount device\n"); | 75 | 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 | } | 367 | } |
370 | memset(&oob, 0xff, sizeof(struct nftl_oob)); | 368 | memset(&oob, 0xff, sizeof(struct nftl_oob)); |
371 | oob.b.Status = oob.b.Status1 = SECTOR_USED; | 369 | oob.b.Status = oob.b.Status1 = SECTOR_USED; |
372 | MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512), | 370 | |
373 | 512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo); | 371 | nand_write_raw(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + |
372 | (block * 512), 512, &retlen, movebuf, | ||
373 | (char *)&oob); | ||
374 | |||
374 | } | 375 | } |
375 | 376 | ||
376 | /* add the header so that it is now a valid chain */ | 377 | /* 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 | 640 | ||
640 | memset(&oob, 0xff, sizeof(struct nftl_oob)); | 641 | memset(&oob, 0xff, sizeof(struct nftl_oob)); |
641 | oob.b.Status = oob.b.Status1 = SECTOR_USED; | 642 | oob.b.Status = oob.b.Status1 = SECTOR_USED; |
642 | MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, | ||
643 | 512, &retlen, (char *)buffer, (char *)&oob, &nftl->oobinfo); | ||
644 | /* need to write SECTOR_USED flags since they are not written in mtd_writeecc */ | ||
645 | 643 | ||
644 | nand_write_raw(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + | ||
645 | blockofs, 512, &retlen, (char *)buffer, | ||
646 | (char *)&oob); | ||
646 | return 0; | 647 | return 0; |
647 | } | 648 | } |
648 | #endif /* CONFIG_NFTL_RW */ | 649 | #endif /* CONFIG_NFTL_RW */ |
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index 3b104ebb219a..90e5e7e97fdc 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c | |||
@@ -268,18 +268,22 @@ static int memcmpb(void *a, int c, int n) | |||
268 | static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, | 268 | static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, |
269 | int check_oob) | 269 | int check_oob) |
270 | { | 270 | { |
271 | int i; | ||
272 | size_t retlen; | ||
273 | u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize]; | 271 | u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize]; |
272 | struct mtd_info *mtd = nftl->mbd.mtd; | ||
273 | size_t retlen; | ||
274 | int i; | ||
274 | 275 | ||
275 | for (i = 0; i < len; i += SECTORSIZE) { | 276 | for (i = 0; i < len; i += SECTORSIZE) { |
276 | if (MTD_READECC(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &nftl->oobinfo) < 0) | 277 | if (mtd->read(mtd, address, SECTORSIZE, &retlen, buf)) |
277 | return -1; | 278 | return -1; |
278 | if (memcmpb(buf, 0xff, SECTORSIZE) != 0) | 279 | if (memcmpb(buf, 0xff, SECTORSIZE) != 0) |
279 | return -1; | 280 | return -1; |
280 | 281 | ||
281 | if (check_oob) { | 282 | if (check_oob) { |
282 | if (memcmpb(buf + SECTORSIZE, 0xff, nftl->mbd.mtd->oobsize) != 0) | 283 | if(mtd->read_oob(mtd, address, mtd->oobsize, |
284 | &retlen, &buf[SECTORSIZE]) < 0) | ||
285 | return -1; | ||
286 | if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0) | ||
283 | return -1; | 287 | return -1; |
284 | } | 288 | } |
285 | address += SECTORSIZE; | 289 | address += SECTORSIZE; |
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 4c2c61d54b3a..7a2419186ff4 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -597,31 +597,28 @@ static void onenand_release_device(struct mtd_info *mtd) | |||
597 | } | 597 | } |
598 | 598 | ||
599 | /** | 599 | /** |
600 | * onenand_read_ecc - [MTD Interface] Read data with ECC | 600 | * onenand_read - [MTD Interface] Read data from flash |
601 | * @param mtd MTD device structure | 601 | * @param mtd MTD device structure |
602 | * @param from offset to read from | 602 | * @param from offset to read from |
603 | * @param len number of bytes to read | 603 | * @param len number of bytes to read |
604 | * @param retlen pointer to variable to store the number of read bytes | 604 | * @param retlen pointer to variable to store the number of read bytes |
605 | * @param buf the databuffer to put data | 605 | * @param buf the databuffer to put data |
606 | * @param oob_buf filesystem supplied oob data buffer | ||
607 | * @param oobsel oob selection structure | ||
608 | * | 606 | * |
609 | * OneNAND read with ECC | 607 | * Read with ecc |
610 | */ | 608 | */ |
611 | static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | 609 | static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, |
612 | size_t *retlen, u_char *buf, | 610 | size_t *retlen, u_char *buf) |
613 | u_char *oob_buf, struct nand_oobinfo *oobsel) | ||
614 | { | 611 | { |
615 | struct onenand_chip *this = mtd->priv; | 612 | struct onenand_chip *this = mtd->priv; |
616 | int read = 0, column; | 613 | int read = 0, column; |
617 | int thislen; | 614 | int thislen; |
618 | int ret = 0; | 615 | int ret = 0; |
619 | 616 | ||
620 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | 617 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); |
621 | 618 | ||
622 | /* Do not allow reads past end of device */ | 619 | /* Do not allow reads past end of device */ |
623 | if ((from + len) > mtd->size) { | 620 | if ((from + len) > mtd->size) { |
624 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n"); | 621 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end of device\n"); |
625 | *retlen = 0; | 622 | *retlen = 0; |
626 | return -EINVAL; | 623 | return -EINVAL; |
627 | } | 624 | } |
@@ -654,7 +651,7 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
654 | break; | 651 | break; |
655 | 652 | ||
656 | if (ret) { | 653 | if (ret) { |
657 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret); | 654 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret); |
658 | goto out; | 655 | goto out; |
659 | } | 656 | } |
660 | 657 | ||
@@ -676,22 +673,6 @@ out: | |||
676 | } | 673 | } |
677 | 674 | ||
678 | /** | 675 | /** |
679 | * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc | ||
680 | * @param mtd MTD device structure | ||
681 | * @param from offset to read from | ||
682 | * @param len number of bytes to read | ||
683 | * @param retlen pointer to variable to store the number of read bytes | ||
684 | * @param buf the databuffer to put data | ||
685 | * | ||
686 | * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL | ||
687 | */ | ||
688 | static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
689 | size_t *retlen, u_char *buf) | ||
690 | { | ||
691 | return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL); | ||
692 | } | ||
693 | |||
694 | /** | ||
695 | * onenand_read_oob - [MTD Interface] OneNAND read out-of-band | 676 | * onenand_read_oob - [MTD Interface] OneNAND read out-of-band |
696 | * @param mtd MTD device structure | 677 | * @param mtd MTD device structure |
697 | * @param from offset to read from | 678 | * @param from offset to read from |
@@ -834,39 +815,36 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) | |||
834 | #define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) | 815 | #define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) |
835 | 816 | ||
836 | /** | 817 | /** |
837 | * onenand_write_ecc - [MTD Interface] OneNAND write with ECC | 818 | * onenand_write - [MTD Interface] write buffer to FLASH |
838 | * @param mtd MTD device structure | 819 | * @param mtd MTD device structure |
839 | * @param to offset to write to | 820 | * @param to offset to write to |
840 | * @param len number of bytes to write | 821 | * @param len number of bytes to write |
841 | * @param retlen pointer to variable to store the number of written bytes | 822 | * @param retlen pointer to variable to store the number of written bytes |
842 | * @param buf the data to write | 823 | * @param buf the data to write |
843 | * @param eccbuf filesystem supplied oob data buffer | ||
844 | * @param oobsel oob selection structure | ||
845 | * | 824 | * |
846 | * OneNAND write with ECC | 825 | * Write with ECC |
847 | */ | 826 | */ |
848 | static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | 827 | static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, |
849 | size_t *retlen, const u_char *buf, | 828 | size_t *retlen, const u_char *buf) |
850 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
851 | { | 829 | { |
852 | struct onenand_chip *this = mtd->priv; | 830 | struct onenand_chip *this = mtd->priv; |
853 | int written = 0; | 831 | int written = 0; |
854 | int ret = 0; | 832 | int ret = 0; |
855 | 833 | ||
856 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | 834 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
857 | 835 | ||
858 | /* Initialize retlen, in case of early exit */ | 836 | /* Initialize retlen, in case of early exit */ |
859 | *retlen = 0; | 837 | *retlen = 0; |
860 | 838 | ||
861 | /* Do not allow writes past end of device */ | 839 | /* Do not allow writes past end of device */ |
862 | if (unlikely((to + len) > mtd->size)) { | 840 | if (unlikely((to + len) > mtd->size)) { |
863 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n"); | 841 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past end of device\n"); |
864 | return -EINVAL; | 842 | return -EINVAL; |
865 | } | 843 | } |
866 | 844 | ||
867 | /* Reject writes, which are not page aligned */ | 845 | /* Reject writes, which are not page aligned */ |
868 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { | 846 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { |
869 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n"); | 847 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not page aligned data\n"); |
870 | return -EINVAL; | 848 | return -EINVAL; |
871 | } | 849 | } |
872 | 850 | ||
@@ -888,7 +866,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
888 | 866 | ||
889 | ret = this->wait(mtd, FL_WRITING); | 867 | ret = this->wait(mtd, FL_WRITING); |
890 | if (ret) { | 868 | if (ret) { |
891 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret); | 869 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); |
892 | goto out; | 870 | goto out; |
893 | } | 871 | } |
894 | 872 | ||
@@ -897,7 +875,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
897 | /* Only check verify write turn on */ | 875 | /* Only check verify write turn on */ |
898 | ret = onenand_verify_page(mtd, (u_char *) buf, to); | 876 | ret = onenand_verify_page(mtd, (u_char *) buf, to); |
899 | if (ret) { | 877 | if (ret) { |
900 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret); | 878 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); |
901 | goto out; | 879 | goto out; |
902 | } | 880 | } |
903 | 881 | ||
@@ -918,23 +896,6 @@ out: | |||
918 | } | 896 | } |
919 | 897 | ||
920 | /** | 898 | /** |
921 | * onenand_write - [MTD Interface] compability function for onenand_write_ecc | ||
922 | * @param mtd MTD device structure | ||
923 | * @param to offset to write to | ||
924 | * @param len number of bytes to write | ||
925 | * @param retlen pointer to variable to store the number of written bytes | ||
926 | * @param buf the data to write | ||
927 | * | ||
928 | * This function simply calls onenand_write_ecc | ||
929 | * with oob buffer and oobsel = NULL | ||
930 | */ | ||
931 | static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
932 | size_t *retlen, const u_char *buf) | ||
933 | { | ||
934 | return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL); | ||
935 | } | ||
936 | |||
937 | /** | ||
938 | * onenand_write_oob - [MTD Interface] OneNAND write out-of-band | 899 | * onenand_write_oob - [MTD Interface] OneNAND write out-of-band |
939 | * @param mtd MTD device structure | 900 | * @param mtd MTD device structure |
940 | * @param to offset to write to | 901 | * @param to offset to write to |
@@ -1014,144 +975,6 @@ out: | |||
1014 | } | 975 | } |
1015 | 976 | ||
1016 | /** | 977 | /** |
1017 | * onenand_writev_ecc - [MTD Interface] write with iovec with ecc | ||
1018 | * @param mtd MTD device structure | ||
1019 | * @param vecs the iovectors to write | ||
1020 | * @param count number of vectors | ||
1021 | * @param to offset to write to | ||
1022 | * @param retlen pointer to variable to store the number of written bytes | ||
1023 | * @param eccbuf filesystem supplied oob data buffer | ||
1024 | * @param oobsel oob selection structure | ||
1025 | * | ||
1026 | * OneNAND write with iovec with ecc | ||
1027 | */ | ||
1028 | static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | ||
1029 | unsigned long count, loff_t to, size_t *retlen, | ||
1030 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
1031 | { | ||
1032 | struct onenand_chip *this = mtd->priv; | ||
1033 | unsigned char *pbuf; | ||
1034 | size_t total_len, len; | ||
1035 | int i, written = 0; | ||
1036 | int ret = 0; | ||
1037 | |||
1038 | /* Preset written len for early exit */ | ||
1039 | *retlen = 0; | ||
1040 | |||
1041 | /* Calculate total length of data */ | ||
1042 | total_len = 0; | ||
1043 | for (i = 0; i < count; i++) | ||
1044 | total_len += vecs[i].iov_len; | ||
1045 | |||
1046 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); | ||
1047 | |||
1048 | /* Do not allow write past end of the device */ | ||
1049 | if (unlikely((to + total_len) > mtd->size)) { | ||
1050 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n"); | ||
1051 | return -EINVAL; | ||
1052 | } | ||
1053 | |||
1054 | /* Reject writes, which are not page aligned */ | ||
1055 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) { | ||
1056 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempt to write not page aligned data\n"); | ||
1057 | return -EINVAL; | ||
1058 | } | ||
1059 | |||
1060 | /* Grab the lock and see if the device is available */ | ||
1061 | onenand_get_device(mtd, FL_WRITING); | ||
1062 | |||
1063 | /* TODO handling oob */ | ||
1064 | |||
1065 | /* Loop until all keve's data has been written */ | ||
1066 | len = 0; | ||
1067 | while (count) { | ||
1068 | pbuf = this->page_buf; | ||
1069 | /* | ||
1070 | * If the given tuple is >= pagesize then | ||
1071 | * write it out from the iov | ||
1072 | */ | ||
1073 | if ((vecs->iov_len - len) >= mtd->writesize) { | ||
1074 | pbuf = vecs->iov_base + len; | ||
1075 | |||
1076 | len += mtd->writesize; | ||
1077 | |||
1078 | /* Check, if we have to switch to the next tuple */ | ||
1079 | if (len >= (int) vecs->iov_len) { | ||
1080 | vecs++; | ||
1081 | len = 0; | ||
1082 | count--; | ||
1083 | } | ||
1084 | } else { | ||
1085 | int cnt = 0, thislen; | ||
1086 | while (cnt < mtd->writesize) { | ||
1087 | thislen = min_t(int, mtd->writesize - cnt, vecs->iov_len - len); | ||
1088 | memcpy(this->page_buf + cnt, vecs->iov_base + len, thislen); | ||
1089 | cnt += thislen; | ||
1090 | len += thislen; | ||
1091 | |||
1092 | /* Check, if we have to switch to the next tuple */ | ||
1093 | if (len >= (int) vecs->iov_len) { | ||
1094 | vecs++; | ||
1095 | len = 0; | ||
1096 | count--; | ||
1097 | } | ||
1098 | } | ||
1099 | } | ||
1100 | |||
1101 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); | ||
1102 | |||
1103 | this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->writesize); | ||
1104 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | ||
1105 | |||
1106 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); | ||
1107 | |||
1108 | onenand_update_bufferram(mtd, to, 1); | ||
1109 | |||
1110 | ret = this->wait(mtd, FL_WRITING); | ||
1111 | if (ret) { | ||
1112 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: write failed %d\n", ret); | ||
1113 | goto out; | ||
1114 | } | ||
1115 | |||
1116 | |||
1117 | /* Only check verify write turn on */ | ||
1118 | ret = onenand_verify_page(mtd, (u_char *) pbuf, to); | ||
1119 | if (ret) { | ||
1120 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: verify failed %d\n", ret); | ||
1121 | goto out; | ||
1122 | } | ||
1123 | |||
1124 | written += mtd->writesize; | ||
1125 | |||
1126 | to += mtd->writesize; | ||
1127 | } | ||
1128 | |||
1129 | out: | ||
1130 | /* Deselect and wakt up anyone waiting on the device */ | ||
1131 | onenand_release_device(mtd); | ||
1132 | |||
1133 | *retlen = written; | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | /** | ||
1139 | * onenand_writev - [MTD Interface] compabilty function for onenand_writev_ecc | ||
1140 | * @param mtd MTD device structure | ||
1141 | * @param vecs the iovectors to write | ||
1142 | * @param count number of vectors | ||
1143 | * @param to offset to write to | ||
1144 | * @param retlen pointer to variable to store the number of written bytes | ||
1145 | * | ||
1146 | * OneNAND write with kvec. This just calls the ecc function | ||
1147 | */ | ||
1148 | static int onenand_writev(struct mtd_info *mtd, const struct kvec *vecs, | ||
1149 | unsigned long count, loff_t to, size_t *retlen) | ||
1150 | { | ||
1151 | return onenand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL); | ||
1152 | } | ||
1153 | |||
1154 | /** | ||
1155 | * onenand_block_checkbad - [GENERIC] Check if a block is marked bad | 978 | * onenand_block_checkbad - [GENERIC] Check if a block is marked bad |
1156 | * @param mtd MTD device structure | 979 | * @param mtd MTD device structure |
1157 | * @param ofs offset from device start | 980 | * @param ofs offset from device start |
@@ -1950,8 +1773,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
1950 | mtd->unpoint = NULL; | 1773 | mtd->unpoint = NULL; |
1951 | mtd->read = onenand_read; | 1774 | mtd->read = onenand_read; |
1952 | mtd->write = onenand_write; | 1775 | mtd->write = onenand_write; |
1953 | mtd->read_ecc = onenand_read_ecc; | ||
1954 | mtd->write_ecc = onenand_write_ecc; | ||
1955 | mtd->read_oob = onenand_read_oob; | 1776 | mtd->read_oob = onenand_read_oob; |
1956 | mtd->write_oob = onenand_write_oob; | 1777 | mtd->write_oob = onenand_write_oob; |
1957 | #ifdef CONFIG_MTD_ONENAND_OTP | 1778 | #ifdef CONFIG_MTD_ONENAND_OTP |
@@ -1962,10 +1783,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
1962 | mtd->write_user_prot_reg = onenand_write_user_prot_reg; | 1783 | mtd->write_user_prot_reg = onenand_write_user_prot_reg; |
1963 | mtd->lock_user_prot_reg = onenand_lock_user_prot_reg; | 1784 | mtd->lock_user_prot_reg = onenand_lock_user_prot_reg; |
1964 | #endif | 1785 | #endif |
1965 | mtd->readv = NULL; | ||
1966 | mtd->readv_ecc = NULL; | ||
1967 | mtd->writev = onenand_writev; | ||
1968 | mtd->writev_ecc = onenand_writev_ecc; | ||
1969 | mtd->sync = onenand_sync; | 1786 | mtd->sync = onenand_sync; |
1970 | mtd->lock = NULL; | 1787 | mtd->lock = NULL; |
1971 | mtd->unlock = onenand_unlock; | 1788 | mtd->unlock = onenand_unlock; |
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 0d7abb260489..1871140e1e78 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -236,10 +236,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
236 | } | 236 | } |
237 | 237 | ||
238 | /* Do the read... */ | 238 | /* Do the read... */ |
239 | if (jffs2_cleanmarker_oob(c)) | 239 | ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); |
240 | ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo); | ||
241 | else | ||
242 | ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); | ||
243 | 240 | ||
244 | if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { | 241 | if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { |
245 | /* ECC recovered */ | 242 | /* ECC recovered */ |
@@ -293,16 +290,13 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
293 | if (breakme++ == 20) { | 290 | if (breakme++ == 20) { |
294 | printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs); | 291 | printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs); |
295 | breakme = 0; | 292 | breakme = 0; |
296 | c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, | 293 | c->mtd->write(c->mtd, ofs, towrite, &retlen, |
297 | brokenbuf, NULL, c->oobinfo); | 294 | brokenbuf); |
298 | ret = -EIO; | 295 | ret = -EIO; |
299 | } else | 296 | } else |
300 | #endif | 297 | #endif |
301 | if (jffs2_cleanmarker_oob(c)) | 298 | ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, |
302 | ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, | 299 | rewrite_buf); |
303 | rewrite_buf, NULL, c->oobinfo); | ||
304 | else | ||
305 | ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf); | ||
306 | 300 | ||
307 | if (ret || retlen != towrite) { | 301 | if (ret || retlen != towrite) { |
308 | /* Argh. We tried. Really we did. */ | 302 | /* Argh. We tried. Really we did. */ |
@@ -455,15 +449,12 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
455 | if (breakme++ == 20) { | 449 | if (breakme++ == 20) { |
456 | printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs); | 450 | printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs); |
457 | breakme = 0; | 451 | breakme = 0; |
458 | c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, | 452 | c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, |
459 | &retlen, brokenbuf, NULL, c->oobinfo); | 453 | brokenbuf); |
460 | ret = -EIO; | 454 | ret = -EIO; |
461 | } else | 455 | } else |
462 | #endif | 456 | #endif |
463 | 457 | ||
464 | if (jffs2_cleanmarker_oob(c)) | ||
465 | ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo); | ||
466 | else | ||
467 | ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); | 458 | ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); |
468 | 459 | ||
469 | if (ret || retlen != c->wbuf_pagesize) { | 460 | 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 | 783 | ||
793 | /* Read flash */ | 784 | /* Read flash */ |
794 | down_read(&c->wbuf_sem); | 785 | down_read(&c->wbuf_sem); |
795 | if (jffs2_cleanmarker_oob(c)) | 786 | ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); |
796 | ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); | ||
797 | else | ||
798 | ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); | ||
799 | 787 | ||
800 | if ( (ret == -EBADMSG) && (*retlen == len) ) { | 788 | if ( (ret == -EBADMSG) && (*retlen == len) ) { |
801 | printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", | 789 | printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", |
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index d48c7492392b..b8ad634391db 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
@@ -115,9 +115,6 @@ struct mtd_info { | |||
115 | int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); | 115 | int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); |
116 | int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); | 116 | int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); |
117 | 117 | ||
118 | 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); | ||
119 | 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); | ||
120 | |||
121 | int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); | 118 | int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); |
122 | int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); | 119 | int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); |
123 | 120 | ||
@@ -133,17 +130,11 @@ struct mtd_info { | |||
133 | int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); | 130 | int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); |
134 | int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); | 131 | int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); |
135 | 132 | ||
136 | /* kvec-based read/write methods. We need these especially for NAND flash, | 133 | /* kvec-based read/write methods. |
137 | with its limited number of write cycles per erase. | ||
138 | NB: The 'count' parameter is the number of _vectors_, each of | 134 | NB: The 'count' parameter is the number of _vectors_, each of |
139 | which contains an (ofs, len) tuple. | 135 | which contains an (ofs, len) tuple. |
140 | */ | 136 | */ |
141 | int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen); | ||
142 | int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, | ||
143 | size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); | ||
144 | int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); | 137 | int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); |
145 | int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, | ||
146 | size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); | ||
147 | 138 | ||
148 | /* Sync */ | 139 | /* Sync */ |
149 | void (*sync) (struct mtd_info *mtd); | 140 | void (*sync) (struct mtd_info *mtd); |
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 460525841a27..2c0fb6380461 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h | |||
@@ -36,6 +36,9 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, | |||
36 | size_t len, size_t ooblen); | 36 | size_t len, size_t ooblen); |
37 | 37 | ||
38 | 38 | ||
39 | extern int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, | ||
40 | size_t *retlen, uint8_t *buf, uint8_t *oob); | ||
41 | |||
39 | /* The maximum number of NAND chips in an array */ | 42 | /* The maximum number of NAND chips in an array */ |
40 | #define NAND_MAX_CHIPS 8 | 43 | #define NAND_MAX_CHIPS 8 |
41 | 44 | ||
@@ -47,23 +50,20 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, | |||
47 | 50 | ||
48 | /* | 51 | /* |
49 | * Constants for hardware specific CLE/ALE/NCE function | 52 | * Constants for hardware specific CLE/ALE/NCE function |
50 | */ | 53 | * |
54 | * These are bits which can be or'ed to set/clear multiple | ||
55 | * bits in one go. | ||
56 | */ | ||
51 | /* Select the chip by setting nCE to low */ | 57 | /* Select the chip by setting nCE to low */ |
52 | #define NAND_CTL_SETNCE 1 | 58 | #define NAND_NCE 0x01 |
53 | /* Deselect the chip by setting nCE to high */ | ||
54 | #define NAND_CTL_CLRNCE 2 | ||
55 | /* Select the command latch by setting CLE to high */ | 59 | /* Select the command latch by setting CLE to high */ |
56 | #define NAND_CTL_SETCLE 3 | 60 | #define NAND_CLE 0x02 |
57 | /* Deselect the command latch by setting CLE to low */ | ||
58 | #define NAND_CTL_CLRCLE 4 | ||
59 | /* Select the address latch by setting ALE to high */ | 61 | /* Select the address latch by setting ALE to high */ |
60 | #define NAND_CTL_SETALE 5 | 62 | #define NAND_ALE 0x04 |
61 | /* Deselect the address latch by setting ALE to low */ | 63 | |
62 | #define NAND_CTL_CLRALE 6 | 64 | #define NAND_CTRL_CLE (NAND_NCE | NAND_CLE) |
63 | /* Set write protection by setting WP to high. Not used! */ | 65 | #define NAND_CTRL_ALE (NAND_NCE | NAND_ALE) |
64 | #define NAND_CTL_SETWP 7 | 66 | #define NAND_CTRL_CHANGE 0x80 |
65 | /* Clear write protection by setting WP to low. Not used! */ | ||
66 | #define NAND_CTL_CLRWP 8 | ||
67 | 67 | ||
68 | /* | 68 | /* |
69 | * Standard NAND flash commands | 69 | * Standard NAND flash commands |
@@ -103,6 +103,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, | |||
103 | #define NAND_CMD_STATUS_RESET 0x7f | 103 | #define NAND_CMD_STATUS_RESET 0x7f |
104 | #define NAND_CMD_STATUS_CLEAR 0xff | 104 | #define NAND_CMD_STATUS_CLEAR 0xff |
105 | 105 | ||
106 | #define NAND_CMD_NONE -1 | ||
107 | |||
106 | /* Status bits */ | 108 | /* Status bits */ |
107 | #define NAND_STATUS_FAIL 0x01 | 109 | #define NAND_STATUS_FAIL 0x01 |
108 | #define NAND_STATUS_FAIL_N1 0x02 | 110 | #define NAND_STATUS_FAIL_N1 0x02 |
@@ -237,7 +239,7 @@ struct nand_ecc_ctrl { | |||
237 | int steps; | 239 | int steps; |
238 | int size; | 240 | int size; |
239 | int bytes; | 241 | int bytes; |
240 | int (*hwctl)(struct mtd_info *mtd, int mode); | 242 | void (*hwctl)(struct mtd_info *mtd, int mode); |
241 | int (*calculate)(struct mtd_info *mtd, | 243 | int (*calculate)(struct mtd_info *mtd, |
242 | const uint8_t *dat, | 244 | const uint8_t *dat, |
243 | uint8_t *ecc_code); | 245 | uint8_t *ecc_code); |
@@ -251,16 +253,15 @@ struct nand_ecc_ctrl { | |||
251 | * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device | 253 | * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device |
252 | * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device | 254 | * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device |
253 | * @read_byte: [REPLACEABLE] read one byte from the chip | 255 | * @read_byte: [REPLACEABLE] read one byte from the chip |
254 | * @write_byte: [REPLACEABLE] write one byte to the chip | ||
255 | * @read_word: [REPLACEABLE] read one word from the chip | 256 | * @read_word: [REPLACEABLE] read one word from the chip |
256 | * @write_word: [REPLACEABLE] write one word to the chip | ||
257 | * @write_buf: [REPLACEABLE] write data from the buffer to the chip | 257 | * @write_buf: [REPLACEABLE] write data from the buffer to the chip |
258 | * @read_buf: [REPLACEABLE] read data from the chip into the buffer | 258 | * @read_buf: [REPLACEABLE] read data from the chip into the buffer |
259 | * @verify_buf: [REPLACEABLE] verify buffer contents against the chip data | 259 | * @verify_buf: [REPLACEABLE] verify buffer contents against the chip data |
260 | * @select_chip: [REPLACEABLE] select chip nr | 260 | * @select_chip: [REPLACEABLE] select chip nr |
261 | * @block_bad: [REPLACEABLE] check, if the block is bad | 261 | * @block_bad: [REPLACEABLE] check, if the block is bad |
262 | * @block_markbad: [REPLACEABLE] mark the block bad | 262 | * @block_markbad: [REPLACEABLE] mark the block bad |
263 | * @hwcontrol: [BOARDSPECIFIC] hardwarespecific function for accesing control-lines | 263 | * @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific funtion for controlling |
264 | * ALE/CLE/nCE. Also used to write command and address | ||
264 | * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line | 265 | * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line |
265 | * If set to NULL no access to ready/busy is available and the ready/busy information | 266 | * If set to NULL no access to ready/busy is available and the ready/busy information |
266 | * is read from the chip status register | 267 | * is read from the chip status register |
@@ -304,17 +305,15 @@ struct nand_chip { | |||
304 | void __iomem *IO_ADDR_W; | 305 | void __iomem *IO_ADDR_W; |
305 | 306 | ||
306 | uint8_t (*read_byte)(struct mtd_info *mtd); | 307 | uint8_t (*read_byte)(struct mtd_info *mtd); |
307 | void (*write_byte)(struct mtd_info *mtd, uint8_t byte); | ||
308 | u16 (*read_word)(struct mtd_info *mtd); | 308 | u16 (*read_word)(struct mtd_info *mtd); |
309 | void (*write_word)(struct mtd_info *mtd, u16 word); | ||
310 | |||
311 | void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); | 309 | void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); |
312 | void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); | 310 | void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); |
313 | int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); | 311 | int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); |
314 | void (*select_chip)(struct mtd_info *mtd, int chip); | 312 | void (*select_chip)(struct mtd_info *mtd, int chip); |
315 | int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); | 313 | int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); |
316 | int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); | 314 | int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); |
317 | void (*hwcontrol)(struct mtd_info *mtd, int cmd); | 315 | void (*cmd_ctrl)(struct mtd_info *mtd, int dat, |
316 | unsigned int ctrl); | ||
318 | int (*dev_ready)(struct mtd_info *mtd); | 317 | int (*dev_ready)(struct mtd_info *mtd); |
319 | void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); | 318 | void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); |
320 | int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); | 319 | int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); |