aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/onenand/onenand_base.c145
1 files changed, 96 insertions, 49 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 529af271db1..30d6999e5f9 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1455,7 +1455,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
1455 struct mtd_oob_ops *ops) 1455 struct mtd_oob_ops *ops)
1456{ 1456{
1457 struct onenand_chip *this = mtd->priv; 1457 struct onenand_chip *this = mtd->priv;
1458 int written = 0, column, thislen, subpage; 1458 int written = 0, column, thislen = 0, subpage = 0;
1459 int prev = 0, prevlen = 0, prev_subpage = 0, first = 1;
1459 int oobwritten = 0, oobcolumn, thisooblen, oobsize; 1460 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1460 size_t len = ops->len; 1461 size_t len = ops->len;
1461 size_t ooblen = ops->ooblen; 1462 size_t ooblen = ops->ooblen;
@@ -1482,6 +1483,10 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
1482 return -EINVAL; 1483 return -EINVAL;
1483 } 1484 }
1484 1485
1486 /* Check zero length */
1487 if (!len)
1488 return 0;
1489
1485 if (ops->mode == MTD_OOB_AUTO) 1490 if (ops->mode == MTD_OOB_AUTO)
1486 oobsize = this->ecclayout->oobavail; 1491 oobsize = this->ecclayout->oobavail;
1487 else 1492 else
@@ -1492,79 +1497,121 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
1492 column = to & (mtd->writesize - 1); 1497 column = to & (mtd->writesize - 1);
1493 1498
1494 /* Loop until all data write */ 1499 /* Loop until all data write */
1495 while (written < len) { 1500 while (1) {
1496 u_char *wbuf = (u_char *) buf; 1501 if (written < len) {
1502 u_char *wbuf = (u_char *) buf;
1497 1503
1498 thislen = min_t(int, mtd->writesize - column, len - written); 1504 thislen = min_t(int, mtd->writesize - column, len - written);
1499 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten); 1505 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
1500 1506
1501 cond_resched(); 1507 cond_resched();
1502 1508
1503 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); 1509 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1504 1510
1505 /* Partial page write */ 1511 /* Partial page write */
1506 subpage = thislen < mtd->writesize; 1512 subpage = thislen < mtd->writesize;
1507 if (subpage) { 1513 if (subpage) {
1508 memset(this->page_buf, 0xff, mtd->writesize); 1514 memset(this->page_buf, 0xff, mtd->writesize);
1509 memcpy(this->page_buf + column, buf, thislen); 1515 memcpy(this->page_buf + column, buf, thislen);
1510 wbuf = this->page_buf; 1516 wbuf = this->page_buf;
1511 } 1517 }
1512 1518
1513 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); 1519 this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
1514 1520
1515 if (oob) { 1521 if (oob) {
1516 oobbuf = this->oob_buf; 1522 oobbuf = this->oob_buf;
1517 1523
1518 /* We send data to spare ram with oobsize 1524 /* We send data to spare ram with oobsize
1519 * to prevent byte access */ 1525 * to prevent byte access */
1520 memset(oobbuf, 0xff, mtd->oobsize); 1526 memset(oobbuf, 0xff, mtd->oobsize);
1521 if (ops->mode == MTD_OOB_AUTO) 1527 if (ops->mode == MTD_OOB_AUTO)
1522 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); 1528 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1523 else 1529 else
1524 memcpy(oobbuf + oobcolumn, oob, thisooblen); 1530 memcpy(oobbuf + oobcolumn, oob, thisooblen);
1525 1531
1526 oobwritten += thisooblen; 1532 oobwritten += thisooblen;
1527 oob += thisooblen; 1533 oob += thisooblen;
1528 oobcolumn = 0; 1534 oobcolumn = 0;
1535 } else
1536 oobbuf = (u_char *) ffchars;
1537
1538 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
1529 } else 1539 } else
1530 oobbuf = (u_char *) ffchars; 1540 ONENAND_SET_NEXT_BUFFERRAM(this);
1531 1541
1532 this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); 1542 /*
1543 * 2 PLANE, MLC, and Flex-OneNAND doesn't support
1544 * write-while-programe feature.
1545 */
1546 if (!ONENAND_IS_2PLANE(this) && !first) {
1547 ONENAND_SET_PREV_BUFFERRAM(this);
1533 1548
1534 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); 1549 ret = this->wait(mtd, FL_WRITING);
1535 1550
1536 ret = this->wait(mtd, FL_WRITING); 1551 /* In partial page write we don't update bufferram */
1552 onenand_update_bufferram(mtd, prev, !ret && !prev_subpage);
1553 if (ret) {
1554 written -= prevlen;
1555 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
1556 break;
1557 }
1537 1558
1538 /* In partial page write we don't update bufferram */ 1559 if (written == len) {
1539 onenand_update_bufferram(mtd, to, !ret && !subpage); 1560 /* Only check verify write turn on */
1540 if (ONENAND_IS_2PLANE(this)) { 1561 ret = onenand_verify(mtd, buf - len, to - len, len);
1541 ONENAND_SET_BUFFERRAM1(this); 1562 if (ret)
1542 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage); 1563 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
1543 } 1564 break;
1565 }
1544 1566
1545 if (ret) { 1567 ONENAND_SET_NEXT_BUFFERRAM(this);
1546 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
1547 break;
1548 } 1568 }
1549 1569
1550 /* Only check verify write turn on */ 1570 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
1551 ret = onenand_verify(mtd, buf, to, thislen);
1552 if (ret) {
1553 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
1554 break;
1555 }
1556 1571
1557 written += thislen; 1572 /*
1573 * 2 PLANE, MLC, and Flex-OneNAND wait here
1574 */
1575 if (ONENAND_IS_2PLANE(this)) {
1576 ret = this->wait(mtd, FL_WRITING);
1558 1577
1559 if (written == len) 1578 /* In partial page write we don't update bufferram */
1560 break; 1579 onenand_update_bufferram(mtd, to, !ret && !subpage);
1580 if (ret) {
1581 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
1582 break;
1583 }
1584
1585 /* Only check verify write turn on */
1586 ret = onenand_verify(mtd, buf, to, thislen);
1587 if (ret) {
1588 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
1589 break;
1590 }
1591
1592 written += thislen;
1593
1594 if (written == len)
1595 break;
1596
1597 } else
1598 written += thislen;
1561 1599
1562 column = 0; 1600 column = 0;
1601 prev_subpage = subpage;
1602 prev = to;
1603 prevlen = thislen;
1563 to += thislen; 1604 to += thislen;
1564 buf += thislen; 1605 buf += thislen;
1606 first = 0;
1565 } 1607 }
1566 1608
1609 /* In error case, clear all bufferrams */
1610 if (written != len)
1611 onenand_invalidate_bufferram(mtd, 0, -1);
1612
1567 ops->retlen = written; 1613 ops->retlen = written;
1614 ops->oobretlen = oobwritten;
1568 1615
1569 return ret; 1616 return ret;
1570} 1617}