diff options
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 542 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 188 |
2 files changed, 459 insertions, 271 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e922b829c4be..b8e6e1579cf1 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -81,23 +81,12 @@ static struct nand_ecclayout nand_oob_64 = { | |||
81 | .length = 38}} | 81 | .length = 38}} |
82 | }; | 82 | }; |
83 | 83 | ||
84 | /* This is used for padding purposes in nand_write_oob */ | ||
85 | static uint8_t ffchars[] = { | ||
86 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
87 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
88 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
89 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
90 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
91 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
92 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
93 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
94 | }; | ||
95 | |||
96 | static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | ||
97 | size_t *retlen, const uint8_t *buf); | ||
98 | static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, | 84 | static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, |
99 | int new_state); | 85 | int new_state); |
100 | 86 | ||
87 | static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | ||
88 | struct mtd_oob_ops *ops); | ||
89 | |||
101 | /* | 90 | /* |
102 | * For devices which display every fart in the system on a seperate LED. Is | 91 | * For devices which display every fart in the system on a seperate LED. Is |
103 | * compiled away when LED support is disabled. | 92 | * compiled away when LED support is disabled. |
@@ -358,7 +347,6 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
358 | { | 347 | { |
359 | struct nand_chip *chip = mtd->priv; | 348 | struct nand_chip *chip = mtd->priv; |
360 | uint8_t buf[2] = { 0, 0 }; | 349 | uint8_t buf[2] = { 0, 0 }; |
361 | size_t retlen; | ||
362 | int block; | 350 | int block; |
363 | 351 | ||
364 | /* Get block number */ | 352 | /* Get block number */ |
@@ -371,8 +359,13 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
371 | return nand_update_bbt(mtd, ofs); | 359 | return nand_update_bbt(mtd, ofs); |
372 | 360 | ||
373 | /* We write two bytes, so we dont have to mess with 16 bit access */ | 361 | /* We write two bytes, so we dont have to mess with 16 bit access */ |
374 | ofs += mtd->oobsize + (chip->badblockpos & ~0x01); | 362 | ofs += mtd->oobsize; |
375 | return nand_write_oob(mtd, ofs, 2, &retlen, buf); | 363 | chip->ops.len = 2; |
364 | chip->ops.datbuf = NULL; | ||
365 | chip->ops.oobbuf = buf; | ||
366 | chip->ops.ooboffs = chip->badblockpos & ~0x01; | ||
367 | |||
368 | return nand_do_write_oob(mtd, ofs, &chip->ops); | ||
376 | } | 369 | } |
377 | 370 | ||
378 | /** | 371 | /** |
@@ -740,6 +733,20 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip, int state) | |||
740 | } | 733 | } |
741 | 734 | ||
742 | /** | 735 | /** |
736 | * nand_read_page_raw - [Intern] read raw page data without ecc | ||
737 | * @mtd: mtd info structure | ||
738 | * @chip: nand chip info structure | ||
739 | * @buf: buffer to store read data | ||
740 | */ | ||
741 | static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | ||
742 | uint8_t *buf) | ||
743 | { | ||
744 | chip->read_buf(mtd, buf, mtd->writesize); | ||
745 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | /** | ||
743 | * nand_read_page_swecc - {REPLACABLE] software ecc based page read function | 750 | * nand_read_page_swecc - {REPLACABLE] software ecc based page read function |
744 | * @mtd: mtd info structure | 751 | * @mtd: mtd info structure |
745 | * @chip: nand chip info structure | 752 | * @chip: nand chip info structure |
@@ -756,11 +763,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
756 | uint8_t *ecc_code = chip->buffers.ecccode; | 763 | uint8_t *ecc_code = chip->buffers.ecccode; |
757 | int *eccpos = chip->ecc.layout->eccpos; | 764 | int *eccpos = chip->ecc.layout->eccpos; |
758 | 765 | ||
759 | chip->read_buf(mtd, buf, mtd->writesize); | 766 | nand_read_page_raw(mtd, chip, buf); |
760 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
761 | |||
762 | if (chip->ecc.mode == NAND_ECC_NONE) | ||
763 | return 0; | ||
764 | 767 | ||
765 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) | 768 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) |
766 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); | 769 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); |
@@ -882,18 +885,50 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | |||
882 | } | 885 | } |
883 | 886 | ||
884 | /** | 887 | /** |
885 | * nand_do_read - [Internal] Read data with ECC | 888 | * nand_transfer_oob - [Internal] Transfer oob to client buffer |
889 | * @chip: nand chip structure | ||
890 | * @ops: oob ops structure | ||
891 | */ | ||
892 | static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, | ||
893 | struct mtd_oob_ops *ops) | ||
894 | { | ||
895 | size_t len = ops->ooblen; | ||
896 | |||
897 | switch(ops->mode) { | ||
898 | |||
899 | case MTD_OOB_PLACE: | ||
900 | case MTD_OOB_RAW: | ||
901 | memcpy(oob, chip->oob_poi + ops->ooboffs, len); | ||
902 | return oob + len; | ||
903 | |||
904 | case MTD_OOB_AUTO: { | ||
905 | struct nand_oobfree *free = chip->ecc.layout->oobfree; | ||
906 | size_t bytes; | ||
907 | |||
908 | for(; free->length && len; free++, len -= bytes) { | ||
909 | bytes = min(len, free->length); | ||
910 | |||
911 | memcpy(oob, chip->oob_poi + free->offset, bytes); | ||
912 | oob += bytes; | ||
913 | } | ||
914 | return oob; | ||
915 | } | ||
916 | default: | ||
917 | BUG(); | ||
918 | } | ||
919 | return NULL; | ||
920 | } | ||
921 | |||
922 | /** | ||
923 | * nand_do_read_ops - [Internal] Read data with ECC | ||
886 | * | 924 | * |
887 | * @mtd: MTD device structure | 925 | * @mtd: MTD device structure |
888 | * @from: offset to read from | 926 | * @from: offset to read from |
889 | * @len: number of bytes to read | ||
890 | * @retlen: pointer to variable to store the number of read bytes | ||
891 | * @buf: the databuffer to put data | ||
892 | * | 927 | * |
893 | * Internal function. Called with chip held. | 928 | * Internal function. Called with chip held. |
894 | */ | 929 | */ |
895 | int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | 930 | static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, |
896 | size_t *retlen, uint8_t *buf) | 931 | struct mtd_oob_ops *ops) |
897 | { | 932 | { |
898 | int chipnr, page, realpage, col, bytes, aligned; | 933 | int chipnr, page, realpage, col, bytes, aligned; |
899 | struct nand_chip *chip = mtd->priv; | 934 | struct nand_chip *chip = mtd->priv; |
@@ -901,8 +936,8 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
901 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; | 936 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; |
902 | int sndcmd = 1; | 937 | int sndcmd = 1; |
903 | int ret = 0; | 938 | int ret = 0; |
904 | uint32_t readlen = len; | 939 | uint32_t readlen = ops->len; |
905 | uint8_t *bufpoi; | 940 | uint8_t *bufpoi, *oob, *buf; |
906 | 941 | ||
907 | stats = mtd->ecc_stats; | 942 | stats = mtd->ecc_stats; |
908 | 943 | ||
@@ -915,12 +950,15 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
915 | col = (int)(from & (mtd->writesize - 1)); | 950 | col = (int)(from & (mtd->writesize - 1)); |
916 | chip->oob_poi = chip->buffers.oobrbuf; | 951 | chip->oob_poi = chip->buffers.oobrbuf; |
917 | 952 | ||
953 | buf = ops->datbuf; | ||
954 | oob = ops->oobbuf; | ||
955 | |||
918 | while(1) { | 956 | while(1) { |
919 | bytes = min(mtd->writesize - col, readlen); | 957 | bytes = min(mtd->writesize - col, readlen); |
920 | aligned = (bytes == mtd->writesize); | 958 | aligned = (bytes == mtd->writesize); |
921 | 959 | ||
922 | /* Is the current page in the buffer ? */ | 960 | /* Is the current page in the buffer ? */ |
923 | if (realpage != chip->pagebuf) { | 961 | if (realpage != chip->pagebuf || oob) { |
924 | bufpoi = aligned ? buf : chip->buffers.databuf; | 962 | bufpoi = aligned ? buf : chip->buffers.databuf; |
925 | 963 | ||
926 | if (likely(sndcmd)) { | 964 | if (likely(sndcmd)) { |
@@ -939,6 +977,16 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
939 | memcpy(buf, chip->buffers.databuf + col, bytes); | 977 | memcpy(buf, chip->buffers.databuf + col, bytes); |
940 | } | 978 | } |
941 | 979 | ||
980 | buf += bytes; | ||
981 | |||
982 | if (unlikely(oob)) { | ||
983 | /* Raw mode does data:oob:data:oob */ | ||
984 | if (ops->mode != MTD_OOB_RAW) | ||
985 | oob = nand_transfer_oob(chip, oob, ops); | ||
986 | else | ||
987 | buf = nand_transfer_oob(chip, buf, ops); | ||
988 | } | ||
989 | |||
942 | if (!(chip->options & NAND_NO_READRDY)) { | 990 | if (!(chip->options & NAND_NO_READRDY)) { |
943 | /* | 991 | /* |
944 | * Apply delay or wait for ready/busy pin. Do | 992 | * Apply delay or wait for ready/busy pin. Do |
@@ -952,10 +1000,11 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
952 | else | 1000 | else |
953 | nand_wait_ready(mtd); | 1001 | nand_wait_ready(mtd); |
954 | } | 1002 | } |
955 | } else | 1003 | } else { |
956 | memcpy(buf, chip->buffers.databuf + col, bytes); | 1004 | memcpy(buf, chip->buffers.databuf + col, bytes); |
1005 | buf += bytes; | ||
1006 | } | ||
957 | 1007 | ||
958 | buf += bytes; | ||
959 | readlen -= bytes; | 1008 | readlen -= bytes; |
960 | 1009 | ||
961 | if (!readlen) | 1010 | if (!readlen) |
@@ -981,7 +1030,7 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
981 | sndcmd = 1; | 1030 | sndcmd = 1; |
982 | } | 1031 | } |
983 | 1032 | ||
984 | *retlen = len - (size_t) readlen; | 1033 | ops->retlen = ops->len - (size_t) readlen; |
985 | 1034 | ||
986 | if (ret) | 1035 | if (ret) |
987 | return ret; | 1036 | return ret; |
@@ -1002,57 +1051,49 @@ int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
1002 | static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, | 1051 | static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, |
1003 | size_t *retlen, uint8_t *buf) | 1052 | size_t *retlen, uint8_t *buf) |
1004 | { | 1053 | { |
1054 | struct nand_chip *chip = mtd->priv; | ||
1005 | int ret; | 1055 | int ret; |
1006 | 1056 | ||
1007 | *retlen = 0; | ||
1008 | /* Do not allow reads past end of device */ | 1057 | /* Do not allow reads past end of device */ |
1009 | if ((from + len) > mtd->size) | 1058 | if ((from + len) > mtd->size) |
1010 | return -EINVAL; | 1059 | return -EINVAL; |
1011 | if (!len) | 1060 | if (!len) |
1012 | return 0; | 1061 | return 0; |
1013 | 1062 | ||
1014 | nand_get_device(mtd->priv, mtd, FL_READING); | 1063 | nand_get_device(chip, mtd, FL_READING); |
1015 | 1064 | ||
1016 | ret = nand_do_read(mtd, from, len, retlen, buf); | 1065 | chip->ops.len = len; |
1066 | chip->ops.datbuf = buf; | ||
1067 | chip->ops.oobbuf = NULL; | ||
1068 | |||
1069 | ret = nand_do_read_ops(mtd, from, &chip->ops); | ||
1017 | 1070 | ||
1018 | nand_release_device(mtd); | 1071 | nand_release_device(mtd); |
1019 | 1072 | ||
1073 | *retlen = chip->ops.retlen; | ||
1020 | return ret; | 1074 | return ret; |
1021 | } | 1075 | } |
1022 | 1076 | ||
1023 | /** | 1077 | /** |
1024 | * nand_read_oob - [MTD Interface] NAND read out-of-band | 1078 | * nand_do_read_oob - [Intern] NAND read out-of-band |
1025 | * @mtd: MTD device structure | 1079 | * @mtd: MTD device structure |
1026 | * @from: offset to read from | 1080 | * @from: offset to read from |
1027 | * @len: number of bytes to read | 1081 | * @ops: oob operations description structure |
1028 | * @retlen: pointer to variable to store the number of read bytes | ||
1029 | * @buf: the databuffer to put data | ||
1030 | * | 1082 | * |
1031 | * NAND read out-of-band data from the spare area | 1083 | * NAND read out-of-band data from the spare area |
1032 | */ | 1084 | */ |
1033 | static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | 1085 | static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, |
1034 | size_t *retlen, uint8_t *buf) | 1086 | struct mtd_oob_ops *ops) |
1035 | { | 1087 | { |
1036 | int col, page, realpage, chipnr, sndcmd = 1; | 1088 | int col, page, realpage, chipnr, sndcmd = 1; |
1037 | struct nand_chip *chip = mtd->priv; | 1089 | struct nand_chip *chip = mtd->priv; |
1038 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; | 1090 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; |
1039 | int readlen = len; | 1091 | int direct, bytes, readlen = ops->len; |
1092 | uint8_t *bufpoi, *buf = ops->oobbuf; | ||
1040 | 1093 | ||
1041 | DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", | 1094 | DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", |
1042 | (unsigned int)from, (int)len); | 1095 | (unsigned int)from, (int)len); |
1043 | 1096 | ||
1044 | /* Initialize return length value */ | ||
1045 | *retlen = 0; | ||
1046 | |||
1047 | /* Do not allow reads past end of device */ | ||
1048 | if ((from + len) > mtd->size) { | ||
1049 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " | ||
1050 | "Attempt read beyond end of device\n"); | ||
1051 | return -EINVAL; | ||
1052 | } | ||
1053 | |||
1054 | nand_get_device(chip, mtd, FL_READING); | ||
1055 | |||
1056 | chipnr = (int)(from >> chip->chip_shift); | 1097 | chipnr = (int)(from >> chip->chip_shift); |
1057 | chip->select_chip(mtd, chipnr); | 1098 | chip->select_chip(mtd, chipnr); |
1058 | 1099 | ||
@@ -1060,20 +1101,31 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | |||
1060 | realpage = (int)(from >> chip->page_shift); | 1101 | realpage = (int)(from >> chip->page_shift); |
1061 | page = realpage & chip->pagemask; | 1102 | page = realpage & chip->pagemask; |
1062 | 1103 | ||
1063 | /* Mask to get column */ | 1104 | if (ops->mode != MTD_OOB_AUTO) { |
1064 | col = from & (mtd->oobsize - 1); | 1105 | col = ops->ooboffs; |
1106 | direct = 1; | ||
1107 | } else { | ||
1108 | col = 0; | ||
1109 | direct = 0; | ||
1110 | } | ||
1065 | 1111 | ||
1066 | while(1) { | 1112 | while(1) { |
1067 | int bytes = min((int)(mtd->oobsize - col), readlen); | 1113 | bytes = direct ? ops->ooblen : mtd->oobsize; |
1114 | bufpoi = direct ? buf : chip->buffers.oobrbuf; | ||
1068 | 1115 | ||
1069 | if (likely(sndcmd)) { | 1116 | if (likely(sndcmd)) { |
1070 | chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page); | 1117 | chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page); |
1071 | sndcmd = 0; | 1118 | sndcmd = 0; |
1072 | } | 1119 | } |
1073 | 1120 | ||
1074 | chip->read_buf(mtd, buf, bytes); | 1121 | chip->read_buf(mtd, bufpoi, bytes); |
1075 | 1122 | ||
1076 | readlen -= bytes; | 1123 | if (unlikely(!direct)) |
1124 | buf = nand_transfer_oob(chip, buf, ops); | ||
1125 | else | ||
1126 | buf += ops->ooblen; | ||
1127 | |||
1128 | readlen -= ops->ooblen; | ||
1077 | if (!readlen) | 1129 | if (!readlen) |
1078 | break; | 1130 | break; |
1079 | 1131 | ||
@@ -1090,10 +1142,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | |||
1090 | nand_wait_ready(mtd); | 1142 | nand_wait_ready(mtd); |
1091 | } | 1143 | } |
1092 | 1144 | ||
1093 | buf += bytes; | ||
1094 | bytes = mtd->oobsize; | ||
1095 | col = 0; | ||
1096 | |||
1097 | /* Increment page address */ | 1145 | /* Increment page address */ |
1098 | realpage++; | 1146 | realpage++; |
1099 | 1147 | ||
@@ -1112,81 +1160,76 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | |||
1112 | sndcmd = 1; | 1160 | sndcmd = 1; |
1113 | } | 1161 | } |
1114 | 1162 | ||
1115 | /* Deselect and wake up anyone waiting on the device */ | 1163 | ops->retlen = ops->len; |
1116 | nand_release_device(mtd); | ||
1117 | |||
1118 | *retlen = len; | ||
1119 | return 0; | 1164 | return 0; |
1120 | } | 1165 | } |
1121 | 1166 | ||
1122 | /** | 1167 | /** |
1123 | * nand_read_raw - [GENERIC] Read raw data including oob into buffer | 1168 | * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band |
1124 | * @mtd: MTD device structure | 1169 | * @mtd: MTD device structure |
1125 | * @buf: temporary buffer | ||
1126 | * @from: offset to read from | 1170 | * @from: offset to read from |
1127 | * @len: number of bytes to read | 1171 | * @ops: oob operation description structure |
1128 | * @ooblen: number of oob data bytes to read | ||
1129 | * | 1172 | * |
1130 | * Read raw data including oob into buffer | 1173 | * NAND read data and/or out-of-band data |
1131 | */ | 1174 | */ |
1132 | int nand_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, | 1175 | static int nand_read_oob(struct mtd_info *mtd, loff_t from, |
1133 | size_t ooblen) | 1176 | struct mtd_oob_ops *ops) |
1134 | { | 1177 | { |
1178 | int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, | ||
1179 | uint8_t *buf) = NULL; | ||
1135 | struct nand_chip *chip = mtd->priv; | 1180 | struct nand_chip *chip = mtd->priv; |
1136 | int page = (int)(from >> chip->page_shift); | 1181 | int ret = -ENOTSUPP; |
1137 | int chipnr = (int)(from >> chip->chip_shift); | 1182 | |
1138 | int sndcmd = 1; | 1183 | ops->retlen = 0; |
1139 | int cnt = 0; | ||
1140 | int pagesize = mtd->writesize + mtd->oobsize; | ||
1141 | int blockcheck; | ||
1142 | 1184 | ||
1143 | /* Do not allow reads past end of device */ | 1185 | /* Do not allow reads past end of device */ |
1144 | if ((from + len) > mtd->size) { | 1186 | if ((from + ops->len) > mtd->size) { |
1145 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: " | 1187 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " |
1146 | "Attempt read beyond end of device\n"); | 1188 | "Attempt read beyond end of device\n"); |
1147 | return -EINVAL; | 1189 | return -EINVAL; |
1148 | } | 1190 | } |
1149 | 1191 | ||
1150 | /* Grab the lock and see if the device is available */ | ||
1151 | nand_get_device(chip, mtd, FL_READING); | 1192 | nand_get_device(chip, mtd, FL_READING); |
1152 | 1193 | ||
1153 | chip->select_chip(mtd, chipnr); | 1194 | switch(ops->mode) { |
1154 | 1195 | case MTD_OOB_PLACE: | |
1155 | /* Add requested oob length */ | 1196 | case MTD_OOB_AUTO: |
1156 | len += ooblen; | 1197 | break; |
1157 | blockcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; | ||
1158 | 1198 | ||
1159 | while (len) { | 1199 | case MTD_OOB_RAW: |
1160 | if (likely(sndcmd)) { | 1200 | /* Replace the read_page algorithm temporary */ |
1161 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0, | 1201 | read_page = chip->ecc.read_page; |
1162 | page & chip->pagemask); | 1202 | chip->ecc.read_page = nand_read_page_raw; |
1163 | sndcmd = 0; | 1203 | break; |
1164 | } | ||
1165 | 1204 | ||
1166 | chip->read_buf(mtd, &buf[cnt], pagesize); | 1205 | default: |
1206 | goto out; | ||
1207 | } | ||
1167 | 1208 | ||
1168 | len -= pagesize; | 1209 | if (!ops->datbuf) |
1169 | cnt += pagesize; | 1210 | ret = nand_do_read_oob(mtd, from, ops); |
1170 | page++; | 1211 | else |
1212 | ret = nand_do_read_ops(mtd, from, ops); | ||
1171 | 1213 | ||
1172 | if (!(chip->options & NAND_NO_READRDY)) { | 1214 | if (unlikely(ops->mode == MTD_OOB_RAW)) |
1173 | if (!chip->dev_ready) | 1215 | chip->ecc.read_page = read_page; |
1174 | udelay(chip->chip_delay); | 1216 | out: |
1175 | else | 1217 | nand_release_device(mtd); |
1176 | nand_wait_ready(mtd); | 1218 | return ret; |
1177 | } | 1219 | } |
1178 | 1220 | ||
1179 | /* | ||
1180 | * Check, if the chip supports auto page increment or if we | ||
1181 | * cross a block boundary. | ||
1182 | */ | ||
1183 | if (!NAND_CANAUTOINCR(chip) || !(page & blockcheck)) | ||
1184 | sndcmd = 1; | ||
1185 | } | ||
1186 | 1221 | ||
1187 | /* Deselect and wake up anyone waiting on the device */ | 1222 | /** |
1188 | nand_release_device(mtd); | 1223 | * nand_write_page_raw - [Intern] raw page write function |
1189 | return 0; | 1224 | * @mtd: mtd info structure |
1225 | * @chip: nand chip info structure | ||
1226 | * @buf: data buffer | ||
1227 | */ | ||
1228 | static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, | ||
1229 | const uint8_t *buf) | ||
1230 | { | ||
1231 | chip->write_buf(mtd, buf, mtd->writesize); | ||
1232 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
1190 | } | 1233 | } |
1191 | 1234 | ||
1192 | /** | 1235 | /** |
@@ -1205,17 +1248,14 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
1205 | const uint8_t *p = buf; | 1248 | const uint8_t *p = buf; |
1206 | int *eccpos = chip->ecc.layout->eccpos; | 1249 | int *eccpos = chip->ecc.layout->eccpos; |
1207 | 1250 | ||
1208 | if (chip->ecc.mode != NAND_ECC_NONE) { | 1251 | /* Software ecc calculation */ |
1209 | /* Software ecc calculation */ | 1252 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) |
1210 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) | 1253 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); |
1211 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); | ||
1212 | 1254 | ||
1213 | for (i = 0; i < chip->ecc.total; i++) | 1255 | for (i = 0; i < chip->ecc.total; i++) |
1214 | chip->oob_poi[eccpos[i]] = ecc_calc[i]; | 1256 | chip->oob_poi[eccpos[i]] = ecc_calc[i]; |
1215 | } | ||
1216 | 1257 | ||
1217 | chip->write_buf(mtd, buf, mtd->writesize); | 1258 | nand_write_page_raw(mtd, chip, buf); |
1218 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
1219 | } | 1259 | } |
1220 | 1260 | ||
1221 | /** | 1261 | /** |
@@ -1342,51 +1382,77 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
1342 | return 0; | 1382 | return 0; |
1343 | } | 1383 | } |
1344 | 1384 | ||
1385 | /** | ||
1386 | * nand_fill_oob - [Internal] Transfer client buffer to oob | ||
1387 | * @chip: nand chip structure | ||
1388 | * @oob: oob data buffer | ||
1389 | * @ops: oob ops structure | ||
1390 | */ | ||
1391 | static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, | ||
1392 | struct mtd_oob_ops *ops) | ||
1393 | { | ||
1394 | size_t len = ops->ooblen; | ||
1395 | |||
1396 | switch(ops->mode) { | ||
1397 | |||
1398 | case MTD_OOB_PLACE: | ||
1399 | case MTD_OOB_RAW: | ||
1400 | memcpy(chip->oob_poi + ops->ooboffs, oob, len); | ||
1401 | return oob + len; | ||
1402 | |||
1403 | case MTD_OOB_AUTO: { | ||
1404 | struct nand_oobfree *free = chip->ecc.layout->oobfree; | ||
1405 | size_t bytes; | ||
1406 | |||
1407 | for(; free->length && len; free++, len -= bytes) { | ||
1408 | bytes = min(len, free->length); | ||
1409 | memcpy(chip->oob_poi + free->offset, oob, bytes); | ||
1410 | oob += bytes; | ||
1411 | } | ||
1412 | return oob; | ||
1413 | } | ||
1414 | default: | ||
1415 | BUG(); | ||
1416 | } | ||
1417 | return NULL; | ||
1418 | } | ||
1419 | |||
1345 | #define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0 | 1420 | #define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0 |
1346 | 1421 | ||
1347 | /** | 1422 | /** |
1348 | * nand_write - [MTD Interface] NAND write with ECC | 1423 | * nand_do_write_ops - [Internal] NAND write with ECC |
1349 | * @mtd: MTD device structure | 1424 | * @mtd: MTD device structure |
1350 | * @to: offset to write to | 1425 | * @to: offset to write to |
1351 | * @len: number of bytes to write | 1426 | * @ops: oob operations description structure |
1352 | * @retlen: pointer to variable to store the number of written bytes | ||
1353 | * @buf: the data to write | ||
1354 | * | 1427 | * |
1355 | * NAND write with ECC | 1428 | * NAND write with ECC |
1356 | */ | 1429 | */ |
1357 | static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, | 1430 | static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, |
1358 | size_t *retlen, const uint8_t *buf) | 1431 | struct mtd_oob_ops *ops) |
1359 | { | 1432 | { |
1360 | int chipnr, realpage, page, blockmask; | 1433 | int chipnr, realpage, page, blockmask; |
1361 | struct nand_chip *chip = mtd->priv; | 1434 | struct nand_chip *chip = mtd->priv; |
1362 | uint32_t writelen = len; | 1435 | uint32_t writelen = ops->len; |
1436 | uint8_t *oob = ops->oobbuf; | ||
1437 | uint8_t *buf = ops->datbuf; | ||
1363 | int bytes = mtd->writesize; | 1438 | int bytes = mtd->writesize; |
1364 | int ret = -EIO; | 1439 | int ret; |
1365 | 1440 | ||
1366 | *retlen = 0; | 1441 | ops->retlen = 0; |
1367 | |||
1368 | /* Do not allow write past end of device */ | ||
1369 | if ((to + len) > mtd->size) { | ||
1370 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write: " | ||
1371 | "Attempt to write past end of page\n"); | ||
1372 | return -EINVAL; | ||
1373 | } | ||
1374 | 1442 | ||
1375 | /* reject writes, which are not page aligned */ | 1443 | /* reject writes, which are not page aligned */ |
1376 | if (NOTALIGNED(to) || NOTALIGNED(len)) { | 1444 | if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { |
1377 | printk(KERN_NOTICE "nand_write: " | 1445 | printk(KERN_NOTICE "nand_write: " |
1378 | "Attempt to write not page aligned data\n"); | 1446 | "Attempt to write not page aligned data\n"); |
1379 | return -EINVAL; | 1447 | return -EINVAL; |
1380 | } | 1448 | } |
1381 | 1449 | ||
1382 | if (!len) | 1450 | if (!writelen) |
1383 | return 0; | 1451 | return 0; |
1384 | 1452 | ||
1385 | nand_get_device(chip, mtd, FL_WRITING); | ||
1386 | |||
1387 | /* Check, if it is write protected */ | 1453 | /* Check, if it is write protected */ |
1388 | if (nand_check_wp(mtd)) | 1454 | if (nand_check_wp(mtd)) |
1389 | goto out; | 1455 | return -EIO; |
1390 | 1456 | ||
1391 | chipnr = (int)(to >> chip->chip_shift); | 1457 | chipnr = (int)(to >> chip->chip_shift); |
1392 | chip->select_chip(mtd, chipnr); | 1458 | chip->select_chip(mtd, chipnr); |
@@ -1397,7 +1463,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1397 | 1463 | ||
1398 | /* Invalidate the page cache, when we write to the cached page */ | 1464 | /* Invalidate the page cache, when we write to the cached page */ |
1399 | if (to <= (chip->pagebuf << chip->page_shift) && | 1465 | if (to <= (chip->pagebuf << chip->page_shift) && |
1400 | (chip->pagebuf << chip->page_shift) < (to + len)) | 1466 | (chip->pagebuf << chip->page_shift) < (to + ops->len)) |
1401 | chip->pagebuf = -1; | 1467 | chip->pagebuf = -1; |
1402 | 1468 | ||
1403 | chip->oob_poi = chip->buffers.oobwbuf; | 1469 | chip->oob_poi = chip->buffers.oobwbuf; |
@@ -1405,6 +1471,9 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1405 | while(1) { | 1471 | while(1) { |
1406 | int cached = writelen > bytes && page != blockmask; | 1472 | int cached = writelen > bytes && page != blockmask; |
1407 | 1473 | ||
1474 | if (unlikely(oob)) | ||
1475 | oob = nand_fill_oob(chip, oob, ops); | ||
1476 | |||
1408 | ret = nand_write_page(mtd, chip, buf, page, cached); | 1477 | ret = nand_write_page(mtd, chip, buf, page, cached); |
1409 | if (ret) | 1478 | if (ret) |
1410 | break; | 1479 | break; |
@@ -1424,94 +1493,74 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1424 | chip->select_chip(mtd, chipnr); | 1493 | chip->select_chip(mtd, chipnr); |
1425 | } | 1494 | } |
1426 | } | 1495 | } |
1427 | out: | 1496 | |
1428 | *retlen = len - writelen; | 1497 | if (unlikely(oob)) |
1429 | nand_release_device(mtd); | 1498 | memset(chip->oob_poi, 0xff, mtd->oobsize); |
1499 | |||
1500 | ops->retlen = ops->len - writelen; | ||
1430 | return ret; | 1501 | return ret; |
1431 | } | 1502 | } |
1432 | 1503 | ||
1433 | /** | 1504 | /** |
1434 | * nand_write_raw - [GENERIC] Write raw data including oob | 1505 | * nand_write - [MTD Interface] NAND write with ECC |
1435 | * @mtd: MTD device structure | 1506 | * @mtd: MTD device structure |
1436 | * @buf: source buffer | ||
1437 | * @to: offset to write to | 1507 | * @to: offset to write to |
1438 | * @len: number of bytes to write | 1508 | * @len: number of bytes to write |
1439 | * @buf: source buffer | 1509 | * @retlen: pointer to variable to store the number of written bytes |
1440 | * @oob: oob buffer | 1510 | * @buf: the data to write |
1441 | * | 1511 | * |
1442 | * Write raw data including oob | 1512 | * NAND write with ECC |
1443 | */ | 1513 | */ |
1444 | int nand_write_raw(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, | 1514 | static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, |
1445 | const uint8_t *buf, uint8_t *oob) | 1515 | size_t *retlen, const uint8_t *buf) |
1446 | { | 1516 | { |
1447 | struct nand_chip *chip = mtd->priv; | 1517 | struct nand_chip *chip = mtd->priv; |
1448 | int page = (int)(to >> chip->page_shift); | ||
1449 | int chipnr = (int)(to >> chip->chip_shift); | ||
1450 | int ret; | 1518 | int ret; |
1451 | 1519 | ||
1452 | *retlen = 0; | 1520 | /* Do not allow reads past end of device */ |
1453 | 1521 | if ((to + len) > mtd->size) | |
1454 | /* Do not allow writes past end of device */ | ||
1455 | if ((to + len) > mtd->size) { | ||
1456 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt write " | ||
1457 | "beyond end of device\n"); | ||
1458 | return -EINVAL; | 1522 | return -EINVAL; |
1459 | } | 1523 | if (!len) |
1524 | return 0; | ||
1460 | 1525 | ||
1461 | /* Grab the lock and see if the device is available */ | 1526 | nand_get_device(chip, mtd, FL_READING); |
1462 | nand_get_device(chip, mtd, FL_WRITING); | ||
1463 | 1527 | ||
1464 | chip->select_chip(mtd, chipnr); | 1528 | chip->ops.len = len; |
1465 | chip->oob_poi = oob; | 1529 | chip->ops.datbuf = (uint8_t *)buf; |
1530 | chip->ops.oobbuf = NULL; | ||
1466 | 1531 | ||
1467 | while (len != *retlen) { | 1532 | ret = nand_do_write_ops(mtd, to, &chip->ops); |
1468 | ret = nand_write_page(mtd, chip, buf, page, 0); | ||
1469 | if (ret) | ||
1470 | return ret; | ||
1471 | page++; | ||
1472 | *retlen += mtd->writesize; | ||
1473 | buf += mtd->writesize; | ||
1474 | chip->oob_poi += mtd->oobsize; | ||
1475 | } | ||
1476 | 1533 | ||
1477 | /* Deselect and wake up anyone waiting on the device */ | ||
1478 | nand_release_device(mtd); | 1534 | nand_release_device(mtd); |
1479 | return 0; | 1535 | |
1536 | *retlen = chip->ops.retlen; | ||
1537 | return ret; | ||
1480 | } | 1538 | } |
1481 | EXPORT_SYMBOL_GPL(nand_write_raw); | ||
1482 | 1539 | ||
1483 | /** | 1540 | /** |
1484 | * nand_write_oob - [MTD Interface] NAND write out-of-band | 1541 | * nand_do_write_oob - [MTD Interface] NAND write out-of-band |
1485 | * @mtd: MTD device structure | 1542 | * @mtd: MTD device structure |
1486 | * @to: offset to write to | 1543 | * @to: offset to write to |
1487 | * @len: number of bytes to write | 1544 | * @ops: oob operation description structure |
1488 | * @retlen: pointer to variable to store the number of written bytes | ||
1489 | * @buf: the data to write | ||
1490 | * | 1545 | * |
1491 | * NAND write out-of-band | 1546 | * NAND write out-of-band |
1492 | */ | 1547 | */ |
1493 | static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | 1548 | static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, |
1494 | size_t *retlen, const uint8_t *buf) | 1549 | struct mtd_oob_ops *ops) |
1495 | { | 1550 | { |
1496 | int column, page, status, ret = -EIO, chipnr; | 1551 | int chipnr, page, status; |
1497 | struct nand_chip *chip = mtd->priv; | 1552 | struct nand_chip *chip = mtd->priv; |
1498 | 1553 | ||
1499 | DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", | 1554 | DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", |
1500 | (unsigned int)to, (int)len); | 1555 | (unsigned int)to, (int)ops->len); |
1501 | |||
1502 | /* Initialize return length value */ | ||
1503 | *retlen = 0; | ||
1504 | 1556 | ||
1505 | /* Do not allow write past end of page */ | 1557 | /* Do not allow write past end of page */ |
1506 | column = to & (mtd->oobsize - 1); | 1558 | if ((ops->ooboffs + ops->len) > mtd->oobsize) { |
1507 | if ((column + len) > mtd->oobsize) { | ||
1508 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " | 1559 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " |
1509 | "Attempt to write past end of page\n"); | 1560 | "Attempt to write past end of page\n"); |
1510 | return -EINVAL; | 1561 | return -EINVAL; |
1511 | } | 1562 | } |
1512 | 1563 | ||
1513 | nand_get_device(chip, mtd, FL_WRITING); | ||
1514 | |||
1515 | chipnr = (int)(to >> chip->chip_shift); | 1564 | chipnr = (int)(to >> chip->chip_shift); |
1516 | chip->select_chip(mtd, chipnr); | 1565 | chip->select_chip(mtd, chipnr); |
1517 | 1566 | ||
@@ -1528,26 +1577,27 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1528 | 1577 | ||
1529 | /* Check, if it is write protected */ | 1578 | /* Check, if it is write protected */ |
1530 | if (nand_check_wp(mtd)) | 1579 | if (nand_check_wp(mtd)) |
1531 | goto out; | 1580 | return -EROFS; |
1532 | 1581 | ||
1533 | /* Invalidate the page cache, if we write to the cached page */ | 1582 | /* Invalidate the page cache, if we write to the cached page */ |
1534 | if (page == chip->pagebuf) | 1583 | if (page == chip->pagebuf) |
1535 | chip->pagebuf = -1; | 1584 | chip->pagebuf = -1; |
1536 | 1585 | ||
1537 | if (NAND_MUST_PAD(chip)) { | 1586 | if (ops->mode == MTD_OOB_AUTO || NAND_MUST_PAD(chip)) { |
1587 | chip->oob_poi = chip->buffers.oobwbuf; | ||
1588 | memset(chip->oob_poi, 0xff, mtd->oobsize); | ||
1589 | nand_fill_oob(chip, ops->oobbuf, ops); | ||
1538 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, | 1590 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, |
1539 | page & chip->pagemask); | 1591 | page & chip->pagemask); |
1540 | /* prepad 0xff for partial programming */ | 1592 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); |
1541 | chip->write_buf(mtd, ffchars, column); | 1593 | memset(chip->oob_poi, 0xff, mtd->oobsize); |
1542 | /* write data */ | ||
1543 | chip->write_buf(mtd, buf, len); | ||
1544 | /* postpad 0xff for partial programming */ | ||
1545 | chip->write_buf(mtd, ffchars, mtd->oobsize - (len + column)); | ||
1546 | } else { | 1594 | } else { |
1547 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize + column, | 1595 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, |
1596 | mtd->writesize + ops->ooboffs, | ||
1548 | page & chip->pagemask); | 1597 | page & chip->pagemask); |
1549 | chip->write_buf(mtd, buf, len); | 1598 | chip->write_buf(mtd, ops->oobbuf, ops->len); |
1550 | } | 1599 | } |
1600 | |||
1551 | /* Send command to program the OOB data */ | 1601 | /* Send command to program the OOB data */ |
1552 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | 1602 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); |
1553 | 1603 | ||
@@ -1557,27 +1607,75 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1557 | if (status & NAND_STATUS_FAIL) { | 1607 | if (status & NAND_STATUS_FAIL) { |
1558 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " | 1608 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " |
1559 | "Failed write, page 0x%08x\n", page); | 1609 | "Failed write, page 0x%08x\n", page); |
1560 | ret = -EIO; | 1610 | return -EIO; |
1561 | goto out; | ||
1562 | } | 1611 | } |
1563 | *retlen = len; | 1612 | ops->retlen = ops->len; |
1564 | 1613 | ||
1565 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE | 1614 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE |
1566 | /* Send command to read back the data */ | 1615 | if (ops->mode != MTD_OOB_AUTO) { |
1567 | chip->cmdfunc(mtd, NAND_CMD_READOOB, column, page & chip->pagemask); | 1616 | /* Send command to read back the data */ |
1617 | chip->cmdfunc(mtd, NAND_CMD_READOOB, ops->ooboffs, | ||
1618 | page & chip->pagemask); | ||
1568 | 1619 | ||
1569 | if (chip->verify_buf(mtd, buf, len)) { | 1620 | if (chip->verify_buf(mtd, ops->oobbuf, ops->len)) { |
1570 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " | 1621 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " |
1571 | "Failed write verify, page 0x%08x\n", page); | 1622 | "Failed write verify, page 0x%08x\n", page); |
1572 | ret = -EIO; | 1623 | return -EIO; |
1573 | goto out; | 1624 | } |
1574 | } | 1625 | } |
1575 | #endif | 1626 | #endif |
1576 | ret = 0; | 1627 | return 0; |
1628 | } | ||
1629 | |||
1630 | /** | ||
1631 | * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band | ||
1632 | * @mtd: MTD device structure | ||
1633 | * @from: offset to read from | ||
1634 | * @ops: oob operation description structure | ||
1635 | */ | ||
1636 | static int nand_write_oob(struct mtd_info *mtd, loff_t to, | ||
1637 | struct mtd_oob_ops *ops) | ||
1638 | { | ||
1639 | void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, | ||
1640 | const uint8_t *buf) = NULL; | ||
1641 | struct nand_chip *chip = mtd->priv; | ||
1642 | int ret = -ENOTSUPP; | ||
1643 | |||
1644 | ops->retlen = 0; | ||
1645 | |||
1646 | /* Do not allow writes past end of device */ | ||
1647 | if ((to + ops->len) > mtd->size) { | ||
1648 | DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " | ||
1649 | "Attempt read beyond end of device\n"); | ||
1650 | return -EINVAL; | ||
1651 | } | ||
1652 | |||
1653 | nand_get_device(chip, mtd, FL_READING); | ||
1654 | |||
1655 | switch(ops->mode) { | ||
1656 | case MTD_OOB_PLACE: | ||
1657 | case MTD_OOB_AUTO: | ||
1658 | break; | ||
1659 | |||
1660 | case MTD_OOB_RAW: | ||
1661 | /* Replace the write_page algorithm temporary */ | ||
1662 | write_page = chip->ecc.write_page; | ||
1663 | chip->ecc.write_page = nand_write_page_raw; | ||
1664 | break; | ||
1665 | |||
1666 | default: | ||
1667 | goto out; | ||
1668 | } | ||
1669 | |||
1670 | if (!ops->datbuf) | ||
1671 | ret = nand_do_write_oob(mtd, to, ops); | ||
1672 | else | ||
1673 | ret = nand_do_write_ops(mtd, to, ops); | ||
1674 | |||
1675 | if (unlikely(ops->mode == MTD_OOB_RAW)) | ||
1676 | chip->ecc.write_page = write_page; | ||
1577 | out: | 1677 | out: |
1578 | /* Deselect and wake up anyone waiting on the device */ | ||
1579 | nand_release_device(mtd); | 1678 | nand_release_device(mtd); |
1580 | |||
1581 | return ret; | 1679 | return ret; |
1582 | } | 1680 | } |
1583 | 1681 | ||
@@ -2191,8 +2289,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips) | |||
2191 | case NAND_ECC_NONE: | 2289 | case NAND_ECC_NONE: |
2192 | printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " | 2290 | printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " |
2193 | "This is not recommended !!\n"); | 2291 | "This is not recommended !!\n"); |
2194 | chip->ecc.read_page = nand_read_page_swecc; | 2292 | chip->ecc.read_page = nand_read_page_raw; |
2195 | chip->ecc.write_page = nand_write_page_swecc; | 2293 | chip->ecc.write_page = nand_write_page_raw; |
2196 | chip->ecc.size = mtd->writesize; | 2294 | chip->ecc.size = mtd->writesize; |
2197 | chip->ecc.bytes = 0; | 2295 | chip->ecc.bytes = 0; |
2198 | break; | 2296 | break; |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 40f99304df76..480c3cbf9bf9 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -230,6 +230,42 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
230 | return 0; | 230 | return 0; |
231 | } | 231 | } |
232 | 232 | ||
233 | /* | ||
234 | * Scan read raw data from flash | ||
235 | */ | ||
236 | static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, | ||
237 | size_t len) | ||
238 | { | ||
239 | struct mtd_oob_ops ops; | ||
240 | |||
241 | ops.mode = MTD_OOB_RAW; | ||
242 | ops.ooboffs = 0; | ||
243 | ops.ooblen = mtd->oobsize; | ||
244 | ops.oobbuf = buf; | ||
245 | ops.datbuf = buf; | ||
246 | ops.len = len; | ||
247 | |||
248 | return mtd->read_oob(mtd, offs, &ops); | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * Scan write data with oob to flash | ||
253 | */ | ||
254 | static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, | ||
255 | uint8_t *buf, uint8_t *oob) | ||
256 | { | ||
257 | struct mtd_oob_ops ops; | ||
258 | |||
259 | ops.mode = MTD_OOB_PLACE; | ||
260 | ops.ooboffs = 0; | ||
261 | ops.ooblen = mtd->oobsize; | ||
262 | ops.datbuf = buf; | ||
263 | ops.oobbuf = oob; | ||
264 | ops.len = len; | ||
265 | |||
266 | return mtd->write_oob(mtd, offs, &ops); | ||
267 | } | ||
268 | |||
233 | /** | 269 | /** |
234 | * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page | 270 | * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page |
235 | * @mtd: MTD device structure | 271 | * @mtd: MTD device structure |
@@ -241,27 +277,85 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
241 | * We assume that the bbt bits are in consecutive order. | 277 | * We assume that the bbt bits are in consecutive order. |
242 | * | 278 | * |
243 | */ | 279 | */ |
244 | static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) | 280 | static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, |
281 | struct nand_bbt_descr *td, struct nand_bbt_descr *md) | ||
245 | { | 282 | { |
246 | struct nand_chip *this = mtd->priv; | 283 | struct nand_chip *this = mtd->priv; |
247 | 284 | ||
248 | /* Read the primary version, if available */ | 285 | /* Read the primary version, if available */ |
249 | if (td->options & NAND_BBT_VERSION) { | 286 | if (td->options & NAND_BBT_VERSION) { |
250 | nand_read_raw(mtd, buf, td->pages[0] << this->page_shift, mtd->writesize, mtd->oobsize); | 287 | scan_read_raw(mtd, buf, td->pages[0] << this->page_shift, |
288 | mtd->writesize); | ||
251 | td->version[0] = buf[mtd->writesize + td->veroffs]; | 289 | td->version[0] = buf[mtd->writesize + td->veroffs]; |
252 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); | 290 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", |
291 | td->pages[0], td->version[0]); | ||
253 | } | 292 | } |
254 | 293 | ||
255 | /* Read the mirror version, if available */ | 294 | /* Read the mirror version, if available */ |
256 | if (md && (md->options & NAND_BBT_VERSION)) { | 295 | if (md && (md->options & NAND_BBT_VERSION)) { |
257 | nand_read_raw(mtd, buf, md->pages[0] << this->page_shift, mtd->writesize, mtd->oobsize); | 296 | scan_read_raw(mtd, buf, md->pages[0] << this->page_shift, |
297 | mtd->writesize); | ||
258 | md->version[0] = buf[mtd->writesize + md->veroffs]; | 298 | md->version[0] = buf[mtd->writesize + md->veroffs]; |
259 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); | 299 | printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", |
300 | md->pages[0], md->version[0]); | ||
260 | } | 301 | } |
261 | |||
262 | return 1; | 302 | return 1; |
263 | } | 303 | } |
264 | 304 | ||
305 | /* | ||
306 | * Scan a given block full | ||
307 | */ | ||
308 | static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, | ||
309 | loff_t offs, uint8_t *buf, size_t readlen, | ||
310 | int scanlen, int len) | ||
311 | { | ||
312 | int ret, j; | ||
313 | |||
314 | ret = scan_read_raw(mtd, buf, offs, readlen); | ||
315 | if (ret) | ||
316 | return ret; | ||
317 | |||
318 | for (j = 0; j < len; j++, buf += scanlen) { | ||
319 | if (check_pattern(buf, scanlen, mtd->writesize, bd)) | ||
320 | return 1; | ||
321 | } | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * Scan a given block partially | ||
327 | */ | ||
328 | static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, | ||
329 | loff_t offs, uint8_t *buf, int len) | ||
330 | { | ||
331 | struct mtd_oob_ops ops; | ||
332 | int j, ret; | ||
333 | |||
334 | ops.len = mtd->oobsize; | ||
335 | ops.ooblen = mtd->oobsize; | ||
336 | ops.oobbuf = buf; | ||
337 | ops.ooboffs = 0; | ||
338 | ops.datbuf = NULL; | ||
339 | ops.mode = MTD_OOB_PLACE; | ||
340 | |||
341 | for (j = 0; j < len; j++) { | ||
342 | /* | ||
343 | * Read the full oob until read_oob is fixed to | ||
344 | * handle single byte reads for 16 bit | ||
345 | * buswidth | ||
346 | */ | ||
347 | ret = mtd->read_oob(mtd, offs, &ops); | ||
348 | if (ret) | ||
349 | return ret; | ||
350 | |||
351 | if (check_short_pattern(buf, bd)) | ||
352 | return 1; | ||
353 | |||
354 | offs += mtd->writesize; | ||
355 | } | ||
356 | return 0; | ||
357 | } | ||
358 | |||
265 | /** | 359 | /** |
266 | * create_bbt - [GENERIC] Create a bad block table by scanning the device | 360 | * create_bbt - [GENERIC] Create a bad block table by scanning the device |
267 | * @mtd: MTD device structure | 361 | * @mtd: MTD device structure |
@@ -273,13 +367,14 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des | |||
273 | * Create a bad block table by scanning the device | 367 | * Create a bad block table by scanning the device |
274 | * for the given good/bad block identify pattern | 368 | * for the given good/bad block identify pattern |
275 | */ | 369 | */ |
276 | static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) | 370 | static int create_bbt(struct mtd_info *mtd, uint8_t *buf, |
371 | struct nand_bbt_descr *bd, int chip) | ||
277 | { | 372 | { |
278 | struct nand_chip *this = mtd->priv; | 373 | struct nand_chip *this = mtd->priv; |
279 | int i, j, numblocks, len, scanlen; | 374 | int i, numblocks, len, scanlen; |
280 | int startblock; | 375 | int startblock; |
281 | loff_t from; | 376 | loff_t from; |
282 | size_t readlen, ooblen; | 377 | size_t readlen; |
283 | 378 | ||
284 | printk(KERN_INFO "Scanning device for bad blocks\n"); | 379 | printk(KERN_INFO "Scanning device for bad blocks\n"); |
285 | 380 | ||
@@ -294,18 +389,17 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
294 | 389 | ||
295 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { | 390 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { |
296 | /* We need only read few bytes from the OOB area */ | 391 | /* We need only read few bytes from the OOB area */ |
297 | scanlen = ooblen = 0; | 392 | scanlen = 0; |
298 | readlen = bd->len; | 393 | readlen = bd->len; |
299 | } else { | 394 | } else { |
300 | /* Full page content should be read */ | 395 | /* Full page content should be read */ |
301 | scanlen = mtd->writesize + mtd->oobsize; | 396 | scanlen = mtd->writesize + mtd->oobsize; |
302 | readlen = len * mtd->writesize; | 397 | readlen = len * mtd->writesize; |
303 | ooblen = len * mtd->oobsize; | ||
304 | } | 398 | } |
305 | 399 | ||
306 | if (chip == -1) { | 400 | if (chip == -1) { |
307 | /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it | 401 | /* Note that numblocks is 2 * (real numblocks) here, see i+=2 |
308 | * makes shifting and masking less painful */ | 402 | * below as it makes shifting and masking less painful */ |
309 | numblocks = mtd->size >> (this->bbt_erase_shift - 1); | 403 | numblocks = mtd->size >> (this->bbt_erase_shift - 1); |
310 | startblock = 0; | 404 | startblock = 0; |
311 | from = 0; | 405 | from = 0; |
@@ -324,35 +418,21 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
324 | for (i = startblock; i < numblocks;) { | 418 | for (i = startblock; i < numblocks;) { |
325 | int ret; | 419 | int ret; |
326 | 420 | ||
327 | if (bd->options & NAND_BBT_SCANEMPTY) | 421 | if (bd->options & NAND_BBT_SCANALLPAGES) |
328 | if ((ret = nand_read_raw(mtd, buf, from, readlen, ooblen))) | 422 | ret = scan_block_full(mtd, bd, from, buf, readlen, |
329 | return ret; | 423 | scanlen, len); |
330 | 424 | else | |
331 | for (j = 0; j < len; j++) { | 425 | ret = scan_block_fast(mtd, bd, from, buf, len); |
332 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { | 426 | |
333 | size_t retlen; | 427 | if (ret < 0) |
334 | 428 | return ret; | |
335 | /* Read the full oob until read_oob is fixed to | 429 | |
336 | * handle single byte reads for 16 bit buswidth */ | 430 | if (ret) { |
337 | ret = mtd->read_oob(mtd, from + j * mtd->writesize, mtd->oobsize, &retlen, buf); | 431 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); |
338 | if (ret) | 432 | printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", |
339 | return ret; | 433 | i >> 1, (unsigned int)from); |
340 | |||
341 | if (check_short_pattern(buf, bd)) { | ||
342 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | ||
343 | printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | ||
344 | i >> 1, (unsigned int)from); | ||
345 | break; | ||
346 | } | ||
347 | } else { | ||
348 | if (check_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { | ||
349 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | ||
350 | printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | ||
351 | i >> 1, (unsigned int)from); | ||
352 | break; | ||
353 | } | ||
354 | } | ||
355 | } | 434 | } |
435 | |||
356 | i += 2; | 436 | i += 2; |
357 | from += (1 << this->bbt_erase_shift); | 437 | from += (1 << this->bbt_erase_shift); |
358 | } | 438 | } |
@@ -383,6 +463,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
383 | int bits, startblock, block, dir; | 463 | int bits, startblock, block, dir; |
384 | int scanlen = mtd->writesize + mtd->oobsize; | 464 | int scanlen = mtd->writesize + mtd->oobsize; |
385 | int bbtblocks; | 465 | int bbtblocks; |
466 | int blocktopage = this->bbt_erase_shift - this->page_shift; | ||
386 | 467 | ||
387 | /* Search direction top -> down ? */ | 468 | /* Search direction top -> down ? */ |
388 | if (td->options & NAND_BBT_LASTBLOCK) { | 469 | if (td->options & NAND_BBT_LASTBLOCK) { |
@@ -412,11 +493,14 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr | |||
412 | td->pages[i] = -1; | 493 | td->pages[i] = -1; |
413 | /* Scan the maximum number of blocks */ | 494 | /* Scan the maximum number of blocks */ |
414 | for (block = 0; block < td->maxblocks; block++) { | 495 | for (block = 0; block < td->maxblocks; block++) { |
496 | |||
415 | int actblock = startblock + dir * block; | 497 | int actblock = startblock + dir * block; |
498 | loff_t offs = actblock << this->bbt_erase_shift; | ||
499 | |||
416 | /* Read first page */ | 500 | /* Read first page */ |
417 | nand_read_raw(mtd, buf, actblock << this->bbt_erase_shift, mtd->writesize, mtd->oobsize); | 501 | scan_read_raw(mtd, buf, offs, mtd->writesize); |
418 | if (!check_pattern(buf, scanlen, mtd->writesize, td)) { | 502 | if (!check_pattern(buf, scanlen, mtd->writesize, td)) { |
419 | td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); | 503 | td->pages[i] = actblock << blocktopage; |
420 | if (td->options & NAND_BBT_VERSION) { | 504 | if (td->options & NAND_BBT_VERSION) { |
421 | td->version[i] = buf[mtd->writesize + td->veroffs]; | 505 | td->version[i] = buf[mtd->writesize + td->veroffs]; |
422 | } | 506 | } |
@@ -481,8 +565,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
481 | int nrchips, bbtoffs, pageoffs, ooboffs; | 565 | int nrchips, bbtoffs, pageoffs, ooboffs; |
482 | uint8_t msk[4]; | 566 | uint8_t msk[4]; |
483 | uint8_t rcode = td->reserved_block_code; | 567 | uint8_t rcode = td->reserved_block_code; |
484 | size_t retlen, len = 0, ooblen; | 568 | size_t retlen, len = 0; |
485 | loff_t to; | 569 | loff_t to; |
570 | struct mtd_oob_ops ops; | ||
571 | |||
572 | ops.ooblen = mtd->oobsize; | ||
573 | ops.ooboffs = 0; | ||
574 | ops.datbuf = NULL; | ||
575 | ops.mode = MTD_OOB_PLACE; | ||
486 | 576 | ||
487 | if (!rcode) | 577 | if (!rcode) |
488 | rcode = 0xff; | 578 | rcode = 0xff; |
@@ -583,10 +673,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
583 | "bad block table\n"); | 673 | "bad block table\n"); |
584 | } | 674 | } |
585 | /* Read oob data */ | 675 | /* Read oob data */ |
586 | ooblen = (len >> this->page_shift) * mtd->oobsize; | 676 | ops.len = (len >> this->page_shift) * mtd->oobsize; |
587 | res = mtd->read_oob(mtd, to + mtd->writesize, ooblen, | 677 | ops.oobbuf = &buf[len]; |
588 | &retlen, &buf[len]); | 678 | res = mtd->read_oob(mtd, to + mtd->writesize, &ops); |
589 | if (res < 0 || retlen != ooblen) | 679 | if (res < 0 || ops.retlen != ops.len) |
590 | goto outerr; | 680 | goto outerr; |
591 | 681 | ||
592 | /* Calc the byte offset in the buffer */ | 682 | /* Calc the byte offset in the buffer */ |
@@ -635,7 +725,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
635 | if (res < 0) | 725 | if (res < 0) |
636 | goto outerr; | 726 | goto outerr; |
637 | 727 | ||
638 | res = nand_write_raw(mtd, to, len, &retlen, buf, &buf[len]); | 728 | res = scan_write_bbt(mtd, to, len, buf, &buf[len]); |
639 | if (res < 0) | 729 | if (res < 0) |
640 | goto outerr; | 730 | goto outerr; |
641 | 731 | ||