Commit ef0921d6b05aeb9034158f9bef5323d6da9c925e
Committed by
Scott Wood
1 parent
4d0b54685c
Exists in
master
and in
54 other branches
Sync with 2.6.27
Sync with OneNAND kernel codes Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Showing 6 changed files with 406 additions and 179 deletions Side-by-side Diff
drivers/mtd/onenand/onenand_base.c
... | ... | @@ -78,21 +78,12 @@ |
78 | 78 | * |
79 | 79 | * Setup Start Address 1 Register (F100h) |
80 | 80 | */ |
81 | -static int onenand_block_address(int device, int block) | |
81 | +static int onenand_block_address(struct onenand_chip *this, int block) | |
82 | 82 | { |
83 | - if (device & ONENAND_DEVICE_IS_DDP) { | |
84 | - /* Device Flash Core select, NAND Flash Block Address */ | |
85 | - int dfs = 0, density, mask; | |
83 | + /* Device Flash Core select, NAND Flash Block Address */ | |
84 | + if (block & this->density_mask) | |
85 | + return ONENAND_DDP_CHIP1 | (block ^ this->density_mask); | |
86 | 86 | |
87 | - density = device >> ONENAND_DEVICE_DENSITY_SHIFT; | |
88 | - mask = (1 << (density + 6)); | |
89 | - | |
90 | - if (block & mask) | |
91 | - dfs = 1; | |
92 | - | |
93 | - return (dfs << ONENAND_DDP_SHIFT) | (block & (mask - 1)); | |
94 | - } | |
95 | - | |
96 | 87 | return block; |
97 | 88 | } |
98 | 89 | |
99 | 90 | |
100 | 91 | |
... | ... | @@ -104,22 +95,13 @@ |
104 | 95 | * |
105 | 96 | * Setup Start Address 2 Register (F101h) for DDP |
106 | 97 | */ |
107 | -static int onenand_bufferram_address(int device, int block) | |
98 | +static int onenand_bufferram_address(struct onenand_chip *this, int block) | |
108 | 99 | { |
109 | - if (device & ONENAND_DEVICE_IS_DDP) { | |
110 | - /* Device BufferRAM Select */ | |
111 | - int dbs = 0, density, mask; | |
100 | + /* Device BufferRAM Select */ | |
101 | + if (block & this->density_mask) | |
102 | + return ONENAND_DDP_CHIP1; | |
112 | 103 | |
113 | - density = device >> ONENAND_DEVICE_DENSITY_SHIFT; | |
114 | - mask = (1 << (density + 6)); | |
115 | - | |
116 | - if (block & mask) | |
117 | - dbs = 1; | |
118 | - | |
119 | - return (dbs << ONENAND_DDP_SHIFT); | |
120 | - } | |
121 | - | |
122 | - return 0; | |
104 | + return ONENAND_DDP_CHIP0; | |
123 | 105 | } |
124 | 106 | |
125 | 107 | /** |
... | ... | @@ -169,6 +151,18 @@ |
169 | 151 | } |
170 | 152 | |
171 | 153 | /** |
154 | + * onenand_get_density - [DEFAULT] Get OneNAND density | |
155 | + * @param dev_id OneNAND device ID | |
156 | + * | |
157 | + * Get OneNAND density from device ID | |
158 | + */ | |
159 | +static inline int onenand_get_density(int dev_id) | |
160 | +{ | |
161 | + int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | |
162 | + return (density & ONENAND_DEVICE_DENSITY_MASK); | |
163 | +} | |
164 | + | |
165 | +/** | |
172 | 166 | * onenand_command - [DEFAULT] Send command to OneNAND device |
173 | 167 | * @param mtd MTD device structure |
174 | 168 | * @param cmd the command to be sent |
... | ... | @@ -192,6 +186,7 @@ |
192 | 186 | case ONENAND_CMD_UNLOCK: |
193 | 187 | case ONENAND_CMD_LOCK: |
194 | 188 | case ONENAND_CMD_LOCK_TIGHT: |
189 | + case ONENAND_CMD_UNLOCK_ALL: | |
195 | 190 | block = -1; |
196 | 191 | page = -1; |
197 | 192 | break; |
... | ... | @@ -212,7 +207,7 @@ |
212 | 207 | /* NOTE: The setting order of the registers is very important! */ |
213 | 208 | if (cmd == ONENAND_CMD_BUFFERRAM) { |
214 | 209 | /* Select DataRAM for DDP */ |
215 | - value = onenand_bufferram_address(this->device_id, block); | |
210 | + value = onenand_bufferram_address(this, block); | |
216 | 211 | this->write_word(value, |
217 | 212 | this->base + ONENAND_REG_START_ADDRESS2); |
218 | 213 | |
219 | 214 | |
... | ... | @@ -224,9 +219,14 @@ |
224 | 219 | |
225 | 220 | if (block != -1) { |
226 | 221 | /* Write 'DFS, FBA' of Flash */ |
227 | - value = onenand_block_address(this->device_id, block); | |
222 | + value = onenand_block_address(this, block); | |
228 | 223 | this->write_word(value, |
229 | 224 | this->base + ONENAND_REG_START_ADDRESS1); |
225 | + | |
226 | + /* Write 'DFS, FBA' of Flash */ | |
227 | + value = onenand_bufferram_address(this, block); | |
228 | + this->write_word(value, | |
229 | + this->base + ONENAND_REG_START_ADDRESS2); | |
230 | 230 | } |
231 | 231 | |
232 | 232 | if (page != -1) { |
... | ... | @@ -252,15 +252,6 @@ |
252 | 252 | /* Write 'BSA, BSC' of DataRAM */ |
253 | 253 | value = onenand_buffer_address(dataram, sectors, count); |
254 | 254 | this->write_word(value, this->base + ONENAND_REG_START_BUFFER); |
255 | - | |
256 | - if (readcmd) { | |
257 | - /* Select DataRAM for DDP */ | |
258 | - value = | |
259 | - onenand_bufferram_address(this->device_id, block); | |
260 | - this->write_word(value, | |
261 | - this->base + | |
262 | - ONENAND_REG_START_ADDRESS2); | |
263 | - } | |
264 | 255 | } |
265 | 256 | |
266 | 257 | /* Interrupt clear */ |
267 | 258 | |
... | ... | @@ -296,14 +287,11 @@ |
296 | 287 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
297 | 288 | |
298 | 289 | if (ctrl & ONENAND_CTRL_ERROR) { |
299 | - MTDDEBUG (MTD_DEBUG_LEVEL0, | |
300 | - "onenand_wait: controller error = 0x%04x\n", ctrl); | |
301 | - return -EAGAIN; | |
302 | - } | |
290 | + printk("onenand_wait: controller error = 0x%04x\n", ctrl); | |
291 | + if (ctrl & ONENAND_CTRL_LOCK) | |
292 | + printk("onenand_wait: it's locked error = 0x%04x\n", | |
293 | + ctrl); | |
303 | 294 | |
304 | - if (ctrl & ONENAND_CTRL_LOCK) { | |
305 | - MTDDEBUG (MTD_DEBUG_LEVEL0, | |
306 | - "onenand_wait: it's locked error = 0x%04x\n", ctrl); | |
307 | 295 | return -EIO; |
308 | 296 | } |
309 | 297 | |
... | ... | @@ -351,7 +339,7 @@ |
351 | 339 | * |
352 | 340 | * Read the BufferRAM area |
353 | 341 | */ |
354 | -static int onenand_read_bufferram(struct mtd_info *mtd, int area, | |
342 | +static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area, | |
355 | 343 | unsigned char *buffer, int offset, |
356 | 344 | size_t count) |
357 | 345 | { |
... | ... | @@ -376,7 +364,7 @@ |
376 | 364 | * |
377 | 365 | * Read the BufferRAM area with Sync. Burst Mode |
378 | 366 | */ |
379 | -static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area, | |
367 | +static int onenand_sync_read_bufferram(struct mtd_info *mtd, loff_t addr, int area, | |
380 | 368 | unsigned char *buffer, int offset, |
381 | 369 | size_t count) |
382 | 370 | { |
... | ... | @@ -405,7 +393,7 @@ |
405 | 393 | * |
406 | 394 | * Write the BufferRAM area |
407 | 395 | */ |
408 | -static int onenand_write_bufferram(struct mtd_info *mtd, int area, | |
396 | +static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area, | |
409 | 397 | const unsigned char *buffer, int offset, |
410 | 398 | size_t count) |
411 | 399 | { |
412 | 400 | |
413 | 401 | |
414 | 402 | |
415 | 403 | |
... | ... | @@ -431,21 +419,39 @@ |
431 | 419 | static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr) |
432 | 420 | { |
433 | 421 | struct onenand_chip *this = mtd->priv; |
434 | - int block, page; | |
435 | - int i; | |
422 | + int blockpage, found = 0; | |
423 | + unsigned int i; | |
436 | 424 | |
437 | - block = (int)(addr >> this->erase_shift); | |
438 | - page = (int)(addr >> this->page_shift); | |
439 | - page &= this->page_mask; | |
425 | +#ifdef CONFIG_S3C64XX | |
426 | + return 0; | |
427 | +#endif | |
440 | 428 | |
441 | - i = ONENAND_CURRENT_BUFFERRAM(this); | |
429 | + if (ONENAND_IS_2PLANE(this)) | |
430 | + blockpage = onenand_get_2x_blockpage(mtd, addr); | |
431 | + else | |
432 | + blockpage = (int) (addr >> this->page_shift); | |
442 | 433 | |
443 | 434 | /* Is there valid data? */ |
444 | - if (this->bufferram[i].block == block && | |
445 | - this->bufferram[i].page == page && this->bufferram[i].valid) | |
446 | - return 1; | |
435 | + i = ONENAND_CURRENT_BUFFERRAM(this); | |
436 | + if (this->bufferram[i].blockpage == blockpage) | |
437 | + found = 1; | |
438 | + else { | |
439 | + /* Check another BufferRAM */ | |
440 | + i = ONENAND_NEXT_BUFFERRAM(this); | |
441 | + if (this->bufferram[i].blockpage == blockpage) { | |
442 | + ONENAND_SET_NEXT_BUFFERRAM(this); | |
443 | + found = 1; | |
444 | + } | |
445 | + } | |
447 | 446 | |
448 | - return 0; | |
447 | + if (found && ONENAND_IS_DDP(this)) { | |
448 | + /* Select DataRAM for DDP */ | |
449 | + int block = (int) (addr >> this->erase_shift); | |
450 | + int value = onenand_bufferram_address(this, block); | |
451 | + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | |
452 | + } | |
453 | + | |
454 | + return found; | |
449 | 455 | } |
450 | 456 | |
451 | 457 | /** |
452 | 458 | |
453 | 459 | |
454 | 460 | |
... | ... | @@ -460,25 +466,25 @@ |
460 | 466 | int valid) |
461 | 467 | { |
462 | 468 | struct onenand_chip *this = mtd->priv; |
463 | - int block, page; | |
464 | - int i; | |
469 | + int blockpage; | |
470 | + unsigned int i; | |
465 | 471 | |
466 | - block = (int)(addr >> this->erase_shift); | |
467 | - page = (int)(addr >> this->page_shift); | |
468 | - page &= this->page_mask; | |
472 | + if (ONENAND_IS_2PLANE(this)) | |
473 | + blockpage = onenand_get_2x_blockpage(mtd, addr); | |
474 | + else | |
475 | + blockpage = (int)(addr >> this->page_shift); | |
469 | 476 | |
470 | - /* Invalidate BufferRAM */ | |
471 | - for (i = 0; i < MAX_BUFFERRAM; i++) { | |
472 | - if (this->bufferram[i].block == block && | |
473 | - this->bufferram[i].page == page) | |
474 | - this->bufferram[i].valid = 0; | |
475 | - } | |
477 | + /* Invalidate another BufferRAM */ | |
478 | + i = ONENAND_NEXT_BUFFERRAM(this); | |
479 | + if (this->bufferram[i].blockpage == blockpage) | |
480 | + this->bufferram[i].blockpage = -1; | |
476 | 481 | |
477 | 482 | /* Update BufferRAM */ |
478 | 483 | i = ONENAND_CURRENT_BUFFERRAM(this); |
479 | - this->bufferram[i].block = block; | |
480 | - this->bufferram[i].page = page; | |
481 | - this->bufferram[i].valid = valid; | |
484 | + if (valid) | |
485 | + this->bufferram[i].blockpage = blockpage; | |
486 | + else | |
487 | + this->bufferram[i].blockpage = -1; | |
482 | 488 | |
483 | 489 | return 0; |
484 | 490 | } |
485 | 491 | |
... | ... | @@ -500,10 +506,10 @@ |
500 | 506 | |
501 | 507 | /* Invalidate BufferRAM */ |
502 | 508 | for (i = 0; i < MAX_BUFFERRAM; i++) { |
503 | - loff_t buf_addr = this->bufferram[i].block << this->erase_shift; | |
509 | + loff_t buf_addr = this->bufferram[i].blockpage << this->page_shift; | |
504 | 510 | |
505 | 511 | if (buf_addr >= addr && buf_addr < end_addr) |
506 | - this->bufferram[i].valid = 0; | |
512 | + this->bufferram[i].blockpage = -1; | |
507 | 513 | } |
508 | 514 | } |
509 | 515 | |
... | ... | @@ -556,7 +562,7 @@ |
556 | 562 | readend += free->offset - lastgap; |
557 | 563 | lastgap = free->offset + free->length; |
558 | 564 | } |
559 | - this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); | |
565 | + this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); | |
560 | 566 | free = this->ecclayout->oobfree; |
561 | 567 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { |
562 | 568 | int free_end = free->offset + free->length; |
... | ... | @@ -594,9 +600,7 @@ |
594 | 600 | int ret = 0, boundary = 0; |
595 | 601 | int writesize = this->writesize; |
596 | 602 | |
597 | - MTDDEBUG(MTD_DEBUG_LEVEL3, | |
598 | - "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", | |
599 | - (unsigned int) from, (int) len); | |
603 | + MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | |
600 | 604 | |
601 | 605 | if (ops->mode == MTD_OOB_AUTO) |
602 | 606 | oobsize = this->ecclayout->oobavail; |
... | ... | @@ -620,6 +624,7 @@ |
620 | 624 | /* Do first load to bufferRAM */ |
621 | 625 | if (read < len) { |
622 | 626 | if (!onenand_check_bufferram(mtd, from)) { |
627 | + this->main_buf = buf; | |
623 | 628 | this->command(mtd, ONENAND_CMD_READ, from, writesize); |
624 | 629 | ret = this->wait(mtd, FL_READING); |
625 | 630 | onenand_update_bufferram(mtd, from, !ret); |
... | ... | @@ -637,6 +642,7 @@ |
637 | 642 | /* If there is more to load then start next load */ |
638 | 643 | from += thislen; |
639 | 644 | if (read + thislen < len) { |
645 | + this->main_buf = buf + thislen; | |
640 | 646 | this->command(mtd, ONENAND_CMD_READ, from, writesize); |
641 | 647 | /* |
642 | 648 | * Chip boundary handling in DDP |
... | ... | @@ -653,7 +659,7 @@ |
653 | 659 | } |
654 | 660 | |
655 | 661 | /* While load is going, read from last bufferRAM */ |
656 | - this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); | |
662 | + this->read_bufferram(mtd, from - thislen, ONENAND_DATARAM, buf, column, thislen); | |
657 | 663 | |
658 | 664 | /* Read oob area if needed */ |
659 | 665 | if (oobbuf) { |
... | ... | @@ -663,7 +669,7 @@ |
663 | 669 | if (ops->mode == MTD_OOB_AUTO) |
664 | 670 | onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); |
665 | 671 | else |
666 | - this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); | |
672 | + this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); | |
667 | 673 | oobread += thisooblen; |
668 | 674 | oobbuf += thisooblen; |
669 | 675 | oobcolumn = 0; |
... | ... | @@ -726,9 +732,7 @@ |
726 | 732 | |
727 | 733 | from += ops->ooboffs; |
728 | 734 | |
729 | - MTDDEBUG(MTD_DEBUG_LEVEL3, | |
730 | - "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", | |
731 | - (unsigned int) from, (int) len); | |
735 | + MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); | |
732 | 736 | |
733 | 737 | /* Initialize return length value */ |
734 | 738 | ops->oobretlen = 0; |
... | ... | @@ -759,6 +763,7 @@ |
759 | 763 | thislen = oobsize - column; |
760 | 764 | thislen = min_t(int, thislen, len); |
761 | 765 | |
766 | + this->spare_buf = buf; | |
762 | 767 | this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); |
763 | 768 | |
764 | 769 | onenand_update_bufferram(mtd, from, 0); |
... | ... | @@ -772,7 +777,7 @@ |
772 | 777 | if (mode == MTD_OOB_AUTO) |
773 | 778 | onenand_transfer_auto_oob(mtd, buf, column, thislen); |
774 | 779 | else |
775 | - this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | |
780 | + this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen); | |
776 | 781 | |
777 | 782 | read += thislen; |
778 | 783 | |
... | ... | @@ -886,12 +891,6 @@ |
886 | 891 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); |
887 | 892 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
888 | 893 | |
889 | - /* Initial bad block case: 0x2400 or 0x0400 */ | |
890 | - if (ctrl & ONENAND_CTRL_ERROR) { | |
891 | - printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); | |
892 | - return ONENAND_BBT_READ_ERROR; | |
893 | - } | |
894 | - | |
895 | 894 | if (interrupt & ONENAND_INT_READ) { |
896 | 895 | int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); |
897 | 896 | if (ecc & ONENAND_ECC_2BIT_ALL) |
... | ... | @@ -902,6 +901,12 @@ |
902 | 901 | return ONENAND_BBT_READ_FATAL_ERROR; |
903 | 902 | } |
904 | 903 | |
904 | + /* Initial bad block case: 0x2400 or 0x0400 */ | |
905 | + if (ctrl & ONENAND_CTRL_ERROR) { | |
906 | + printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); | |
907 | + return ONENAND_BBT_READ_ERROR; | |
908 | + } | |
909 | + | |
905 | 910 | return 0; |
906 | 911 | } |
907 | 912 | |
... | ... | @@ -922,9 +927,7 @@ |
922 | 927 | size_t len = ops->ooblen; |
923 | 928 | u_char *buf = ops->oobbuf; |
924 | 929 | |
925 | - MTDDEBUG(MTD_DEBUG_LEVEL3, | |
926 | - "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", | |
927 | - (unsigned int) from, len); | |
930 | + MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len); | |
928 | 931 | |
929 | 932 | /* Initialize return value */ |
930 | 933 | ops->oobretlen = 0; |
931 | 934 | |
932 | 935 | |
... | ... | @@ -945,15 +948,16 @@ |
945 | 948 | thislen = mtd->oobsize - column; |
946 | 949 | thislen = min_t(int, thislen, len); |
947 | 950 | |
951 | + this->spare_buf = buf; | |
948 | 952 | this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); |
949 | 953 | |
950 | 954 | onenand_update_bufferram(mtd, from, 0); |
951 | 955 | |
952 | - ret = onenand_bbt_wait(mtd, FL_READING); | |
956 | + ret = this->bbt_wait(mtd, FL_READING); | |
953 | 957 | if (ret) |
954 | 958 | break; |
955 | 959 | |
956 | - this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | |
960 | + this->read_spareram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen); | |
957 | 961 | read += thislen; |
958 | 962 | if (read == len) |
959 | 963 | break; |
... | ... | @@ -995,7 +999,7 @@ |
995 | 999 | if (status) |
996 | 1000 | return status; |
997 | 1001 | |
998 | - this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); | |
1002 | + this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); | |
999 | 1003 | for (i = 0; i < mtd->oobsize; i++) |
1000 | 1004 | if (buf[i] != 0xFF && buf[i] != oob_buf[i]) |
1001 | 1005 | return -EBADMSG; |
... | ... | @@ -1115,9 +1119,7 @@ |
1115 | 1119 | u_char *oobbuf; |
1116 | 1120 | int ret = 0; |
1117 | 1121 | |
1118 | - MTDDEBUG(MTD_DEBUG_LEVEL3, | |
1119 | - "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", | |
1120 | - (unsigned int) to, (int) len); | |
1122 | + MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | |
1121 | 1123 | |
1122 | 1124 | /* Initialize retlen, in case of early exit */ |
1123 | 1125 | ops->retlen = 0; |
... | ... | @@ -1161,7 +1163,7 @@ |
1161 | 1163 | wbuf = this->page_buf; |
1162 | 1164 | } |
1163 | 1165 | |
1164 | - this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); | |
1166 | + this->write_bufferram(mtd, to, ONENAND_DATARAM, wbuf, 0, mtd->writesize); | |
1165 | 1167 | |
1166 | 1168 | if (oob) { |
1167 | 1169 | oobbuf = this->oob_buf; |
... | ... | @@ -1180,7 +1182,7 @@ |
1180 | 1182 | } else |
1181 | 1183 | oobbuf = (u_char *) ffchars; |
1182 | 1184 | |
1183 | - this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); | |
1185 | + this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); | |
1184 | 1186 | |
1185 | 1187 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); |
1186 | 1188 | |
... | ... | @@ -1244,9 +1246,7 @@ |
1244 | 1246 | |
1245 | 1247 | to += ops->ooboffs; |
1246 | 1248 | |
1247 | - MTDDEBUG(MTD_DEBUG_LEVEL3, | |
1248 | - "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", | |
1249 | - (unsigned int) to, (int) len); | |
1249 | + MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); | |
1250 | 1250 | |
1251 | 1251 | /* Initialize retlen, in case of early exit */ |
1252 | 1252 | ops->oobretlen = 0; |
... | ... | @@ -1293,7 +1293,7 @@ |
1293 | 1293 | onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen); |
1294 | 1294 | else |
1295 | 1295 | memcpy(oobbuf + column, buf, thislen); |
1296 | - this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); | |
1296 | + this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); | |
1297 | 1297 | |
1298 | 1298 | this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); |
1299 | 1299 | |
... | ... | @@ -1466,7 +1466,14 @@ |
1466 | 1466 | |
1467 | 1467 | while (len) { |
1468 | 1468 | |
1469 | - /* TODO Check badblock */ | |
1469 | + /* Check if we have a bad block, we do not erase bad blocks */ | |
1470 | + if (instr->priv == 0 && onenand_block_isbad_nolock(mtd, addr, 0)) { | |
1471 | + printk(KERN_WARNING "onenand_erase: attempt to erase" | |
1472 | + " a bad block at addr 0x%08x\n", | |
1473 | + (unsigned int) addr); | |
1474 | + instr->state = MTD_ERASE_FAILED; | |
1475 | + goto erase_exit; | |
1476 | + } | |
1470 | 1477 | |
1471 | 1478 | this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); |
1472 | 1479 | |
1473 | 1480 | |
... | ... | @@ -1482,8 +1489,16 @@ |
1482 | 1489 | MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: " |
1483 | 1490 | "Failed erase, block %d\n", |
1484 | 1491 | (unsigned)(addr >> this->erase_shift)); |
1492 | + if (ret == -EPERM) | |
1493 | + printk("onenand_erase: " | |
1494 | + "Device is write protected!!!\n"); | |
1495 | + else | |
1496 | + printk("onenand_erase: " | |
1497 | + "Failed erase, block %d\n", | |
1498 | + (unsigned)(addr >> this->erase_shift)); | |
1485 | 1499 | instr->state = MTD_ERASE_FAILED; |
1486 | 1500 | instr->fail_addr = addr; |
1501 | + | |
1487 | 1502 | goto erase_exit; |
1488 | 1503 | } |
1489 | 1504 | |
... | ... | @@ -1493,7 +1508,7 @@ |
1493 | 1508 | |
1494 | 1509 | instr->state = MTD_ERASE_DONE; |
1495 | 1510 | |
1496 | - erase_exit: | |
1511 | +erase_exit: | |
1497 | 1512 | |
1498 | 1513 | ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; |
1499 | 1514 | /* Do call back function */ |
1500 | 1515 | |
1501 | 1516 | |
1502 | 1517 | |
1503 | 1518 | |
1504 | 1519 | |
... | ... | @@ -1569,23 +1584,30 @@ |
1569 | 1584 | } |
1570 | 1585 | |
1571 | 1586 | /** |
1572 | - * onenand_unlock - [MTD Interface] Unlock block(s) | |
1573 | - * @param mtd MTD device structure | |
1574 | - * @param ofs offset relative to mtd start | |
1575 | - * @param len number of bytes to unlock | |
1587 | + * onenand_do_lock_cmd - [OneNAND Interface] Lock or unlock block(s) | |
1588 | + * @param mtd MTD device structure | |
1589 | + * @param ofs offset relative to mtd start | |
1590 | + * @param len number of bytes to lock or unlock | |
1591 | + * @param cmd lock or unlock command | |
1576 | 1592 | * |
1577 | - * Unlock one or more blocks | |
1593 | + * Lock or unlock one or more blocks | |
1578 | 1594 | */ |
1579 | -int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |
1595 | +static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd) | |
1580 | 1596 | { |
1581 | 1597 | struct onenand_chip *this = mtd->priv; |
1582 | 1598 | int start, end, block, value, status; |
1599 | + int wp_status_mask; | |
1583 | 1600 | |
1584 | 1601 | start = ofs >> this->erase_shift; |
1585 | 1602 | end = len >> this->erase_shift; |
1586 | 1603 | |
1604 | + if (cmd == ONENAND_CMD_LOCK) | |
1605 | + wp_status_mask = ONENAND_WP_LS; | |
1606 | + else | |
1607 | + wp_status_mask = ONENAND_WP_US; | |
1608 | + | |
1587 | 1609 | /* Continuous lock scheme */ |
1588 | - if (this->options & ONENAND_CONT_LOCK) { | |
1610 | + if (this->options & ONENAND_HAS_CONT_LOCK) { | |
1589 | 1611 | /* Set start block address */ |
1590 | 1612 | this->write_word(start, |
1591 | 1613 | this->base + ONENAND_REG_START_BLOCK_ADDRESS); |
... | ... | @@ -1593,7 +1615,7 @@ |
1593 | 1615 | this->write_word(end - 1, |
1594 | 1616 | this->base + ONENAND_REG_END_BLOCK_ADDRESS); |
1595 | 1617 | /* Write unlock command */ |
1596 | - this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0); | |
1618 | + this->command(mtd, cmd, 0, 0); | |
1597 | 1619 | |
1598 | 1620 | /* There's no return value */ |
1599 | 1621 | this->wait(mtd, FL_UNLOCKING); |
... | ... | @@ -1612,7 +1634,14 @@ |
1612 | 1634 | } |
1613 | 1635 | |
1614 | 1636 | /* Block lock scheme */ |
1615 | - for (block = start; block < end; block++) { | |
1637 | + for (block = start; block < start + end; block++) { | |
1638 | + /* Set block address */ | |
1639 | + value = onenand_block_address(this, block); | |
1640 | + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); | |
1641 | + /* Select DataRAM for DDP */ | |
1642 | + value = onenand_bufferram_address(this, block); | |
1643 | + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | |
1644 | + | |
1616 | 1645 | /* Set start block address */ |
1617 | 1646 | this->write_word(block, |
1618 | 1647 | this->base + ONENAND_REG_START_BLOCK_ADDRESS); |
... | ... | @@ -1627,11 +1656,6 @@ |
1627 | 1656 | & ONENAND_CTRL_ONGO) |
1628 | 1657 | continue; |
1629 | 1658 | |
1630 | - /* Set block address for read block status */ | |
1631 | - value = onenand_block_address(this->device_id, block); | |
1632 | - this->write_word(value, | |
1633 | - this->base + ONENAND_REG_START_ADDRESS1); | |
1634 | - | |
1635 | 1659 | /* Check lock status */ |
1636 | 1660 | status = this->read_word(this->base + ONENAND_REG_WP_STATUS); |
1637 | 1661 | if (!(status & ONENAND_WP_US)) |
1638 | 1662 | |
1639 | 1663 | |
1640 | 1664 | |
1641 | 1665 | |
1642 | 1666 | |
... | ... | @@ -1643,31 +1667,196 @@ |
1643 | 1667 | } |
1644 | 1668 | |
1645 | 1669 | /** |
1670 | + * onenand_lock - [MTD Interface] Lock block(s) | |
1671 | + * @param mtd MTD device structure | |
1672 | + * @param ofs offset relative to mtd start | |
1673 | + * @param len number of bytes to unlock | |
1674 | + * | |
1675 | + * Lock one or more blocks | |
1676 | + */ | |
1677 | +static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) | |
1678 | +{ | |
1679 | + int ret; | |
1680 | + | |
1681 | + onenand_get_device(mtd, FL_LOCKING); | |
1682 | + ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK); | |
1683 | + onenand_release_device(mtd); | |
1684 | + return ret; | |
1685 | +} | |
1686 | + | |
1687 | +/** | |
1688 | + * onenand_unlock - [MTD Interface] Unlock block(s) | |
1689 | + * @param mtd MTD device structure | |
1690 | + * @param ofs offset relative to mtd start | |
1691 | + * @param len number of bytes to unlock | |
1692 | + * | |
1693 | + * Unlock one or more blocks | |
1694 | + */ | |
1695 | +static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) | |
1696 | +{ | |
1697 | + int ret; | |
1698 | + | |
1699 | + onenand_get_device(mtd, FL_LOCKING); | |
1700 | + ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); | |
1701 | + onenand_release_device(mtd); | |
1702 | + return ret; | |
1703 | +} | |
1704 | + | |
1705 | +/** | |
1706 | + * onenand_check_lock_status - [OneNAND Interface] Check lock status | |
1707 | + * @param this onenand chip data structure | |
1708 | + * | |
1709 | + * Check lock status | |
1710 | + */ | |
1711 | +static int onenand_check_lock_status(struct onenand_chip *this) | |
1712 | +{ | |
1713 | + unsigned int value, block, status; | |
1714 | + unsigned int end; | |
1715 | + | |
1716 | + end = this->chipsize >> this->erase_shift; | |
1717 | + for (block = 0; block < end; block++) { | |
1718 | + /* Set block address */ | |
1719 | + value = onenand_block_address(this, block); | |
1720 | + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); | |
1721 | + /* Select DataRAM for DDP */ | |
1722 | + value = onenand_bufferram_address(this, block); | |
1723 | + this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | |
1724 | + /* Set start block address */ | |
1725 | + this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS); | |
1726 | + | |
1727 | + /* Check lock status */ | |
1728 | + status = this->read_word(this->base + ONENAND_REG_WP_STATUS); | |
1729 | + if (!(status & ONENAND_WP_US)) { | |
1730 | + printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status); | |
1731 | + return 0; | |
1732 | + } | |
1733 | + } | |
1734 | + | |
1735 | + return 1; | |
1736 | +} | |
1737 | + | |
1738 | +/** | |
1739 | + * onenand_unlock_all - [OneNAND Interface] unlock all blocks | |
1740 | + * @param mtd MTD device structure | |
1741 | + * | |
1742 | + * Unlock all blocks | |
1743 | + */ | |
1744 | +static void onenand_unlock_all(struct mtd_info *mtd) | |
1745 | +{ | |
1746 | + struct onenand_chip *this = mtd->priv; | |
1747 | + loff_t ofs = 0; | |
1748 | + size_t len = this->chipsize; | |
1749 | + | |
1750 | + if (this->options & ONENAND_HAS_UNLOCK_ALL) { | |
1751 | + /* Set start block address */ | |
1752 | + this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS); | |
1753 | + /* Write unlock command */ | |
1754 | + this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0); | |
1755 | + | |
1756 | + /* There's no return value */ | |
1757 | + this->wait(mtd, FL_LOCKING); | |
1758 | + | |
1759 | + /* Sanity check */ | |
1760 | + while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS) | |
1761 | + & ONENAND_CTRL_ONGO) | |
1762 | + continue; | |
1763 | + | |
1764 | + return; | |
1765 | + | |
1766 | + /* Check lock status */ | |
1767 | + if (onenand_check_lock_status(this)) | |
1768 | + return; | |
1769 | + | |
1770 | + /* Workaround for all block unlock in DDP */ | |
1771 | + if (ONENAND_IS_DDP(this)) { | |
1772 | + /* All blocks on another chip */ | |
1773 | + ofs = this->chipsize >> 1; | |
1774 | + len = this->chipsize >> 1; | |
1775 | + } | |
1776 | + } | |
1777 | + | |
1778 | + onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK); | |
1779 | +} | |
1780 | + | |
1781 | + | |
1782 | +/** | |
1783 | + * onenand_check_features - Check and set OneNAND features | |
1784 | + * @param mtd MTD data structure | |
1785 | + * | |
1786 | + * Check and set OneNAND features | |
1787 | + * - lock scheme | |
1788 | + * - two plane | |
1789 | + */ | |
1790 | +static void onenand_check_features(struct mtd_info *mtd) | |
1791 | +{ | |
1792 | + struct onenand_chip *this = mtd->priv; | |
1793 | + unsigned int density, process; | |
1794 | + | |
1795 | + /* Lock scheme depends on density and process */ | |
1796 | + density = onenand_get_density(this->device_id); | |
1797 | + process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; | |
1798 | + | |
1799 | + /* Lock scheme */ | |
1800 | + switch (density) { | |
1801 | + case ONENAND_DEVICE_DENSITY_4Gb: | |
1802 | + this->options |= ONENAND_HAS_2PLANE; | |
1803 | + | |
1804 | + case ONENAND_DEVICE_DENSITY_2Gb: | |
1805 | + /* 2Gb DDP don't have 2 plane */ | |
1806 | + if (!ONENAND_IS_DDP(this)) | |
1807 | + this->options |= ONENAND_HAS_2PLANE; | |
1808 | + this->options |= ONENAND_HAS_UNLOCK_ALL; | |
1809 | + | |
1810 | + case ONENAND_DEVICE_DENSITY_1Gb: | |
1811 | + /* A-Die has all block unlock */ | |
1812 | + if (process) | |
1813 | + this->options |= ONENAND_HAS_UNLOCK_ALL; | |
1814 | + break; | |
1815 | + | |
1816 | + default: | |
1817 | + /* Some OneNAND has continuous lock scheme */ | |
1818 | + if (!process) | |
1819 | + this->options |= ONENAND_HAS_CONT_LOCK; | |
1820 | + break; | |
1821 | + } | |
1822 | + | |
1823 | + if (this->options & ONENAND_HAS_CONT_LOCK) | |
1824 | + printk(KERN_DEBUG "Lock scheme is Continuous Lock\n"); | |
1825 | + if (this->options & ONENAND_HAS_UNLOCK_ALL) | |
1826 | + printk(KERN_DEBUG "Chip support all block unlock\n"); | |
1827 | + if (this->options & ONENAND_HAS_2PLANE) | |
1828 | + printk(KERN_DEBUG "Chip has 2 plane\n"); | |
1829 | +} | |
1830 | + | |
1831 | +/** | |
1646 | 1832 | * onenand_print_device_info - Print device ID |
1647 | 1833 | * @param device device ID |
1648 | 1834 | * |
1649 | 1835 | * Print device ID |
1650 | 1836 | */ |
1651 | -char * onenand_print_device_info(int device) | |
1837 | +char *onenand_print_device_info(int device, int version) | |
1652 | 1838 | { |
1653 | 1839 | int vcc, demuxed, ddp, density; |
1654 | 1840 | char *dev_info = malloc(80); |
1841 | + char *p = dev_info; | |
1655 | 1842 | |
1656 | 1843 | vcc = device & ONENAND_DEVICE_VCC_MASK; |
1657 | 1844 | demuxed = device & ONENAND_DEVICE_IS_DEMUX; |
1658 | 1845 | ddp = device & ONENAND_DEVICE_IS_DDP; |
1659 | 1846 | density = device >> ONENAND_DEVICE_DENSITY_SHIFT; |
1660 | - sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)", | |
1847 | + p += sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)", | |
1661 | 1848 | demuxed ? "" : "Muxed ", |
1662 | 1849 | ddp ? "(DDP)" : "", |
1663 | 1850 | (16 << density), vcc ? "2.65/3.3" : "1.8", device); |
1664 | 1851 | |
1852 | + sprintf(p, "\nOneNAND version = 0x%04x", version); | |
1853 | + printk("%s\n", dev_info); | |
1854 | + | |
1665 | 1855 | return dev_info; |
1666 | 1856 | } |
1667 | 1857 | |
1668 | 1858 | static const struct onenand_manufacturers onenand_manuf_ids[] = { |
1669 | 1859 | {ONENAND_MFR_SAMSUNG, "Samsung"}, |
1670 | - {ONENAND_MFR_UNKNOWN, "Unknown"} | |
1671 | 1860 | }; |
1672 | 1861 | |
1673 | 1862 | /** |
1674 | 1863 | |
1675 | 1864 | |
1676 | 1865 | |
1677 | 1866 | |
1678 | 1867 | |
... | ... | @@ -1678,19 +1867,24 @@ |
1678 | 1867 | */ |
1679 | 1868 | static int onenand_check_maf(int manuf) |
1680 | 1869 | { |
1870 | + int size = ARRAY_SIZE(onenand_manuf_ids); | |
1871 | + char *name; | |
1681 | 1872 | int i; |
1682 | 1873 | |
1683 | - for (i = 0; onenand_manuf_ids[i].id; i++) { | |
1874 | + for (i = 0; size; i++) | |
1684 | 1875 | if (manuf == onenand_manuf_ids[i].id) |
1685 | 1876 | break; |
1686 | - } | |
1687 | 1877 | |
1878 | + if (i < size) | |
1879 | + name = onenand_manuf_ids[i].name; | |
1880 | + else | |
1881 | + name = "Unknown"; | |
1882 | + | |
1688 | 1883 | #ifdef ONENAND_DEBUG |
1689 | - printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", | |
1690 | - onenand_manuf_ids[i].name, manuf); | |
1884 | + printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf); | |
1691 | 1885 | #endif |
1692 | 1886 | |
1693 | - return (i != ONENAND_MFR_UNKNOWN); | |
1887 | + return i == size; | |
1694 | 1888 | } |
1695 | 1889 | |
1696 | 1890 | /** |
1697 | 1891 | |
1698 | 1892 | |
... | ... | @@ -1703,10 +1897,15 @@ |
1703 | 1897 | static int onenand_probe(struct mtd_info *mtd) |
1704 | 1898 | { |
1705 | 1899 | struct onenand_chip *this = mtd->priv; |
1706 | - int bram_maf_id, bram_dev_id, maf_id, dev_id; | |
1707 | - int version_id; | |
1900 | + int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id; | |
1708 | 1901 | int density; |
1902 | + int syscfg; | |
1709 | 1903 | |
1904 | + /* Save system configuration 1 */ | |
1905 | + syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1); | |
1906 | + /* Clear Sync. Burst Read mode to read BootRAM */ | |
1907 | + this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ), this->base + ONENAND_REG_SYS_CFG1); | |
1908 | + | |
1710 | 1909 | /* Send the command for reading device ID from BootRAM */ |
1711 | 1910 | this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM); |
1712 | 1911 | |
1713 | 1912 | |
1714 | 1913 | |
... | ... | @@ -1714,19 +1913,23 @@ |
1714 | 1913 | bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0); |
1715 | 1914 | bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2); |
1716 | 1915 | |
1717 | - /* Check manufacturer ID */ | |
1718 | - if (onenand_check_maf(bram_maf_id)) | |
1719 | - return -ENXIO; | |
1720 | - | |
1721 | 1916 | /* Reset OneNAND to read default register values */ |
1722 | 1917 | this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM); |
1723 | 1918 | |
1724 | 1919 | /* Wait reset */ |
1725 | 1920 | this->wait(mtd, FL_RESETING); |
1726 | 1921 | |
1922 | + /* Restore system configuration 1 */ | |
1923 | + this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1); | |
1924 | + | |
1925 | + /* Check manufacturer ID */ | |
1926 | + if (onenand_check_maf(bram_maf_id)) | |
1927 | + return -ENXIO; | |
1928 | + | |
1727 | 1929 | /* Read manufacturer and device IDs from Register */ |
1728 | 1930 | maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); |
1729 | 1931 | dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID); |
1932 | + ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); | |
1730 | 1933 | |
1731 | 1934 | /* Check OneNAND device */ |
1732 | 1935 | if (maf_id != bram_maf_id || dev_id != bram_dev_id) |
1733 | 1936 | |
1734 | 1937 | |
... | ... | @@ -1739,11 +1942,16 @@ |
1739 | 1942 | } |
1740 | 1943 | |
1741 | 1944 | /* Flash device information */ |
1742 | - mtd->name = onenand_print_device_info(dev_id); | |
1945 | + mtd->name = onenand_print_device_info(dev_id, ver_id); | |
1743 | 1946 | this->device_id = dev_id; |
1744 | 1947 | |
1745 | - density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | |
1948 | + density = onenand_get_density(dev_id); | |
1746 | 1949 | this->chipsize = (16 << density) << 20; |
1950 | + /* Set density mask. it is used for DDP */ | |
1951 | + if (ONENAND_IS_DDP(this)) | |
1952 | + this->density_mask = (1 << (density + 6)); | |
1953 | + else | |
1954 | + this->density_mask = 0; | |
1747 | 1955 | |
1748 | 1956 | /* OneNAND page size & block size */ |
1749 | 1957 | /* The data buffer size is equal to page size */ |
1750 | 1958 | |
... | ... | @@ -1764,19 +1972,9 @@ |
1764 | 1972 | |
1765 | 1973 | mtd->size = this->chipsize; |
1766 | 1974 | |
1767 | - /* Version ID */ | |
1768 | - version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID); | |
1769 | -#ifdef ONENAND_DEBUG | |
1770 | - printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id); | |
1771 | -#endif | |
1975 | + /* Check OneNAND features */ | |
1976 | + onenand_check_features(mtd); | |
1772 | 1977 | |
1773 | - /* Lock scheme */ | |
1774 | - if (density <= ONENAND_DEVICE_DENSITY_512Mb && | |
1775 | - !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) { | |
1776 | - printk(KERN_INFO "Lock scheme is Continues Lock\n"); | |
1777 | - this->options |= ONENAND_CONT_LOCK; | |
1778 | - } | |
1779 | - | |
1780 | 1978 | mtd->flags = MTD_CAP_NANDFLASH; |
1781 | 1979 | mtd->erase = onenand_erase; |
1782 | 1980 | mtd->read = onenand_read; |
1783 | 1981 | |
1784 | 1982 | |
... | ... | @@ -1813,12 +2011,19 @@ |
1813 | 2011 | this->command = onenand_command; |
1814 | 2012 | if (!this->wait) |
1815 | 2013 | this->wait = onenand_wait; |
2014 | + if (!this->bbt_wait) | |
2015 | + this->bbt_wait = onenand_bbt_wait; | |
1816 | 2016 | |
1817 | 2017 | if (!this->read_bufferram) |
1818 | 2018 | this->read_bufferram = onenand_read_bufferram; |
2019 | + if (!this->read_spareram) | |
2020 | + this->read_spareram = onenand_read_bufferram; | |
1819 | 2021 | if (!this->write_bufferram) |
1820 | 2022 | this->write_bufferram = onenand_write_bufferram; |
1821 | 2023 | |
2024 | + if (!this->scan_bbt) | |
2025 | + this->scan_bbt = onenand_default_bbt; | |
2026 | + | |
1822 | 2027 | if (onenand_probe(mtd)) |
1823 | 2028 | return -ENXIO; |
1824 | 2029 | |
1825 | 2030 | |
... | ... | @@ -1850,9 +2055,10 @@ |
1850 | 2055 | this->options |= ONENAND_OOBBUF_ALLOC; |
1851 | 2056 | } |
1852 | 2057 | |
1853 | - onenand_unlock(mtd, 0, mtd->size); | |
2058 | + /* Unlock whole block */ | |
2059 | + onenand_unlock_all(mtd); | |
1854 | 2060 | |
1855 | - return onenand_default_bbt(mtd); | |
2061 | + return this->scan_bbt(mtd); | |
1856 | 2062 | } |
1857 | 2063 | |
1858 | 2064 | /** |
drivers/mtd/onenand/onenand_bbt.c
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | * |
4 | 4 | * Bad Block Table support for the OneNAND driver |
5 | 5 | * |
6 | - * Copyright(c) 2005-2007 Samsung Electronics | |
6 | + * Copyright(c) 2005-2008 Samsung Electronics | |
7 | 7 | * Kyungmin Park <kyungmin.park@samsung.com> |
8 | 8 | * |
9 | 9 | * TODO: |
... | ... | @@ -54,7 +54,7 @@ |
54 | 54 | * @param buf temporary buffer |
55 | 55 | * @param bd descriptor for the good/bad block search pattern |
56 | 56 | * @param chip create the table for a specific chip, -1 read all chips. |
57 | - * Applies only if NAND_BBT_PERCHIP option is set | |
57 | + * Applies only if NAND_BBT_PERCHIP option is set | |
58 | 58 | * |
59 | 59 | * Create a bad block table by scanning the device |
60 | 60 | * for the given good/bad block identify pattern |
... | ... | @@ -156,8 +156,8 @@ |
156 | 156 | res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; |
157 | 157 | |
158 | 158 | MTDDEBUG (MTD_DEBUG_LEVEL2, |
159 | - "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", | |
160 | - (unsigned int)offs, block >> 1, res); | |
159 | + "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", | |
160 | + (unsigned int)offs, block >> 1, res); | |
161 | 161 | |
162 | 162 | switch ((int)res) { |
163 | 163 | case 0x00: |
drivers/mtd/onenand/onenand_uboot.c
... | ... | @@ -26,8 +26,16 @@ |
26 | 26 | memset(&onenand_mtd, 0, sizeof(struct mtd_info)); |
27 | 27 | memset(&onenand_chip, 0, sizeof(struct onenand_chip)); |
28 | 28 | |
29 | - onenand_chip.base = (void *) CONFIG_SYS_ONENAND_BASE; | |
30 | 29 | onenand_mtd.priv = &onenand_chip; |
30 | + | |
31 | +#ifdef CONFIG_USE_ONENAND_BOARD_INIT | |
32 | + /* | |
33 | + * It's used for some board init required | |
34 | + */ | |
35 | + onenand_board_init(&onenand_mtd); | |
36 | +#else | |
37 | + onenand_chip.base = (void *) CONFIG_SYS_ONENAND_BASE; | |
38 | +#endif | |
31 | 39 | |
32 | 40 | onenand_scan(&onenand_mtd, 1); |
33 | 41 |
include/linux/mtd/onenand.h
... | ... | @@ -30,14 +30,10 @@ |
30 | 30 | |
31 | 31 | /** |
32 | 32 | * struct onenand_bufferram - OneNAND BufferRAM Data |
33 | - * @param block block address in BufferRAM | |
34 | - * @param page page address in BufferRAM | |
35 | - * @param valid valid flag | |
33 | + * @param blockpage block & page address in BufferRAM | |
36 | 34 | */ |
37 | 35 | struct onenand_bufferram { |
38 | - int block; | |
39 | - int page; | |
40 | - int valid; | |
36 | + int blockpage; | |
41 | 37 | }; |
42 | 38 | |
43 | 39 | /** |
... | ... | @@ -70,6 +66,8 @@ |
70 | 66 | void __iomem *base; |
71 | 67 | unsigned int chipsize; |
72 | 68 | unsigned int device_id; |
69 | + unsigned int version_id; | |
70 | + unsigned int density_mask; | |
73 | 71 | unsigned int options; |
74 | 72 | |
75 | 73 | unsigned int erase_shift; |
76 | 74 | |
77 | 75 | |
78 | 76 | |
79 | 77 | |
80 | 78 | |
81 | 79 | |
... | ... | @@ -81,26 +79,35 @@ |
81 | 79 | unsigned int bufferram_index; |
82 | 80 | struct onenand_bufferram bufferram[MAX_BUFFERRAM]; |
83 | 81 | |
84 | - int (*command) (struct mtd_info * mtd, int cmd, loff_t address, | |
82 | + int (*command) (struct mtd_info *mtd, int cmd, loff_t address, | |
85 | 83 | size_t len); |
86 | - int (*wait) (struct mtd_info * mtd, int state); | |
87 | - int (*read_bufferram) (struct mtd_info * mtd, int area, | |
84 | + int (*wait) (struct mtd_info *mtd, int state); | |
85 | + int (*bbt_wait) (struct mtd_info *mtd, int state); | |
86 | + int (*read_bufferram) (struct mtd_info *mtd, loff_t addr, int area, | |
88 | 87 | unsigned char *buffer, int offset, size_t count); |
89 | - int (*write_bufferram) (struct mtd_info * mtd, int area, | |
88 | + int (*read_spareram) (struct mtd_info *mtd, loff_t addr, int area, | |
89 | + unsigned char *buffer, int offset, size_t count); | |
90 | + int (*write_bufferram) (struct mtd_info *mtd, loff_t addr, int area, | |
90 | 91 | const unsigned char *buffer, int offset, |
91 | 92 | size_t count); |
92 | - unsigned short (*read_word) (void __iomem * addr); | |
93 | - void (*write_word) (unsigned short value, void __iomem * addr); | |
94 | - void (*mmcontrol) (struct mtd_info * mtd, int sync_read); | |
93 | + unsigned short (*read_word) (void __iomem *addr); | |
94 | + void (*write_word) (unsigned short value, void __iomem *addr); | |
95 | + void (*mmcontrol) (struct mtd_info *mtd, int sync_read); | |
95 | 96 | int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); |
96 | 97 | int (*scan_bbt)(struct mtd_info *mtd); |
97 | 98 | |
99 | + unsigned char *main_buf; | |
100 | + unsigned char *spare_buf; | |
101 | +#ifdef DONT_USE_UBOOT | |
102 | + spinlock_t chip_lock; | |
103 | + wait_queue_head_t wq; | |
104 | +#endif | |
98 | 105 | int state; |
99 | - unsigned char *page_buf; | |
100 | - unsigned char *oob_buf; | |
106 | + unsigned char *page_buf; | |
107 | + unsigned char *oob_buf; | |
101 | 108 | |
102 | 109 | struct nand_oobinfo *autooob; |
103 | - struct nand_ecclayout *ecclayout; | |
110 | + struct nand_ecclayout *ecclayout; | |
104 | 111 | |
105 | 112 | void *bbm; |
106 | 113 | |
... | ... | @@ -125,7 +132,9 @@ |
125 | 132 | /* |
126 | 133 | * Options bits |
127 | 134 | */ |
128 | -#define ONENAND_CONT_LOCK (0x0001) | |
135 | +#define ONENAND_HAS_CONT_LOCK (0x0001) | |
136 | +#define ONENAND_HAS_UNLOCK_ALL (0x0002) | |
137 | +#define ONENAND_HAS_2PLANE (0x0004) | |
129 | 138 | #define ONENAND_PAGEBUF_ALLOC (0x1000) |
130 | 139 | #define ONENAND_OOBBUF_ALLOC (0x2000) |
131 | 140 | |
... | ... | @@ -133,7 +142,6 @@ |
133 | 142 | * OneNAND Flash Manufacturer ID Codes |
134 | 143 | */ |
135 | 144 | #define ONENAND_MFR_SAMSUNG 0xec |
136 | -#define ONENAND_MFR_UNKNOWN 0x00 | |
137 | 145 | |
138 | 146 | /** |
139 | 147 | * struct nand_manufacturers - NAND Flash Manufacturer ID Structure |
include/linux/mtd/onenand_regs.h
... | ... | @@ -119,6 +119,7 @@ |
119 | 119 | #define ONENAND_CMD_UNLOCK (0x23) |
120 | 120 | #define ONENAND_CMD_LOCK (0x2A) |
121 | 121 | #define ONENAND_CMD_LOCK_TIGHT (0x2C) |
122 | +#define ONENAND_CMD_UNLOCK_ALL (0x27) | |
122 | 123 | #define ONENAND_CMD_ERASE (0x94) |
123 | 124 | #define ONENAND_CMD_RESET (0xF0) |
124 | 125 | #define ONENAND_CMD_READID (0x90) |
include/onenand_uboot.h
... | ... | @@ -15,26 +15,30 @@ |
15 | 15 | #define __UBOOT_ONENAND_H |
16 | 16 | |
17 | 17 | #include <linux/types.h> |
18 | -#include <linux/mtd/mtd.h> | |
19 | 18 | |
20 | 19 | struct mtd_info; |
21 | 20 | struct erase_info; |
21 | +struct onenand_chip; | |
22 | 22 | |
23 | 23 | extern struct mtd_info onenand_mtd; |
24 | 24 | |
25 | +/* board */ | |
26 | +extern void onenand_board_init(struct mtd_info *); | |
27 | + | |
25 | 28 | /* Functions */ |
26 | 29 | extern void onenand_init(void); |
27 | 30 | extern int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, |
28 | 31 | size_t * retlen, u_char * buf); |
29 | -extern int onenand_read_oob(struct mtd_info *mtd, loff_t from, | |
30 | - struct mtd_oob_ops *ops); | |
32 | +extern int onenand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops); | |
31 | 33 | extern int onenand_write(struct mtd_info *mtd, loff_t from, size_t len, |
32 | 34 | size_t * retlen, const u_char * buf); |
33 | 35 | extern int onenand_erase(struct mtd_info *mtd, struct erase_info *instr); |
34 | 36 | |
35 | -extern int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); | |
37 | +extern char *onenand_print_device_info(int device, int version); | |
36 | 38 | |
37 | -extern char *onenand_print_device_info(int device); | |
39 | +/* S3C64xx */ | |
40 | +extern void s3c64xx_onenand_init(struct mtd_info *); | |
41 | +extern void s3c64xx_set_width_regs(struct onenand_chip *); | |
38 | 42 | |
39 | 43 | #endif /* __UBOOT_ONENAND_H */ |