aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyungmin Park <kyungmin.park@samsung.com>2007-06-30 00:57:49 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-06-30 03:24:57 -0400
commitee9745fcf214272b7cdd9d320d044cf433ee958e (patch)
tree340cbf42788ea9ea9f504eeb80efc12c5d1c11ed
parent1bddb9a8ba30dffa963c76283bc482b67fb90d8a (diff)
[MTD] [OneNAND] 2X program support
The 2X Program is an extension of Program Operation. Since the device is equipped with two DataRAMs, and two-plane NAND Flash memory array, these two component enables simultaneous program of 4KiB. Plane1 has only even blocks such as block0, block2, block4 while Plane2 has only odd blocks such as block1, block3, block5. So MTD regards it as 4KiB page size and 256KiB block size Now the following chips support it. (KFXXX16Q2M) Demux: KFG2G16Q2M, KFH4G16Q2M, KFW8G16Q2M, Mux: KFM2G16Q2M, KFN4G16Q2M, And more recent chips Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r--drivers/mtd/onenand/Kconfig16
-rw-r--r--drivers/mtd/onenand/onenand_base.c139
-rw-r--r--include/linux/mtd/onenand.h12
-rw-r--r--include/linux/mtd/onenand_regs.h4
4 files changed, 144 insertions, 27 deletions
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index c257d397d08a..64ec034c43c5 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -40,4 +40,20 @@ config MTD_ONENAND_OTP
40 40
41 OTP block is fully-guaranteed to be a valid block. 41 OTP block is fully-guaranteed to be a valid block.
42 42
43config MTD_ONENAND_2X_PROGRAM
44 bool "OneNAND 2X program support"
45 help
46 The 2X Program is an extension of Program Operation.
47 Since the device is equipped with two DataRAMs, and two-plane NAND
48 Flash memory array, these two component enables simultaneous program
49 of 4KiB. Plane1 has only even blocks such as block0, block2, block4
50 while Plane2 has only odd blocks such as block1, block3, block5.
51 So MTD regards it as 4KiB page size and 256KiB block size
52
53 Now the following chips support it. (KFXXX16Q2M)
54 Demux: KFG2G16Q2M, KFH4G16Q2M, KFW8G16Q2M,
55 Mux: KFM2G16Q2M, KFN4G16Q2M,
56
57 And more recent chips
58
43endif # MTD_ONENAND 59endif # MTD_ONENAND
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 0537fac8de74..7d194cfdb873 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -206,6 +206,15 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
206 default: 206 default:
207 block = (int) (addr >> this->erase_shift); 207 block = (int) (addr >> this->erase_shift);
208 page = (int) (addr >> this->page_shift); 208 page = (int) (addr >> this->page_shift);
209
210 if (ONENAND_IS_2PLANE(this)) {
211 /* Make the even block number */
212 block &= ~1;
213 /* Is it the odd plane? */
214 if (addr & this->writesize)
215 block++;
216 page >>= 1;
217 }
209 page &= this->page_mask; 218 page &= this->page_mask;
210 break; 219 break;
211 } 220 }
@@ -216,8 +225,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
216 value = onenand_bufferram_address(this, block); 225 value = onenand_bufferram_address(this, block);
217 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); 226 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
218 227
219 /* Switch to the next data buffer */ 228 if (ONENAND_IS_2PLANE(this))
220 ONENAND_SET_NEXT_BUFFERRAM(this); 229 /* It is always BufferRAM0 */
230 ONENAND_SET_BUFFERRAM0(this);
231 else
232 /* Switch to the next data buffer */
233 ONENAND_SET_NEXT_BUFFERRAM(this);
221 234
222 return 0; 235 return 0;
223 } 236 }
@@ -247,6 +260,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
247 break; 260 break;
248 261
249 default: 262 default:
263 if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
264 cmd = ONENAND_CMD_2X_PROG;
250 dataram = ONENAND_CURRENT_BUFFERRAM(this); 265 dataram = ONENAND_CURRENT_BUFFERRAM(this);
251 break; 266 break;
252 } 267 }
@@ -445,8 +460,9 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
445 struct onenand_chip *this = mtd->priv; 460 struct onenand_chip *this = mtd->priv;
446 461
447 if (ONENAND_CURRENT_BUFFERRAM(this)) { 462 if (ONENAND_CURRENT_BUFFERRAM(this)) {
463 /* Note: the 'this->writesize' is a real page size */
448 if (area == ONENAND_DATARAM) 464 if (area == ONENAND_DATARAM)
449 return mtd->writesize; 465 return this->writesize;
450 if (area == ONENAND_SPARERAM) 466 if (area == ONENAND_SPARERAM)
451 return mtd->oobsize; 467 return mtd->oobsize;
452 } 468 }
@@ -572,6 +588,30 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area,
572} 588}
573 589
574/** 590/**
591 * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode
592 * @param mtd MTD data structure
593 * @param addr address to check
594 * @return blockpage address
595 *
596 * Get blockpage address at 2x program mode
597 */
598static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr)
599{
600 struct onenand_chip *this = mtd->priv;
601 int blockpage, block, page;
602
603 /* Calculate the even block number */
604 block = (int) (addr >> this->erase_shift) & ~1;
605 /* Is it the odd plane? */
606 if (addr & this->writesize)
607 block++;
608 page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;
609 blockpage = (block << 7) | page;
610
611 return blockpage;
612}
613
614/**
575 * onenand_check_bufferram - [GENERIC] Check BufferRAM information 615 * onenand_check_bufferram - [GENERIC] Check BufferRAM information
576 * @param mtd MTD data structure 616 * @param mtd MTD data structure
577 * @param addr address to check 617 * @param addr address to check
@@ -585,7 +625,10 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
585 int blockpage, found = 0; 625 int blockpage, found = 0;
586 unsigned int i; 626 unsigned int i;
587 627
588 blockpage = (int) (addr >> this->page_shift); 628 if (ONENAND_IS_2PLANE(this))
629 blockpage = onenand_get_2x_blockpage(mtd, addr);
630 else
631 blockpage = (int) (addr >> this->page_shift);
589 632
590 /* Is there valid data? */ 633 /* Is there valid data? */
591 i = ONENAND_CURRENT_BUFFERRAM(this); 634 i = ONENAND_CURRENT_BUFFERRAM(this);
@@ -625,7 +668,10 @@ static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
625 int blockpage; 668 int blockpage;
626 unsigned int i; 669 unsigned int i;
627 670
628 blockpage = (int) (addr >> this->page_shift); 671 if (ONENAND_IS_2PLANE(this))
672 blockpage = onenand_get_2x_blockpage(mtd, addr);
673 else
674 blockpage = (int) (addr >> this->page_shift);
629 675
630 /* Invalidate another BufferRAM */ 676 /* Invalidate another BufferRAM */
631 i = ONENAND_NEXT_BUFFERRAM(this); 677 i = ONENAND_NEXT_BUFFERRAM(this);
@@ -734,6 +780,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
734 int read = 0, column; 780 int read = 0, column;
735 int thislen; 781 int thislen;
736 int ret = 0, boundary = 0; 782 int ret = 0, boundary = 0;
783 int writesize = this->writesize;
737 784
738 DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); 785 DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
739 786
@@ -754,22 +801,22 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
754 /* Do first load to bufferRAM */ 801 /* Do first load to bufferRAM */
755 if (read < len) { 802 if (read < len) {
756 if (!onenand_check_bufferram(mtd, from)) { 803 if (!onenand_check_bufferram(mtd, from)) {
757 this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); 804 this->command(mtd, ONENAND_CMD_READ, from, writesize);
758 ret = this->wait(mtd, FL_READING); 805 ret = this->wait(mtd, FL_READING);
759 onenand_update_bufferram(mtd, from, !ret); 806 onenand_update_bufferram(mtd, from, !ret);
760 } 807 }
761 } 808 }
762 809
763 thislen = min_t(int, mtd->writesize, len - read); 810 thislen = min_t(int, writesize, len - read);
764 column = from & (mtd->writesize - 1); 811 column = from & (writesize - 1);
765 if (column + thislen > mtd->writesize) 812 if (column + thislen > writesize)