diff options
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 192 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_bbt.c | 3 | ||||
-rw-r--r-- | include/linux/mtd/onenand.h | 3 |
3 files changed, 124 insertions, 74 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 63ca61b83bf5..2da6bb26353e 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -192,8 +192,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
192 | struct onenand_chip *this = mtd->priv; | 192 | struct onenand_chip *this = mtd->priv; |
193 | int value, readcmd = 0, block_cmd = 0; | 193 | int value, readcmd = 0, block_cmd = 0; |
194 | int block, page; | 194 | int block, page; |
195 | /* Now we use page size operation */ | ||
196 | int sectors = 4, count = 4; | ||
197 | 195 | ||
198 | /* Address translation */ | 196 | /* Address translation */ |
199 | switch (cmd) { | 197 | switch (cmd) { |
@@ -245,6 +243,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
245 | } | 243 | } |
246 | 244 | ||
247 | if (page != -1) { | 245 | if (page != -1) { |
246 | /* Now we use page size operation */ | ||
247 | int sectors = 4, count = 4; | ||
248 | int dataram; | 248 | int dataram; |
249 | 249 | ||
250 | switch (cmd) { | 250 | switch (cmd) { |
@@ -298,7 +298,7 @@ static int onenand_wait(struct mtd_info *mtd, int state) | |||
298 | unsigned long timeout; | 298 | unsigned long timeout; |
299 | unsigned int flags = ONENAND_INT_MASTER; | 299 | unsigned int flags = ONENAND_INT_MASTER; |
300 | unsigned int interrupt = 0; | 300 | unsigned int interrupt = 0; |
301 | unsigned int ctrl, ecc; | 301 | unsigned int ctrl; |
302 | 302 | ||
303 | /* The 20 msec is enough */ | 303 | /* The 20 msec is enough */ |
304 | timeout = jiffies + msecs_to_jiffies(20); | 304 | timeout = jiffies + msecs_to_jiffies(20); |
@@ -310,7 +310,6 @@ static int onenand_wait(struct mtd_info *mtd, int state) | |||
310 | 310 | ||
311 | if (state != FL_READING) | 311 | if (state != FL_READING) |
312 | cond_resched(); | 312 | cond_resched(); |
313 | touch_softlockup_watchdog(); | ||
314 | } | 313 | } |
315 | /* To get correct interrupt status in timeout case */ | 314 | /* To get correct interrupt status in timeout case */ |
316 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | 315 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); |
@@ -318,24 +317,20 @@ static int onenand_wait(struct mtd_info *mtd, int state) | |||
318 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); | 317 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
319 | 318 | ||
320 | if (ctrl & ONENAND_CTRL_ERROR) { | 319 | if (ctrl & ONENAND_CTRL_ERROR) { |
321 | /* It maybe occur at initial bad block */ | ||
322 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl); | 320 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl); |
323 | /* Clear other interrupt bits for preventing ECC error */ | 321 | if (ctrl & ONENAND_CTRL_LOCK) |
324 | interrupt &= ONENAND_INT_MASTER; | 322 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error.\n"); |
325 | } | 323 | return ctrl; |
326 | |||
327 | if (ctrl & ONENAND_CTRL_LOCK) { | ||
328 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error = 0x%04x\n", ctrl); | ||
329 | return -EACCES; | ||
330 | } | 324 | } |
331 | 325 | ||
332 | if (interrupt & ONENAND_INT_READ) { | 326 | if (interrupt & ONENAND_INT_READ) { |
333 | ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); | 327 | int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); |
334 | if (ecc) { | 328 | if (ecc) { |
335 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc); | 329 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc); |
336 | if (ecc & ONENAND_ECC_2BIT_ALL) | 330 | if (ecc & ONENAND_ECC_2BIT_ALL) { |
337 | mtd->ecc_stats.failed++; | 331 | mtd->ecc_stats.failed++; |
338 | else if (ecc & ONENAND_ECC_1BIT_ALL) | 332 | return ecc; |
333 | } else if (ecc & ONENAND_ECC_1BIT_ALL) | ||
339 | mtd->ecc_stats.corrected++; | 334 | mtd->ecc_stats.corrected++; |
340 | } | 335 | } |
341 | } | 336 | } |
@@ -372,9 +367,6 @@ static int onenand_interrupt_wait(struct mtd_info *mtd, int state) | |||
372 | { | 367 | { |
373 | struct onenand_chip *this = mtd->priv; | 368 | struct onenand_chip *this = mtd->priv; |
374 | 369 | ||
375 | /* To prevent soft lockup */ | ||
376 | touch_softlockup_watchdog(); | ||
377 | |||
378 | wait_for_completion(&this->complete); | 370 | wait_for_completion(&this->complete); |
379 | 371 | ||
380 | return onenand_wait(mtd, state); | 372 | return onenand_wait(mtd, state); |
@@ -395,9 +387,6 @@ static int onenand_try_interrupt_wait(struct mtd_info *mtd, int state) | |||
395 | /* We use interrupt wait first */ | 387 | /* We use interrupt wait first */ |
396 | this->wait = onenand_interrupt_wait; | 388 | this->wait = onenand_interrupt_wait; |
397 | 389 | ||
398 | /* To prevent soft lockup */ | ||
399 | touch_softlockup_watchdog(); | ||
400 | |||
401 | timeout = msecs_to_jiffies(100); | 390 | timeout = msecs_to_jiffies(100); |
402 | remain = wait_for_completion_timeout(&this->complete, timeout); | 391 | remain = wait_for_completion_timeout(&this->complete, timeout); |
403 | if (!remain) { | 392 | if (!remain) { |
@@ -721,7 +710,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
721 | struct mtd_ecc_stats stats; | 710 | struct mtd_ecc_stats stats; |
722 | int read = 0, column; | 711 | int read = 0, column; |
723 | int thislen; | 712 | int thislen; |
724 | int ret = 0; | 713 | int ret = 0, boundary = 0; |
725 | 714 | ||
726 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | 715 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); |
727 | 716 | ||
@@ -738,38 +727,60 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
738 | /* TODO handling oob */ | 727 | /* TODO handling oob */ |
739 | 728 | ||
740 | stats = mtd->ecc_stats; | 729 | stats = mtd->ecc_stats; |
741 | while (read < len) { | ||
742 | thislen = min_t(int, mtd->writesize, len - read); | ||
743 | |||
744 | column = from & (mtd->writesize - 1); | ||
745 | if (column + thislen > mtd->writesize) | ||
746 | thislen = mtd->writesize - column; | ||
747 | |||
748 | if (!onenand_check_bufferram(mtd, from)) { | ||
749 | this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); | ||
750 | |||
751 | ret = this->wait(mtd, FL_READING); | ||
752 | /* First copy data and check return value for ECC handling */ | ||
753 | onenand_update_bufferram(mtd, from, 1); | ||
754 | } | ||
755 | |||
756 | this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); | ||
757 | |||
758 | read += thislen; | ||
759 | 730 | ||
760 | if (read == len) | 731 | /* Read-while-load method */ |
761 | break; | 732 | |
733 | /* Do first load to bufferRAM */ | ||
734 | if (read < len) { | ||
735 | if (!onenand_check_bufferram(mtd, from)) { | ||
736 | this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); | ||
737 | ret = this->wait(mtd, FL_READING); | ||
738 | onenand_update_bufferram(mtd, from, !ret); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | thislen = min_t(int, mtd->writesize, len - read); | ||
743 | column = from & (mtd->writesize - 1); | ||
744 | if (column + thislen > mtd->writesize) | ||
745 | thislen = mtd->writesize - column; | ||
746 | |||
747 | while (!ret) { | ||
748 | /* If there is more to load then start next load */ | ||
749 | from += thislen; | ||
750 | if (read + thislen < len) { | ||
751 | this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); | ||
752 | /* | ||
753 | * Chip boundary handling in DDP | ||
754 | * Now we issued chip 1 read and pointed chip 1 | ||
755 | * bufferam so we have to point chip 0 bufferam. | ||
756 | */ | ||
757 | if (this->device_id & ONENAND_DEVICE_IS_DDP && | ||
758 | unlikely(from == (this->chipsize >> 1))) { | ||
759 | this->write_word(0, this->base + ONENAND_REG_START_ADDRESS2); | ||
760 | boundary = 1; | ||
761 | } else | ||
762 | boundary = 0; | ||
763 | ONENAND_SET_PREV_BUFFERRAM(this); | ||
764 | } | ||
765 | /* While load is going, read from last bufferRAM */ | ||
766 | this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); | ||
767 | /* See if we are done */ | ||
768 | read += thislen; | ||
769 | if (read == len) | ||
770 | break; | ||
771 | /* Set up for next read from bufferRAM */ | ||
772 | if (unlikely(boundary)) | ||
773 | this->write_word(0x8000, this->base + ONENAND_REG_START_ADDRESS2); | ||
774 | ONENAND_SET_NEXT_BUFFERRAM(this); | ||
775 | buf += thislen; | ||
776 | thislen = min_t(int, mtd->writesize, len - read); | ||
777 | column = 0; | ||
778 | cond_resched(); | ||
779 | /* Now wait for load */ | ||
780 | ret = this->wait(mtd, FL_READING); | ||
781 | onenand_update_bufferram(mtd, from, !ret); | ||
782 | } | ||
762 | 783 | ||
763 | if (ret) { | ||
764 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read: read failed = %d\n", ret); | ||
765 | goto out; | ||
766 | } | ||
767 | |||
768 | from += thislen; | ||
769 | buf += thislen; | ||
770 | } | ||
771 | |||
772 | out: | ||
773 | /* Deselect and wake up anyone waiting on the device */ | 784 | /* Deselect and wake up anyone waiting on the device */ |
774 | onenand_release_device(mtd); | 785 | onenand_release_device(mtd); |
775 | 786 | ||
@@ -783,6 +794,9 @@ out: | |||
783 | if (mtd->ecc_stats.failed - stats.failed) | 794 | if (mtd->ecc_stats.failed - stats.failed) |
784 | return -EBADMSG; | 795 | return -EBADMSG; |
785 | 796 | ||
797 | if (ret) | ||
798 | return ret; | ||
799 | |||
786 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; | 800 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; |
787 | } | 801 | } |
788 | 802 | ||
@@ -820,6 +834,8 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | |||
820 | column = from & (mtd->oobsize - 1); | 834 | column = from & (mtd->oobsize - 1); |
821 | 835 | ||
822 | while (read < len) { | 836 | while (read < len) { |
837 | cond_resched(); | ||
838 | |||
823 | thislen = mtd->oobsize - column; | 839 | thislen = mtd->oobsize - column; |
824 | thislen = min_t(int, thislen, len); | 840 | thislen = min_t(int, thislen, len); |
825 | 841 | ||
@@ -832,16 +848,16 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | |||
832 | 848 | ||
833 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | 849 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); |
834 | 850 | ||
851 | if (ret) { | ||
852 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = 0x%x\n", ret); | ||
853 | goto out; | ||
854 | } | ||
855 | |||
835 | read += thislen; | 856 | read += thislen; |
836 | 857 | ||
837 | if (read == len) | 858 | if (read == len) |
838 | break; | 859 | break; |
839 | 860 | ||
840 | if (ret) { | ||
841 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret); | ||
842 | goto out; | ||
843 | } | ||
844 | |||
845 | buf += thislen; | 861 | buf += thislen; |
846 | 862 | ||
847 | /* Read more? */ | 863 | /* Read more? */ |
@@ -919,6 +935,10 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) | |||
919 | void __iomem *dataram0, *dataram1; | 935 | void __iomem *dataram0, *dataram1; |
920 | int ret = 0; | 936 | int ret = 0; |
921 | 937 | ||
938 | /* In partial page write, just skip it */ | ||
939 | if ((addr & (mtd->writesize - 1)) != 0) | ||
940 | return 0; | ||
941 | |||
922 | this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); | 942 | this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); |
923 | 943 | ||
924 | ret = this->wait(mtd, FL_READING); | 944 | ret = this->wait(mtd, FL_READING); |
@@ -941,7 +961,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr) | |||
941 | #define onenand_verify_oob(...) (0) | 961 | #define onenand_verify_oob(...) (0) |
942 | #endif | 962 | #endif |
943 | 963 | ||
944 | #define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) | 964 | #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) |
945 | 965 | ||
946 | /** | 966 | /** |
947 | * onenand_write - [MTD Interface] write buffer to FLASH | 967 | * onenand_write - [MTD Interface] write buffer to FLASH |
@@ -959,6 +979,7 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
959 | struct onenand_chip *this = mtd->priv; | 979 | struct onenand_chip *this = mtd->priv; |
960 | int written = 0; | 980 | int written = 0; |
961 | int ret = 0; | 981 | int ret = 0; |
982 | int column, subpage; | ||
962 | 983 | ||
963 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | 984 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
964 | 985 | ||
@@ -977,45 +998,63 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
977 | return -EINVAL; | 998 | return -EINVAL; |
978 | } | 999 | } |
979 | 1000 | ||
1001 | column = to & (mtd->writesize - 1); | ||
1002 | subpage = column || (len & (mtd->writesize - 1)); | ||
1003 | |||
980 | /* Grab the lock and see if the device is available */ | 1004 | /* Grab the lock and see if the device is available */ |
981 | onenand_get_device(mtd, FL_WRITING); | 1005 | onenand_get_device(mtd, FL_WRITING); |
982 | 1006 | ||
983 | /* Loop until all data write */ | 1007 | /* Loop until all data write */ |
984 | while (written < len) { | 1008 | while (written < len) { |
985 | int thislen = min_t(int, mtd->writesize, len - written); | 1009 | int bytes = mtd->writesize; |
986 | 1010 | int thislen = min_t(int, bytes, len - written); | |
987 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); | 1011 | u_char *wbuf = (u_char *) buf; |
1012 | |||
1013 | cond_resched(); | ||
1014 | |||
1015 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, bytes); | ||
1016 | |||
1017 | /* Partial page write */ | ||
1018 | if (subpage) { | ||
1019 | bytes = min_t(int, bytes - column, (int) len); | ||
1020 | memset(this->page_buf, 0xff, mtd->writesize); | ||
1021 | memcpy(this->page_buf + column, buf, bytes); | ||
1022 | wbuf = this->page_buf; | ||
1023 | /* Even though partial write, we need page size */ | ||
1024 | thislen = mtd->writesize; | ||
1025 | } | ||
988 | 1026 | ||
989 | this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); | 1027 | this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, thislen); |
990 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | 1028 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); |
991 | 1029 | ||
992 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); | 1030 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); |
993 | 1031 | ||
994 | onenand_update_bufferram(mtd, to, 1); | 1032 | /* In partial page write we don't update bufferram */ |
1033 | onenand_update_bufferram(mtd, to, !subpage); | ||
995 | 1034 | ||
996 | ret = this->wait(mtd, FL_WRITING); | 1035 | ret = this->wait(mtd, FL_WRITING); |
997 | if (ret) { | 1036 | if (ret) { |
998 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); | 1037 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: write filaed %d\n", ret); |
999 | goto out; | 1038 | break; |
1000 | } | 1039 | } |
1001 | 1040 | ||
1002 | written += thislen; | ||
1003 | |||
1004 | /* Only check verify write turn on */ | 1041 | /* Only check verify write turn on */ |
1005 | ret = onenand_verify_page(mtd, (u_char *) buf, to); | 1042 | ret = onenand_verify_page(mtd, (u_char *) wbuf, to); |
1006 | if (ret) { | 1043 | if (ret) { |
1007 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); | 1044 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write: verify failed %d\n", ret); |
1008 | goto out; | 1045 | break; |
1009 | } | 1046 | } |
1010 | 1047 | ||
1048 | written += thislen; | ||
1049 | |||
1011 | if (written == len) | 1050 | if (written == len) |
1012 | break; | 1051 | break; |
1013 | 1052 | ||
1053 | column = 0; | ||
1014 | to += thislen; | 1054 | to += thislen; |
1015 | buf += thislen; | 1055 | buf += thislen; |
1016 | } | 1056 | } |
1017 | 1057 | ||
1018 | out: | ||
1019 | /* Deselect and wake up anyone waiting on the device */ | 1058 | /* Deselect and wake up anyone waiting on the device */ |
1020 | onenand_release_device(mtd); | 1059 | onenand_release_device(mtd); |
1021 | 1060 | ||
@@ -1059,6 +1098,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1059 | while (written < len) { | 1098 | while (written < len) { |
1060 | int thislen = min_t(int, mtd->oobsize, len - written); | 1099 | int thislen = min_t(int, mtd->oobsize, len - written); |
1061 | 1100 | ||
1101 | cond_resched(); | ||
1102 | |||
1062 | column = to & (mtd->oobsize - 1); | 1103 | column = to & (mtd->oobsize - 1); |
1063 | 1104 | ||
1064 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); | 1105 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); |
@@ -1186,6 +1227,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1186 | instr->state = MTD_ERASING; | 1227 | instr->state = MTD_ERASING; |
1187 | 1228 | ||
1188 | while (len) { | 1229 | while (len) { |
1230 | cond_resched(); | ||
1189 | 1231 | ||
1190 | /* Check if we have a bad block, we do not erase bad blocks */ | 1232 | /* Check if we have a bad block, we do not erase bad blocks */ |
1191 | if (onenand_block_checkbad(mtd, addr, 0, 0)) { | 1233 | if (onenand_block_checkbad(mtd, addr, 0, 0)) { |
@@ -1199,10 +1241,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
1199 | ret = this->wait(mtd, FL_ERASING); | 1241 | ret = this->wait(mtd, FL_ERASING); |
1200 | /* Check, if it is write protected */ | 1242 | /* Check, if it is write protected */ |
1201 | if (ret) { | 1243 | if (ret) { |
1202 | if (ret == -EPERM) | 1244 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); |
1203 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Device is write protected!!!\n"); | ||
1204 | else | ||
1205 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift)); | ||
1206 | instr->state = MTD_ERASE_FAILED; | 1245 | instr->state = MTD_ERASE_FAILED; |
1207 | instr->fail_addr = addr; | 1246 | instr->fail_addr = addr; |
1208 | goto erase_exit; | 1247 | goto erase_exit; |
@@ -2029,23 +2068,30 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
2029 | init_waitqueue_head(&this->wq); | 2068 | init_waitqueue_head(&this->wq); |
2030 | spin_lock_init(&this->chip_lock); | 2069 | spin_lock_init(&this->chip_lock); |
2031 | 2070 | ||
2071 | /* | ||
2072 | * Allow subpage writes up to oobsize. | ||
2073 | */ | ||
2032 | switch (mtd->oobsize) { | 2074 | switch (mtd->oobsize) { |
2033 | case 64: | 2075 | case 64: |
2034 | this->ecclayout = &onenand_oob_64; | 2076 | this->ecclayout = &onenand_oob_64; |
2077 | mtd->subpage_sft = 2; | ||
2035 | break; | 2078 | break; |
2036 | 2079 | ||
2037 | case 32: | 2080 | case 32: |
2038 | this->ecclayout = &onenand_oob_32; | 2081 | this->ecclayout = &onenand_oob_32; |
2082 | mtd->subpage_sft = 1; | ||
2039 | break; | 2083 | break; |
2040 | 2084 | ||
2041 | default: | 2085 | default: |
2042 | printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", | 2086 | printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n", |
2043 | mtd->oobsize); | 2087 | mtd->oobsize); |
2088 | mtd->subpage_sft = 0; | ||
2044 | /* To prevent kernel oops */ | 2089 | /* To prevent kernel oops */ |
2045 | this->ecclayout = &onenand_oob_32; | 2090 | this->ecclayout = &onenand_oob_32; |
2046 | break; | 2091 | break; |
2047 | } | 2092 | } |
2048 | 2093 | ||
2094 | this->subpagesize = mtd->writesize >> mtd->subpage_sft; | ||
2049 | mtd->ecclayout = this->ecclayout; | 2095 | mtd->ecclayout = this->ecclayout; |
2050 | 2096 | ||
2051 | /* Fill in remaining MTD driver data */ | 2097 | /* Fill in remaining MTD driver data */ |
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 6cceeca40567..98f8fd1c6375 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c | |||
@@ -93,7 +93,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
93 | ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs, | 93 | ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs, |
94 | readlen, &retlen, &buf[0]); | 94 | readlen, &retlen, &buf[0]); |
95 | 95 | ||
96 | if (ret) | 96 | /* If it is a initial bad block, just ignore it */ |
97 | if (ret && !(ret & ONENAND_CTRL_LOAD)) | ||
97 | return ret; | 98 | return ret; |
98 | 99 | ||
99 | if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { | 100 | if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { |
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h index 62ca0f429822..f775a7af3890 100644 --- a/include/linux/mtd/onenand.h +++ b/include/linux/mtd/onenand.h | |||
@@ -88,6 +88,7 @@ struct onenand_bufferram { | |||
88 | * operation is in progress | 88 | * operation is in progress |
89 | * @state: [INTERN] the current state of the OneNAND device | 89 | * @state: [INTERN] the current state of the OneNAND device |
90 | * @page_buf: data buffer | 90 | * @page_buf: data buffer |
91 | * @subpagesize: [INTERN] holds the subpagesize | ||
91 | * @ecclayout: [REPLACEABLE] the default ecc placement scheme | 92 | * @ecclayout: [REPLACEABLE] the default ecc placement scheme |
92 | * @bbm: [REPLACEABLE] pointer to Bad Block Management | 93 | * @bbm: [REPLACEABLE] pointer to Bad Block Management |
93 | * @priv: [OPTIONAL] pointer to private chip date | 94 | * @priv: [OPTIONAL] pointer to private chip date |
@@ -128,6 +129,7 @@ struct onenand_chip { | |||
128 | onenand_state_t state; | 129 | onenand_state_t state; |
129 | unsigned char *page_buf; | 130 | unsigned char *page_buf; |
130 | 131 | ||
132 | int subpagesize; | ||
131 | struct nand_ecclayout *ecclayout; | 133 | struct nand_ecclayout *ecclayout; |
132 | 134 | ||
133 | void *bbm; | 135 | void *bbm; |
@@ -141,6 +143,7 @@ struct onenand_chip { | |||
141 | #define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) | 143 | #define ONENAND_CURRENT_BUFFERRAM(this) (this->bufferram_index) |
142 | #define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) | 144 | #define ONENAND_NEXT_BUFFERRAM(this) (this->bufferram_index ^ 1) |
143 | #define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1) | 145 | #define ONENAND_SET_NEXT_BUFFERRAM(this) (this->bufferram_index ^= 1) |
146 | #define ONENAND_SET_PREV_BUFFERRAM(this) (this->bufferram_index ^= 1) | ||
144 | 147 | ||
145 | #define ONENAND_GET_SYS_CFG1(this) \ | 148 | #define ONENAND_GET_SYS_CFG1(this) \ |
146 | (this->read_word(this->base + ONENAND_REG_SYS_CFG1)) | 149 | (this->read_word(this->base + ONENAND_REG_SYS_CFG1)) |