diff options
author | Kyungmin Park <kyungmin.park@samsung.com> | 2007-09-05 21:06:12 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2007-09-06 04:27:03 -0400 |
commit | d15057b7034d9fdc4259b66a0367c9d8ffcf0620 (patch) | |
tree | f558b496605b553ecf86a957a23e63f26d0b9e03 /drivers/mtd/onenand | |
parent | 12f77c9eed0d2a9f598500d9c1e3dd48883f1d0c (diff) |
[MTD] [OneNAND] main read/write ops support for yaffs2
Now we can use yaffs2 on OneNAND
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'drivers/mtd/onenand')
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 349 |
1 files changed, 233 insertions, 116 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 45bc1433b28d..40d8d6ff626b 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -763,31 +763,83 @@ static void onenand_release_device(struct mtd_info *mtd) | |||
763 | } | 763 | } |
764 | 764 | ||
765 | /** | 765 | /** |
766 | * onenand_read - [MTD Interface] Read data from flash | 766 | * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer |
767 | * @param mtd MTD device structure | ||
768 | * @param buf destination address | ||
769 | * @param column oob offset to read from | ||
770 | * @param thislen oob length to read | ||
771 | */ | ||
772 | static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, | ||
773 | int thislen) | ||
774 | { | ||
775 | struct onenand_chip *this = mtd->priv; | ||
776 | struct nand_oobfree *free; | ||
777 | int readcol = column; | ||
778 | int readend = column + thislen; | ||
779 | int lastgap = 0; | ||
780 | unsigned int i; | ||
781 | uint8_t *oob_buf = this->oob_buf; | ||
782 | |||
783 | free = this->ecclayout->oobfree; | ||
784 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
785 | if (readcol >= lastgap) | ||
786 | readcol += free->offset - lastgap; | ||
787 | if (readend >= lastgap) | ||
788 | readend += free->offset - lastgap; | ||
789 | lastgap = free->offset + free->length; | ||
790 | } | ||
791 | this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); | ||
792 | free = this->ecclayout->oobfree; | ||
793 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
794 | int free_end = free->offset + free->length; | ||
795 | if (free->offset < readend && free_end > readcol) { | ||
796 | int st = max_t(int,free->offset,readcol); | ||
797 | int ed = min_t(int,free_end,readend); | ||
798 | int n = ed - st; | ||
799 | memcpy(buf, oob_buf + st, n); | ||
800 | buf += n; | ||
801 | } else if (column == 0) | ||
802 | break; | ||
803 | } | ||
804 | return 0; | ||
805 | } | ||
806 | |||
807 | /** | ||
808 | * onenand_read_ops - [OneNAND Interface] OneNAND read main and/or out-of-band | ||
767 | * @param mtd MTD device structure | 809 | * @param mtd MTD device structure |
768 | * @param from offset to read from | 810 | * @param from offset to read from |
769 | * @param len number of bytes to read | 811 | * @param ops: oob operation description structure |
770 | * @param retlen pointer to variable to store the number of read bytes | ||
771 | * @param buf the databuffer to put data | ||
772 | * | 812 | * |
773 | * Read with ecc | 813 | * OneNAND read main and/or out-of-band data |
774 | */ | 814 | */ |
775 | static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | 815 | static int onenand_read_ops(struct mtd_info *mtd, loff_t from, |
776 | size_t *retlen, u_char *buf) | 816 | struct mtd_oob_ops *ops) |
777 | { | 817 | { |
778 | struct onenand_chip *this = mtd->priv; | 818 | struct onenand_chip *this = mtd->priv; |
779 | struct mtd_ecc_stats stats; | 819 | struct mtd_ecc_stats stats; |
780 | int read = 0, column; | 820 | size_t len = ops->len; |
781 | int thislen; | 821 | size_t ooblen = ops->ooblen; |
822 | u_char *buf = ops->datbuf; | ||
823 | u_char *oobbuf = ops->oobbuf; | ||
824 | int read = 0, column, thislen; | ||
825 | int oobread = 0, oobcolumn, thisooblen, oobsize; | ||
782 | int ret = 0, boundary = 0; | 826 | int ret = 0, boundary = 0; |
783 | int writesize = this->writesize; | 827 | int writesize = this->writesize; |
784 | 828 | ||
785 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | 829 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); |
830 | |||
831 | if (ops->mode == MTD_OOB_AUTO) | ||
832 | oobsize = this->ecclayout->oobavail; | ||
833 | else | ||
834 | oobsize = mtd->oobsize; | ||
835 | |||
836 | oobcolumn = from & (mtd->oobsize - 1); | ||
786 | 837 | ||
787 | /* Do not allow reads past end of device */ | 838 | /* Do not allow reads past end of device */ |
788 | if ((from + len) > mtd->size) { | 839 | if ((from + len) > mtd->size) { |
789 | printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n"); | 840 | printk(KERN_ERR "onenand_read_ops: Attempt read beyond end of device\n"); |
790 | *retlen = 0; | 841 | ops->retlen = 0; |
842 | ops->oobretlen = 0; | ||
791 | return -EINVAL; | 843 | return -EINVAL; |
792 | } | 844 | } |
793 | 845 | ||
@@ -832,6 +884,21 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
832 | } | 884 | } |
833 | /* While load is going, read from last bufferRAM */ | 885 | /* While load is going, read from last bufferRAM */ |
834 | this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); | 886 | this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); |
887 | |||
888 | /* Read oob area if needed */ | ||
889 | if (oobbuf) { | ||
890 | thisooblen = oobsize - oobcolumn; | ||
891 | thisooblen = min_t(int, thisooblen, ooblen - oobread); | ||
892 | |||
893 | if (ops->mode == MTD_OOB_AUTO) | ||
894 | onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); | ||
895 | else | ||
896 | this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); | ||
897 | oobread += thisooblen; | ||
898 | oobbuf += thisooblen; | ||
899 | oobcolumn = 0; | ||
900 | } | ||
901 | |||
835 | /* See if we are done */ | 902 | /* See if we are done */ |
836 | read += thislen; | 903 | read += thislen; |
837 | if (read == len) | 904 | if (read == len) |
@@ -857,7 +924,8 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
857 | * fs driver will take care of that, because | 924 | * fs driver will take care of that, because |
858 | * retlen == desired len and result == -EBADMSG | 925 | * retlen == desired len and result == -EBADMSG |
859 | */ | 926 | */ |
860 | *retlen = read; | 927 | ops->retlen = read; |
928 | ops->oobretlen = oobread; | ||
861 | 929 | ||
862 | if (mtd->ecc_stats.failed - stats.failed) | 930 | if (mtd->ecc_stats.failed - stats.failed) |
863 | return -EBADMSG; | 931 | return -EBADMSG; |
@@ -869,55 +937,10 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
869 | } | 937 | } |
870 | 938 | ||
871 | /** | 939 | /** |
872 | * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer | ||
873 | * @param mtd MTD device structure | ||
874 | * @param buf destination address | ||
875 | * @param column oob offset to read from | ||
876 | * @param thislen oob length to read | ||
877 | */ | ||
878 | static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, | ||
879 | int thislen) | ||
880 | { | ||
881 | struct onenand_chip *this = mtd->priv; | ||
882 | struct nand_oobfree *free; | ||
883 | int readcol = column; | ||
884 | int readend = column + thislen; | ||
885 | int lastgap = 0; | ||
886 | unsigned int i; | ||
887 | uint8_t *oob_buf = this->oob_buf; | ||
888 | |||
889 | free = this->ecclayout->oobfree; | ||
890 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
891 | if (readcol >= lastgap) | ||
892 | readcol += free->offset - lastgap; | ||
893 | if (readend >= lastgap) | ||
894 | readend += free->offset - lastgap; | ||
895 | lastgap = free->offset + free->length; | ||
896 | } | ||
897 | this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); | ||
898 | free = this->ecclayout->oobfree; | ||
899 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
900 | int free_end = free->offset + free->length; | ||
901 | if (free->offset < readend && free_end > readcol) { | ||
902 | int st = max_t(int,free->offset,readcol); | ||
903 | int ed = min_t(int,free_end,readend); | ||
904 | int n = ed - st; | ||
905 | memcpy(buf, oob_buf + st, n); | ||
906 | buf += n; | ||
907 | } else if (column == 0) | ||
908 | break; | ||
909 | } | ||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | /** | ||
914 | * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band | 940 | * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band |
915 | * @param mtd MTD device structure | 941 | * @param mtd MTD device structure |
916 | * @param from offset to read from | 942 | * @param from offset to read from |
917 | * @param len number of bytes to read | 943 | * @param ops: oob operation description structure |
918 | * @param retlen pointer to variable to store the number of read bytes | ||
919 | * @param buf the databuffer to put data | ||
920 | * @param mode operation mode | ||
921 | * | 944 | * |
922 | * OneNAND read out-of-band data from the spare area | 945 | * OneNAND read out-of-band data from the spare area |
923 | */ | 946 | */ |
@@ -1007,10 +1030,39 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1007 | } | 1030 | } |
1008 | 1031 | ||
1009 | /** | 1032 | /** |
1010 | * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band | 1033 | * onenand_read - [MTD Interface] Read data from flash |
1034 | * @param mtd MTD device structure | ||
1035 | * @param from offset to read from | ||
1036 | * @param len number of bytes to read | ||
1037 | * @param retlen pointer to variable to store the number of read bytes | ||
1038 | * @param buf the databuffer to put data | ||
1039 | * | ||
1040 | * Read with ecc | ||
1041 | */ | ||
1042 | static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
1043 | size_t *retlen, u_char *buf) | ||
1044 | { | ||
1045 | struct mtd_oob_ops ops = { | ||
1046 | .len = len, | ||
1047 | .ooblen = 0, | ||
1048 | .datbuf = buf, | ||
1049 | .oobbuf = NULL, | ||
1050 | }; | ||
1051 | int ret; | ||
1052 | |||
1053 | ret = onenand_read_ops(mtd, from, &ops); | ||
1054 | *retlen = ops.retlen; | ||
1055 | |||
1056 | return ret; | ||
1057 | } | ||
1058 | |||
1059 | /** | ||
1060 | * onenand_read_oob - [MTD Interface] Read main and/or out-of-band | ||
1011 | * @param mtd: MTD device structure | 1061 | * @param mtd: MTD device structure |
1012 | * @param from: offset to read from | 1062 | * @param from: offset to read from |
1013 | * @param ops: oob operation description structure | 1063 | * @param ops: oob operation description structure |
1064 | |||
1065 | * Read main and/or out-of-band | ||
1014 | */ | 1066 | */ |
1015 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, | 1067 | static int onenand_read_oob(struct mtd_info *mtd, loff_t from, |
1016 | struct mtd_oob_ops *ops) | 1068 | struct mtd_oob_ops *ops) |
@@ -1024,6 +1076,10 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, | |||
1024 | default: | 1076 | default: |
1025 | return -EINVAL; | 1077 | return -EINVAL; |
1026 | } | 1078 | } |
1079 | |||
1080 | if (ops->datbuf) | ||
1081 | return onenand_read_ops(mtd, from, ops); | ||
1082 | |||
1027 | return onenand_do_read_oob(mtd, from, ops); | 1083 | return onenand_do_read_oob(mtd, from, ops); |
1028 | } | 1084 | } |
1029 | 1085 | ||
@@ -1148,7 +1204,6 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, | |||
1148 | * @param mtd MTD device structure | 1204 | * @param mtd MTD device structure |
1149 | * @param buf the databuffer to verify | 1205 | * @param buf the databuffer to verify |
1150 | * @param to offset to read from | 1206 | * @param to offset to read from |
1151 | * | ||
1152 | */ | 1207 | */ |
1153 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) | 1208 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) |
1154 | { | 1209 | { |
@@ -1176,7 +1231,6 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to | |||
1176 | * @param buf the databuffer to verify | 1231 | * @param buf the databuffer to verify |
1177 | * @param addr offset to read from | 1232 | * @param addr offset to read from |
1178 | * @param len number of bytes to read and compare | 1233 | * @param len number of bytes to read and compare |
1179 | * | ||
1180 | */ | 1234 | */ |
1181 | static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len) | 1235 | static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len) |
1182 | { | 1236 | { |
@@ -1222,27 +1276,72 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, | |||
1222 | #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) | 1276 | #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) |
1223 | 1277 | ||
1224 | /** | 1278 | /** |
1225 | * onenand_write - [MTD Interface] write buffer to FLASH | 1279 | * onenand_fill_auto_oob - [Internal] oob auto-placement transfer |
1280 | * @param mtd MTD device structure | ||
1281 | * @param oob_buf oob buffer | ||
1282 | * @param buf source address | ||
1283 | * @param column oob offset to write to | ||
1284 | * @param thislen oob length to write | ||
1285 | */ | ||
1286 | static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, | ||
1287 | const u_char *buf, int column, int thislen) | ||
1288 | { | ||
1289 | struct onenand_chip *this = mtd->priv; | ||
1290 | struct nand_oobfree *free; | ||
1291 | int writecol = column; | ||
1292 | int writeend = column + thislen; | ||
1293 | int lastgap = 0; | ||
1294 | unsigned int i; | ||
1295 | |||
1296 | free = this->ecclayout->oobfree; | ||
1297 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
1298 | if (writecol >= lastgap) | ||
1299 | writecol += free->offset - lastgap; | ||
1300 | if (writeend >= lastgap) | ||
1301 | writeend += free->offset - lastgap; | ||
1302 | lastgap = free->offset + free->length; | ||
1303 | } | ||
1304 | free = this->ecclayout->oobfree; | ||
1305 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
1306 | int free_end = free->offset + free->length; | ||
1307 | if (free->offset < writeend && free_end > writecol) { | ||
1308 | int st = max_t(int,free->offset,writecol); | ||
1309 | int ed = min_t(int,free_end,writeend); | ||
1310 | int n = ed - st; | ||
1311 | memcpy(oob_buf + st, buf, n); | ||
1312 | buf += n; | ||
1313 | } else if (column == 0) | ||
1314 | break; | ||
1315 | } | ||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | /** | ||
1320 | * onenand_write_ops - [OneNAND Interface] write main and/or out-of-band | ||
1226 | * @param mtd MTD device structure | 1321 | * @param mtd MTD device structure |
1227 | * @param to offset to write to | 1322 | * @param to offset to write to |
1228 | * @param len number of bytes to write | 1323 | * @param ops oob operation description structure |
1229 | * @param retlen pointer to variable to store the number of written bytes | ||
1230 | * @param buf the data to write | ||
1231 | * | 1324 | * |
1232 | * Write with ECC | 1325 | * Write main and/or oob with ECC |
1233 | */ | 1326 | */ |
1234 | static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | 1327 | static int onenand_write_ops(struct mtd_info *mtd, loff_t to, |
1235 | size_t *retlen, const u_char *buf) | 1328 | struct mtd_oob_ops *ops) |
1236 | { | 1329 | { |
1237 | struct onenand_chip *this = mtd->priv; | 1330 | struct onenand_chip *this = mtd->priv; |
1238 | int written = 0; | 1331 | int written = 0, column, thislen, subpage; |
1332 | int oobwritten = 0, oobcolumn, thisooblen, oobsize; | ||
1333 | size_t len = ops->len; | ||
1334 | size_t ooblen = ops->ooblen; | ||
1335 | const u_char *buf = ops->datbuf; | ||
1336 | const u_char *oob = ops->oobbuf; | ||
1337 | u_char *oobbuf; | ||
1239 | int ret = 0; | 1338 | int ret = 0; |
1240 | int column, subpage; | ||
1241 | 1339 | ||
1242 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | 1340 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); |
1243 | 1341 | ||
1244 | /* Initialize retlen, in case of early exit */ | 1342 | /* Initialize retlen, in case of early exit */ |
1245 | *retlen = 0; | 1343 | ops->retlen = 0; |
1344 | ops->oobretlen = 0; | ||
1246 | 1345 | ||
1247 | /* Do not allow writes past end of device */ | 1346 | /* Do not allow writes past end of device */ |
1248 | if (unlikely((to + len) > mtd->size)) { | 1347 | if (unlikely((to + len) > mtd->size)) { |
@@ -1256,6 +1355,13 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1256 | return -EINVAL; | 1355 | return -EINVAL; |
1257 | } | 1356 | } |
1258 | 1357 | ||
1358 | if (ops->mode == MTD_OOB_AUTO) | ||
1359 | oobsize = this->ecclayout->oobavail; | ||
1360 | else | ||
1361 | oobsize = mtd->oobsize; | ||
1362 | |||
1363 | oobcolumn = to & (mtd->oobsize - 1); | ||
1364 | |||
1259 | column = to & (mtd->writesize - 1); | 1365 | column = to & (mtd->writesize - 1); |
1260 | 1366 | ||
1261 | /* Grab the lock and see if the device is available */ | 1367 | /* Grab the lock and see if the device is available */ |
@@ -1263,9 +1369,11 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1263 | 1369 | ||
1264 | /* Loop until all data write */ | 1370 | /* Loop until all data write */ |
1265 | while (written < len) { | 1371 | while (written < len) { |
1266 | int thislen = min_t(int, mtd->writesize - column, len - written); | ||
1267 | u_char *wbuf = (u_char *) buf; | 1372 | u_char *wbuf = (u_char *) buf; |
1268 | 1373 | ||
1374 | thislen = min_t(int, mtd->writesize - column, len - written); | ||
1375 | thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten); | ||
1376 | |||
1269 | cond_resched(); | 1377 | cond_resched(); |
1270 | 1378 | ||
1271 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); | 1379 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); |
@@ -1279,7 +1387,25 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1279 | } | 1387 | } |
1280 | 1388 | ||
1281 | this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); | 1389 | this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); |
1282 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | 1390 | |
1391 | if (oob) { | ||
1392 | oobbuf = this->oob_buf; | ||
1393 | |||
1394 | /* We send data to spare ram with oobsize | ||
1395 | * to prevent byte access */ | ||
1396 | memset(oobbuf, 0xff, mtd->oobsize); | ||
1397 | if (ops->mode == MTD_OOB_AUTO) | ||
1398 | onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); | ||
1399 | else | ||
1400 | memcpy(oobbuf + oobcolumn, oob, thisooblen); | ||
1401 | |||
1402 | oobwritten += thisooblen; | ||
1403 | oob += thisooblen; | ||
1404 | oobcolumn = 0; | ||
1405 | } else | ||
1406 | oobbuf = (u_char *) ffchars; | ||
1407 | |||
1408 | this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); | ||
1283 | 1409 | ||
1284 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); | 1410 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); |
1285 | 1411 | ||
@@ -1317,51 +1443,11 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1317 | /* Deselect and wake up anyone waiting on the device */ | 1443 | /* Deselect and wake up anyone waiting on the device */ |
1318 | onenand_release_device(mtd); | 1444 | onenand_release_device(mtd); |
1319 | 1445 | ||
1320 | *retlen = written; | 1446 | ops->retlen = written; |
1321 | 1447 | ||
1322 | return ret; | 1448 | return ret; |
1323 | } | 1449 | } |
1324 | 1450 | ||
1325 | /** | ||
1326 | * onenand_fill_auto_oob - [Internal] oob auto-placement transfer | ||
1327 | * @param mtd MTD device structure | ||
1328 | * @param oob_buf oob buffer | ||
1329 | * @param buf source address | ||
1330 | * @param column oob offset to write to | ||
1331 | * @param thislen oob length to write | ||
1332 | */ | ||
1333 | static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, | ||
1334 | const u_char *buf, int column, int thislen) | ||
1335 | { | ||
1336 | struct onenand_chip *this = mtd->priv; | ||
1337 | struct nand_oobfree *free; | ||
1338 | int writecol = column; | ||
1339 | int writeend = column + thislen; | ||
1340 | int lastgap = 0; | ||
1341 | unsigned int i; | ||
1342 | |||
1343 | free = this->ecclayout->oobfree; | ||
1344 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
1345 | if (writecol >= lastgap) | ||
1346 | writecol += free->offset - lastgap; | ||
1347 | if (writeend >= lastgap) | ||
1348 | writeend += free->offset - lastgap; | ||
1349 | lastgap = free->offset + free->length; | ||
1350 | } | ||
1351 | free = this->ecclayout->oobfree; | ||
1352 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
1353 | int free_end = free->offset + free->length; | ||
1354 | if (free->offset < writeend && free_end > writecol) { | ||
1355 | int st = max_t(int,free->offset,writecol); | ||
1356 | int ed = min_t(int,free_end,writeend); | ||
1357 | int n = ed - st; | ||
1358 | memcpy(oob_buf + st, buf, n); | ||
1359 | buf += n; | ||
1360 | } else if (column == 0) | ||
1361 | break; | ||
1362 | } | ||
1363 | return 0; | ||
1364 | } | ||
1365 | 1451 | ||
1366 | /** | 1452 | /** |
1367 | * onenand_do_write_oob - [Internal] OneNAND write out-of-band | 1453 | * onenand_do_write_oob - [Internal] OneNAND write out-of-band |
@@ -1479,6 +1565,33 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
1479 | } | 1565 | } |
1480 | 1566 | ||
1481 | /** | 1567 | /** |
1568 | * onenand_write - [MTD Interface] write buffer to FLASH | ||
1569 | * @param mtd MTD device structure | ||
1570 | * @param to offset to write to | ||
1571 | * @param len number of bytes to write | ||
1572 | * @param retlen pointer to variable to store the number of written bytes | ||
1573 | * @param buf the data to write | ||
1574 | * | ||
1575 | * Write with ECC | ||
1576 | */ | ||
1577 | static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
1578 | size_t *retlen, const u_char *buf) | ||
1579 | { | ||
1580 | struct mtd_oob_ops ops = { | ||
1581 | .len = len, | ||
1582 | .ooblen = 0, | ||
1583 | .datbuf = (u_char *) buf, | ||
1584 | .oobbuf = NULL, | ||
1585 | }; | ||
1586 | int ret; | ||
1587 | |||
1588 | ret = onenand_write_ops(mtd, to, &ops); | ||
1589 | *retlen = ops.retlen; | ||
1590 | |||
1591 | return ret; | ||
1592 | } | ||
1593 | |||
1594 | /** | ||
1482 | * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band | 1595 | * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band |
1483 | * @param mtd: MTD device structure | 1596 | * @param mtd: MTD device structure |
1484 | * @param to: offset to write | 1597 | * @param to: offset to write |
@@ -1496,6 +1609,10 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, | |||
1496 | default: | 1609 | default: |
1497 | return -EINVAL; | 1610 | return -EINVAL; |
1498 | } | 1611 | } |
1612 | |||
1613 | if (ops->datbuf) | ||
1614 | return onenand_write_ops(mtd, to, ops); | ||
1615 | |||
1499 | return onenand_do_write_oob(mtd, to, ops); | 1616 | return onenand_do_write_oob(mtd, to, ops); |
1500 | } | 1617 | } |
1501 | 1618 | ||