aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/onenand/onenand_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/onenand/onenand_base.c')
-rw-r--r--drivers/mtd/onenand/onenand_base.c77
1 files changed, 51 insertions, 26 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 7f1cb6e5dccb..9e14a26ca4e8 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -4,6 +4,11 @@
4 * Copyright (C) 2005-2007 Samsung Electronics 4 * Copyright (C) 2005-2007 Samsung Electronics
5 * Kyungmin Park <kyungmin.park@samsung.com> 5 * Kyungmin Park <kyungmin.park@samsung.com>
6 * 6 *
7 * Credits:
8 * Adrian Hunter <ext-adrian.hunter@nokia.com>:
9 * auto-placement support, read-while load support, various fixes
10 * Copyright (C) Nokia Corporation, 2007
11 *
7 * This program is free software; you can redistribute it and/or modify 12 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 13 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation. 14 * published by the Free Software Foundation.
@@ -831,7 +836,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
831 int readcol = column; 836 int readcol = column;
832 int readend = column + thislen; 837 int readend = column + thislen;
833 int lastgap = 0; 838 int lastgap = 0;
834 uint8_t *oob_buf = this->page_buf + mtd->writesize; 839 uint8_t *oob_buf = this->oob_buf;
835 840
836 for (free = this->ecclayout->oobfree; free->length; ++free) { 841 for (free = this->ecclayout->oobfree; free->length; ++free) {
837 if (readcol >= lastgap) 842 if (readcol >= lastgap)
@@ -849,7 +854,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col
849 int n = ed - st; 854 int n = ed - st;
850 memcpy(buf, oob_buf + st, n); 855 memcpy(buf, oob_buf + st, n);
851 buf += n; 856 buf += n;
852 } 857 } else
858 break;
853 } 859 }
854 return 0; 860 return 0;
855} 861}
@@ -947,9 +953,9 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
947 953
948/** 954/**
949 * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band 955 * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band
950 * @mtd: MTD device structure 956 * @param mtd: MTD device structure
951 * @from: offset to read from 957 * @param from: offset to read from
952 * @ops: oob operation description structure 958 * @param ops: oob operation description structure
953 */ 959 */
954static int onenand_read_oob(struct mtd_info *mtd, loff_t from, 960static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
955 struct mtd_oob_ops *ops) 961 struct mtd_oob_ops *ops)
@@ -1017,7 +1023,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
1017 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan 1023 * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan
1018 * @param mtd MTD device structure 1024 * @param mtd MTD device structure
1019 * @param from offset to read from 1025 * @param from offset to read from
1020 * @param @ops oob operation description structure 1026 * @param ops oob operation description structure
1021 * 1027 *
1022 * OneNAND read out-of-band data from the spare area for bbt scan 1028 * OneNAND read out-of-band data from the spare area for bbt scan
1023 */ 1029 */
@@ -1093,7 +1099,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
1093static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) 1099static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
1094{ 1100{
1095 struct onenand_chip *this = mtd->priv; 1101 struct onenand_chip *this = mtd->priv;
1096 char *readp = this->page_buf + mtd->writesize; 1102 char oobbuf[64];
1097 int status, i; 1103 int status, i;
1098 1104
1099 this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); 1105 this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
@@ -1102,9 +1108,9 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
1102 if (status) 1108 if (status)
1103 return status; 1109 return status;
1104 1110
1105 this->read_bufferram(mtd, ONENAND_SPARERAM, readp, 0, mtd->oobsize); 1111 this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
1106 for(i = 0; i < mtd->oobsize; i++) 1112 for (i = 0; i < mtd->oobsize; i++)
1107 if (buf[i] != 0xFF && buf[i] != readp[i]) 1113 if (buf[i] != 0xFF && buf[i] != oobbuf[i])
1108 return -EBADMSG; 1114 return -EBADMSG;
1109 1115
1110 return 0; 1116 return 0;
@@ -1290,7 +1296,8 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1290 int n = ed - st; 1296 int n = ed - st;
1291 memcpy(oob_buf + st, buf, n); 1297 memcpy(oob_buf + st, buf, n);
1292 buf += n; 1298 buf += n;
1293 } 1299 } else
1300 break;
1294 } 1301 }
1295 return 0; 1302 return 0;
1296} 1303}
@@ -1312,6 +1319,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1312 struct onenand_chip *this = mtd->priv; 1319 struct onenand_chip *this = mtd->priv;
1313 int column, ret = 0, oobsize; 1320 int column, ret = 0, oobsize;
1314 int written = 0; 1321 int written = 0;
1322 u_char *oobbuf;
1315 1323
1316 DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); 1324 DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
1317 1325
@@ -1331,7 +1339,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1331 } 1339 }
1332 1340
1333 /* For compatibility with NAND: Do not allow write past end of page */ 1341 /* For compatibility with NAND: Do not allow write past end of page */
1334 if (column + len > oobsize) { 1342 if (unlikely(column + len > oobsize)) {
1335 printk(KERN_ERR "onenand_write_oob: " 1343 printk(KERN_ERR "onenand_write_oob: "
1336 "Attempt to write past end of page\n"); 1344 "Attempt to write past end of page\n");
1337 return -EINVAL; 1345 return -EINVAL;
@@ -1348,6 +1356,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1348 /* Grab the lock and see if the device is available */ 1356 /* Grab the lock and see if the device is available */
1349 onenand_get_device(mtd, FL_WRITING); 1357 onenand_get_device(mtd, FL_WRITING);
1350 1358
1359 oobbuf = this->oob_buf;
1360
1351 /* Loop until all data write */ 1361 /* Loop until all data write */
1352 while (written < len) { 1362 while (written < len) {
1353 int thislen = min_t(int, oobsize, len - written); 1363 int thislen = min_t(int, oobsize, len - written);
@@ -1358,12 +1368,12 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1358 1368
1359 /* We send data to spare ram with oobsize 1369 /* We send data to spare ram with oobsize
1360 * to prevent byte access */ 1370 * to prevent byte access */
1361 memset(this->page_buf, 0xff, mtd->oobsize); 1371 memset(oobbuf, 0xff, mtd->oobsize);
1362 if (mode == MTD_OOB_AUTO) 1372 if (mode == MTD_OOB_AUTO)
1363 onenand_fill_auto_oob(mtd, this->page_buf, buf, column, thislen); 1373 onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
1364 else 1374 else
1365 memcpy(this->page_buf + column, buf, thislen); 1375 memcpy(oobbuf + column, buf, thislen);
1366 this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize); 1376 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
1367 1377
1368 this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); 1378 this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
1369 1379
@@ -1375,7 +1385,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1375 break; 1385 break;
1376 } 1386 }
1377 1387
1378 ret = onenand_verify_oob(mtd, this->page_buf, to); 1388 ret = onenand_verify_oob(mtd, oobbuf, to);
1379 if (ret) { 1389 if (ret) {
1380 printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret); 1390 printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret);
1381 break; 1391 break;
@@ -1400,9 +1410,9 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
1400 1410
1401/** 1411/**
1402 * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band 1412 * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band
1403 * @mtd: MTD device structure 1413 * @param mtd: MTD device structure
1404 * @from: offset to read from 1414 * @param to: offset to write
1405 * @ops: oob operation description structure 1415 * @param ops: oob operation description structure
1406 */ 1416 */
1407static int onenand_write_oob(struct mtd_info *mtd, loff_t to, 1417static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
1408 struct mtd_oob_ops *ops) 1418 struct mtd_oob_ops *ops)
@@ -1616,6 +1626,7 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
1616 * @param mtd MTD device structure 1626 * @param mtd MTD device structure
1617 * @param ofs offset relative to mtd start 1627 * @param ofs offset relative to mtd start
1618 * @param len number of bytes to lock or unlock 1628 * @param len number of bytes to lock or unlock
1629 * @param cmd lock or unlock command
1619 * 1630 *
1620 * Lock or unlock one or more blocks 1631 * Lock or unlock one or more blocks
1621 */ 1632 */
@@ -2117,10 +2128,11 @@ static void onenand_check_features(struct mtd_info *mtd)
2117} 2128}
2118 2129
2119/** 2130/**
2120 * onenand_print_device_info - Print device ID 2131 * onenand_print_device_info - Print device & version ID
2121 * @param device device ID 2132 * @param device device ID
2133 * @param version version ID
2122 * 2134 *
2123 * Print device ID 2135 * Print device & version ID
2124 */ 2136 */
2125static void onenand_print_device_info(int device, int version) 2137static void onenand_print_device_info(int device, int version)
2126{ 2138{
@@ -2320,15 +2332,25 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
2320 2332
2321 /* Allocate buffers, if necessary */ 2333 /* Allocate buffers, if necessary */
2322 if (!this->page_buf) { 2334 if (!this->page_buf) {
2323 size_t len; 2335 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
2324 len = mtd->writesize + mtd->oobsize;
2325 this->page_buf = kmalloc(len, GFP_KERNEL);
2326 if (!this->page_buf) { 2336 if (!this->page_buf) {
2327 printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n"); 2337 printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
2328 return -ENOMEM; 2338 return -ENOMEM;
2329 } 2339 }
2330 this->options |= ONENAND_PAGEBUF_ALLOC; 2340 this->options |= ONENAND_PAGEBUF_ALLOC;
2331 } 2341 }
2342 if (!this->oob_buf) {
2343 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
2344 if (!this->oob_buf) {
2345 printk(KERN_ERR "onenand_scan(): Can't allocate oob_buf\n");
2346 if (this->options & ONENAND_PAGEBUF_ALLOC) {
2347 this->options &= ~ONENAND_PAGEBUF_ALLOC;
2348 kfree(this->page_buf);
2349 }
2350 return -ENOMEM;
2351 }
2352 this->options |= ONENAND_OOBBUF_ALLOC;
2353 }
2332 2354
2333 this->state = FL_READY; 2355 this->state = FL_READY;
2334 init_waitqueue_head(&this->wq); 2356 init_waitqueue_head(&this->wq);
@@ -2367,6 +2389,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
2367 for (i = 0; this->ecclayout->oobfree[i].length; i++) 2389 for (i = 0; this->ecclayout->oobfree[i].length; i++)
2368 this->ecclayout->oobavail += 2390 this->ecclayout->oobavail +=
2369 this->ecclayout->oobfree[i].length; 2391 this->ecclayout->oobfree[i].length;
2392 mtd->oobavail = this->ecclayout->oobavail;
2370 2393
2371 mtd->ecclayout = this->ecclayout; 2394 mtd->ecclayout = this->ecclayout;
2372 2395
@@ -2424,9 +2447,11 @@ void onenand_release(struct mtd_info *mtd)
2424 kfree(bbm->bbt); 2447 kfree(bbm->bbt);
2425 kfree(this->bbm); 2448 kfree(this->bbm);
2426 } 2449 }
2427 /* Buffer allocated by onenand_scan */ 2450 /* Buffers allocated by onenand_scan */
2428 if (this->options & ONENAND_PAGEBUF_ALLOC) 2451 if (this->options & ONENAND_PAGEBUF_ALLOC)
2429 kfree(this->page_buf); 2452 kfree(this->page_buf);
2453 if (this->options & ONENAND_OOBBUF_ALLOC)
2454 kfree(this->oob_buf);
2430} 2455}
2431 2456
2432EXPORT_SYMBOL_GPL(onenand_scan); 2457EXPORT_SYMBOL_GPL(onenand_scan);