aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/onenand
diff options
context:
space:
mode:
authorKyungmin Park <kyungmin.park@samsung.com>2006-05-12 10:03:07 -0400
committerJarkko Lavinen <lavinen@pentafluge.infradead.org>2006-05-12 10:35:50 -0400
commit493c646077ef0b8668ed71b8057f81cb7454af87 (patch)
treee05992a8d8c9ba911e5a9809dc0678ca50e96c76 /drivers/mtd/onenand
parent3cecf69ecde22199699c4f0e609dfed2a487b674 (diff)
OneNAND: One-Time Programmable (OTP) support
One Block of the NAND Flash Array memory is reserved as a One-Time Programmable Block memory area. Also, 1st Block of NAND Flash Array can be used as OTP. The OTP block can be read, programmed and locked using the same operations as any other NAND Flash Array memory block. OTP block cannot be erased. OTP block is fully-guaranteed to be a valid block. Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Diffstat (limited to 'drivers/mtd/onenand')
-rw-r--r--drivers/mtd/onenand/Kconfig14
-rw-r--r--drivers/mtd/onenand/onenand_base.c313
2 files changed, 324 insertions, 3 deletions
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index 126ff6bf63d5..5930a03736d7 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -29,6 +29,20 @@ config MTD_ONENAND_GENERIC
29 help 29 help
30 Support for OneNAND flash via platform device driver. 30 Support for OneNAND flash via platform device driver.
31 31
32config MTD_ONENAND_OTP
33 bool "OneNAND OTP Support"
34 depends on MTD_ONENAND
35 help
36 One Block of the NAND Flash Array memory is reserved as
37 a One-Time Programmable Block memory area.
38 Also, 1st Block of NAND Flash Array can be used as OTP.
39
40 The OTP block can be read, programmed and locked using the same
41 operations as any other NAND Flash Array memory block.
42 OTP block cannot be erased.
43
44 OTP block is fully-guaranteed to be a valid block.
45
32config MTD_ONENAND_SYNC_READ 46config MTD_ONENAND_SYNC_READ
33 bool "OneNAND Sync. Burst Read Support" 47 bool "OneNAND Sync. Burst Read Support"
34 depends on ARCH_OMAP 48 depends on ARCH_OMAP
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 7c7dc0ae5a19..163c81135447 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -191,7 +191,7 @@ static int onenand_buffer_address(int dataram1, int sectors, int count)
191static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) 191static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len)
192{ 192{
193 struct onenand_chip *this = mtd->priv; 193 struct onenand_chip *this = mtd->priv;
194 int value, readcmd = 0; 194 int value, readcmd = 0, block_cmd = 0;
195 int block, page; 195 int block, page;
196 /* Now we use page size operation */ 196 /* Now we use page size operation */
197 int sectors = 4, count = 4; 197 int sectors = 4, count = 4;
@@ -207,6 +207,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
207 207
208 case ONENAND_CMD_ERASE: 208 case ONENAND_CMD_ERASE:
209 case ONENAND_CMD_BUFFERRAM: 209 case ONENAND_CMD_BUFFERRAM:
210 case ONENAND_CMD_OTP_ACCESS:
211 block_cmd = 1;
210 block = (int) (addr >> this->erase_shift); 212 block = (int) (addr >> this->erase_shift);
211 page = -1; 213 page = -1;
212 break; 214 break;
@@ -235,7 +237,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
235 value = onenand_block_address(this, block); 237 value = onenand_block_address(this, block);
236 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); 238 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
237 239
238 if (cmd == ONENAND_CMD_ERASE) { 240 if (cmd == block_cmd) {
239 /* Select DataRAM for DDP */ 241 /* Select DataRAM for DDP */
240 value = onenand_bufferram_address(this, block); 242 value = onenand_bufferram_address(this, block);
241 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); 243 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
@@ -1412,6 +1414,304 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
1412 return 0; 1414 return 0;
1413} 1415}
1414 1416
1417#ifdef CONFIG_MTD_ONENAND_OTP
1418
1419/* Interal OTP operation */
1420typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len,
1421 size_t *retlen, u_char *buf);
1422
1423/**
1424 * do_otp_read - [DEFAULT] Read OTP block area
1425 * @param mtd MTD device structure
1426 * @param from The offset to read
1427 * @param len number of bytes to read
1428 * @param retlen pointer to variable to store the number of readbytes
1429 * @param buf the databuffer to put/get data
1430 *
1431 * Read OTP block area.
1432 */
1433static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
1434 size_t *retlen, u_char *buf)
1435{
1436 struct onenand_chip *this = mtd->priv;
1437 int ret;
1438
1439 /* Enter OTP access mode */
1440 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
1441 this->wait(mtd, FL_OTPING);
1442
1443 ret = mtd->read(mtd, from, len, retlen, buf);
1444
1445 /* Exit OTP access mode */
1446 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
1447 this->wait(mtd, FL_RESETING);
1448
1449 return ret;
1450}
1451
1452/**
1453 * do_otp_write - [DEFAULT] Write OTP block area
1454 * @param mtd MTD device structure
1455 * @param from The offset to write
1456 * @param len number of bytes to write
1457 * @param retlen pointer to variable to store the number of write bytes
1458 * @param buf the databuffer to put/get data
1459 *
1460 * Write OTP block area.
1461 */
1462static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
1463 size_t *retlen, u_char *buf)
1464{
1465 struct onenand_chip *this = mtd->priv;
1466 unsigned char *pbuf = buf;
1467 int ret;
1468
1469 /* Force buffer page aligned */
1470 if (len < mtd->oobblock) {
1471 memcpy(this->page_buf, buf, len);
1472 memset(this->page_buf + len, 0xff, mtd->oobblock - len);
1473 pbuf = this->page_buf;
1474 len = mtd->oobblock;
1475 }
1476
1477 /* Enter OTP access mode */
1478 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
1479 this->wait(mtd, FL_OTPING);
1480
1481 ret = mtd->write(mtd, from, len, retlen, pbuf);
1482
1483 /* Exit OTP access mode */
1484 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
1485 this->wait(mtd, FL_RESETING);
1486
1487 return ret;
1488}
1489
1490/**
1491 * do_otp_lock - [DEFAULT] Lock OTP block area
1492 * @param mtd MTD device structure
1493 * @param from The offset to lock
1494 * @param len number of bytes to lock
1495 * @param retlen pointer to variable to store the number of lock bytes
1496 * @param buf the databuffer to put/get data
1497 *
1498 * Lock OTP block area.
1499 */
1500static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
1501 size_t *retlen, u_char *buf)
1502{
1503 struct onenand_chip *this = mtd->priv;
1504 int ret;
1505
1506 /* Enter OTP access mode */
1507 this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
1508 this->wait(mtd, FL_OTPING);
1509
1510 ret = mtd->write_oob(mtd, from, len, retlen, buf);
1511
1512 /* Exit OTP access mode */
1513 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
1514 this->wait(mtd, FL_RESETING);
1515
1516 return ret;
1517}
1518
1519/**
1520 * onenand_otp_walk - [DEFAULT] Handle OTP operation
1521 * @param mtd MTD device structure
1522 * @param from The offset to read/write
1523 * @param len number of bytes to read/write
1524 * @param retlen pointer to variable to store the number of read bytes
1525 * @param buf the databuffer to put/get data
1526 * @param action do given action
1527 * @param mode specify user and factory
1528 *
1529 * Handle OTP operation.
1530 */
1531static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
1532 size_t *retlen, u_char *buf,
1533 otp_op_t action, int mode)
1534{
1535 struct onenand_chip *this = mtd->priv;
1536 int otp_pages;
1537 int density;
1538 int ret = 0;
1539
1540 *retlen = 0;
1541
1542 density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
1543 if (density < ONENAND_DEVICE_DENSITY_512Mb)
1544 otp_pages = 20;
1545 else
1546 otp_pages = 10;
1547
1548 if (mode == MTD_OTP_FACTORY) {
1549 from += mtd->oobblock * otp_pages;
1550 otp_pages = 64 - otp_pages;
1551 }
1552
1553 /* Check User/Factory boundary */
1554 if (((mtd->oobblock * otp_pages) - (from + len)) < 0)
1555 return 0;
1556
1557 while (len > 0 && otp_pages > 0) {
1558 if (!action) { /* OTP Info functions */
1559 struct otp_info *otpinfo;
1560
1561 len -= sizeof(struct otp_info);
1562 if (len <= 0)
1563 return -ENOSPC;
1564
1565 otpinfo = (struct otp_info *) buf;
1566 otpinfo->start = from;
1567 otpinfo->length = mtd->oobblock;
1568 otpinfo->locked = 0;
1569
1570 from += mtd->oobblock;
1571 buf += sizeof(struct otp_info);
1572 *retlen += sizeof(struct otp_info);
1573 } else {
1574 size_t tmp_retlen;
1575 int size = len;
1576
1577 ret = action(mtd, from, len, &tmp_retlen, buf);
1578
1579 buf += size;
1580 len -= size;
1581 *retlen += size;
1582
1583 if (ret < 0)
1584 return ret;
1585 }
1586 otp_pages--;
1587 }
1588
1589 return 0;
1590}
1591
1592/**
1593 * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info
1594 * @param mtd MTD device structure
1595 * @param buf the databuffer to put/get data
1596 * @param len number of bytes to read
1597 *
1598 * Read factory OTP info.
1599 */
1600static int onenand_get_fact_prot_info(struct mtd_info *mtd,
1601 struct otp_info *buf, size_t len)
1602{
1603 size_t retlen;
1604 int ret;
1605
1606 ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_FACTORY);
1607
1608 return ret ? : retlen;
1609}
1610
1611/**
1612 * onenand_read_fact_prot_reg - [MTD Interface] Read factory OTP area
1613 * @param mtd MTD device structure
1614 * @param from The offset to read
1615 * @param len number of bytes to read
1616 * @param retlen pointer to variable to store the number of read bytes
1617 * @param buf the databuffer to put/get data
1618 *
1619 * Read factory OTP area.
1620 */
1621static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
1622 size_t len, size_t *retlen, u_char *buf)
1623{
1624 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_FACTORY);
1625}
1626
1627/**
1628 * onenand_get_user_prot_info - [MTD Interface] Read user OTP info
1629 * @param mtd MTD device structure
1630 * @param buf the databuffer to put/get data
1631 * @param len number of bytes to read
1632 *
1633 * Read user OTP info.
1634 */
1635static int onenand_get_user_prot_info(struct mtd_info *mtd,
1636 struct otp_info *buf, size_t len)
1637{
1638 size_t retlen;
1639 int ret;
1640
1641 ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_USER);
1642
1643 return ret ? : retlen;
1644}
1645
1646/**
1647 * onenand_read_user_prot_reg - [MTD Interface] Read user OTP area
1648 * @param mtd MTD device structure
1649 * @param from The offset to read
1650 * @param len number of bytes to read
1651 * @param retlen pointer to variable to store the number of read bytes
1652 * @param buf the databuffer to put/get data
1653 *
1654 * Read user OTP area.
1655 */
1656static int onenand_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
1657 size_t len, size_t *retlen, u_char *buf)
1658{
1659 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_read, MTD_OTP_USER);
1660}
1661
1662/**
1663 * onenand_write_user_prot_reg - [MTD Interface] Write user OTP area
1664 * @param mtd MTD device structure
1665 * @param from The offset to write
1666 * @param len number of bytes to write
1667 * @param retlen pointer to variable to store the number of write bytes
1668 * @param buf the databuffer to put/get data
1669 *
1670 * Write user OTP area.
1671 */
1672static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
1673 size_t len, size_t *retlen, u_char *buf)
1674{
1675 return onenand_otp_walk(mtd, from, len, retlen, buf, do_otp_write, MTD_OTP_USER);
1676}
1677
1678/**
1679 * onenand_lock_user_prot_reg - [MTD Interface] Lock user OTP area
1680 * @param mtd MTD device structure
1681 * @param from The offset to lock
1682 * @param len number of bytes to unlock
1683 *
1684 * Write lock mark on spare area in page 0 in OTP block
1685 */
1686static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
1687 size_t len)
1688{
1689 unsigned char oob_buf[64];
1690 size_t retlen;
1691 int ret;
1692
1693 memset(oob_buf, 0xff, mtd->oobsize);
1694 /*
1695 * Note: OTP lock operation
1696 * OTP block : 0xXXFC
1697 * 1st block : 0xXXF3 (If chip support)
1698 * Both : 0xXXF0 (If chip support)
1699 */
1700 oob_buf[ONENAND_OTP_LOCK_OFFSET] = 0xFC;
1701
1702 /*
1703 * Write lock mark to 8th word of sector0 of page0 of the spare0.
1704 * We write 16 bytes spare area instead of 2 bytes.
1705 */
1706 from = 0;
1707 len = 16;
1708
1709 ret = onenand_otp_walk(mtd, from, len, &retlen, oob_buf, do_otp_lock, MTD_OTP_USER);
1710
1711 return ret ? : retlen;
1712}
1713#endif /* CONFIG_MTD_ONENAND_OTP */
1714
1415/** 1715/**
1416 * onenand_print_device_info - Print device ID 1716 * onenand_print_device_info - Print device ID
1417 * @param device device ID 1717 * @param device device ID
@@ -1563,7 +1863,6 @@ static void onenand_resume(struct mtd_info *mtd)
1563 "in suspended state\n"); 1863 "in suspended state\n");
1564} 1864}
1565 1865
1566
1567/** 1866/**
1568 * onenand_scan - [OneNAND Interface] Scan for the OneNAND device 1867 * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
1569 * @param mtd MTD device structure 1868 * @param mtd MTD device structure
@@ -1655,6 +1954,14 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
1655 mtd->write_ecc = onenand_write_ecc; 1954 mtd->write_ecc = onenand_write_ecc;
1656 mtd->read_oob = onenand_read_oob; 1955 mtd->read_oob = onenand_read_oob;
1657 mtd->write_oob = onenand_write_oob; 1956 mtd->write_oob = onenand_write_oob;
1957#ifdef CONFIG_MTD_ONENAND_OTP
1958 mtd->get_fact_prot_info = onenand_get_fact_prot_info;
1959 mtd->read_fact_prot_reg = onenand_read_fact_prot_reg;
1960 mtd->get_user_prot_info = onenand_get_user_prot_info;
1961 mtd->read_user_prot_reg = onenand_read_user_prot_reg;
1962 mtd->write_user_prot_reg = onenand_write_user_prot_reg;
1963 mtd->lock_user_prot_reg = onenand_lock_user_prot_reg;
1964#endif
1658 mtd->readv = NULL; 1965 mtd->readv = NULL;
1659 mtd->readv_ecc = NULL; 1966 mtd->readv_ecc = NULL;
1660 mtd->writev = onenand_writev; 1967 mtd->writev = onenand_writev;