aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorKyungmin Park <kyungmin.park@samsung.com>2007-09-05 21:06:12 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-09-06 04:27:03 -0400
commitd15057b7034d9fdc4259b66a0367c9d8ffcf0620 (patch)
treef558b496605b553ecf86a957a23e63f26d0b9e03 /drivers/mtd
parent12f77c9eed0d2a9f598500d9c1e3dd48883f1d0c (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')
-rw-r--r--drivers/mtd/onenand/onenand_base.c349
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 */
772static 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 */
775static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, 815static 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 */
878static 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*/
1042static 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 */
1015static int onenand_read_oob(struct mtd_info *mtd, loff_t from, 1067static 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 */
1153static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) 1208static 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 */
1181static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len) 1235static 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 */
1286static 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 */
1234static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, 1327static 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 */
1333static 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 */
1577static 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