aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/onenand/onenand_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/onenand/onenand_base.c')
-rw-r--r--drivers/mtd/onenand/onenand_base.c139
1 files changed, 112 insertions, 27 deletions
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