1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <common.h>
23#include <linux/mtd/compat.h>
24#include <linux/mtd/mtd.h>
25#include <linux/mtd/onenand.h>
26
27#include <asm/io.h>
28#include <asm/errno.h>
29#include <malloc.h>
30
31
32static void *memcpy_16(void *dst, const void *src, unsigned int len)
33{
34 void *ret = dst;
35 short *d = dst;
36 const short *s = src;
37
38 len >>= 1;
39 while (len-- > 0)
40 *d++ = *s++;
41 return ret;
42}
43
44
45
46
47
48static struct nand_ecclayout onenand_oob_128 = {
49 .eccbytes = 64,
50 .eccpos = {
51 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
52 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
53 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
54 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
55 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
56 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
57 102, 103, 104, 105
58 },
59 .oobfree = {
60 {2, 4}, {18, 4}, {34, 4}, {50, 4},
61 {66, 4}, {82, 4}, {98, 4}, {114, 4}
62 }
63};
64
65
66
67
68static struct nand_ecclayout onenand_oob_64 = {
69 .eccbytes = 20,
70 .eccpos = {
71 8, 9, 10, 11, 12,
72 24, 25, 26, 27, 28,
73 40, 41, 42, 43, 44,
74 56, 57, 58, 59, 60,
75 },
76 .oobfree = {
77 {2, 3}, {14, 2}, {18, 3}, {30, 2},
78 {34, 3}, {46, 2}, {50, 3}, {62, 2}
79 }
80};
81
82
83
84
85static struct nand_ecclayout onenand_oob_32 = {
86 .eccbytes = 10,
87 .eccpos = {
88 8, 9, 10, 11, 12,
89 24, 25, 26, 27, 28,
90 },
91 .oobfree = { {2, 3}, {14, 2}, {18, 3}, {30, 2} }
92};
93
94static const unsigned char ffchars[] = {
95 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
96 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
97 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
98 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
99 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
102 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
103 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
104 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
105 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
106 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
107 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
109 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
110 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
111};
112
113
114
115
116
117
118
119static unsigned short onenand_readw(void __iomem * addr)
120{
121 return readw(addr);
122}
123
124
125
126
127
128
129
130
131static void onenand_writew(unsigned short value, void __iomem * addr)
132{
133 writew(value, addr);
134}
135
136
137
138
139
140
141
142
143
144static int onenand_block_address(struct onenand_chip *this, int block)
145{
146
147 if (block & this->density_mask)
148 return ONENAND_DDP_CHIP1 | (block ^ this->density_mask);
149
150 return block;
151}
152
153
154
155
156
157
158
159
160
161static int onenand_bufferram_address(struct onenand_chip *this, int block)
162{
163
164 if (block & this->density_mask)
165 return ONENAND_DDP_CHIP1;
166
167 return ONENAND_DDP_CHIP0;
168}
169
170
171
172
173
174
175
176
177
178static int onenand_page_address(int page, int sector)
179{
180
181 int fpa, fsa;
182
183 fpa = page & ONENAND_FPA_MASK;
184 fsa = sector & ONENAND_FSA_MASK;
185
186 return ((fpa << ONENAND_FPA_SHIFT) | fsa);
187}
188
189
190
191
192
193
194
195
196
197
198static int onenand_buffer_address(int dataram1, int sectors, int count)
199{
200 int bsa, bsc;
201
202
203 bsa = sectors & ONENAND_BSA_MASK;
204
205 if (dataram1)
206 bsa |= ONENAND_BSA_DATARAM1;
207 else
208 bsa |= ONENAND_BSA_DATARAM0;
209
210
211 bsc = count & ONENAND_BSC_MASK;
212
213 return ((bsa << ONENAND_BSA_SHIFT) | bsc);
214}
215
216
217
218
219
220
221static unsigned int flexonenand_block(struct onenand_chip *this, loff_t addr)
222{
223 unsigned int boundary, blk, die = 0;
224
225 if (ONENAND_IS_DDP(this) && addr >= this->diesize[0]) {
226 die = 1;
227 addr -= this->diesize[0];
228 }
229
230 boundary = this->boundary[die];
231
232 blk = addr >> (this->erase_shift - 1);
233 if (blk > boundary)
234 blk = (blk + boundary + 1) >> 1;
235
236 blk += die ? this->density_mask : 0;
237 return blk;
238}
239
240unsigned int onenand_block(struct onenand_chip *this, loff_t addr)
241{
242 if (!FLEXONENAND(this))
243 return addr >> this->erase_shift;
244 return flexonenand_block(this, addr);
245}
246
247
248
249
250
251
252
253
254static loff_t flexonenand_addr(struct onenand_chip *this, int block)
255{
256 loff_t ofs = 0;
257 int die = 0, boundary;
258
259 if (ONENAND_IS_DDP(this) && block >= this->density_mask) {
260 block -= this->density_mask;
261 die = 1;
262 ofs = this->diesize[0];
263 }
264
265 boundary = this->boundary[die];
266 ofs += (loff_t) block << (this->erase_shift - 1);
267 if (block > (boundary + 1))
268 ofs += (loff_t) (block - boundary - 1)
269 << (this->erase_shift - 1);
270 return ofs;
271}
272
273loff_t onenand_addr(struct onenand_chip *this, int block)
274{
275 if (!FLEXONENAND(this))
276 return (loff_t) block << this->erase_shift;
277 return flexonenand_addr(this, block);
278}
279
280
281
282
283
284
285int flexonenand_region(struct mtd_info *mtd, loff_t addr)
286{
287 int i;
288
289 for (i = 0; i < mtd->numeraseregions; i++)
290 if (addr < mtd->eraseregions[i].offset)
291 break;
292 return i - 1;
293}
294
295
296
297
298
299
300
301static inline int onenand_get_density(int dev_id)
302{
303 int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
304 return (density & ONENAND_DEVICE_DENSITY_MASK);
305}
306
307
308
309
310
311
312
313
314
315
316
317static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
318 size_t len)
319{
320 struct onenand_chip *this = mtd->priv;
321 int value;
322 int block, page;
323
324
325 int sectors = 0, count = 0;
326
327
328 switch (cmd) {
329 case ONENAND_CMD_UNLOCK:
330 case ONENAND_CMD_LOCK:
331 case ONENAND_CMD_LOCK_TIGHT:
332 case ONENAND_CMD_UNLOCK_ALL:
333 block = -1;
334 page = -1;
335 break;
336
337 case FLEXONENAND_CMD_PI_ACCESS:
338
339 block = addr * this->density_mask;
340 page = -1;
341 break;
342
343 case ONENAND_CMD_ERASE:
344 case ONENAND_CMD_BUFFERRAM:
345 block = onenand_block(this, addr);
346 page = -1;
347 break;
348
349 case FLEXONENAND_CMD_READ_PI:
350 cmd = ONENAND_CMD_READ;
351 block = addr * this->density_mask;
352 page = 0;
353 break;
354
355 default:
356 block = onenand_block(this, addr);
357 page = (int) (addr
358 - onenand_addr(this, block)) >> this->page_shift;
359 page &= this->page_mask;
360 break;
361 }
362
363
364 if (cmd == ONENAND_CMD_BUFFERRAM) {
365
366 value = onenand_bufferram_address(this, block);
367 this->write_word(value,
368 this->base + ONENAND_REG_START_ADDRESS2);
369
370 if (ONENAND_IS_MLC(this))
371 ONENAND_SET_BUFFERRAM0(this);
372 else
373
374 ONENAND_SET_NEXT_BUFFERRAM(this);
375
376 return 0;
377 }
378
379 if (block != -1) {
380
381 value = onenand_block_address(this, block);
382 this->write_word(value,
383 this->base + ONENAND_REG_START_ADDRESS1);
384
385
386 value = onenand_bufferram_address(this, block);
387 this->write_word(value,
388 this->base + ONENAND_REG_START_ADDRESS2);
389 }
390
391 if (page != -1) {
392 int dataram;
393
394 switch (cmd) {
395 case FLEXONENAND_CMD_RECOVER_LSB:
396 case ONENAND_CMD_READ:
397 case ONENAND_CMD_READOOB:
398 if (ONENAND_IS_MLC(this))
399 dataram = ONENAND_SET_BUFFERRAM0(this);
400 else
401 dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
402
403 break;
404
405 default:
406 dataram = ONENAND_CURRENT_BUFFERRAM(this);
407 break;
408 }
409
410
411 value = onenand_page_address(page, sectors);
412 this->write_word(value,
413 this->base + ONENAND_REG_START_ADDRESS8);
414
415
416 value = onenand_buffer_address(dataram, sectors, count);
417 this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
418 }
419
420
421 this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
422
423 this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
424
425 return 0;
426}
427
428
429
430
431
432static int onenand_read_ecc(struct onenand_chip *this)
433{
434 int ecc, i;
435
436 if (!FLEXONENAND(this))
437 return this->read_word(this->base + ONENAND_REG_ECC_STATUS);
438
439 for (i = 0; i < 4; i++) {
440 ecc = this->read_word(this->base
441 + ((ONENAND_REG_ECC_STATUS + i) << 1));
442 if (likely(!ecc))
443 continue;
444 if (ecc & FLEXONENAND_UNCORRECTABLE_ERROR)
445 return ONENAND_ECC_2BIT_ALL;
446 }
447
448 return 0;
449}
450
451
452
453
454
455
456
457
458
459
460static int onenand_wait(struct mtd_info *mtd, int state)
461{
462 struct onenand_chip *this = mtd->priv;
463 unsigned int flags = ONENAND_INT_MASTER;
464 unsigned int interrupt = 0;
465 unsigned int ctrl;
466
467 while (1) {
468 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
469 if (interrupt & flags)
470 break;
471 }
472
473 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
474
475 if (interrupt & ONENAND_INT_READ) {
476 int ecc = onenand_read_ecc(this);
477 if (ecc & ONENAND_ECC_2BIT_ALL) {
478 printk("onenand_wait: ECC error = 0x%04x\n", ecc);
479 return -EBADMSG;
480 }
481 }
482
483 if (ctrl & ONENAND_CTRL_ERROR) {
484 printk("onenand_wait: controller error = 0x%04x\n", ctrl);
485 if (ctrl & ONENAND_CTRL_LOCK)
486 printk("onenand_wait: it's locked error = 0x%04x\n",
487 ctrl);
488
489 return -EIO;
490 }
491
492
493 return 0;
494}
495
496
497
498
499
500
501
502
503
504static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
505{
506 struct onenand_chip *this = mtd->priv;
507
508 if (ONENAND_CURRENT_BUFFERRAM(this)) {
509 if (area == ONENAND_DATARAM)
510 return mtd->writesize;
511 if (area == ONENAND_SPARERAM)
512 return mtd->oobsize;
513 }
514
515 return 0;
516}
517
518
519
520
521
522
523
524
525
526
527
528static int onenand_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,
529 unsigned char *buffer, int offset,
530 size_t count)
531{
532 struct onenand_chip *this = mtd->priv;
533 void __iomem *bufferram;
534
535 bufferram = this->base + area;
536 bufferram += onenand_bufferram_offset(mtd, area);
537
538 memcpy_16(buffer, bufferram + offset, count);
539
540 return 0;
541}
542
543
544
545
546
547
548
549
550
551
552
553static int onenand_sync_read_bufferram(struct mtd_info *mtd, loff_t addr, int area,
554 unsigned char *buffer, int offset,
555 size_t count)
556{
557 struct onenand_chip *this = mtd->priv;
558 void __iomem *bufferram;
559
560 bufferram = this->base + area;
561 bufferram += onenand_bufferram_offset(mtd, area);
562
563 this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ);
564
565 memcpy_16(buffer, bufferram + offset, count);
566
567 this->mmcontrol(mtd, 0);
568
569 return 0;
570}
571
572
573
574
575
576
577
578
579
580
581
582static int onenand_write_bufferram(struct mtd_info *mtd, loff_t addr, int area,
583 const unsigned char *buffer, int offset,
584 size_t count)
585{
586 struct onenand_chip *this = mtd->priv;
587 void __iomem *bufferram;
588
589 bufferram = this->base + area;
590 bufferram += onenand_bufferram_offset(mtd, area);
591
592 memcpy_16(bufferram + offset, buffer, count);
593
594 return 0;
595}
596
597
598
599
600
601
602
603
604
605static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr)
606{
607 struct onenand_chip *this = mtd->priv;
608 int blockpage, block, page;
609
610
611 block = (int) (addr >> this->erase_shift) & ~1;
612
613 if (addr & this->writesize)
614 block++;
615 page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;
616 blockpage = (block << 7) | page;
617
618 return blockpage;
619}
620
621
622
623
624
625
626
627
628
629static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
630{
631 struct onenand_chip *this = mtd->priv;
632 int blockpage, found = 0;
633 unsigned int i;
634
635#ifdef CONFIG_S3C64XX
636 return 0;
637#endif
638
639 if (ONENAND_IS_2PLANE(this))
640 blockpage = onenand_get_2x_blockpage(mtd, addr);
641 else
642 blockpage = (int) (addr >> this->page_shift);
643
644
645 i = ONENAND_CURRENT_BUFFERRAM(this);
646 if (this->bufferram[i].blockpage == blockpage)
647 found = 1;
648 else {
649
650 i = ONENAND_NEXT_BUFFERRAM(this);
651 if (this->bufferram[i].blockpage == blockpage) {
652 ONENAND_SET_NEXT_BUFFERRAM(this);
653 found = 1;
654 }
655 }
656
657 if (found && ONENAND_IS_DDP(this)) {
658
659 int block = onenand_block(this, addr);
660 int value = onenand_bufferram_address(this, block);
661 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
662 }
663
664 return found;
665}
666
667
668
669
670
671
672
673
674
675static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
676 int valid)
677{
678 struct onenand_chip *this = mtd->priv;
679 int blockpage;
680 unsigned int i;
681
682 if (ONENAND_IS_2PLANE(this))
683 blockpage = onenand_get_2x_blockpage(mtd, addr);
684 else
685 blockpage = (int)(addr >> this->page_shift);
686
687
688 i = ONENAND_NEXT_BUFFERRAM(this);
689 if (this->bufferram[i].blockpage == blockpage)
690 this->bufferram[i].blockpage = -1;
691
692
693 i = ONENAND_CURRENT_BUFFERRAM(this);
694 if (valid)
695 this->bufferram[i].blockpage = blockpage;
696 else
697 this->bufferram[i].blockpage = -1;
698
699 return 0;
700}
701
702
703
704
705
706
707
708
709
710static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr,
711 unsigned int len)
712{
713 struct onenand_chip *this = mtd->priv;
714 int i;
715 loff_t end_addr = addr + len;
716
717
718 for (i = 0; i < MAX_BUFFERRAM; i++) {
719 loff_t buf_addr = this->bufferram[i].blockpage << this->page_shift;
720
721 if (buf_addr >= addr && buf_addr < end_addr)
722 this->bufferram[i].blockpage = -1;
723 }
724}
725
726
727
728
729
730
731
732
733static void onenand_get_device(struct mtd_info *mtd, int new_state)
734{
735
736}
737
738
739
740
741
742
743
744static void onenand_release_device(struct mtd_info *mtd)
745{
746
747}
748
749
750
751
752
753
754
755
756static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
757 int column, int thislen)
758{
759 struct onenand_chip *this = mtd->priv;
760 struct nand_oobfree *free;
761 int readcol = column;
762 int readend = column + thislen;
763 int lastgap = 0;
764 unsigned int i;
765 uint8_t *oob_buf = this->oob_buf;
766
767 free = this->ecclayout->oobfree;
768 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
769 if (readcol >= lastgap)
770 readcol += free->offset - lastgap;
771 if (readend >= lastgap)
772 readend += free->offset - lastgap;
773 lastgap = free->offset + free->length;
774 }
775 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
776 free = this->ecclayout->oobfree;
777 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
778 int free_end = free->offset + free->length;
779 if (free->offset < readend && free_end > readcol) {
780 int st = max_t(int,free->offset,readcol);
781 int ed = min_t(int,free_end,readend);
782 int n = ed - st;
783 memcpy(buf, oob_buf + st, n);
784 buf += n;
785 } else if (column == 0)
786 break;
787 }
788 return 0;
789}
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
805{
806 struct onenand_chip *this = mtd->priv;
807 int i;
808
809
810 if (!FLEXONENAND(this))
811 return status;
812
813
814 if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR)
815 return status;
816
817
818 i = flexonenand_region(mtd, addr);
819 if (mtd->eraseregions[i].erasesize < (1 << this->erase_shift))
820 return status;
821
822 printk("onenand_recover_lsb:"
823 "Attempting to recover from uncorrectable read\n");
824
825
826 this->command(mtd, FLEXONENAND_CMD_RECOVER_LSB, addr, this->writesize);
827 return this->wait(mtd, FL_READING);
828}
829
830
831
832
833
834
835
836
837
838static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
839 struct mtd_oob_ops *ops)
840{
841 struct onenand_chip *this = mtd->priv;
842 struct mtd_ecc_stats stats;
843 size_t len = ops->len;
844 size_t ooblen = ops->ooblen;
845 u_char *buf = ops->datbuf;
846 u_char *oobbuf = ops->oobbuf;
847 int read = 0, column, thislen;
848 int oobread = 0, oobcolumn, thisooblen, oobsize;
849 int ret = 0, boundary = 0;
850 int writesize = this->writesize;
851
852 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
853
854 if (ops->mode == MTD_OOB_AUTO)
855 oobsize = this->ecclayout->oobavail;
856 else
857 oobsize = mtd->oobsize;
858
859 oobcolumn = from & (mtd->oobsize - 1);
860
861
862 if ((from + len) > mtd->size) {
863 printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n");
864 ops->retlen = 0;
865 ops->oobretlen = 0;
866 return -EINVAL;
867 }
868
869 stats = mtd->ecc_stats;
870
871
872
873
874
875 if (read < len) {
876 if (!onenand_check_bufferram(mtd, from)) {
877 this->main_buf = buf;
878 this->command(mtd, ONENAND_CMD_READ, from, writesize);
879 ret = this->wait(mtd, FL_READING);
880 if (unlikely(ret))
881 ret = onenand_recover_lsb(mtd, from, ret);
882 onenand_update_bufferram(mtd, from, !ret);
883 if (ret == -EBADMSG)
884 ret = 0;
885 }
886 }
887
888 thislen = min_t(int, writesize, len - read);
889 column = from & (writesize - 1);
890 if (column + thislen > writesize)
891 thislen = writesize - column;
892
893 while (!ret) {
894
895 from += thislen;
896 if (!ONENAND_IS_MLC(this) && read + thislen < len) {
897 this->main_buf = buf + thislen;
898 this->command(mtd, ONENAND_CMD_READ, from, writesize);
899
900
901
902
903
904 if (ONENAND_IS_DDP(this) &&
905 unlikely(from == (this->chipsize >> 1))) {
906 this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);
907 boundary = 1;
908 } else
909 boundary = 0;
910 ONENAND_SET_PREV_BUFFERRAM(this);
911 }
912
913
914 this->read_bufferram(mtd, from - thislen, ONENAND_DATARAM, buf, column, thislen);
915
916
917 if (oobbuf) {
918 thisooblen = oobsize - oobcolumn;
919 thisooblen = min_t(int, thisooblen, ooblen - oobread);
920
921 if (ops->mode == MTD_OOB_AUTO)
922 onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
923 else
924 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
925 oobread += thisooblen;
926 oobbuf += thisooblen;
927 oobcolumn = 0;
928 }
929
930 if (ONENAND_IS_MLC(this) && (read + thislen < len)) {
931 this->command(mtd, ONENAND_CMD_READ, from, writesize);
932 ret = this->wait(mtd, FL_READING);
933 if (unlikely(ret))
934 ret = onenand_recover_lsb(mtd, from, ret);
935 onenand_update_bufferram(mtd, from, !ret);
936 if (ret == -EBADMSG)
937 ret = 0;
938 }
939
940
941 read += thislen;
942 if (read == len)
943 break;
944
945 if (unlikely(boundary))
946 this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
947 if (!ONENAND_IS_MLC(this))
948 ONENAND_SET_NEXT_BUFFERRAM(this);
949 buf += thislen;
950 thislen = min_t(int, writesize, len - read);
951 column = 0;
952
953 if (!ONENAND_IS_MLC(this)) {
954
955 ret = this->wait(mtd, FL_READING);
956 onenand_update_bufferram(mtd, from, !ret);
957 if (ret == -EBADMSG)
958 ret = 0;
959 }
960 }
961
962
963
964
965
966
967 ops->retlen = read;
968 ops->oobretlen = oobread;
969
970 if (ret)
971 return ret;
972
973 if (mtd->ecc_stats.failed - stats.failed)
974 return -EBADMSG;
975
976 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
977}
978
979
980
981
982
983
984
985
986
987static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
988 struct mtd_oob_ops *ops)
989{
990 struct onenand_chip *this = mtd->priv;
991 struct mtd_ecc_stats stats;
992 int read = 0, thislen, column, oobsize;
993 size_t len = ops->ooblen;
994 mtd_oob_mode_t mode = ops->mode;
995 u_char *buf = ops->oobbuf;
996 int ret = 0, readcmd;
997
998 from += ops->ooboffs;
999
1000 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
1001
1002
1003 ops->oobretlen = 0;
1004
1005 if (mode == MTD_OOB_AUTO)
1006 oobsize = this->ecclayout->oobavail;
1007 else
1008 oobsize = mtd->oobsize;
1009
1010 column = from & (mtd->oobsize - 1);
1011
1012 if (unlikely(column >= oobsize)) {
1013 printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");
1014 return -EINVAL;
1015 }
1016
1017
1018 if (unlikely(from >= mtd->size ||
1019 column + len > ((mtd->size >> this->page_shift) -
1020 (from >> this->page_shift)) * oobsize)) {
1021 printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");
1022 return -EINVAL;
1023 }
1024
1025 stats = mtd->ecc_stats;
1026
1027 readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
1028
1029 while (read < len) {
1030 thislen = oobsize - column;
1031 thislen = min_t(int, thislen, len);
1032
1033 this->spare_buf = buf;
1034 this->command(mtd, readcmd, from, mtd->oobsize);
1035
1036 onenand_update_bufferram(mtd, from, 0);
1037
1038 ret = this->wait(mtd, FL_READING);
1039 if (unlikely(ret))
1040 ret = onenand_recover_lsb(mtd, from, ret);
1041
1042 if (ret && ret != -EBADMSG) {
1043 printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
1044 break;
1045 }
1046
1047 if (mode == MTD_OOB_AUTO)
1048 onenand_transfer_auto_oob(mtd, buf, column, thislen);
1049 else
1050 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
1051
1052 read += thislen;
1053
1054 if (read == len)
1055 break;
1056
1057 buf += thislen;
1058
1059
1060 if (read < len) {
1061
1062 from += mtd->writesize;
1063 column = 0;
1064 }
1065 }
1066
1067 ops->oobretlen = read;
1068
1069 if (ret)
1070 return ret;
1071
1072 if (mtd->ecc_stats.failed - stats.failed)
1073 return -EBADMSG;
1074
1075 return 0;
1076}
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
1089 size_t * retlen, u_char * buf)
1090{
1091 struct mtd_oob_ops ops = {
1092 .len = len,
1093 .ooblen = 0,
1094 .datbuf = buf,
1095 .oobbuf = NULL,
1096 };
1097 int ret;
1098
1099 onenand_get_device(mtd, FL_READING);
1100 ret = onenand_read_ops_nolock(mtd, from, &ops);
1101 onenand_release_device(mtd);
1102
1103 *retlen = ops.retlen;
1104 return ret;
1105}
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115int onenand_read_oob(struct mtd_info *mtd, loff_t from,
1116 struct mtd_oob_ops *ops)
1117{
1118 int ret;
1119
1120 switch (ops->mode) {
1121 case MTD_OOB_PLACE:
1122 case MTD_OOB_AUTO:
1123 break;
1124 case MTD_OOB_RAW:
1125
1126 default:
1127 return -EINVAL;
1128 }
1129
1130 onenand_get_device(mtd, FL_READING);
1131 if (ops->datbuf)
1132 ret = onenand_read_ops_nolock(mtd, from, ops);
1133 else
1134 ret = onenand_read_oob_nolock(mtd, from, ops);
1135 onenand_release_device(mtd);
1136
1137 return ret;
1138}
1139
1140
1141
1142
1143
1144
1145
1146
1147static int onenand_bbt_wait(struct mtd_info *mtd, int state)
1148{
1149 struct onenand_chip *this = mtd->priv;
1150 unsigned int flags = ONENAND_INT_MASTER;
1151 unsigned int interrupt;
1152 unsigned int ctrl;
1153
1154 while (1) {
1155 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1156 if (interrupt & flags)
1157 break;
1158 }
1159
1160
1161 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1162 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
1163
1164 if (interrupt & ONENAND_INT_READ) {
1165 int ecc = onenand_read_ecc(this);
1166 if (ecc & ONENAND_ECC_2BIT_ALL) {
1167 printk(KERN_INFO "onenand_bbt_wait: ecc error = 0x%04x"
1168 ", controller = 0x%04x\n", ecc, ctrl);
1169 return ONENAND_BBT_READ_ERROR;
1170 }
1171 } else {
1172 printk(KERN_ERR "onenand_bbt_wait: read timeout!"
1173 "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
1174 return ONENAND_BBT_READ_FATAL_ERROR;
1175 }
1176
1177
1178 if (ctrl & ONENAND_CTRL_ERROR) {
1179 printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
1180 return ONENAND_BBT_READ_ERROR;
1181 }
1182
1183 return 0;
1184}
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
1195 struct mtd_oob_ops *ops)
1196{
1197 struct onenand_chip *this = mtd->priv;
1198 int read = 0, thislen, column;
1199 int ret = 0, readcmd;
1200 size_t len = ops->ooblen;
1201 u_char *buf = ops->oobbuf;
1202
1203 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len);
1204
1205 readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
1206
1207
1208 ops->oobretlen = 0;
1209
1210
1211 if (unlikely((from + len) > mtd->size)) {
1212 printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");
1213 return ONENAND_BBT_READ_FATAL_ERROR;
1214 }
1215
1216
1217 onenand_get_device(mtd, FL_READING);
1218
1219 column = from & (mtd->oobsize - 1);
1220
1221 while (read < len) {
1222
1223 thislen = mtd->oobsize - column;
1224 thislen = min_t(int, thislen, len);
1225
1226 this->spare_buf = buf;
1227 this->command(mtd, readcmd, from, mtd->oobsize);
1228
1229 onenand_update_bufferram(mtd, from, 0);
1230
1231 ret = this->bbt_wait(mtd, FL_READING);
1232 if (unlikely(ret))
1233 ret = onenand_recover_lsb(mtd, from, ret);
1234
1235 if (ret)
1236 break;
1237
1238 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
1239 read += thislen;
1240 if (read == len)
1241 break;
1242
1243 buf += thislen;
1244
1245
1246 if (read < len) {
1247
1248 from += this->writesize;
1249 column = 0;
1250 }
1251 }
1252
1253
1254 onenand_release_device(mtd);
1255
1256 ops->oobretlen = read;
1257 return ret;
1258}
1259
1260
1261#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
1262
1263
1264
1265
1266
1267
1268static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
1269{
1270 struct onenand_chip *this = mtd->priv;
1271 u_char *oob_buf = this->oob_buf;
1272 int status, i, readcmd;
1273
1274 readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
1275
1276 this->command(mtd, readcmd, to, mtd->oobsize);
1277 onenand_update_bufferram(mtd, to, 0);
1278 status = this->wait(mtd, FL_READING);
1279 if (status)
1280 return status;
1281
1282 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
1283 for (i = 0; i < mtd->oobsize; i++)
1284 if (buf[i] != 0xFF && buf[i] != oob_buf[i])
1285 return -EBADMSG;
1286
1287 return 0;
1288}
1289
1290
1291
1292
1293
1294
1295
1296
1297static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
1298{
1299 struct onenand_chip *this = mtd->priv;
1300 void __iomem *dataram;
1301 int ret = 0;
1302 int thislen, column;
1303
1304 while (len != 0) {
1305 thislen = min_t(int, this->writesize, len);
1306 column = addr & (this->writesize - 1);
1307 if (column + thislen > this->writesize)
1308 thislen = this->writesize - column;
1309
1310 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
1311
1312 onenand_update_bufferram(mtd, addr, 0);
1313
1314 ret = this->wait(mtd, FL_READING);
1315 if (ret)
1316 return ret;
1317
1318 onenand_update_bufferram(mtd, addr, 1);
1319
1320 dataram = this->base + ONENAND_DATARAM;
1321 dataram += onenand_bufferram_offset(mtd, ONENAND_DATARAM);
1322
1323 if (memcmp(buf, dataram + column, thislen))
1324 return -EBADMSG;
1325
1326 len -= thislen;
1327 buf += thislen;
1328 addr += thislen;
1329 }
1330
1331 return 0;
1332}
1333#else
1334#define onenand_verify(...) (0)
1335#define onenand_verify_oob(...) (0)
1336#endif
1337
1338#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1349 const u_char *buf, int column, int thislen)
1350{
1351 struct onenand_chip *this = mtd->priv;
1352 struct nand_oobfree *free;
1353 int writecol = column;
1354 int writeend = column + thislen;
1355 int lastgap = 0;
1356 unsigned int i;
1357
1358 free = this->ecclayout->oobfree;
1359 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1360 if (writecol >= lastgap)
1361 writecol += free->offset - lastgap;
1362 if (writeend >= lastgap)
1363 writeend += free->offset - lastgap;
1364 lastgap = free->offset + free->length;
1365 }
1366 free = this->ecclayout->oobfree;
1367 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1368 int free_end = free->offset + free->length;
1369 if (free->offset < writeend && free_end > writecol) {
1370 int st = max_t(int,free->offset,writecol);
1371 int ed = min_t(int,free_end,writeend);
1372 int n = ed - st;
1373 memcpy(oob_buf + st, buf, n);
1374 buf += n;
1375 } else if (column == 0)
1376 break;
1377 }
1378 return 0;
1379}
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
1390 struct mtd_oob_ops *ops)
1391{
1392 struct onenand_chip *this = mtd->priv;
1393 int written = 0, column, thislen, subpage;
1394 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1395 size_t len = ops->len;
1396 size_t ooblen = ops->ooblen;
1397 const u_char *buf = ops->datbuf;
1398 const u_char *oob = ops->oobbuf;
1399 u_char *oobbuf;
1400 int ret = 0;
1401
1402 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
1403
1404
1405 ops->retlen = 0;
1406 ops->oobretlen = 0;
1407
1408
1409 if (unlikely((to + len) > mtd->size)) {
1410 printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
1411 return -EINVAL;
1412 }
1413
1414
1415 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
1416 printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
1417 return -EINVAL;
1418 }
1419
1420 if (ops->mode == MTD_OOB_AUTO)
1421 oobsize = this->ecclayout->oobavail;
1422 else
1423 oobsize = mtd->oobsize;
1424
1425 oobcolumn = to & (mtd->oobsize - 1);
1426
1427 column = to & (mtd->writesize - 1);
1428
1429
1430 while (written < len) {
1431 u_char *wbuf = (u_char *) buf;
1432
1433 thislen = min_t(int, mtd->writesize - column, len - written);
1434 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
1435
1436 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1437
1438
1439 subpage = thislen < mtd->writesize;
1440 if (subpage) {
1441 memset(this->page_buf, 0xff, mtd->writesize);
1442 memcpy(this->page_buf + column, buf, thislen);
1443 wbuf = this->page_buf;
1444 }
1445
1446 this->write_bufferram(mtd, to, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
1447
1448 if (oob) {
1449 oobbuf = this->oob_buf;
1450
1451
1452
1453 memset(oobbuf, 0xff, mtd->oobsize);
1454 if (ops->mode == MTD_OOB_AUTO)
1455 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1456 else
1457 memcpy(oobbuf + oobcolumn, oob, thisooblen);
1458
1459 oobwritten += thisooblen;
1460 oob += thisooblen;
1461 oobcolumn = 0;
1462 } else
1463 oobbuf = (u_char *) ffchars;
1464
1465 this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
1466
1467 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
1468
1469 ret = this->wait(mtd, FL_WRITING);
1470
1471
1472 onenand_update_bufferram(mtd, to, !ret && !subpage);
1473 if (ONENAND_IS_2PLANE(this)) {
1474 ONENAND_SET_BUFFERRAM1(this);
1475 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
1476 }
1477
1478 if (ret) {
1479 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
1480 break;
1481 }
1482
1483
1484 ret = onenand_verify(mtd, buf, to, thislen);
1485 if (ret) {
1486 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
1487 break;
1488 }
1489
1490 written += thislen;
1491
1492 if (written == len)
1493 break;
1494
1495 column = 0;
1496 to += thislen;
1497 buf += thislen;
1498 }
1499
1500 ops->retlen = written;
1501
1502 return ret;
1503}
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
1517 struct mtd_oob_ops *ops)
1518{
1519 struct onenand_chip *this = mtd->priv;
1520 int column, ret = 0, oobsize;
1521 int written = 0, oobcmd;
1522 u_char *oobbuf;
1523 size_t len = ops->ooblen;
1524 const u_char *buf = ops->oobbuf;
1525 mtd_oob_mode_t mode = ops->mode;
1526
1527 to += ops->ooboffs;
1528
1529 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
1530
1531
1532 ops->oobretlen = 0;
1533
1534 if (mode == MTD_OOB_AUTO)
1535 oobsize = this->ecclayout->oobavail;
1536 else
1537 oobsize = mtd->oobsize;
1538
1539 column = to & (mtd->oobsize - 1);
1540
1541 if (unlikely(column >= oobsize)) {
1542 printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");
1543 return -EINVAL;
1544 }
1545
1546
1547 if (unlikely(column + len > oobsize)) {
1548 printk(KERN_ERR "onenand_write_oob_nolock: "
1549 "Attempt to write past end of page\n");
1550 return -EINVAL;
1551 }
1552
1553
1554 if (unlikely(to >= mtd->size ||
1555 column + len > ((mtd->size >> this->page_shift) -
1556 (to >> this->page_shift)) * oobsize)) {
1557 printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");
1558 return -EINVAL;
1559 }
1560
1561 oobbuf = this->oob_buf;
1562
1563 oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
1564
1565
1566 while (written < len) {
1567 int thislen = min_t(int, oobsize, len - written);
1568
1569 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
1570
1571
1572
1573 memset(oobbuf, 0xff, mtd->oobsize);
1574 if (mode == MTD_OOB_AUTO)
1575 onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
1576 else
1577 memcpy(oobbuf + column, buf, thislen);
1578 this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
1579
1580 if (ONENAND_IS_MLC(this)) {
1581
1582 memset(this->page_buf, 0xff, mtd->writesize);
1583 this->write_bufferram(mtd, 0, ONENAND_DATARAM,
1584 this->page_buf, 0, mtd->writesize);
1585 }
1586
1587 this->command(mtd, oobcmd, to, mtd->oobsize);
1588
1589 onenand_update_bufferram(mtd, to, 0);
1590 if (ONENAND_IS_2PLANE(this)) {
1591 ONENAND_SET_BUFFERRAM1(this);
1592 onenand_update_bufferram(mtd, to + this->writesize, 0);
1593 }
1594
1595 ret = this->wait(mtd, FL_WRITING);
1596 if (ret) {
1597 printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret);
1598 break;
1599 }
1600
1601 ret = onenand_verify_oob(mtd, oobbuf, to);
1602 if (ret) {
1603 printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);
1604 break;
1605 }
1606
1607 written += thislen;
1608 if (written == len)
1609 break;
1610
1611 to += mtd->writesize;
1612 buf += thislen;
1613 column = 0;
1614 }
1615
1616 ops->oobretlen = written;
1617
1618 return ret;
1619}
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
1632 size_t * retlen, const u_char * buf)
1633{
1634 struct mtd_oob_ops ops = {
1635 .len = len,
1636 .ooblen = 0,
1637 .datbuf = (u_char *) buf,
1638 .oobbuf = NULL,
1639 };
1640 int ret;
1641
1642 onenand_get_device(mtd, FL_WRITING);
1643 ret = onenand_write_ops_nolock(mtd, to, &ops);
1644 onenand_release_device(mtd);
1645
1646 *retlen = ops.retlen;
1647 return ret;
1648}
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658int onenand_write_oob(struct mtd_info *mtd, loff_t to,
1659 struct mtd_oob_ops *ops)
1660{
1661 int ret;
1662
1663 switch (ops->mode) {
1664 case MTD_OOB_PLACE:
1665 case MTD_OOB_AUTO:
1666 break;
1667 case MTD_OOB_RAW:
1668
1669 default:
1670 return -EINVAL;
1671 }
1672
1673 onenand_get_device(mtd, FL_WRITING);
1674 if (ops->datbuf)
1675 ret = onenand_write_ops_nolock(mtd, to, ops);
1676 else
1677 ret = onenand_write_oob_nolock(mtd, to, ops);
1678 onenand_release_device(mtd);
1679
1680 return ret;
1681
1682}
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
1694{
1695 struct onenand_chip *this = mtd->priv;
1696 struct bbm_info *bbm = this->bbm;
1697
1698
1699 return bbm->isbad_bbt(mtd, ofs, allowbbt);
1700}
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
1711{
1712 struct onenand_chip *this = mtd->priv;
1713 unsigned int block_size;
1714 loff_t addr = instr->addr;
1715 unsigned int len = instr->len;
1716 int ret = 0, i;
1717 struct mtd_erase_region_info *region = NULL;
1718 unsigned int region_end = 0;
1719
1720 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",
1721 (unsigned int) addr, len);
1722
1723
1724 if (unlikely((len + addr) > mtd->size)) {
1725 MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
1726 "Erase past end of device\n");
1727 return -EINVAL;
1728 }
1729
1730 if (FLEXONENAND(this)) {
1731
1732 i = flexonenand_region(mtd, addr);
1733 region = &mtd->eraseregions[i];
1734
1735 block_size = region->erasesize;
1736 region_end = region->offset
1737 + region->erasesize * region->numblocks;
1738
1739
1740
1741
1742 if (unlikely((addr - region->offset) & (block_size - 1))) {
1743 MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
1744 " Unaligned address\n");
1745 return -EINVAL;
1746 }
1747 } else {
1748 block_size = 1 << this->erase_shift;
1749
1750
1751 if (unlikely(addr & (block_size - 1))) {
1752 MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
1753 "Unaligned address\n");
1754 return -EINVAL;
1755 }
1756 }
1757
1758
1759 if (unlikely(len & (block_size - 1))) {
1760 MTDDEBUG (MTD_DEBUG_LEVEL0,
1761 "onenand_erase: Length not block aligned\n");
1762 return -EINVAL;
1763 }
1764
1765 instr->fail_addr = 0xffffffff;
1766
1767
1768 onenand_get_device(mtd, FL_ERASING);
1769
1770
1771 instr->state = MTD_ERASING;
1772
1773 while (len) {
1774
1775
1776 if (instr->priv == 0 && onenand_block_isbad_nolock(mtd, addr, 0)) {
1777 printk(KERN_WARNING "onenand_erase: attempt to erase"
1778 " a bad block at addr 0x%08x\n",
1779 (unsigned int) addr);
1780 instr->state = MTD_ERASE_FAILED;
1781 goto erase_exit;
1782 }
1783
1784 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
1785
1786 onenand_invalidate_bufferram(mtd, addr, block_size);
1787
1788 ret = this->wait(mtd, FL_ERASING);
1789
1790 if (ret) {
1791 if (ret == -EPERM)
1792 MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
1793 "Device is write protected!!!\n");
1794 else
1795 MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
1796 "Failed erase, block %d\n",
1797 onenand_block(this, addr));
1798 instr->state = MTD_ERASE_FAILED;
1799 instr->fail_addr = addr;
1800
1801 goto erase_exit;
1802 }
1803
1804 len -= block_size;
1805 addr += block_size;
1806
1807 if (addr == region_end) {
1808 if (!len)
1809 break;
1810 region++;
1811
1812 block_size = region->erasesize;
1813 region_end = region->offset
1814 + region->erasesize * region->numblocks;
1815
1816 if (len & (block_size - 1)) {
1817
1818
1819 printk("onenand_erase: Unaligned address\n");
1820 goto erase_exit;
1821 }
1822 }
1823 }
1824
1825 instr->state = MTD_ERASE_DONE;
1826
1827erase_exit:
1828
1829 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
1830
1831 if (!ret)
1832 mtd_erase_callback(instr);
1833
1834
1835 onenand_release_device(mtd);
1836
1837 return ret;
1838}
1839
1840
1841
1842
1843
1844
1845
1846void onenand_sync(struct mtd_info *mtd)
1847{
1848 MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_sync: called\n");
1849
1850
1851 onenand_get_device(mtd, FL_SYNCING);
1852
1853
1854 onenand_release_device(mtd);
1855}
1856
1857
1858
1859
1860
1861
1862
1863
1864int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
1865{
1866 int ret;
1867
1868
1869 if (ofs > mtd->size)
1870 return -EINVAL;
1871
1872 onenand_get_device(mtd, FL_READING);
1873 ret = onenand_block_isbad_nolock(mtd,ofs, 0);
1874 onenand_release_device(mtd);
1875 return ret;
1876}
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
1887{
1888 struct onenand_chip *this = mtd->priv;
1889 struct bbm_info *bbm = this->bbm;
1890 u_char buf[2] = {0, 0};
1891 struct mtd_oob_ops ops = {
1892 .mode = MTD_OOB_PLACE,
1893 .ooblen = 2,
1894 .oobbuf = buf,
1895 .ooboffs = 0,
1896 };
1897 int block;
1898
1899
1900 block = onenand_block(this, ofs);
1901 if (bbm->bbt)
1902 bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
1903
1904
1905 ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
1906 return onenand_write_oob_nolock(mtd, ofs, &ops);
1907}
1908
1909
1910
1911
1912
1913
1914
1915
1916int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
1917{
1918 struct onenand_chip *this = mtd->priv;
1919 int ret;
1920
1921 ret = onenand_block_isbad(mtd, ofs);
1922 if (ret) {
1923
1924 if (ret > 0)
1925 return 0;
1926 return ret;
1927 }
1928
1929 ret = this->block_markbad(mtd, ofs);
1930 return ret;
1931}
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
1943{
1944 struct onenand_chip *this = mtd->priv;
1945 int start, end, block, value, status;
1946 int wp_status_mask;
1947
1948 start = onenand_block(this, ofs);
1949 end = onenand_block(this, ofs + len);
1950
1951 if (cmd == ONENAND_CMD_LOCK)
1952 wp_status_mask = ONENAND_WP_LS;
1953 else
1954 wp_status_mask = ONENAND_WP_US;
1955
1956
1957 if (this->options & ONENAND_HAS_CONT_LOCK) {
1958
1959 this->write_word(start,
1960 this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1961
1962 this->write_word(end - 1,
1963 this->base + ONENAND_REG_END_BLOCK_ADDRESS);
1964
1965 this->command(mtd, cmd, 0, 0);
1966
1967
1968 this->wait(mtd, FL_UNLOCKING);
1969
1970
1971 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1972 & ONENAND_CTRL_ONGO)
1973 continue;
1974
1975
1976 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1977 if (!(status & ONENAND_WP_US))
1978 printk(KERN_ERR "wp status = 0x%x\n", status);
1979
1980 return 0;
1981 }
1982
1983
1984 for (block = start; block < end; block++) {
1985
1986 value = onenand_block_address(this, block);
1987 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
1988
1989 value = onenand_bufferram_address(this, block);
1990 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
1991
1992
1993 this->write_word(block,
1994 this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1995
1996 this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
1997
1998
1999 this->wait(mtd, FL_UNLOCKING);
2000
2001
2002 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2003 & ONENAND_CTRL_ONGO)
2004 continue;
2005
2006
2007 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
2008 if (!(status & ONENAND_WP_US))
2009 printk(KERN_ERR "block = %d, wp status = 0x%x\n",
2010 block, status);
2011 }
2012
2013 return 0;
2014}
2015
2016#ifdef ONENAND_LINUX
2017
2018
2019
2020
2021
2022
2023
2024
2025static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
2026{
2027 int ret;
2028
2029 onenand_get_device(mtd, FL_LOCKING);
2030 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
2031 onenand_release_device(mtd);
2032 return ret;
2033}
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
2044{
2045 int ret;
2046
2047 onenand_get_device(mtd, FL_LOCKING);
2048 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
2049 onenand_release_device(mtd);
2050 return ret;
2051}
2052#endif
2053
2054
2055
2056
2057
2058
2059
2060static int onenand_check_lock_status(struct onenand_chip *this)
2061{
2062 unsigned int value, block, status;
2063 unsigned int end;
2064
2065 end = this->chipsize >> this->erase_shift;
2066 for (block = 0; block < end; block++) {
2067
2068 value = onenand_block_address(this, block);
2069 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2070
2071 value = onenand_bufferram_address(this, block);
2072 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
2073
2074 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2075
2076
2077 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
2078 if (!(status & ONENAND_WP_US)) {
2079 printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
2080 return 0;
2081 }
2082 }
2083
2084 return 1;
2085}
2086
2087
2088
2089
2090
2091
2092
2093static void onenand_unlock_all(struct mtd_info *mtd)
2094{
2095 struct onenand_chip *this = mtd->priv;
2096 loff_t ofs = 0;
2097 size_t len = mtd->size;
2098
2099 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
2100
2101 this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2102
2103 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
2104
2105
2106 this->wait(mtd, FL_LOCKING);
2107
2108
2109 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2110 & ONENAND_CTRL_ONGO)
2111 continue;
2112
2113
2114 if (onenand_check_lock_status(this))
2115 return;
2116
2117
2118 if (ONENAND_IS_DDP(this) && !FLEXONENAND(this)) {
2119
2120 ofs = this->chipsize >> 1;
2121 len = this->chipsize >> 1;
2122 }
2123 }
2124
2125 onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
2126}
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137static void onenand_check_features(struct mtd_info *mtd)
2138{
2139 struct onenand_chip *this = mtd->priv;
2140 unsigned int density, process;
2141
2142
2143 density = onenand_get_density(this->device_id);
2144 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
2145
2146
2147 switch (density) {
2148 case ONENAND_DEVICE_DENSITY_4Gb:
2149 this->options |= ONENAND_HAS_2PLANE;
2150
2151 case ONENAND_DEVICE_DENSITY_2Gb:
2152
2153 if (!ONENAND_IS_DDP(this))
2154 this->options |= ONENAND_HAS_2PLANE;
2155 this->options |= ONENAND_HAS_UNLOCK_ALL;
2156
2157 case ONENAND_DEVICE_DENSITY_1Gb:
2158
2159 if (process)
2160 this->options |= ONENAND_HAS_UNLOCK_ALL;
2161 break;
2162
2163 default:
2164
2165 if (!process)
2166 this->options |= ONENAND_HAS_CONT_LOCK;
2167 break;
2168 }
2169
2170 if (ONENAND_IS_MLC(this))
2171 this->options &= ~ONENAND_HAS_2PLANE;
2172
2173 if (FLEXONENAND(this)) {
2174 this->options &= ~ONENAND_HAS_CONT_LOCK;
2175 this->options |= ONENAND_HAS_UNLOCK_ALL;
2176 }
2177
2178 if (this->options & ONENAND_HAS_CONT_LOCK)
2179 printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
2180 if (this->options & ONENAND_HAS_UNLOCK_ALL)
2181 printk(KERN_DEBUG "Chip support all block unlock\n");
2182 if (this->options & ONENAND_HAS_2PLANE)
2183 printk(KERN_DEBUG "Chip has 2 plane\n");
2184}
2185
2186
2187
2188
2189
2190
2191
2192char *onenand_print_device_info(int device, int version)
2193{
2194 int vcc, demuxed, ddp, density, flexonenand;
2195 char *dev_info = malloc(80);
2196 char *p = dev_info;
2197
2198 vcc = device & ONENAND_DEVICE_VCC_MASK;
2199 demuxed = device & ONENAND_DEVICE_IS_DEMUX;
2200 ddp = device & ONENAND_DEVICE_IS_DDP;
2201 density = onenand_get_density(device);
2202 flexonenand = device & DEVICE_IS_FLEXONENAND;
2203 p += sprintf(dev_info, "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
2204 demuxed ? "" : "Muxed ",
2205 flexonenand ? "Flex-" : "",
2206 ddp ? "(DDP)" : "",
2207 (16 << density), vcc ? "2.65/3.3" : "1.8", device);
2208
2209 sprintf(p, "\nOneNAND version = 0x%04x", version);
2210 printk("%s\n", dev_info);
2211
2212 return dev_info;
2213}
2214
2215static const struct onenand_manufacturers onenand_manuf_ids[] = {
2216 {ONENAND_MFR_NUMONYX, "Numonyx"},
2217 {ONENAND_MFR_SAMSUNG, "Samsung"},
2218};
2219
2220
2221
2222
2223
2224
2225
2226static int onenand_check_maf(int manuf)
2227{
2228 int size = ARRAY_SIZE(onenand_manuf_ids);
2229 char *name;
2230 int i;
2231
2232 for (i = 0; i < size; i++)
2233 if (manuf == onenand_manuf_ids[i].id)
2234 break;
2235
2236 if (i < size)
2237 name = onenand_manuf_ids[i].name;
2238 else
2239 name = "Unknown";
2240
2241#ifdef ONENAND_DEBUG
2242 printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);
2243#endif
2244
2245 return i == size;
2246}
2247
2248
2249
2250
2251
2252
2253
2254static int flexonenand_get_boundary(struct mtd_info *mtd)
2255{
2256 struct onenand_chip *this = mtd->priv;
2257 unsigned int die, bdry;
2258 int ret, syscfg, locked;
2259
2260
2261 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
2262 this->write_word((syscfg | 0x0100), this->base + ONENAND_REG_SYS_CFG1);
2263
2264 for (die = 0; die < this->dies; die++) {
2265 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
2266 this->wait(mtd, FL_SYNCING);
2267
2268 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
2269 ret = this->wait(mtd, FL_READING);
2270
2271 bdry = this->read_word(this->base + ONENAND_DATARAM);
2272 if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3)
2273 locked = 0;
2274 else
2275 locked = 1;
2276 this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
2277
2278 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
2279 ret = this->wait(mtd, FL_RESETING);
2280
2281 printk(KERN_INFO "Die %d boundary: %d%s\n", die,
2282 this->boundary[die], locked ? "(Locked)" : "(Unlocked)");
2283 }
2284
2285
2286 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
2287 return 0;
2288}
2289
2290
2291
2292
2293
2294
2295
2296static void flexonenand_get_size(struct mtd_info *mtd)
2297{
2298 struct onenand_chip *this = mtd->priv;
2299 int die, i, eraseshift, density;
2300 int blksperdie, maxbdry;
2301 loff_t ofs;
2302
2303 density = onenand_get_density(this->device_id);
2304 blksperdie = ((loff_t)(16 << density) << 20) >> (this->erase_shift);
2305 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
2306 maxbdry = blksperdie - 1;
2307 eraseshift = this->erase_shift - 1;
2308
2309 mtd->numeraseregions = this->dies << 1;
2310
2311
2312 flexonenand_get_boundary(mtd);
2313 die = 0;
2314 ofs = 0;
2315 i = -1;
2316 for (; die < this->dies; die++) {
2317 if (!die || this->boundary[die-1] != maxbdry) {
2318 i++;
2319 mtd->eraseregions[i].offset = ofs;
2320 mtd->eraseregions[i].erasesize = 1 << eraseshift;
2321 mtd->eraseregions[i].numblocks =
2322 this->boundary[die] + 1;
2323 ofs += mtd->eraseregions[i].numblocks << eraseshift;
2324 eraseshift++;
2325 } else {
2326 mtd->numeraseregions -= 1;
2327 mtd->eraseregions[i].numblocks +=
2328 this->boundary[die] + 1;
2329 ofs += (this->boundary[die] + 1) << (eraseshift - 1);
2330 }
2331 if (this->boundary[die] != maxbdry) {
2332 i++;
2333 mtd->eraseregions[i].offset = ofs;
2334 mtd->eraseregions[i].erasesize = 1 << eraseshift;
2335 mtd->eraseregions[i].numblocks = maxbdry ^
2336 this->boundary[die];
2337 ofs += mtd->eraseregions[i].numblocks << eraseshift;
2338 eraseshift--;
2339 } else
2340 mtd->numeraseregions -= 1;
2341 }
2342
2343
2344 mtd->erasesize = 1 << this->erase_shift;
2345 if (mtd->numeraseregions == 1)
2346 mtd->erasesize >>= 1;
2347
2348 printk(KERN_INFO "Device has %d eraseregions\n", mtd->numeraseregions);
2349 for (i = 0; i < mtd->numeraseregions; i++)
2350 printk(KERN_INFO "[offset: 0x%08llx, erasesize: 0x%05x,"
2351 " numblocks: %04u]\n", mtd->eraseregions[i].offset,
2352 mtd->eraseregions[i].erasesize,
2353 mtd->eraseregions[i].numblocks);
2354
2355 for (die = 0, mtd->size = 0; die < this->dies; die++) {
2356 this->diesize[die] = (loff_t) (blksperdie << this->erase_shift);
2357 this->diesize[die] -= (loff_t) (this->boundary[die] + 1)
2358 << (this->erase_shift - 1);
2359 mtd->size += this->diesize[die];
2360 }
2361}
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377static int flexonenand_check_blocks_erased(struct mtd_info *mtd,
2378 int start, int end)
2379{
2380 struct onenand_chip *this = mtd->priv;
2381 int i, ret;
2382 int block;
2383 struct mtd_oob_ops ops = {
2384 .mode = MTD_OOB_PLACE,
2385 .ooboffs = 0,
2386 .ooblen = mtd->oobsize,
2387 .datbuf = NULL,
2388 .oobbuf = this->oob_buf,
2389 };
2390 loff_t addr;
2391
2392 printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end);
2393
2394 for (block = start; block <= end; block++) {
2395 addr = flexonenand_addr(this, block);
2396 if (onenand_block_isbad_nolock(mtd, addr, 0))
2397 continue;
2398
2399
2400
2401
2402
2403 ret = onenand_read_oob_nolock(mtd, addr, &ops);
2404 if (ret)
2405 return ret;
2406
2407 for (i = 0; i < mtd->oobsize; i++)
2408 if (this->oob_buf[i] != 0xff)
2409 break;
2410
2411 if (i != mtd->oobsize) {
2412 printk(KERN_WARNING "Block %d not erased.\n", block);
2413 return 1;
2414 }
2415 }
2416
2417 return 0;
2418}
2419
2420
2421
2422
2423
2424int flexonenand_set_boundary(struct mtd_info *mtd, int die,
2425 int boundary, int lock)
2426{
2427 struct onenand_chip *this = mtd->priv;
2428 int ret, density, blksperdie, old, new, thisboundary;
2429 loff_t addr;
2430
2431 if (die >= this->dies)
2432 return -EINVAL;
2433
2434 if (boundary == this->boundary[die])
2435 return 0;
2436
2437 density = onenand_get_density(this->device_id);
2438 blksperdie = ((16 << density) << 20) >> this->erase_shift;
2439 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
2440
2441 if (boundary >= blksperdie) {
2442 printk("flexonenand_set_boundary:"
2443 "Invalid boundary value. "
2444 "Boundary not changed.\n");
2445 return -EINVAL;
2446 }
2447
2448
2449 old = this->boundary[die] + (die * this->density_mask);
2450 new = boundary + (die * this->density_mask);
2451 ret = flexonenand_check_blocks_erased(mtd, min(old, new)
2452 + 1, max(old, new));
2453 if (ret) {
2454 printk(KERN_ERR "flexonenand_set_boundary: Please erase blocks before boundary change\n");
2455 return ret;
2456 }
2457
2458 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
2459 this->wait(mtd, FL_SYNCING);
2460
2461
2462 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
2463 ret = this->wait(mtd, FL_READING);
2464
2465 thisboundary = this->read_word(this->base + ONENAND_DATARAM);
2466 if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) {
2467 printk(KERN_ERR "flexonenand_set_boundary: boundary locked\n");
2468 goto out;
2469 }
2470
2471 printk(KERN_INFO "flexonenand_set_boundary: Changing die %d boundary: %d%s\n",
2472 die, boundary, lock ? "(Locked)" : "(Unlocked)");
2473
2474 boundary &= FLEXONENAND_PI_MASK;
2475 boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
2476
2477 addr = die ? this->diesize[0] : 0;
2478 this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
2479 ret = this->wait(mtd, FL_ERASING);
2480 if (ret) {
2481 printk("flexonenand_set_boundary:"
2482 "Failed PI erase for Die %d\n", die);
2483 goto out;
2484 }
2485
2486 this->write_word(boundary, this->base + ONENAND_DATARAM);
2487 this->command(mtd, ONENAND_CMD_PROG, addr, 0);
2488 ret = this->wait(mtd, FL_WRITING);
2489 if (ret) {
2490 printk("flexonenand_set_boundary:"
2491 "Failed PI write for Die %d\n", die);
2492 goto out;
2493 }
2494
2495 this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0);
2496 ret = this->wait(mtd, FL_WRITING);
2497out:
2498 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND);
2499 this->wait(mtd, FL_RESETING);
2500 if (!ret)
2501
2502 flexonenand_get_size(mtd);
2503
2504 return ret;
2505}
2506
2507
2508
2509
2510
2511
2512
2513
2514static int onenand_probe(struct mtd_info *mtd)
2515{
2516 struct onenand_chip *this = mtd->priv;
2517 int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id;
2518 int density;
2519 int syscfg;
2520
2521
2522 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
2523
2524 this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ), this->base + ONENAND_REG_SYS_CFG1);
2525
2526
2527 this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
2528
2529
2530 bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
2531 bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
2532
2533
2534 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
2535
2536
2537 this->wait(mtd, FL_RESETING);
2538
2539
2540 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
2541
2542
2543 if (onenand_check_maf(bram_maf_id))
2544 return -ENXIO;
2545
2546
2547 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
2548 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
2549 ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
2550 this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
2551
2552
2553 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
2554 return -ENXIO;
2555
2556
2557 mtd->name = onenand_print_device_info(dev_id, ver_id);
2558 this->device_id = dev_id;
2559 this->version_id = ver_id;
2560
2561 density = onenand_get_density(dev_id);
2562 if (FLEXONENAND(this)) {
2563 this->dies = ONENAND_IS_DDP(this) ? 2 : 1;
2564
2565 mtd->numeraseregions = this->dies << 1;
2566 mtd->eraseregions = malloc(sizeof(struct mtd_erase_region_info)
2567 * (this->dies << 1));
2568 if (!mtd->eraseregions)
2569 return -ENOMEM;
2570 }
2571
2572
2573
2574
2575
2576 this->chipsize = (16 << density) << 20;
2577
2578
2579
2580 mtd->writesize =
2581 this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
2582
2583 if (ONENAND_IS_MLC(this))
2584 mtd->writesize <<= 1;
2585
2586 mtd->oobsize = mtd->writesize >> 5;
2587
2588 mtd->erasesize = mtd->writesize << 6;
2589
2590
2591
2592
2593
2594 if (FLEXONENAND(this))
2595 mtd->erasesize <<= 1;
2596
2597 this->erase_shift = ffs(mtd->erasesize) - 1;
2598 this->page_shift = ffs(mtd->writesize) - 1;
2599 this->ppb_shift = (this->erase_shift - this->page_shift);
2600 this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
2601
2602 if (ONENAND_IS_DDP(this))
2603 this->density_mask = this->chipsize >> (this->erase_shift + 1);
2604
2605 this->writesize = mtd->writesize;
2606
2607
2608
2609 if (FLEXONENAND(this))
2610 flexonenand_get_size(mtd);
2611 else
2612 mtd->size = this->chipsize;
2613
2614
2615 onenand_check_features(mtd);
2616
2617 mtd->flags = MTD_CAP_NANDFLASH;
2618 mtd->erase = onenand_erase;
2619 mtd->read = onenand_read;
2620 mtd->write = onenand_write;
2621 mtd->read_oob = onenand_read_oob;
2622 mtd->write_oob = onenand_write_oob;
2623 mtd->sync = onenand_sync;
2624 mtd->block_isbad = onenand_block_isbad;
2625 mtd->block_markbad = onenand_block_markbad;
2626
2627 return 0;
2628}
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640int onenand_scan(struct mtd_info *mtd, int maxchips)
2641{
2642 int i;
2643 struct onenand_chip *this = mtd->priv;
2644
2645 if (!this->read_word)
2646 this->read_word = onenand_readw;
2647 if (!this->write_word)
2648 this->write_word = onenand_writew;
2649
2650 if (!this->command)
2651 this->command = onenand_command;
2652 if (!this->wait)
2653 this->wait = onenand_wait;
2654 if (!this->bbt_wait)
2655 this->bbt_wait = onenand_bbt_wait;
2656
2657 if (!this->read_bufferram)
2658 this->read_bufferram = onenand_read_bufferram;
2659 if (!this->write_bufferram)
2660 this->write_bufferram = onenand_write_bufferram;
2661
2662 if (!this->block_markbad)
2663 this->block_markbad = onenand_default_block_markbad;
2664 if (!this->scan_bbt)
2665 this->scan_bbt = onenand_default_bbt;
2666
2667 if (onenand_probe(mtd))
2668 return -ENXIO;
2669
2670
2671 if (this->mmcontrol) {
2672 printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
2673 this->read_bufferram = onenand_sync_read_bufferram;
2674 }
2675
2676
2677 if (!this->page_buf) {
2678 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
2679 if (!this->page_buf) {
2680 printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
2681 return -ENOMEM;
2682 }
2683 this->options |= ONENAND_PAGEBUF_ALLOC;
2684 }
2685 if (!this->oob_buf) {
2686 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
2687 if (!this->oob_buf) {
2688 printk(KERN_ERR "onenand_scan: Can't allocate oob_buf\n");
2689 if (this->options & ONENAND_PAGEBUF_ALLOC) {
2690 this->options &= ~ONENAND_PAGEBUF_ALLOC;
2691 kfree(this->page_buf);
2692 }
2693 return -ENOMEM;
2694 }
2695 this->options |= ONENAND_OOBBUF_ALLOC;
2696 }
2697
2698 this->state = FL_READY;
2699
2700
2701
2702
2703 switch (mtd->oobsize) {
2704 case 128:
2705 this->ecclayout = &onenand_oob_128;
2706 mtd->subpage_sft = 0;
2707 break;
2708
2709 case 64:
2710 this->ecclayout = &onenand_oob_64;
2711 mtd->subpage_sft = 2;
2712 break;
2713
2714 case 32:
2715 this->ecclayout = &onenand_oob_32;
2716 mtd->subpage_sft = 1;
2717 break;
2718
2719 default:
2720 printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n",
2721 mtd->oobsize);
2722 mtd->subpage_sft = 0;
2723
2724 this->ecclayout = &onenand_oob_32;
2725 break;
2726 }
2727
2728 this->subpagesize = mtd->writesize >> mtd->subpage_sft;
2729
2730
2731
2732
2733
2734 this->ecclayout->oobavail = 0;
2735 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
2736 this->ecclayout->oobfree[i].length; i++)
2737 this->ecclayout->oobavail +=
2738 this->ecclayout->oobfree[i].length;
2739 mtd->oobavail = this->ecclayout->oobavail;
2740
2741 mtd->ecclayout = this->ecclayout;
2742
2743
2744 onenand_unlock_all(mtd);
2745
2746 return this->scan_bbt(mtd);
2747}
2748
2749
2750
2751
2752
2753void onenand_release(struct mtd_info *mtd)
2754{
2755}
2756