aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/onenand/onenand_base.c137
1 files changed, 118 insertions, 19 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 09aefe2164aa..8ed68b28afe3 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * linux/drivers/mtd/onenand/onenand_base.c 2 * linux/drivers/mtd/onenand/onenand_base.c
3 * 3 *
4 * Copyright (C) 2005 Samsung Electronics 4 * Copyright (C) 2005-2006 Samsung Electronics
5 * Kyungmin Park <kyungmin.park@samsung.com> 5 * Kyungmin Park <kyungmin.park@samsung.com>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
@@ -199,6 +199,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
199 case ONENAND_CMD_UNLOCK: 199 case ONENAND_CMD_UNLOCK:
200 case ONENAND_CMD_LOCK: 200 case ONENAND_CMD_LOCK:
201 case ONENAND_CMD_LOCK_TIGHT: 201 case ONENAND_CMD_LOCK_TIGHT:
202 case ONENAND_CMD_UNLOCK_ALL:
202 block = -1; 203 block = -1;
203 page = -1; 204 page = -1;
204 break; 205 break;
@@ -1211,11 +1212,11 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
1211 end = len >> this->erase_shift; 1212 end = len >> this->erase_shift;
1212 1213
1213 /* Continuous lock scheme */ 1214 /* Continuous lock scheme */
1214 if (this->options & ONENAND_CONT_LOCK) { 1215 if (this->options & ONENAND_HAS_CONT_LOCK) {
1215 /* Set start block address */ 1216 /* Set start block address */
1216 this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS); 1217 this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1217 /* Set end block address */ 1218 /* Set end block address */
1218 this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS); 1219 this->write_word(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
1219 /* Write unlock command */ 1220 /* Write unlock command */
1220 this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); 1221 this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
1221 1222
@@ -1236,7 +1237,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
1236 } 1237 }
1237 1238
1238 /* Block lock scheme */ 1239 /* Block lock scheme */
1239 for (block = start; block < end; block++) { 1240 for (block = start; block < start + end; block++) {
1240 /* Set block address */ 1241 /* Set block address */
1241 value = onenand_block_address(this, block); 1242 value = onenand_block_address(this, block);
1242 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); 1243 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
@@ -1265,6 +1266,79 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
1265 return 0; 1266 return 0;
1266} 1267}
1267 1268
1269/**
1270 * onenand_check_lock_status - [OneNAND Interface] Check lock status
1271 * @param this onenand chip data structure
1272 *
1273 * Check lock status
1274 */
1275static void onenand_check_lock_status(struct onenand_chip *this)
1276{
1277 unsigned int value, block, status;
1278 unsigned int end;
1279
1280 end = this->chipsize >> this->erase_shift;
1281 for (block = 0; block < end; block++) {
1282 /* Set block address */
1283 value = onenand_block_address(this, block);
1284 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
1285 /* Select DataRAM for DDP */
1286 value = onenand_bufferram_address(this, block);
1287 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
1288 /* Set start block address */
1289 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1290
1291 /* Check lock status */
1292 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1293 if (!(status & ONENAND_WP_US))
1294 printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
1295 }
1296}
1297
1298/**
1299 * onenand_unlock_all - [OneNAND Interface] unlock all blocks
1300 * @param mtd MTD device structure
1301 *
1302 * Unlock all blocks
1303 */
1304static int onenand_unlock_all(struct mtd_info *mtd)
1305{
1306 struct onenand_chip *this = mtd->priv;
1307
1308 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
1309 /* Write unlock command */
1310 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
1311
1312 /* There's no return value */
1313 this->wait(mtd, FL_UNLOCKING);
1314
1315 /* Sanity check */
1316 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1317 & ONENAND_CTRL_ONGO)
1318 continue;
1319
1320 /* Workaround for all block unlock in DDP */
1321 if (this->device_id & ONENAND_DEVICE_IS_DDP) {
1322 loff_t ofs;
1323 size_t len;
1324
1325 /* 1st block on another chip */
1326 ofs = this->chipsize >> 1;
1327 len = 1 << this->erase_shift;
1328
1329 onenand_unlock(mtd, ofs, len);
1330 }
1331
1332 onenand_check_lock_status(this);
1333
1334 return 0;
1335 }
1336
1337 mtd->unlock(mtd, 0x0, this->chipsize);
1338
1339 return 0;
1340}
1341
1268#ifdef CONFIG_MTD_ONENAND_OTP 1342#ifdef CONFIG_MTD_ONENAND_OTP
1269 1343
1270/* Interal OTP operation */ 1344/* Interal OTP operation */
@@ -1564,12 +1638,43 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
1564#endif /* CONFIG_MTD_ONENAND_OTP */ 1638#endif /* CONFIG_MTD_ONENAND_OTP */
1565 1639
1566/** 1640/**
1641 * onenand_lock_scheme - Check and set OneNAND lock scheme
1642 * @param mtd MTD data structure
1643 *
1644 * Check and set OneNAND lock scheme
1645 */
1646static void onenand_lock_scheme(struct mtd_info *mtd)
1647{
1648 struct onenand_chip *this = mtd->priv;
1649 unsigned int density, process;
1650
1651 /* Lock scheme depends on density and process */
1652 density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
1653 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
1654
1655 /* Lock scheme */
1656 if (density >= ONENAND_DEVICE_DENSITY_1Gb) {
1657 /* A-Die has all block unlock */
1658 if (process) {
1659 printk(KERN_DEBUG "Chip support all block unlock\n");
1660 this->options |= ONENAND_HAS_UNLOCK_ALL;
1661 }
1662 } else {
1663 /* Some OneNAND has continues lock scheme */
1664 if (!process) {
1665 printk(KERN_DEBUG "Lock scheme is Continues Lock\n");
1666 this->options |= ONENAND_HAS_CONT_LOCK;
1667 }
1668 }
1669}
1670
1671/**
1567 * onenand_print_device_info - Print device ID 1672 * onenand_print_device_info - Print device ID
1568 * @param device device ID 1673 * @param device device ID
1569 * 1674 *
1570 * Print device ID 1675 * Print device ID
1571 */ 1676 */
1572static void onenand_print_device_info(int device) 1677static void onenand_print_device_info(int device, int version)
1573{ 1678{
1574 int vcc, demuxed, ddp, density; 1679 int vcc, demuxed, ddp, density;
1575 1680
@@ -1583,6 +1688,7 @@ static void onenand_print_device_info(int device)
1583 (16 << density), 1688 (16 << density),
1584 vcc ? "2.65/3.3" : "1.8", 1689 vcc ? "2.65/3.3" : "1.8",
1585 device); 1690 device);
1691 printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version);
1586} 1692}
1587 1693
1588static const struct onenand_manufacturers onenand_manuf_ids[] = { 1694static const struct onenand_manufacturers onenand_manuf_ids[] = {
@@ -1625,8 +1731,7 @@ static int onenand_check_maf(int manuf)
1625static int onenand_probe(struct mtd_info *mtd) 1731static int onenand_probe(struct mtd_info *mtd)
1626{ 1732{
1627 struct onenand_chip *this = mtd->priv; 1733 struct onenand_chip *this = mtd->priv;
1628 int bram_maf_id, bram_dev_id, maf_id, dev_id; 1734 int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id;
1629 int version_id;
1630 int density; 1735 int density;
1631 int syscfg; 1736 int syscfg;
1632 1737
@@ -1657,14 +1762,16 @@ static int onenand_probe(struct mtd_info *mtd)
1657 /* Read manufacturer and device IDs from Register */ 1762 /* Read manufacturer and device IDs from Register */
1658 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); 1763 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
1659 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); 1764 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
1765 ver_id= this->read_word(this->base + ONENAND_REG_VERSION_ID);
1660 1766
1661 /* Check OneNAND device */ 1767 /* Check OneNAND device */
1662 if (maf_id != bram_maf_id || dev_id != bram_dev_id) 1768 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
1663 return -ENXIO; 1769 return -ENXIO;
1664 1770
1665 /* Flash device information */ 1771 /* Flash device information */
1666 onenand_print_device_info(dev_id); 1772 onenand_print_device_info(dev_id, ver_id);
1667 this->device_id = dev_id; 1773 this->device_id = dev_id;
1774 this->version_id = ver_id;
1668 1775
1669 density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; 1776 density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
1670 this->chipsize = (16 << density) << 20; 1777 this->chipsize = (16 << density) << 20;
@@ -1687,16 +1794,8 @@ static int onenand_probe(struct mtd_info *mtd)
1687 1794
1688 mtd->size = this->chipsize; 1795 mtd->size = this->chipsize;
1689 1796
1690 /* Version ID */ 1797 /* Check OneNAND lock scheme */
1691 version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); 1798 onenand_lock_scheme(mtd);
1692 printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id);
1693
1694 /* Lock scheme */
1695 if (density <= ONENAND_DEVICE_DENSITY_512Mb &&
1696 !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) {
1697 printk(KERN_INFO "Lock scheme is Continues Lock\n");
1698 this->options |= ONENAND_CONT_LOCK;
1699 }
1700 1799
1701 return 0; 1800 return 0;
1702} 1801}
@@ -1832,7 +1931,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
1832 mtd->owner = THIS_MODULE; 1931 mtd->owner = THIS_MODULE;
1833 1932
1834 /* Unlock whole block */ 1933 /* Unlock whole block */
1835 mtd->unlock(mtd, 0x0, this->chipsize); 1934 onenand_unlock_all(mtd);
1836 1935
1837 return this->scan_bbt(mtd); 1936 return this->scan_bbt(mtd);
1838} 1937}