diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-06-20 20:46:21 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-06-20 20:46:21 -0400 |
commit | 70ac4385a13f78bc478f26d317511893741b05bd (patch) | |
tree | dafc7f3018295fc4ee00339889e4f35d5b9d7743 /drivers/mtd/onenand | |
parent | d59bf96cdde5b874a57bfd1425faa45da915d0b7 (diff) | |
parent | 077e98945db7e54a9865b5f29a1f02f531eca414 (diff) |
Merge branch 'master' of /home/trondmy/kernel/linux-2.6/
Conflicts:
include/linux/nfs_fs.h
Fixed up conflict with kernel header updates.
Diffstat (limited to 'drivers/mtd/onenand')
-rw-r--r-- | drivers/mtd/onenand/Kconfig | 14 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 718 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_bbt.c | 9 |
3 files changed, 499 insertions, 242 deletions
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig index 126ff6bf63d5..5930a03736d7 100644 --- a/drivers/mtd/onenand/Kconfig +++ b/drivers/mtd/onenand/Kconfig | |||
@@ -29,6 +29,20 @@ config MTD_ONENAND_GENERIC | |||
29 | help | 29 | help |
30 | Support for OneNAND flash via platform device driver. | 30 | Support for OneNAND flash via platform device driver. |
31 | 31 | ||
32 | config MTD_ONENAND_OTP | ||
33 | bool "OneNAND OTP Support" | ||
34 | depends on MTD_ONENAND | ||
35 | help | ||
36 | One Block of the NAND Flash Array memory is reserved as | ||
37 | a One-Time Programmable Block memory area. | ||
38 | Also, 1st Block of NAND Flash Array can be used as OTP. | ||
39 | |||
40 | The OTP block can be read, programmed and locked using the same | ||
41 | operations as any other NAND Flash Array memory block. | ||
42 | OTP block cannot be erased. | ||
43 | |||
44 | OTP block is fully-guaranteed to be a valid block. | ||
45 | |||
32 | config MTD_ONENAND_SYNC_READ | 46 | config MTD_ONENAND_SYNC_READ |
33 | bool "OneNAND Sync. Burst Read Support" | 47 | bool "OneNAND Sync. Burst Read Support" |
34 | depends on ARCH_OMAP | 48 | depends on ARCH_OMAP |
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index a53a73fc2a5a..84ec40d25438 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -23,8 +23,7 @@ | |||
23 | /** | 23 | /** |
24 | * onenand_oob_64 - oob info for large (2KB) page | 24 | * onenand_oob_64 - oob info for large (2KB) page |
25 | */ | 25 | */ |
26 | static struct nand_oobinfo onenand_oob_64 = { | 26 | static struct nand_ecclayout onenand_oob_64 = { |
27 | .useecc = MTD_NANDECC_AUTOPLACE, | ||
28 | .eccbytes = 20, | 27 | .eccbytes = 20, |
29 | .eccpos = { | 28 | .eccpos = { |
30 | 8, 9, 10, 11, 12, | 29 | 8, 9, 10, 11, 12, |
@@ -34,14 +33,14 @@ static struct nand_oobinfo onenand_oob_64 = { | |||
34 | }, | 33 | }, |
35 | .oobfree = { | 34 | .oobfree = { |
36 | {2, 3}, {14, 2}, {18, 3}, {30, 2}, | 35 | {2, 3}, {14, 2}, {18, 3}, {30, 2}, |
37 | {24, 3}, {46, 2}, {40, 3}, {62, 2} } | 36 | {34, 3}, {46, 2}, {50, 3}, {62, 2} |
37 | } | ||
38 | }; | 38 | }; |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * onenand_oob_32 - oob info for middle (1KB) page | 41 | * onenand_oob_32 - oob info for middle (1KB) page |
42 | */ | 42 | */ |
43 | static struct nand_oobinfo onenand_oob_32 = { | 43 | static struct nand_ecclayout onenand_oob_32 = { |
44 | .useecc = MTD_NANDECC_AUTOPLACE, | ||
45 | .eccbytes = 10, | 44 | .eccbytes = 10, |
46 | .eccpos = { | 45 | .eccpos = { |
47 | 8, 9, 10, 11, 12, | 46 | 8, 9, 10, 11, 12, |
@@ -190,7 +189,7 @@ static int onenand_buffer_address(int dataram1, int sectors, int count) | |||
190 | static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) | 189 | static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) |
191 | { | 190 | { |
192 | struct onenand_chip *this = mtd->priv; | 191 | struct onenand_chip *this = mtd->priv; |
193 | int value, readcmd = 0; | 192 | int value, readcmd = 0, block_cmd = 0; |
194 | int block, page; | 193 | int block, page; |
195 | /* Now we use page size operation */ | 194 | /* Now we use page size operation */ |
196 | int sectors = 4, count = 4; | 195 | int sectors = 4, count = 4; |
@@ -206,6 +205,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
206 | 205 | ||
207 | case ONENAND_CMD_ERASE: | 206 | case ONENAND_CMD_ERASE: |
208 | case ONENAND_CMD_BUFFERRAM: | 207 | case ONENAND_CMD_BUFFERRAM: |
208 | case ONENAND_CMD_OTP_ACCESS: | ||
209 | block_cmd = 1; | ||
209 | block = (int) (addr >> this->erase_shift); | 210 | block = (int) (addr >> this->erase_shift); |
210 | page = -1; | 211 | page = -1; |
211 | break; | 212 | break; |
@@ -233,6 +234,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
233 | /* Write 'DFS, FBA' of Flash */ | 234 | /* Write 'DFS, FBA' of Flash */ |
234 | value = onenand_block_address(this, block); | 235 | value = onenand_block_address(this, block); |
235 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); | 236 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); |
237 | |||
238 | if (block_cmd) { | ||
239 | /* Select DataRAM for DDP */ | ||
240 | value = onenand_bufferram_address(this, block); | ||
241 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
242 | } | ||
236 | } | 243 | } |
237 | 244 | ||
238 | if (page != -1) { | 245 | if (page != -1) { |
@@ -301,6 +308,7 @@ static int onenand_wait(struct mtd_info *mtd, int state) | |||
301 | 308 | ||
302 | if (state != FL_READING) | 309 | if (state != FL_READING) |
303 | cond_resched(); | 310 | cond_resched(); |
311 | touch_softlockup_watchdog(); | ||
304 | } | 312 | } |
305 | /* To get correct interrupt status in timeout case */ | 313 | /* To get correct interrupt status in timeout case */ |
306 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | 314 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); |
@@ -344,7 +352,7 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area) | |||
344 | 352 | ||
345 | if (ONENAND_CURRENT_BUFFERRAM(this)) { | 353 | if (ONENAND_CURRENT_BUFFERRAM(this)) { |
346 | if (area == ONENAND_DATARAM) | 354 | if (area == ONENAND_DATARAM) |
347 | return mtd->oobblock; | 355 | return mtd->writesize; |
348 | if (area == ONENAND_SPARERAM) | 356 | if (area == ONENAND_SPARERAM) |
349 | return mtd->oobsize; | 357 | return mtd->oobsize; |
350 | } | 358 | } |
@@ -372,6 +380,17 @@ static int onenand_read_bufferram(struct mtd_info *mtd, int area, | |||
372 | 380 | ||
373 | bufferram += onenand_bufferram_offset(mtd, area); | 381 | bufferram += onenand_bufferram_offset(mtd, area); |
374 | 382 | ||
383 | if (ONENAND_CHECK_BYTE_ACCESS(count)) { | ||
384 | unsigned short word; | ||
385 | |||
386 | /* Align with word(16-bit) size */ | ||
387 | count--; | ||
388 | |||
389 | /* Read word and save byte */ | ||
390 | word = this->read_word(bufferram + offset + count); | ||
391 | buffer[count] = (word & 0xff); | ||
392 | } | ||
393 | |||
375 | memcpy(buffer, bufferram + offset, count); | 394 | memcpy(buffer, bufferram + offset, count); |
376 | 395 | ||
377 | return 0; | 396 | return 0; |
@@ -399,6 +418,17 @@ static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area, | |||
399 | 418 | ||
400 | this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ); | 419 | this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ); |
401 | 420 | ||
421 | if (ONENAND_CHECK_BYTE_ACCESS(count)) { | ||
422 | unsigned short word; | ||
423 | |||
424 | /* Align with word(16-bit) size */ | ||
425 | count--; | ||
426 | |||
427 | /* Read word and save byte */ | ||
428 | word = this->read_word(bufferram + offset + count); | ||
429 | buffer[count] = (word & 0xff); | ||
430 | } | ||
431 | |||
402 | memcpy(buffer, bufferram + offset, count); | 432 | memcpy(buffer, bufferram + offset, count); |
403 | 433 | ||
404 | this->mmcontrol(mtd, 0); | 434 | this->mmcontrol(mtd, 0); |
@@ -426,6 +456,22 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area, | |||
426 | 456 | ||
427 | bufferram += onenand_bufferram_offset(mtd, area); | 457 | bufferram += onenand_bufferram_offset(mtd, area); |
428 | 458 | ||
459 | if (ONENAND_CHECK_BYTE_ACCESS(count)) { | ||
460 | unsigned short word; | ||
461 | int byte_offset; | ||
462 | |||
463 | /* Align with word(16-bit) size */ | ||
464 | count--; | ||
465 | |||
466 | /* Calculate byte access offset */ | ||
467 | byte_offset = offset + count; | ||
468 | |||
469 | /* Read word and save byte */ | ||
470 | word = this->read_word(bufferram + byte_offset); | ||
471 | word = (word & ~0xff) | buffer[count]; | ||
472 | this->write_word(word, bufferram + byte_offset); | ||
473 | } | ||
474 | |||
429 | memcpy(bufferram + offset, buffer, count); | 475 | memcpy(bufferram + offset, buffer, count); |
430 | 476 | ||
431 | return 0; | 477 | return 0; |
@@ -549,31 +595,28 @@ static void onenand_release_device(struct mtd_info *mtd) | |||
549 | } | 595 | } |
550 | 596 | ||
551 | /** | 597 | /** |
552 | * onenand_read_ecc - [MTD Interface] Read data with ECC | 598 | * onenand_read - [MTD Interface] Read data from flash |
553 | * @param mtd MTD device structure | 599 | * @param mtd MTD device structure |
554 | * @param from offset to read from | 600 | * @param from offset to read from |
555 | * @param len number of bytes to read | 601 | * @param len number of bytes to read |
556 | * @param retlen pointer to variable to store the number of read bytes | 602 | * @param retlen pointer to variable to store the number of read bytes |
557 | * @param buf the databuffer to put data | 603 | * @param buf the databuffer to put data |
558 | * @param oob_buf filesystem supplied oob data buffer | ||
559 | * @param oobsel oob selection structure | ||
560 | * | 604 | * |
561 | * OneNAND read with ECC | 605 | * Read with ecc |
562 | */ | 606 | */ |
563 | static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | 607 | static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, |
564 | size_t *retlen, u_char *buf, | 608 | size_t *retlen, u_char *buf) |
565 | u_char *oob_buf, struct nand_oobinfo *oobsel) | ||
566 | { | 609 | { |
567 | struct onenand_chip *this = mtd->priv; | 610 | struct onenand_chip *this = mtd->priv; |
568 | int read = 0, column; | 611 | int read = 0, column; |
569 | int thislen; | 612 | int thislen; |
570 | int ret = 0; | 613 | int ret = 0; |
571 | 614 | ||
572 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | 615 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); |
573 | 616 | ||
574 | /* Do not allow reads past end of device */ | 617 | /* Do not allow reads past end of device */ |
575 | if ((from + len) > mtd->size) { | 618 | if ((from + len) > mtd->size) { |
576 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n"); | 619 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: Attempt read beyond end of device\n"); |
577 | *retlen = 0; | 620 | *retlen = 0; |
578 | return -EINVAL; | 621 | return -EINVAL; |
579 | } | 622 | } |
@@ -584,14 +627,14 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
584 | /* TODO handling oob */ | 627 | /* TODO handling oob */ |
585 | 628 | ||
586 | while (read < len) { | 629 | while (read < len) { |
587 | thislen = min_t(int, mtd->oobblock, len - read); | 630 | thislen = min_t(int, mtd->writesize, len - read); |
588 | 631 | ||
589 | column = from & (mtd->oobblock - 1); | 632 | column = from & (mtd->writesize - 1); |
590 | if (column + thislen > mtd->oobblock) | 633 | if (column + thislen > mtd->writesize) |
591 | thislen = mtd->oobblock - column; | 634 | thislen = mtd->writesize - column; |
592 | 635 | ||
593 | if (!onenand_check_bufferram(mtd, from)) { | 636 | if (!onenand_check_bufferram(mtd, from)) { |
594 | this->command(mtd, ONENAND_CMD_READ, from, mtd->oobblock); | 637 | this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); |
595 | 638 | ||
596 | ret = this->wait(mtd, FL_READING); | 639 | ret = this->wait(mtd, FL_READING); |
597 | /* First copy data and check return value for ECC handling */ | 640 | /* First copy data and check return value for ECC handling */ |
@@ -606,7 +649,7 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | |||
606 | break; | 649 | break; |
607 | 650 | ||
608 | if (ret) { | 651 | if (ret) { |
609 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret); | 652 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret); |
610 | goto out; | 653 | goto out; |
611 | } | 654 | } |
612 | 655 | ||
@@ -628,23 +671,7 @@ out: | |||
628 | } | 671 | } |
629 | 672 | ||
630 | /** | 673 | /** |
631 | * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc | 674 | * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band |
632 | * @param mtd MTD device structure | ||
633 | * @param from offset to read from | ||
634 | * @param len number of bytes to read | ||
635 | * @param retlen pointer to variable to store the number of read bytes | ||
636 | * @param buf the databuffer to put data | ||
637 | * | ||
638 | * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL | ||
639 | */ | ||
640 | static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
641 | size_t *retlen, u_char *buf) | ||
642 | { | ||
643 | return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL); | ||
644 | } | ||
645 | |||
646 | /** | ||
647 | * onenand_read_oob - [MTD Interface] OneNAND read out-of-band | ||
648 | * @param mtd MTD device structure | 675 | * @param mtd MTD device structure |
649 | * @param from offset to read from | 676 | * @param from offset to read from |
650 | * @param len number of bytes to read | 677 | * @param len number of bytes to read |
@@ -653,8 +680,8 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
653 | * | 680 | * |
654 | * OneNAND read out-of-band data from the spare area | 681 | * OneNAND read out-of-band data from the spare area |
655 | */ | 682 | */ |
656 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | 683 | int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, |
657 | size_t *retlen, u_char *buf) | 684 | size_t *retlen, u_char *buf) |
658 | { | 685 | { |
659 | struct onenand_chip *this = mtd->priv; | 686 | struct onenand_chip *this = mtd->priv; |
660 | int read = 0, thislen, column; | 687 | int read = 0, thislen, column; |
@@ -704,7 +731,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | |||
704 | /* Read more? */ | 731 | /* Read more? */ |
705 | if (read < len) { | 732 | if (read < len) { |
706 | /* Page size */ | 733 | /* Page size */ |
707 | from += mtd->oobblock; | 734 | from += mtd->writesize; |
708 | column = 0; | 735 | column = 0; |
709 | } | 736 | } |
710 | } | 737 | } |
@@ -717,8 +744,53 @@ out: | |||
717 | return ret; | 744 | return ret; |
718 | } | 745 | } |
719 | 746 | ||
747 | /** | ||
748 | * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band | ||
749 | * @mtd: MTD device structure | ||
750 | * @from: offset to read from | ||
751 | * @ops: oob operation description structure | ||
752 | */ | ||
753 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, | ||
754 | struct mtd_oob_ops *ops) | ||
755 | { | ||
756 | BUG_ON(ops->mode != MTD_OOB_PLACE); | ||
757 | |||
758 | return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->len, | ||
759 | &ops->retlen, ops->oobbuf); | ||
760 | } | ||
761 | |||
720 | #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE | 762 | #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE |
721 | /** | 763 | /** |
764 | * onenand_verify_oob - [GENERIC] verify the oob contents after a write | ||
765 | * @param mtd MTD device structure | ||
766 | * @param buf the databuffer to verify | ||
767 | * @param to offset to read from | ||
768 | * @param len number of bytes to read and compare | ||
769 | * | ||
770 | */ | ||
771 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to, int len) | ||
772 | { | ||
773 | struct onenand_chip *this = mtd->priv; | ||
774 | char *readp = this->page_buf; | ||
775 | int column = to & (mtd->oobsize - 1); | ||
776 | int status, i; | ||
777 | |||
778 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); | ||
779 | onenand_update_bufferram(mtd, to, 0); | ||
780 | status = this->wait(mtd, FL_READING); | ||
781 | if (status) | ||
782 | return status; | ||
783 | |||
784 | this->read_bufferram(mtd, ONENAND_SPARERAM, readp, column, len); | ||
785 | |||
786 | for(i = 0; i < len; i++) | ||
787 | if (buf[i] != 0xFF && buf[i] != readp[i]) | ||
788 | return -EBADMSG; | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | /** | ||
722 | * onenand_verify_page - [GENERIC] verify the chip contents after a write | 794 | * onenand_verify_page - [GENERIC] verify the chip contents after a write |
723 | * @param mtd MTD device structure | 795 | * @param mtd MTD device structure |
724 | * @param buf the databuffer to verify | 796 | * @param buf the databuffer to verify |
@@ -731,7 +803,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) | |||
731 | void __iomem *dataram0, *dataram1; | 803 | void __iomem *dataram0, *dataram1; |
732 | int ret = 0; | 804 | int ret = 0; |
733 | 805 | ||
734 | this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock); | 806 | this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); |
735 | 807 | ||
736 | ret = this->wait(mtd, FL_READING); | 808 | ret = this->wait(mtd, FL_READING); |
737 | if (ret) | 809 | if (ret) |
@@ -741,53 +813,51 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) | |||
741 | 813 | ||
742 | /* Check, if the two dataram areas are same */ | 814 | /* Check, if the two dataram areas are same */ |
743 | dataram0 = this->base + ONENAND_DATARAM; | 815 | dataram0 = this->base + ONENAND_DATARAM; |
744 | dataram1 = dataram0 + mtd->oobblock; | 816 | dataram1 = dataram0 + mtd->writesize; |
745 | 817 | ||
746 | if (memcmp(dataram0, dataram1, mtd->oobblock)) | 818 | if (memcmp(dataram0, dataram1, mtd->writesize)) |
747 | return -EBADMSG; | 819 | return -EBADMSG; |
748 | 820 | ||
749 | return 0; | 821 | return 0; |
750 | } | 822 | } |
751 | #else | 823 | #else |
752 | #define onenand_verify_page(...) (0) | 824 | #define onenand_verify_page(...) (0) |
825 | #define onenand_verify_oob(...) (0) | ||
753 | #endif | 826 | #endif |
754 | 827 | ||
755 | #define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0) | 828 | #define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) |
756 | 829 | ||
757 | /** | 830 | /** |
758 | * onenand_write_ecc - [MTD Interface] OneNAND write with ECC | 831 | * onenand_write - [MTD Interface] write buffer to FLASH |
759 | * @param mtd MTD device structure | 832 | * @param mtd MTD device structure |
760 | * @param to offset to write to | 833 | * @param to offset to write to |
761 | * @param len number of bytes to write | 834 | * @param len number of bytes to write |
762 | * @param retlen pointer to variable to store the number of written bytes | 835 | * @param retlen pointer to variable to store the number of written bytes |
763 | * @param buf the data to write | 836 | * @param buf the data to write |
764 | * @param eccbuf filesystem supplied oob data buffer | ||
765 | * @param oobsel oob selection structure | ||
766 | * | 837 | * |
767 | * OneNAND write with ECC | 838 | * Write with ECC |
768 | */ | 839 | */ |
769 | static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | 840 | static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, |
770 | size_t *retlen, const u_char *buf, | 841 | size_t *retlen, const u_char *buf) |
771 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
772 | { | 842 | { |
773 | struct onenand_chip *this = mtd->priv; | 843 | struct onenand_chip *this = mtd->priv; |
774 | int written = 0; | 844 | int written = 0; |
775 | int ret = 0; | 845 | int ret = 0; |
776 | 846 | ||
777 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | 847 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
778 | 848 | ||
779 | /* Initialize retlen, in case of early exit */ | 849 | /* Initialize retlen, in case of early exit */ |
780 | *retlen = 0; | 850 | *retlen = 0; |
781 | 851 | ||
782 | /* Do not allow writes past end of device */ | 852 | /* Do not allow writes past end of device */ |
783 | if (unlikely((to + len) > mtd->size)) { | 853 | if (unlikely((to + len) > mtd->size)) { |
784 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n"); | 854 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt write to past end of device\n"); |
785 | return -EINVAL; | 855 | return -EINVAL; |
786 | } | 856 | } |
787 | 857 | ||
788 | /* Reject writes, which are not page aligned */ | 858 | /* Reject writes, which are not page aligned */ |
789 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { | 859 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { |
790 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n"); | 860 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: Attempt to write not page aligned data\n"); |
791 | return -EINVAL; | 861 | return -EINVAL; |
792 | } | 862 | } |
793 | 863 | ||
@@ -796,20 +866,20 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
796 | 866 | ||
797 | /* Loop until all data write */ | 867 | /* Loop until all data write */ |
798 | while (written < len) { | 868 | while (written < len) { |
799 | int thislen = min_t(int, mtd->oobblock, len - written); | 869 | int thislen = min_t(int, mtd->writesize, len - written); |
800 | 870 | ||
801 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); | 871 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); |
802 | 872 | ||
803 | this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); | 873 | this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); |
804 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | 874 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); |
805 | 875 | ||
806 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); | 876 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); |
807 | 877 | ||
808 | onenand_update_bufferram(mtd, to, 1); | 878 | onenand_update_bufferram(mtd, to, 1); |
809 | 879 | ||
810 | ret = this->wait(mtd, FL_WRITING); | 880 | ret = this->wait(mtd, FL_WRITING); |
811 | if (ret) { | 881 | if (ret) { |
812 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret); | 882 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); |
813 | goto out; | 883 | goto out; |
814 | } | 884 | } |
815 | 885 | ||
@@ -818,7 +888,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, | |||
818 | /* Only check verify write turn on */ | 888 | /* Only check verify write turn on */ |
819 | ret = onenand_verify_page(mtd, (u_char *) buf, to); | 889 | ret = onenand_verify_page(mtd, (u_char *) buf, to); |
820 | if (ret) { | 890 | if (ret) { |
821 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret); | 891 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); |
822 | goto out; | 892 | goto out; |
823 | } | 893 | } |
824 | 894 | ||
@@ -839,24 +909,7 @@ out: | |||
839 | } | 909 | } |
840 | 910 | ||
841 | /** | 911 | /** |
842 | * onenand_write - [MTD Interface] compability function for onenand_write_ecc | 912 | * onenand_do_write_oob - [Internal] OneNAND write out-of-band |
843 | * @param mtd MTD device structure | ||
844 | * @param to offset to write to | ||
845 | * @param len number of bytes to write | ||
846 | * @param retlen pointer to variable to store the number of written bytes | ||
847 | * @param buf the data to write | ||
848 | * | ||
849 | * This function simply calls onenand_write_ecc | ||
850 | * with oob buffer and oobsel = NULL | ||
851 | */ | ||
852 | static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
853 | size_t *retlen, const u_char *buf) | ||
854 | { | ||
855 | return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL); | ||
856 | } | ||
857 | |||
858 | /** | ||
859 | * onenand_write_oob - [MTD Interface] OneNAND write out-of-band | ||
860 | * @param mtd MTD device structure | 913 | * @param mtd MTD device structure |
861 | * @param to offset to write to | 914 | * @param to offset to write to |
862 | * @param len number of bytes to write | 915 | * @param len number of bytes to write |
@@ -865,11 +918,11 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
865 | * | 918 | * |
866 | * OneNAND write out-of-band | 919 | * OneNAND write out-of-band |
867 | */ | 920 | */ |
868 | static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | 921 | static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, |
869 | size_t *retlen, const u_char *buf) | 922 | size_t *retlen, const u_char *buf) |
870 | { | 923 | { |
871 | struct onenand_chip *this = mtd->priv; | 924 | struct onenand_chip *this = mtd->priv; |
872 | int column, status; | 925 | int column, ret = 0; |
873 | int written = 0; | 926 | int written = 0; |
874 | 927 | ||
875 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | 928 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
@@ -894,16 +947,27 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
894 | 947 | ||
895 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); | 948 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); |
896 | 949 | ||
897 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | 950 | /* We send data to spare ram with oobsize |
898 | this->write_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | 951 | * to prevent byte access */ |
952 | memset(this->page_buf, 0xff, mtd->oobsize); | ||
953 | memcpy(this->page_buf + column, buf, thislen); | ||
954 | this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize); | ||
899 | 955 | ||
900 | this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); | 956 | this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); |
901 | 957 | ||
902 | onenand_update_bufferram(mtd, to, 0); | 958 | onenand_update_bufferram(mtd, to, 0); |
903 | 959 | ||
904 | status = this->wait(mtd, FL_WRITING); | 960 | ret = this->wait(mtd, FL_WRITING); |
905 | if (status) | 961 | if (ret) { |
962 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write filaed %d\n", ret); | ||
963 | goto out; | ||
964 | } | ||
965 | |||
966 | ret = onenand_verify_oob(mtd, buf, to, thislen); | ||
967 | if (ret) { | ||
968 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify failed %d\n", ret); | ||
906 | goto out; | 969 | goto out; |
970 | } | ||
907 | 971 | ||
908 | written += thislen; | 972 | written += thislen; |
909 | 973 | ||
@@ -920,145 +984,22 @@ out: | |||
920 | 984 | ||
921 | *retlen = written; | 985 | *retlen = written; |
922 | 986 | ||
923 | return 0; | 987 | return ret; |
924 | } | 988 | } |
925 | 989 | ||
926 | /** | 990 | /** |
927 | * onenand_writev_ecc - [MTD Interface] write with iovec with ecc | 991 | * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band |
928 | * @param mtd MTD device structure | 992 | * @mtd: MTD device structure |
929 | * @param vecs the iovectors to write | 993 | * @from: offset to read from |
930 | * @param count number of vectors | 994 | * @ops: oob operation description structure |
931 | * @param to offset to write to | ||
932 | * @param retlen pointer to variable to store the number of written bytes | ||
933 | * @param eccbuf filesystem supplied oob data buffer | ||
934 | * @param oobsel oob selection structure | ||
935 | * | ||
936 | * OneNAND write with iovec with ecc | ||
937 | */ | 995 | */ |
938 | static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, | 996 | static int onenand_write_oob(struct mtd_info *mtd, loff_t to, |
939 | unsigned long count, loff_t to, size_t *retlen, | 997 | struct mtd_oob_ops *ops) |
940 | u_char *eccbuf, struct nand_oobinfo *oobsel) | ||
941 | { | 998 | { |
942 | struct onenand_chip *this = mtd->priv; | 999 | BUG_ON(ops->mode != MTD_OOB_PLACE); |
943 | unsigned char *pbuf; | ||
944 | size_t total_len, len; | ||
945 | int i, written = 0; | ||
946 | int ret = 0; | ||
947 | |||
948 | /* Preset written len for early exit */ | ||
949 | *retlen = 0; | ||
950 | |||
951 | /* Calculate total length of data */ | ||
952 | total_len = 0; | ||
953 | for (i = 0; i < count; i++) | ||
954 | total_len += vecs[i].iov_len; | ||
955 | |||
956 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); | ||
957 | |||
958 | /* Do not allow write past end of the device */ | ||
959 | if (unlikely((to + total_len) > mtd->size)) { | ||
960 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n"); | ||
961 | return -EINVAL; | ||
962 | } | ||
963 | |||
964 | /* Reject writes, which are not page aligned */ | ||
965 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) { | ||
966 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempt to write not page aligned data\n"); | ||
967 | return -EINVAL; | ||
968 | } | ||
969 | |||
970 | /* Grab the lock and see if the device is available */ | ||
971 | onenand_get_device(mtd, FL_WRITING); | ||
972 | |||
973 | /* TODO handling oob */ | ||
974 | |||
975 | /* Loop until all keve's data has been written */ | ||
976 | len = 0; | ||
977 | while (count) { | ||
978 | pbuf = this->page_buf; | ||
979 | /* | ||
980 | * If the given tuple is >= pagesize then | ||
981 | * write it out from the iov | ||
982 | */ | ||
983 | if ((vecs->iov_len - len) >= mtd->oobblock) { | ||
984 | pbuf = vecs->iov_base + len; | ||
985 | |||
986 | len += mtd->oobblock; | ||
987 | |||
988 | /* Check, if we have to switch to the next tuple */ | ||
989 | if (len >= (int) vecs->iov_len) { | ||
990 | vecs++; | ||
991 | len = 0; | ||
992 | count--; | ||
993 | } | ||
994 | } else { | ||
995 | int cnt = 0, thislen; | ||
996 | while (cnt < mtd->oobblock) { | ||
997 | thislen = min_t(int, mtd->oobblock - cnt, vecs->iov_len - len); | ||
998 | memcpy(this->page_buf + cnt, vecs->iov_base + len, thislen); | ||
999 | cnt += thislen; | ||
1000 | len += thislen; | ||
1001 | |||
1002 | /* Check, if we have to switch to the next tuple */ | ||
1003 | if (len >= (int) vecs->iov_len) { | ||
1004 | vecs++; | ||
1005 | len = 0; | ||
1006 | count--; | ||
1007 | } | ||
1008 | } | ||
1009 | } | ||
1010 | |||
1011 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); | ||
1012 | 1000 | ||
1013 | this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->oobblock); | 1001 | return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->len, |
1014 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | 1002 | &ops->retlen, ops->oobbuf); |
1015 | |||
1016 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); | ||
1017 | |||
1018 | onenand_update_bufferram(mtd, to, 1); | ||
1019 | |||
1020 | ret = this->wait(mtd, FL_WRITING); | ||
1021 | if (ret) { | ||
1022 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: write failed %d\n", ret); | ||
1023 | goto out; | ||
1024 | } | ||
1025 | |||
1026 | |||
1027 | /* Only check verify write turn on */ | ||
1028 | ret = onenand_verify_page(mtd, (u_char *) pbuf, to); | ||
1029 | if (ret) { | ||
1030 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: verify failed %d\n", ret); | ||
1031 | goto out; | ||
1032 | } | ||
1033 | |||
1034 | written += mtd->oobblock; | ||
1035 | |||
1036 | to += mtd->oobblock; | ||
1037 | } | ||
1038 | |||
1039 | out: | ||
1040 | /* Deselect and wakt up anyone waiting on the device */ | ||
1041 | onenand_release_device(mtd); | ||
1042 | |||
1043 | *retlen = written; | ||
1044 | |||
1045 | return 0; | ||
1046 | } | ||
1047 | |||
1048 | /** | ||
1049 | * onenand_writev - [MTD Interface] compabilty function for onenand_writev_ecc | ||
1050 | * @param mtd MTD device structure | ||
1051 | * @param vecs the iovectors to write | ||
1052 | * @param count number of vectors | ||
1053 | * @param to offset to write to | ||
1054 | * @param retlen pointer to variable to store the number of written bytes | ||
1055 | * | ||
1056 | * OneNAND write with kvec. This just calls the ecc function | ||
1057 | */ | ||
1058 | static int onenand_writev(struct mtd_info *mtd, const struct kvec *vecs, | ||
1059 | unsigned long count, loff_t to, size_t *retlen) | ||
1060 | { | ||
1061 | return onenand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL); | ||
1062 | } | 1003 | } |
1063 | 1004 | ||
1064 | /** | 1005 | /** |
@@ -1227,7 +1168,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
1227 | 1168 | ||
1228 | /* We write two bytes, so we dont have to mess with 16 bit access */ | 1169 | /* We write two bytes, so we dont have to mess with 16 bit access */ |
1229 | ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); | 1170 | ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); |
1230 | return mtd->write_oob(mtd, ofs , 2, &retlen, buf); | 1171 | return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf); |
1231 | } | 1172 | } |
1232 | 1173 | ||
1233 | /** | 1174 | /** |
@@ -1324,6 +1265,304 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |||
1324 | return 0; | 1265 | return 0; |
1325 | } | 1266 | } |
1326 | 1267 | ||
1268 | #ifdef CONFIG_MTD_ONENAND_OTP | ||
1269 | |||
1270 | /* Interal OTP operation */ | ||
1271 | typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len, | ||
1272 | size_t *retlen, u_char *buf); | ||
1273 | |||
1274 | /** | ||
1275 | * do_otp_read - [DEFAULT] Read OTP block area | ||
1276 | * @param mtd MTD device structure | ||
1277 | * @param from The offset to read | ||
1278 | * @param len number of bytes to read | ||
1279 | * @param retlen pointer to variable to store the number of readbytes | ||
1280 | * @param buf the databuffer to put/get data | ||
1281 | * | ||
1282 | * Read OTP block area. | ||
1283 | */ | ||
1284 | static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
1285 | size_t *retlen, u_char *buf) | ||
1286 | { | ||
1287 | struct onenand_chip *this = mtd->priv; | ||
1288 | int ret; | ||
1289 | |||
1290 | /* Enter OTP access mode */ | ||
1291 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); | ||
1292 | this->wait(mtd, FL_OTPING); | ||
1293 | |||
1294 | ret = mtd->read(mtd, from, len, retlen, buf); | ||
1295 | |||
1296 | /* Exit OTP access mode */ | ||
1297 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); | ||
1298 | this->wait(mtd, FL_RESETING); | ||
1299 | |||
1300 | return ret; | ||
1301 | } | ||
1302 | |||
1303 | /** | ||
1304 | * do_otp_write - [DEFAULT] Write OTP block area | ||
1305 | * @param mtd MTD device structure | ||
1306 | * @param from The offset to write | ||
1307 | * @param len number of bytes to write | ||
1308 | * @param retlen pointer to variable to store the number of write bytes | ||
1309 | * @param buf the databuffer to put/get data | ||
1310 | * | ||
1311 | * Write OTP block area. | ||
1312 | */ | ||
1313 | static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len, | ||
1314 | size_t *retlen, u_char *buf) | ||
1315 | { | ||
1316 | struct onenand_chip *this = mtd->priv; | ||
1317 | unsigned char *pbuf = buf; | ||
1318 | int ret; | ||
1319 | |||
1320 | /* Force buffer page aligned */ | ||
1321 | if (len < mtd->writesize) { | ||
1322 | memcpy(this->page_buf, buf, len); | ||
1323 | memset(this->page_buf + len, 0xff, mtd->writesize - len); | ||
1324 | pbuf = this->page_buf; | ||
1325 | len = mtd->writesize; | ||
1326 | } | ||
1327 | |||
1328 | /* Enter OTP access mode */ | ||
1329 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); | ||
1330 | this->wait(mtd, FL_OTPING); | ||
1331 | |||
1332 | ret = mtd->write(mtd, from, len, retlen, pbuf); | ||
1333 | |||
1334 | /* Exit OTP access mode */ | ||
1335 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); | ||
1336 | this->wait(mtd, FL_RESETING); | ||
1337 | |||
1338 | return ret; | ||
1339 | } | ||
1340 | |||
1341 | /** | ||
1342 | * do_otp_lock - [DEFAULT] Lock OTP block area | ||
1343 | * @param mtd MTD device structure | ||
1344 | * @param from The offset to lock | ||
1345 | * @param len number of bytes to lock | ||
1346 | * @param retlen pointer to variable to store the number of lock bytes | ||
1347 | * @param buf the databuffer to put/get data | ||
1348 | * | ||
1349 | * Lock OTP block area. | ||
1350 | */ | ||
1351 | static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, | ||
1352 | size_t *retlen, u_char *buf) | ||
1353 | { | ||
1354 | struct onenand_chip *this = mtd->priv; | ||
1355 | int ret; | ||
1356 | |||
1357 | /* Enter OTP access mode */ | ||
1358 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); | ||
1359 | this->wait(mtd, FL_OTPING); | ||
1360 | |||
1361 | ret = onenand_do_write_oob(mtd, from, len, retlen, buf); | ||
1362 | |||
1363 | /* Exit OTP access mode */ | ||
1364 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); | ||
1365 | this->wait(mtd, FL_RESETING); | ||
1366 | |||
1367 | return ret; | ||
1368 | } | ||
1369 | |||
1370 | /** | ||
1371 | * onenand_otp_walk - [DEFAULT] Handle OTP operation | ||
1372 | * @param mtd MTD device structure | ||
1373 | * @param from The offset to read/write | ||
1374 | * @param len number of bytes to read/write | ||
1375 | * @param retlen pointer to variable to store the number of read bytes | ||
1376 | * @param buf the databuffer to put/get data | ||
1377 | * @param action do given action | ||
1378 | * @param mode specify user and factory | ||
1379 | * | ||
1380 | * Handle OTP operation. | ||
1381 | */ | ||
1382 | static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, | ||
1383 | size_t *retlen, u_char *buf, | ||
1384 | otp_op_t action, int mode) | ||
1385 | { | ||
1386 | struct onenand_chip *this = mtd->priv; | ||
1387 | int otp_pages; | ||
1388 | int density; | ||
1389 | int ret = 0; | ||
1390 | |||
1391 | *retlen = 0; | ||
1392 | |||
1393 | density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT; | ||
1394 | if (density < ONENAND_DEVICE_DENSITY_512Mb) | ||
1395 | otp_pages = 20; | ||
1396 | else | ||
1397 | otp_pages = 10; | ||
1398 | |||
1399 | if (mode == MTD_OTP_FACTORY) { | ||
1400 | from += mtd->writesize * otp_pages; | ||
1401 | otp_pages = 64 - otp_pages; | ||
1402 | } | ||
1403 | |||
1404 | /* Check User/Factory boundary */ | ||
1405 | if (((mtd->writesize * otp_pages) - (from + len)) < 0) | ||
1406 | return 0; | ||
1407 | |||
1408 | while (len > 0 && otp_pages > 0) { | ||
1409 | if (!action) { /* OTP Info functions */ | ||
1410 | struct otp_info *otpinfo; | ||
1411 | |||
1412 | len -= sizeof(struct otp_info); | ||
1413 | if (len <= 0) | ||
1414 | return -ENOSPC; | ||
1415 | |||
1416 | otpinfo = (struct otp_info *) buf; | ||
1417 | otpinfo->start = from; | ||
1418 | otpinfo->length = mtd->writesize; | ||
1419 | otpinfo->locked = 0; | ||
1420 | |||
1421 | from += mtd->writesize; | ||
1422 | buf += sizeof(struct otp_info); | ||
1423 | *retlen += sizeof(struct otp_info); | ||
1424 | } else { | ||
1425 | size_t tmp_retlen; | ||
1426 | int size = len; | ||
1427 | |||
1428 | ret = action(mtd, from, len, &tmp_retlen, buf); | ||
1429 | |||
1430 | buf += size; | ||
1431 | len -= size; | ||
1432 | *retlen += size; | ||
1433 | |||
1434 | if (ret < 0) | ||
1435 | return ret; | ||
1436 | } | ||
1437 | otp_pages--; | ||
1438 | } | ||
1439 | |||
1440 | return 0; | ||
1441 | } | ||
1442 | |||
1443 | /** | ||
1444 | * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info | ||
1445 | * @param mtd MTD device structure | ||
1446 | * @param buf the databuffer to put/get data | ||
1447 | * @param len number of bytes to read | ||
1448 | * | ||
1449 | * Read factory OTP info. | ||
1450 | */ | ||
1451 | static int onenand_get_fact_prot_info(struct mtd_info *mtd, | ||
1452 | struct otp_info *buf, size_t len) | ||
1453 | { | ||
1454 | size_t retlen; | ||
1455 | int ret; | ||
1456 | |||
1457 | ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_FACTORY); | ||
1458 | |||
1459 | return ret ? : retlen; | ||
1460 | } | ||
1461 | |||
1462 | /** | ||
1463 | * onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area | ||
1464 | * @param mtd MTD device structure | ||
1465 | * @param from The offset to read | ||
1466 | * @param len number of bytes to read | ||
1467 | * @param retlen pointer to variable to store the number of read bytes | ||
1468 | * @param buf the databuffer to put/get data | ||
1469 | * | ||
1470 | * Read factory OTP area. | ||
1471 | */ | ||
1472 | static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, | ||
1473 | size_t len, size_t *retlen, u_char *buf) | ||
1474 | { | ||
1475 | return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_FACTORY); | ||
1476 | } | ||
1477 | |||
1478 | /** | ||
1479 | * onenand_get_user_prot_info - [MTD Interface] Read user OTP info | ||
1480 | * @param mtd MTD device structure | ||
1481 | * @param buf the databuffer to put/get data | ||
1482 | * @param len number of bytes to read | ||
1483 | * | ||
1484 | * Read user OTP info. | ||
1485 | */ | ||
1486 | static int onenand_get_user_prot_info(struct mtd_info *mtd, | ||
1487 | struct otp_info *buf, size_t len) | ||
1488 | { | ||
1489 | size_t retlen; | ||
1490 | int ret; | ||
1491 | |||
1492 | ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_USER); | ||
1493 | |||
1494 | return ret ? : retlen; | ||
1495 | } | ||
1496 | |||
1497 | /** | ||
1498 | * onenand_read_user_prot_reg - [MTD Interface] Read user OTP area | ||
1499 | * @param mtd MTD device structure | ||
1500 | * @param from The offset to read | ||
1501 | * @param len number of bytes to read | ||
1502 | * @param retlen pointer to variable to store the number of read bytes | ||
1503 | * @param buf the databuffer to put/get data | ||
1504 | * | ||
1505 | * Read user OTP area. | ||
1506 | */ | ||
1507 | static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from, | ||
1508 | size_t len, size_t *retlen, u_char *buf) | ||
1509 | { | ||
1510 | return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_USER); | ||
1511 | } | ||
1512 | |||
1513 | /** | ||
1514 | * onenand_write_user_prot_reg - [MTD Interface] Write user OTP area | ||
1515 | * @param mtd MTD device structure | ||
1516 | * @param from The offset to write | ||
1517 | * @param len number of bytes to write | ||
1518 | * @param retlen pointer to variable to store the number of write bytes | ||
1519 | * @param buf the databuffer to put/get data | ||
1520 | * | ||
1521 | * Write user OTP area. | ||
1522 | */ | ||
1523 | static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from, | ||
1524 | size_t len, size_t *retlen, u_char *buf) | ||
1525 | { | ||
1526 | return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER); | ||
1527 | } | ||
1528 | |||
1529 | /** | ||
1530 | * onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area | ||
1531 | * @param mtd MTD device structure | ||
1532 | * @param from The offset to lock | ||
1533 | * @param len number of bytes to unlock | ||
1534 | * | ||
1535 | * Write lock mark on spare area in page 0 in OTP block | ||
1536 | */ | ||
1537 | static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, | ||
1538 | size_t len) | ||
1539 | { | ||
1540 | unsigned char oob_buf[64]; | ||
1541 | size_t retlen; | ||
1542 | int ret; | ||
1543 | |||
1544 | memset(oob_buf, 0xff, mtd->oobsize); | ||
1545 | /* | ||
1546 | * Note: OTP lock operation | ||
1547 | * OTP block : 0xXXFC | ||
1548 | * 1st block : 0xXXF3 (If chip support) | ||
1549 | * Both : 0xXXF0 (If chip support) | ||
1550 | */ | ||
1551 | oob_buf[ONENAND_OTP_LOCK_OFFSET] = 0xFC; | ||
1552 | |||
1553 | /* | ||
1554 | * Write lock mark to 8th word of sector0 of page0 of the spare0. | ||
1555 | * We write 16 bytes spare area instead of 2 bytes. | ||
1556 | */ | ||
1557 | from = 0; | ||
1558 | len = 16; | ||
1559 | |||
1560 | ret = onenand_otp_walk(mtd, from, len, &retlen, oob_buf, do_otp_lock, MTD_OTP_USER); | ||
1561 | |||
1562 | return ret ? : retlen; | ||
1563 | } | ||
1564 | #endif /* CONFIG_MTD_ONENAND_OTP */ | ||
1565 | |||
1327 | /** | 1566 | /** |
1328 | * onenand_print_device_info - Print device ID | 1567 | * onenand_print_device_info - Print device ID |
1329 | * @param device device ID | 1568 | * @param device device ID |
@@ -1423,15 +1662,15 @@ static int onenand_probe(struct mtd_info *mtd) | |||
1423 | 1662 | ||
1424 | /* OneNAND page size & block size */ | 1663 | /* OneNAND page size & block size */ |
1425 | /* The data buffer size is equal to page size */ | 1664 | /* The data buffer size is equal to page size */ |
1426 | mtd->oobblock = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); | 1665 | mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); |
1427 | mtd->oobsize = mtd->oobblock >> 5; | 1666 | mtd->oobsize = mtd->writesize >> 5; |
1428 | /* Pagers per block is always 64 in OneNAND */ | 1667 | /* Pagers per block is always 64 in OneNAND */ |
1429 | mtd->erasesize = mtd->oobblock << 6; | 1668 | mtd->erasesize = mtd->writesize << 6; |
1430 | 1669 | ||
1431 | this->erase_shift = ffs(mtd->erasesize) - 1; | 1670 | this->erase_shift = ffs(mtd->erasesize) - 1; |
1432 | this->page_shift = ffs(mtd->oobblock) - 1; | 1671 | this->page_shift = ffs(mtd->writesize) - 1; |
1433 | this->ppb_shift = (this->erase_shift - this->page_shift); | 1672 | this->ppb_shift = (this->erase_shift - this->page_shift); |
1434 | this->page_mask = (mtd->erasesize / mtd->oobblock) - 1; | 1673 | this->page_mask = (mtd->erasesize / mtd->writesize) - 1; |
1435 | 1674 | ||
1436 | /* REVIST: Multichip handling */ | 1675 | /* REVIST: Multichip handling */ |
1437 | 1676 | ||
@@ -1475,7 +1714,6 @@ static void onenand_resume(struct mtd_info *mtd) | |||
1475 | "in suspended state\n"); | 1714 | "in suspended state\n"); |
1476 | } | 1715 | } |
1477 | 1716 | ||
1478 | |||
1479 | /** | 1717 | /** |
1480 | * onenand_scan - [OneNAND Interface] Scan for the OneNAND device | 1718 | * onenand_scan - [OneNAND Interface] Scan for the OneNAND device |
1481 | * @param mtd MTD device structure | 1719 | * @param mtd MTD device structure |
@@ -1522,7 +1760,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
1522 | /* Allocate buffers, if necessary */ | 1760 | /* Allocate buffers, if necessary */ |
1523 | if (!this->page_buf) { | 1761 | if (!this->page_buf) { |
1524 | size_t len; | 1762 | size_t len; |
1525 | len = mtd->oobblock + mtd->oobsize; | 1763 | len = mtd->writesize + mtd->oobsize; |
1526 | this->page_buf = kmalloc(len, GFP_KERNEL); | 1764 | this->page_buf = kmalloc(len, GFP_KERNEL); |
1527 | if (!this->page_buf) { | 1765 | if (!this->page_buf) { |
1528 | printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n"); | 1766 | printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n"); |
@@ -1537,40 +1775,42 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
1537 | 1775 | ||
1538 | switch (mtd->oobsize) { | 1776 | switch (mtd->oobsize) { |
1539 | case 64: | 1777 | case 64: |
1540 | this->autooob = &onenand_oob_64; | 1778 | this->ecclayout = &onenand_oob_64; |
1541 | break; | 1779 | break; |
1542 | 1780 | ||
1543 | case 32: | 1781 | case 32: |
1544 | this->autooob = &onenand_oob_32; | 1782 | this->ecclayout = &onenand_oob_32; |
1545 | break; | 1783 | break; |
1546 | 1784 | ||
1547 | default: | 1785 | default: |
1548 | printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", | 1786 | printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", |
1549 | mtd->oobsize); | 1787 | mtd->oobsize); |
1550 | /* To prevent kernel oops */ | 1788 | /* To prevent kernel oops */ |
1551 | this->autooob = &onenand_oob_32; | 1789 | this->ecclayout = &onenand_oob_32; |
1552 | break; | 1790 | break; |
1553 | } | 1791 | } |
1554 | 1792 | ||
1555 | memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); | 1793 | mtd->ecclayout = this->ecclayout; |
1556 | 1794 | ||
1557 | /* Fill in remaining MTD driver data */ | 1795 | /* Fill in remaining MTD driver data */ |
1558 | mtd->type = MTD_NANDFLASH; | 1796 | mtd->type = MTD_NANDFLASH; |
1559 | mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; | 1797 | mtd->flags = MTD_CAP_NANDFLASH; |
1560 | mtd->ecctype = MTD_ECC_SW; | 1798 | mtd->ecctype = MTD_ECC_SW; |
1561 | mtd->erase = onenand_erase; | 1799 | mtd->erase = onenand_erase; |
1562 | mtd->point = NULL; | 1800 | mtd->point = NULL; |
1563 | mtd->unpoint = NULL; | 1801 | mtd->unpoint = NULL; |
1564 | mtd->read = onenand_read; | 1802 | mtd->read = onenand_read; |
1565 | mtd->write = onenand_write; | 1803 | mtd->write = onenand_write; |
1566 | mtd->read_ecc = onenand_read_ecc; | ||
1567 | mtd->write_ecc = onenand_write_ecc; | ||
1568 | mtd->read_oob = onenand_read_oob; | 1804 | mtd->read_oob = onenand_read_oob; |
1569 | mtd->write_oob = onenand_write_oob; | 1805 | mtd->write_oob = onenand_write_oob; |
1570 | mtd->readv = NULL; | 1806 | #ifdef CONFIG_MTD_ONENAND_OTP |
1571 | mtd->readv_ecc = NULL; | 1807 | mtd->get_fact_prot_info = onenand_get_fact_prot_info; |
1572 | mtd->writev = onenand_writev; | 1808 | mtd->read_fact_prot_reg = onenand_read_fact_prot_reg; |
1573 | mtd->writev_ecc = onenand_writev_ecc; | 1809 | mtd->get_user_prot_info = onenand_get_user_prot_info; |
1810 | mtd->read_user_prot_reg = onenand_read_user_prot_reg; | ||
1811 | mtd->write_user_prot_reg = onenand_write_user_prot_reg; | ||
1812 | mtd->lock_user_prot_reg = onenand_lock_user_prot_reg; | ||
1813 | #endif | ||
1574 | mtd->sync = onenand_sync; | 1814 | mtd->sync = onenand_sync; |
1575 | mtd->lock = NULL; | 1815 | mtd->lock = NULL; |
1576 | mtd->unlock = onenand_unlock; | 1816 | mtd->unlock = onenand_unlock; |
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 4510d3361eaa..1b00dac3d7d6 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c | |||
@@ -17,6 +17,9 @@ | |||
17 | #include <linux/mtd/onenand.h> | 17 | #include <linux/mtd/onenand.h> |
18 | #include <linux/mtd/compatmac.h> | 18 | #include <linux/mtd/compatmac.h> |
19 | 19 | ||
20 | extern int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | ||
21 | size_t *retlen, u_char *buf); | ||
22 | |||
20 | /** | 23 | /** |
21 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer | 24 | * check_short_pattern - [GENERIC] check if a pattern is in the buffer |
22 | * @param buf the buffer to search | 25 | * @param buf the buffer to search |
@@ -87,13 +90,13 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
87 | 90 | ||
88 | /* No need to read pages fully, | 91 | /* No need to read pages fully, |
89 | * just read required OOB bytes */ | 92 | * just read required OOB bytes */ |
90 | ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs, | 93 | ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs, |
91 | readlen, &retlen, &buf[0]); | 94 | readlen, &retlen, &buf[0]); |
92 | 95 | ||
93 | if (ret) | 96 | if (ret) |
94 | return ret; | 97 | return ret; |
95 | 98 | ||
96 | if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | 99 | if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { |
97 | bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); | 100 | bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); |
98 | printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 101 | printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", |
99 | i >> 1, (unsigned int) from); | 102 | i >> 1, (unsigned int) from); |