|
@@ -206,6 +206,15 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
|
|
|
default:
|
|
|
block = (int) (addr >> this->erase_shift);
|
|
|
page = (int) (addr >> this->page_shift);
|
|
|
+
|
|
|
+ if (ONENAND_IS_2PLANE(this)) {
|
|
|
+ /* Make the even block number */
|
|
|
+ block &= ~1;
|
|
|
+ /* Is it the odd plane? */
|
|
|
+ if (addr & this->writesize)
|
|
|
+ block++;
|
|
|
+ page >>= 1;
|
|
|
+ }
|
|
|
page &= this->page_mask;
|
|
|
break;
|
|
|
}
|
|
@@ -216,8 +225,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
|
|
|
value = onenand_bufferram_address(this, block);
|
|
|
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
|
|
|
|
|
|
- /* Switch to the next data buffer */
|
|
|
- ONENAND_SET_NEXT_BUFFERRAM(this);
|
|
|
+ if (ONENAND_IS_2PLANE(this))
|
|
|
+ /* It is always BufferRAM0 */
|
|
|
+ ONENAND_SET_BUFFERRAM0(this);
|
|
|
+ else
|
|
|
+ /* Switch to the next data buffer */
|
|
|
+ ONENAND_SET_NEXT_BUFFERRAM(this);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -247,6 +260,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
+ if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
|
|
|
+ cmd = ONENAND_CMD_2X_PROG;
|
|
|
dataram = ONENAND_CURRENT_BUFFERRAM(this);
|
|
|
break;
|
|
|
}
|
|
@@ -445,8 +460,9 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
|
|
|
struct onenand_chip *this = mtd->priv;
|
|
|
|
|
|
if (ONENAND_CURRENT_BUFFERRAM(this)) {
|
|
|
+ /* Note: the 'this->writesize' is a real page size */
|
|
|
if (area == ONENAND_DATARAM)
|
|
|
- return mtd->writesize;
|
|
|
+ return this->writesize;
|
|
|
if (area == ONENAND_SPARERAM)
|
|
|
return mtd->oobsize;
|
|
|
}
|
|
@@ -571,6 +587,30 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode
|
|
|
+ * @param mtd MTD data structure
|
|
|
+ * @param addr address to check
|
|
|
+ * @return blockpage address
|
|
|
+ *
|
|
|
+ * Get blockpage address at 2x program mode
|
|
|
+ */
|
|
|
+static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr)
|
|
|
+{
|
|
|
+ struct onenand_chip *this = mtd->priv;
|
|
|
+ int blockpage, block, page;
|
|
|
+
|
|
|
+ /* Calculate the even block number */
|
|
|
+ block = (int) (addr >> this->erase_shift) & ~1;
|
|
|
+ /* Is it the odd plane? */
|
|
|
+ if (addr & this->writesize)
|
|
|
+ block++;
|
|
|
+ page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;
|
|
|
+ blockpage = (block << 7) | page;
|
|
|
+
|
|
|
+ return blockpage;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* onenand_check_bufferram - [GENERIC] Check BufferRAM information
|
|
|
* @param mtd MTD data structure
|
|
@@ -585,7 +625,10 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
|
|
|
int blockpage, found = 0;
|
|
|
unsigned int i;
|
|
|
|
|
|
- blockpage = (int) (addr >> this->page_shift);
|
|
|
+ if (ONENAND_IS_2PLANE(this))
|
|
|
+ blockpage = onenand_get_2x_blockpage(mtd, addr);
|
|
|
+ else
|
|
|
+ blockpage = (int) (addr >> this->page_shift);
|
|
|
|
|
|
/* Is there valid data? */
|
|
|
i = ONENAND_CURRENT_BUFFERRAM(this);
|
|
@@ -625,7 +668,10 @@ static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
|
|
|
int blockpage;
|
|
|
unsigned int i;
|
|
|
|
|
|
- blockpage = (int) (addr >> this->page_shift);
|
|
|
+ if (ONENAND_IS_2PLANE(this))
|
|
|
+ blockpage = onenand_get_2x_blockpage(mtd, addr);
|
|
|
+ else
|
|
|
+ blockpage = (int) (addr >> this->page_shift);
|
|
|
|
|
|
/* Invalidate another BufferRAM */
|
|
|
i = ONENAND_NEXT_BUFFERRAM(this);
|
|
@@ -734,6 +780,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|
|
int read = 0, column;
|
|
|
int thislen;
|
|
|
int ret = 0, boundary = 0;
|
|
|
+ int writesize = this->writesize;
|
|
|
|
|
|
DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
|
|
|
|
|
@@ -754,22 +801,22 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|
|
/* Do first load to bufferRAM */
|
|
|
if (read < len) {
|
|
|
if (!onenand_check_bufferram(mtd, from)) {
|
|
|
- this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
|
|
|
+ this->command(mtd, ONENAND_CMD_READ, from, writesize);
|
|
|
ret = this->wait(mtd, FL_READING);
|
|
|
onenand_update_bufferram(mtd, from, !ret);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- thislen = min_t(int, mtd->writesize, len - read);
|
|
|
- column = from & (mtd->writesize - 1);
|
|
|
- if (column + thislen > mtd->writesize)
|
|
|
- thislen = mtd->writesize - column;
|
|
|
+ thislen = min_t(int, writesize, len - read);
|
|
|
+ column = from & (writesize - 1);
|
|
|
+ if (column + thislen > writesize)
|
|
|
+ thislen = writesize - column;
|
|
|
|
|
|
while (!ret) {
|
|
|
/* If there is more to load then start next load */
|
|
|
from += thislen;
|
|
|
if (read + thislen < len) {
|
|
|
- this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
|
|
|
+ this->command(mtd, ONENAND_CMD_READ, from, writesize);
|
|
|
/*
|
|
|
* Chip boundary handling in DDP
|
|
|
* Now we issued chip 1 read and pointed chip 1
|
|
@@ -794,7 +841,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
|
|
|
this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
|
|
|
ONENAND_SET_NEXT_BUFFERRAM(this);
|
|
|
buf += thislen;
|
|
|
- thislen = min_t(int, mtd->writesize, len - read);
|
|
|
+ thislen = min_t(int, writesize, len - read);
|
|
|
column = 0;
|
|
|
cond_resched();
|
|
|
/* Now wait for load */
|
|
@@ -1079,7 +1126,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
|
|
|
/* Read more? */
|
|
|
if (read < len) {
|
|
|
/* Update Page size */
|
|
|
- from += mtd->writesize;
|
|
|
+ from += this->writesize;
|
|
|
column = 0;
|
|
|
}
|
|
|
}
|
|
@@ -1135,12 +1182,12 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
|
|
|
int thislen, column;
|
|
|
|
|
|
while (len != 0) {
|
|
|
- thislen = min_t(int, mtd->writesize, len);
|
|
|
- column = addr & (mtd->writesize - 1);
|
|
|
- if (column + thislen > mtd->writesize)
|
|
|
- thislen = mtd->writesize - column;
|
|
|
+ thislen = min_t(int, this->writesize, len);
|
|
|
+ column = addr & (this->writesize - 1);
|
|
|
+ if (column + thislen > this->writesize)
|
|
|
+ thislen = this->writesize - column;
|
|
|
|
|
|
- this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
|
|
|
+ this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
|
|
|
|
|
|
onenand_update_bufferram(mtd, addr, 0);
|
|
|
|
|
@@ -1236,6 +1283,10 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
|
|
|
/* In partial page write we don't update bufferram */
|
|
|
onenand_update_bufferram(mtd, to, !ret && !subpage);
|
|
|
+ if (ONENAND_IS_2PLANE(this)) {
|
|
|
+ ONENAND_SET_BUFFERRAM1(this);
|
|
|
+ onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
|
|
|
+ }
|
|
|
|
|
|
if (ret) {
|
|
|
printk(KERN_ERR "onenand_write: write filaed %d\n", ret);
|
|
@@ -1384,6 +1435,10 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
|
|
|
|
|
|
onenand_update_bufferram(mtd, to, 0);
|
|
|
+ if (ONENAND_IS_2PLANE(this)) {
|
|
|
+ ONENAND_SET_BUFFERRAM1(this);
|
|
|
+ onenand_update_bufferram(mtd, to + this->writesize, 0);
|
|
|
+ }
|
|
|
|
|
|
ret = this->wait(mtd, FL_WRITING);
|
|
|
if (ret) {
|
|
@@ -2107,6 +2162,7 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
|
|
|
*
|
|
|
* Check and set OneNAND features
|
|
|
* - lock scheme
|
|
|
+ * - two plane
|
|
|
*/
|
|
|
static void onenand_check_features(struct mtd_info *mtd)
|
|
|
{
|
|
@@ -2118,19 +2174,35 @@ static void onenand_check_features(struct mtd_info *mtd)
|
|
|
process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
|
|
|
|
|
|
/* Lock scheme */
|
|
|
- if (density >= ONENAND_DEVICE_DENSITY_1Gb) {
|
|
|
+ switch (density) {
|
|
|
+ case ONENAND_DEVICE_DENSITY_4Gb:
|
|
|
+ this->options |= ONENAND_HAS_2PLANE;
|
|
|
+
|
|
|
+ case ONENAND_DEVICE_DENSITY_2Gb:
|
|
|
+ /* 2Gb DDP don't have 2 plane */
|
|
|
+ if (!ONENAND_IS_DDP(this))
|
|
|
+ this->options |= ONENAND_HAS_2PLANE;
|
|
|
+ this->options |= ONENAND_HAS_UNLOCK_ALL;
|
|
|
+
|
|
|
+ case ONENAND_DEVICE_DENSITY_1Gb:
|
|
|
/* A-Die has all block unlock */
|
|
|
- if (process) {
|
|
|
- printk(KERN_DEBUG "Chip support all block unlock\n");
|
|
|
+ if (process)
|
|
|
this->options |= ONENAND_HAS_UNLOCK_ALL;
|
|
|
- }
|
|
|
- } else {
|
|
|
- /* Some OneNAND has continues lock scheme */
|
|
|
- if (!process) {
|
|
|
- printk(KERN_DEBUG "Lock scheme is Continues Lock\n");
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ /* Some OneNAND has continuous lock scheme */
|
|
|
+ if (!process)
|
|
|
this->options |= ONENAND_HAS_CONT_LOCK;
|
|
|
- }
|
|
|
+ break;
|
|
|
}
|
|
|
+
|
|
|
+ if (this->options & ONENAND_HAS_CONT_LOCK)
|
|
|
+ printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
|
|
|
+ if (this->options & ONENAND_HAS_UNLOCK_ALL)
|
|
|
+ printk(KERN_DEBUG "Chip support all block unlock\n");
|
|
|
+ if (this->options & ONENAND_HAS_2PLANE)
|
|
|
+ printk(KERN_DEBUG "Chip has 2 plane\n");
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -2257,6 +2329,8 @@ static int onenand_probe(struct mtd_info *mtd)
|
|
|
this->erase_shift = ffs(mtd->erasesize) - 1;
|
|
|
this->page_shift = ffs(mtd->writesize) - 1;
|
|
|
this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
|
|
|
+ /* It's real page size */
|
|
|
+ this->writesize = mtd->writesize;
|
|
|
|
|
|
/* REVIST: Multichip handling */
|
|
|
|
|
@@ -2265,6 +2339,17 @@ static int onenand_probe(struct mtd_info *mtd)
|
|
|
/* Check OneNAND features */
|
|
|
onenand_check_features(mtd);
|
|
|
|
|
|
+ /*
|
|
|
+ * We emulate the 4KiB page and 256KiB erase block size
|
|
|
+ * But oobsize is still 64 bytes.
|
|
|
+ * It is only valid if you turn on 2X program support,
|
|
|
+ * Otherwise it will be ignored by compiler.
|
|
|
+ */
|
|
|
+ if (ONENAND_IS_2PLANE(this)) {
|
|
|
+ mtd->writesize <<= 1;
|
|
|
+ mtd->erasesize <<= 1;
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|