aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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 /drivers
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/onenand/Kconfig16
-rw-r--r--drivers/mtd/onenand/onenand_base.c139
2 files changed, 128 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)
766 thislen = mtd->writesize - column; 813 thislen = writesize - column;
767 814
768 while (!ret) { 815 while (!ret) {
769 /* If there is more to load then start next load */ 816 /* If there is more to load then start next load */
770 from += thislen; 817 from += thislen;
771 if (read + thislen < len) { 818 if (read + thislen < len) {
772 this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize); 819 this->command(mtd, ONENAND_CMD_READ, from, writesize);
773 /* 820 /*
774 * Chip boundary handling in DDP 821 * Chip boundary handling in DDP
775 * Now we issued chip 1 read and pointed chip 1 822 * 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,
794 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2); 841 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
795 ONENAND_SET_NEXT_BUFFERRAM(this); 842 ONENAND_SET_NEXT_BUFFERRAM(this);
796 buf += thislen; 843 buf += thislen;
797 thislen = min_t(int, mtd->writesize, len - read); 844 thislen = min_t(int, writesize, len - read);
798 column = 0; 845 column = 0;
799 cond_resched(); 846 cond_resched();
800 /* Now wait for load */ 847 /* Now wait for load */
@@ -1079,7 +1126,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
1079 /* Read more? */ 1126 /* Read more? */
1080 if (read < len) { 1127 if (read < len) {
1081 /* Update Page size */ 1128 /* Update Page size */
1082 from += mtd->writesize; 1129 from += this->writesize;
1083 column = 0; 1130 column = 0;
1084 } 1131 }
1085 } 1132 }
@@ -1135,12 +1182,12 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
1135 int thislen, column; 1182 int thislen, column;
1136 1183
1137 while (len != 0) { 1184 while (len != 0) {
1138 thislen = min_t(int, mtd->writesize, len); 1185 thislen = min_t(int, this->writesize, len);
1139 column = addr & (mtd->writesize - 1); 1186 column = addr & (this->writesize - 1);
1140 if (column + thislen > mtd->writesize) 1187 if (column + thislen > this->writesize)
1141 thislen = mtd->writesize - column; 1188 thislen = this->writesize - column;
1142 1189
1143 this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); 1190 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
1144 1191
1145 onenand_update_bufferram(mtd, addr, 0); 1192 onenand_update_bufferram(mtd, addr, 0);
1146 1193
@@ -1236,6 +1283,10 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
1236 1283
1237 /* In partial page write we don't update bufferram */ 1284 /* In partial page write we don't update bufferram */
1238 onenand_update_bufferram(mtd, to, !ret && !subpage); 1285 onenand_update_bufferram(mtd, to, !ret && !subpage);
1286 if (ONENAND_IS_2PLANE(this)) {
1287 ONENAND_SET_BUFFERRAM1(this);
1288 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
1289 }
1239 1290
1240 if (ret) { 1291 if (ret) {
1241 printk(KERN_ERR "onenand_write: write filaed %d\n", ret); 1292 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,
1384 this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); 1435 this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
1385 1436
1386 onenand_update_bufferram(mtd, to, 0); 1437 onenand_update_bufferram(mtd, to, 0);
1438 if (ONENAND_IS_2PLANE(this)) {
1439 ONENAND_SET_BUFFERRAM1(this);
1440 onenand_update_bufferram(mtd, to + this->writesize, 0);
1441 }
1387 1442
1388 ret = this->wait(mtd, FL_WRITING); 1443 ret = this->wait(mtd, FL_WRITING);
1389 if (ret) { 1444 if (ret) {
@@ -2107,6 +2162,7 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
2107 * 2162 *
2108 * Check and set OneNAND features 2163 * Check and set OneNAND features
2109 * - lock scheme 2164 * - lock scheme
2165 * - two plane
2110 */ 2166 */
2111static void onenand_check_features(struct mtd_info *mtd) 2167static void onenand_check_features(struct mtd_info *mtd)
2112{ 2168{
@@ -2118,19 +2174,35 @@ static void onenand_check_features(struct mtd_info *mtd)
2118 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; 2174 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
2119 2175
2120 /* Lock scheme */ 2176 /* Lock scheme */
2121 if (density >= ONENAND_DEVICE_DENSITY_1Gb) { 2177 switch (density) {
2178 case ONENAND_DEVICE_DENSITY_4Gb:
2179 this->options |= ONENAND_HAS_2PLANE;
2180
2181 case ONENAND_DEVICE_DENSITY_2Gb:
2182 /* 2Gb DDP don't have 2 plane */
2183 if (!ONENAND_IS_DDP(this))
2184 this->options |= ONENAND_HAS_2PLANE;
2185 this->options |= ONENAND_HAS_UNLOCK_ALL;
2186
2187 case ONENAND_DEVICE_DENSITY_1Gb:
2122 /* A-Die has all block unlock */ 2188 /* A-Die has all block unlock */
2123 if (process) { 2189 if (process)
2124 printk(KERN_DEBUG "Chip support all block unlock\n");
2125 this->options |= ONENAND_HAS_UNLOCK_ALL; 2190 this->options |= ONENAND_HAS_UNLOCK_ALL;
2126 } 2191 break;
2127 } else { 2192
2128 /* Some OneNAND has continues lock scheme */ 2193 default:
2129 if (!process) { 2194 /* Some OneNAND has continuous lock scheme */
2130 printk(KERN_DEBUG "Lock scheme is Continues Lock\n"); 2195 if (!process)
2131 this->options |= ONENAND_HAS_CONT_LOCK; 2196 this->options |= ONENAND_HAS_CONT_LOCK;
2132 } 2197 break;
2133 } 2198 }
2199
2200 if (this->options & ONENAND_HAS_CONT_LOCK)
2201 printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
2202 if (this->options & ONENAND_HAS_UNLOCK_ALL)
2203 printk(KERN_DEBUG "Chip support all block unlock\n");
2204 if (this->options & ONENAND_HAS_2PLANE)
2205 printk(KERN_DEBUG "Chip has 2 plane\n");
2134} 2206}
2135 2207
2136/** 2208/**
@@ -2257,6 +2329,8 @@ static int onenand_probe(struct mtd_info *mtd)
2257 this->erase_shift = ffs(mtd->erasesize) - 1; 2329 this->erase_shift = ffs(mtd->erasesize) - 1;
2258 this->page_shift = ffs(mtd->writesize) - 1; 2330 this->page_shift = ffs(mtd->writesize) - 1;
2259 this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1; 2331 this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
2332 /* It's real page size */
2333 this->writesize = mtd->writesize;
2260 2334
2261 /* REVIST: Multichip handling */ 2335 /* REVIST: Multichip handling */
2262 2336
@@ -2265,6 +2339,17 @@ static int onenand_probe(struct mtd_info *mtd)
2265 /* Check OneNAND features */ 2339 /* Check OneNAND features */
2266 onenand_check_features(mtd); 2340 onenand_check_features(mtd);
2267 2341
2342 /*
2343 * We emulate the 4KiB page and 256KiB erase block size
2344 * But oobsize is still 64 bytes.
2345 * It is only valid if you turn on 2X program support,
2346 * Otherwise it will be ignored by compiler.
2347 */
2348 if (ONENAND_IS_2PLANE(this)) {
2349 mtd->writesize <<= 1;
2350 mtd->erasesize <<= 1;
2351 }
2352
2268 return 0; 2353 return 0;
2269} 2354}
2270 2355