diff options
author | Adrian Hunter <ext-adrian.hunter@nokia.com> | 2007-01-31 10:19:28 -0500 |
---|---|---|
committer | Kyungmin Park <kyungmin.park@samsung.com> | 2007-01-31 19:28:18 -0500 |
commit | a5e7c7b447270d42c3eb4d2259f74019aca9d007 (patch) | |
tree | b454389e425b43c36d23a579e5e2da55ab3f2b00 /drivers/mtd/onenand/onenand_base.c | |
parent | 9bfbc9b24f663b15149874a94a69ba89b3b7e44c (diff) |
[MTD] OneNAND: Add support for auto-placement of out-of-band data
Enable the use of oob operation mode MTD_OOB_AUTO with OneNAND.
Note that MTD_OOB_RAW is still not supported.
Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Diffstat (limited to 'drivers/mtd/onenand/onenand_base.c')
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 204 |
1 files changed, 169 insertions, 35 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index daf298948b9b..67efbc70019e 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -787,20 +787,60 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
787 | } | 787 | } |
788 | 788 | ||
789 | /** | 789 | /** |
790 | * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer | ||
791 | * @param mtd MTD device structure | ||
792 | * @param buf destination address | ||
793 | * @param column oob offset to read from | ||
794 | * @param thislen oob length to read | ||
795 | */ | ||
796 | static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, | ||
797 | int thislen) | ||
798 | { | ||
799 | struct onenand_chip *this = mtd->priv; | ||
800 | struct nand_oobfree *free; | ||
801 | int readcol = column; | ||
802 | int readend = column + thislen; | ||
803 | int lastgap = 0; | ||
804 | uint8_t *oob_buf = this->page_buf + mtd->writesize; | ||
805 | |||
806 | for (free = this->ecclayout->oobfree; free->length; ++free) { | ||
807 | if (readcol >= lastgap) | ||
808 | readcol += free->offset - lastgap; | ||
809 | if (readend >= lastgap) | ||
810 | readend += free->offset - lastgap; | ||
811 | lastgap = free->offset + free->length; | ||
812 | } | ||
813 | this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf + readcol, | ||
814 | readcol, readend - readcol); | ||
815 | for (free = this->ecclayout->oobfree; free->length; ++free) { | ||
816 | int free_end = free->offset + free->length; | ||
817 | if (free->offset < readend && free_end > readcol) { | ||
818 | int st = max_t(int,free->offset,readcol); | ||
819 | int ed = min_t(int,free_end,readend); | ||
820 | int n = ed - st; | ||
821 | memcpy(buf, oob_buf + st, n); | ||
822 | buf += n; | ||
823 | } | ||
824 | } | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | /** | ||
790 | * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band | 829 | * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band |
791 | * @param mtd MTD device structure | 830 | * @param mtd MTD device structure |
792 | * @param from offset to read from | 831 | * @param from offset to read from |
793 | * @param len number of bytes to read | 832 | * @param len number of bytes to read |
794 | * @param retlen pointer to variable to store the number of read bytes | 833 | * @param retlen pointer to variable to store the number of read bytes |
795 | * @param buf the databuffer to put data | 834 | * @param buf the databuffer to put data |
835 | * @param mode operation mode | ||
796 | * | 836 | * |
797 | * OneNAND read out-of-band data from the spare area | 837 | * OneNAND read out-of-band data from the spare area |
798 | */ | 838 | */ |
799 | int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | 839 | int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, |
800 | size_t *retlen, u_char *buf) | 840 | size_t *retlen, u_char *buf, mtd_oob_mode_t mode) |
801 | { | 841 | { |
802 | struct onenand_chip *this = mtd->priv; | 842 | struct onenand_chip *this = mtd->priv; |
803 | int read = 0, thislen, column; | 843 | int read = 0, thislen, column, oobsize; |
804 | int ret = 0; | 844 | int ret = 0; |
805 | 845 | ||
806 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | 846 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); |
@@ -808,21 +848,33 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | |||
808 | /* Initialize return length value */ | 848 | /* Initialize return length value */ |
809 | *retlen = 0; | 849 | *retlen = 0; |
810 | 850 | ||
851 | if (mode == MTD_OOB_AUTO) | ||
852 | oobsize = this->ecclayout->oobavail; | ||
853 | else | ||
854 | oobsize = mtd->oobsize; | ||
855 | |||
856 | column = from & (mtd->oobsize - 1); | ||
857 | |||
858 | if (unlikely(column >= oobsize)) { | ||
859 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempted to start read outside oob\n"); | ||
860 | return -EINVAL; | ||
861 | } | ||
862 | |||
811 | /* Do not allow reads past end of device */ | 863 | /* Do not allow reads past end of device */ |
812 | if (unlikely((from + len) > mtd->size)) { | 864 | if (unlikely(from >= mtd->size || |
813 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n"); | 865 | column + len > ((mtd->size >> this->page_shift) - |
866 | (from >> this->page_shift)) * oobsize)) { | ||
867 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempted to read beyond end of device\n"); | ||
814 | return -EINVAL; | 868 | return -EINVAL; |
815 | } | 869 | } |
816 | 870 | ||
817 | /* Grab the lock and see if the device is available */ | 871 | /* Grab the lock and see if the device is available */ |
818 | onenand_get_device(mtd, FL_READING); | 872 | onenand_get_device(mtd, FL_READING); |
819 | 873 | ||
820 | column = from & (mtd->oobsize - 1); | ||
821 | |||
822 | while (read < len) { | 874 | while (read < len) { |
823 | cond_resched(); | 875 | cond_resched(); |
824 | 876 | ||
825 | thislen = mtd->oobsize - column; | 877 | thislen = oobsize - column; |
826 | thislen = min_t(int, thislen, len); | 878 | thislen = min_t(int, thislen, len); |
827 | 879 | ||
828 | this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); | 880 | this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); |
@@ -832,7 +884,10 @@ int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, | |||
832 | ret = this->wait(mtd, FL_READING); | 884 | ret = this->wait(mtd, FL_READING); |
833 | /* First copy data and check return value for ECC handling */ | 885 | /* First copy data and check return value for ECC handling */ |
834 | 886 | ||
835 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | 887 | if (mode == MTD_OOB_AUTO) |
888 | onenand_transfer_auto_oob(mtd, buf, column, thislen); | ||
889 | else | ||
890 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | ||
836 | 891 | ||
837 | if (ret) { | 892 | if (ret) { |
838 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = 0x%x\n", ret); | 893 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = 0x%x\n", ret); |
@@ -871,10 +926,18 @@ out: | |||
871 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, | 926 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, |
872 | struct mtd_oob_ops *ops) | 927 | struct mtd_oob_ops *ops) |
873 | { | 928 | { |
874 | BUG_ON(ops->mode != MTD_OOB_PLACE); | 929 | switch (ops->mode) |
875 | 930 | { | |
931 | case MTD_OOB_PLACE: | ||
932 | case MTD_OOB_AUTO: | ||
933 | break; | ||
934 | case MTD_OOB_RAW: | ||
935 | return -EINVAL; /* Not implemented yet */ | ||
936 | default: | ||
937 | return -EINVAL; | ||
938 | } | ||
876 | return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen, | 939 | return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen, |
877 | &ops->oobretlen, ops->oobbuf); | 940 | &ops->oobretlen, ops->oobbuf, ops->mode); |
878 | } | 941 | } |
879 | 942 | ||
880 | #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE | 943 | #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE |
@@ -883,14 +946,12 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, | |||
883 | * @param mtd MTD device structure | 946 | * @param mtd MTD device structure |
884 | * @param buf the databuffer to verify | 947 | * @param buf the databuffer to verify |
885 | * @param to offset to read from | 948 | * @param to offset to read from |
886 | * @param len number of bytes to read and compare | ||
887 | * | 949 | * |
888 | */ | 950 | */ |
889 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to, int len) | 951 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) |
890 | { | 952 | { |
891 | struct onenand_chip *this = mtd->priv; | 953 | struct onenand_chip *this = mtd->priv; |
892 | char *readp = this->page_buf; | 954 | char *readp = this->page_buf + mtd->writesize; |
893 | int column = to & (mtd->oobsize - 1); | ||
894 | int status, i; | 955 | int status, i; |
895 | 956 | ||
896 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); | 957 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); |
@@ -899,9 +960,8 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to | |||
899 | if (status) | 960 | if (status) |
900 | return status; | 961 | return status; |
901 | 962 | ||
902 | this->read_bufferram(mtd, ONENAND_SPARERAM, readp, column, len); | 963 | this->read_bufferram(mtd, ONENAND_SPARERAM, readp, 0, mtd->oobsize); |
903 | 964 | for(i = 0; i < mtd->oobsize; i++) | |
904 | for(i = 0; i < len; i++) | ||
905 | if (buf[i] != 0xFF && buf[i] != readp[i]) | 965 | if (buf[i] != 0xFF && buf[i] != readp[i]) |
906 | return -EBADMSG; | 966 | return -EBADMSG; |
907 | 967 | ||
@@ -1060,20 +1120,59 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1060 | } | 1120 | } |
1061 | 1121 | ||
1062 | /** | 1122 | /** |
1123 | * onenand_fill_auto_oob - [Internal] oob auto-placement transfer | ||
1124 | * @param mtd MTD device structure | ||
1125 | * @param oob_buf oob buffer | ||
1126 | * @param buf source address | ||
1127 | * @param column oob offset to write to | ||
1128 | * @param thislen oob length to write | ||
1129 | */ | ||
1130 | static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, | ||
1131 | const u_char *buf, int column, int thislen) | ||
1132 | { | ||
1133 | struct onenand_chip *this = mtd->priv; | ||
1134 | struct nand_oobfree *free; | ||
1135 | int writecol = column; | ||
1136 | int writeend = column + thislen; | ||
1137 | int lastgap = 0; | ||
1138 | |||
1139 | for (free = this->ecclayout->oobfree; free->length; ++free) { | ||
1140 | if (writecol >= lastgap) | ||
1141 | writecol += free->offset - lastgap; | ||
1142 | if (writeend >= lastgap) | ||
1143 | writeend += free->offset - lastgap; | ||
1144 | lastgap = free->offset + free->length; | ||
1145 | } | ||
1146 | writeend = mtd->oobsize; | ||
1147 | for (free = this->ecclayout->oobfree; free->length; ++free) { | ||
1148 | int free_end = free->offset + free->length; | ||
1149 | if (free->offset < writeend && free_end > writecol) { | ||
1150 | int st = max_t(int,free->offset,writecol); | ||
1151 | int ed = min_t(int,free_end,writeend); | ||
1152 | int n = ed - st; | ||
1153 | memcpy(oob_buf + st, buf, n); | ||
1154 | buf += n; | ||
1155 | } | ||
1156 | } | ||
1157 | return 0; | ||
1158 | } | ||
1159 | |||
1160 | /** | ||
1063 | * onenand_do_write_oob - [Internal] OneNAND write out-of-band | 1161 | * onenand_do_write_oob - [Internal] OneNAND write out-of-band |
1064 | * @param mtd MTD device structure | 1162 | * @param mtd MTD device structure |
1065 | * @param to offset to write to | 1163 | * @param to offset to write to |
1066 | * @param len number of bytes to write | 1164 | * @param len number of bytes to write |
1067 | * @param retlen pointer to variable to store the number of written bytes | 1165 | * @param retlen pointer to variable to store the number of written bytes |
1068 | * @param buf the data to write | 1166 | * @param buf the data to write |
1167 | * @param mode operation mode | ||
1069 | * | 1168 | * |
1070 | * OneNAND write out-of-band | 1169 | * OneNAND write out-of-band |
1071 | */ | 1170 | */ |
1072 | static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | 1171 | static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, |
1073 | size_t *retlen, const u_char *buf) | 1172 | size_t *retlen, const u_char *buf, mtd_oob_mode_t mode) |
1074 | { | 1173 | { |
1075 | struct onenand_chip *this = mtd->priv; | 1174 | struct onenand_chip *this = mtd->priv; |
1076 | int column, ret = 0; | 1175 | int column, ret = 0, oobsize; |
1077 | int written = 0; | 1176 | int written = 0; |
1078 | 1177 | ||
1079 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | 1178 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
@@ -1081,9 +1180,23 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1081 | /* Initialize retlen, in case of early exit */ | 1180 | /* Initialize retlen, in case of early exit */ |
1082 | *retlen = 0; | 1181 | *retlen = 0; |
1083 | 1182 | ||
1084 | /* Do not allow writes past end of device */ | 1183 | if (mode == MTD_OOB_AUTO) |
1085 | if (unlikely((to + len) > mtd->size)) { | 1184 | oobsize = this->ecclayout->oobavail; |
1086 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n"); | 1185 | else |
1186 | oobsize = mtd->oobsize; | ||
1187 | |||
1188 | column = to & (mtd->oobsize - 1); | ||
1189 | |||
1190 | if (unlikely(column >= oobsize)) { | ||
1191 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempted to start write outside oob\n"); | ||
1192 | return -EINVAL; | ||
1193 | } | ||
1194 | |||
1195 | /* Do not allow reads past end of device */ | ||
1196 | if (unlikely(to >= mtd->size || | ||
1197 | column + len > ((mtd->size >> this->page_shift) - | ||
1198 | (to >> this->page_shift)) * oobsize)) { | ||
1199 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempted to write past end of device\n"); | ||
1087 | return -EINVAL; | 1200 | return -EINVAL; |
1088 | } | 1201 | } |
1089 | 1202 | ||
@@ -1092,18 +1205,19 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1092 | 1205 | ||
1093 | /* Loop until all data write */ | 1206 | /* Loop until all data write */ |
1094 | while (written < len) { | 1207 | while (written < len) { |
1095 | int thislen = min_t(int, mtd->oobsize, len - written); | 1208 | int thislen = min_t(int, oobsize, len - written); |
1096 | 1209 | ||
1097 | cond_resched(); | 1210 | cond_resched(); |
1098 | 1211 | ||
1099 | column = to & (mtd->oobsize - 1); | ||
1100 | |||
1101 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); | 1212 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); |
1102 | 1213 | ||
1103 | /* We send data to spare ram with oobsize | 1214 | /* We send data to spare ram with oobsize |
1104 | * to prevent byte access */ | 1215 | * to prevent byte access */ |
1105 | memset(this->page_buf, 0xff, mtd->oobsize); | 1216 | memset(this->page_buf, 0xff, mtd->oobsize); |
1106 | memcpy(this->page_buf + column, buf, thislen); | 1217 | if (mode == MTD_OOB_AUTO) |
1218 | onenand_fill_auto_oob(mtd, this->page_buf, buf, column, thislen); | ||
1219 | else | ||
1220 | memcpy(this->page_buf + column, buf, thislen); | ||
1107 | this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize); | 1221 | this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize); |
1108 | 1222 | ||
1109 | this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); | 1223 | this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); |
@@ -1112,11 +1226,11 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1112 | 1226 | ||
1113 | ret = this->wait(mtd, FL_WRITING); | 1227 | ret = this->wait(mtd, FL_WRITING); |
1114 | if (ret) { | 1228 | if (ret) { |
1115 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write filaed %d\n", ret); | 1229 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: write failed %d\n", ret); |
1116 | goto out; | 1230 | goto out; |
1117 | } | 1231 | } |
1118 | 1232 | ||
1119 | ret = onenand_verify_oob(mtd, buf, to, thislen); | 1233 | ret = onenand_verify_oob(mtd, this->page_buf, to); |
1120 | if (ret) { | 1234 | if (ret) { |
1121 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify failed %d\n", ret); | 1235 | DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: verify failed %d\n", ret); |
1122 | goto out; | 1236 | goto out; |
@@ -1127,8 +1241,9 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, | |||
1127 | if (written == len) | 1241 | if (written == len) |
1128 | break; | 1242 | break; |
1129 | 1243 | ||
1130 | to += thislen; | 1244 | to += mtd->writesize; |
1131 | buf += thislen; | 1245 | buf += thislen; |
1246 | column = 0; | ||
1132 | } | 1247 | } |
1133 | 1248 | ||
1134 | out: | 1249 | out: |
@@ -1149,10 +1264,18 @@ out: | |||
1149 | static int onenand_write_oob(struct mtd_info *mtd, loff_t to, | 1264 | static int onenand_write_oob(struct mtd_info *mtd, loff_t to, |
1150 | struct mtd_oob_ops *ops) | 1265 | struct mtd_oob_ops *ops) |
1151 | { | 1266 | { |
1152 | BUG_ON(ops->mode != MTD_OOB_PLACE); | 1267 | switch (ops->mode) |
1153 | 1268 | { | |
1269 | case MTD_OOB_PLACE: | ||
1270 | case MTD_OOB_AUTO: | ||
1271 | break; | ||
1272 | case MTD_OOB_RAW: | ||
1273 | return -EINVAL; /* Not implemented yet */ | ||
1274 | default: | ||
1275 | return -EINVAL; | ||
1276 | } | ||
1154 | return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen, | 1277 | return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen, |
1155 | &ops->oobretlen, ops->oobbuf); | 1278 | &ops->oobretlen, ops->oobbuf, ops->mode); |
1156 | } | 1279 | } |
1157 | 1280 | ||
1158 | /** | 1281 | /** |
@@ -1318,7 +1441,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
1318 | 1441 | ||
1319 | /* We write two bytes, so we dont have to mess with 16 bit access */ | 1442 | /* We write two bytes, so we dont have to mess with 16 bit access */ |
1320 | ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); | 1443 | ofs += mtd->oobsize + (bbm->badblockpos & ~0x01); |
1321 | return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf); | 1444 | return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf, MTD_OOB_PLACE); |
1322 | } | 1445 | } |
1323 | 1446 | ||
1324 | /** | 1447 | /** |
@@ -1612,7 +1735,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, | |||
1612 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); | 1735 | this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); |
1613 | this->wait(mtd, FL_OTPING); | 1736 | this->wait(mtd, FL_OTPING); |
1614 | 1737 | ||
1615 | ret = onenand_do_write_oob(mtd, from, len, retlen, buf); | 1738 | ret = onenand_do_write_oob(mtd, from, len, retlen, buf, MTD_OOB_PLACE); |
1616 | 1739 | ||
1617 | /* Exit OTP access mode */ | 1740 | /* Exit OTP access mode */ |
1618 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); | 1741 | this->command(mtd, ONENAND_CMD_RESET, 0, 0); |
@@ -2019,6 +2142,7 @@ static void onenand_resume(struct mtd_info *mtd) | |||
2019 | */ | 2142 | */ |
2020 | int onenand_scan(struct mtd_info *mtd, int maxchips) | 2143 | int onenand_scan(struct mtd_info *mtd, int maxchips) |
2021 | { | 2144 | { |
2145 | int i; | ||
2022 | struct onenand_chip *this = mtd->priv; | 2146 | struct onenand_chip *this = mtd->priv; |
2023 | 2147 | ||
2024 | if (!this->read_word) | 2148 | if (!this->read_word) |
@@ -2090,6 +2214,16 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
2090 | } | 2214 | } |
2091 | 2215 | ||
2092 | this->subpagesize = mtd->writesize >> mtd->subpage_sft; | 2216 | this->subpagesize = mtd->writesize >> mtd->subpage_sft; |
2217 | |||
2218 | /* | ||
2219 | * The number of bytes available for a client to place data into | ||
2220 | * the out of band area | ||
2221 | */ | ||
2222 | this->ecclayout->oobavail = 0; | ||
2223 | for (i = 0; this->ecclayout->oobfree[i].length; i++) | ||
2224 | this->ecclayout->oobavail += | ||
2225 | this->ecclayout->oobfree[i].length; | ||
2226 | |||
2093 | mtd->ecclayout = this->ecclayout; | 2227 | mtd->ecclayout = this->ecclayout; |
2094 | 2228 | ||
2095 | /* Fill in remaining MTD driver data */ | 2229 | /* Fill in remaining MTD driver data */ |