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_4KB_PAGE(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_4KB_PAGE(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_4KB_PAGE(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_4KB_PAGE(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_4KB_PAGE(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_4KB_PAGE(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_4KB_PAGE(this) ?
1028 ONENAND_CMD_READ : ONENAND_CMD_READOOB;
1029
1030 while (read < len) {
1031 thislen = oobsize - column;
1032 thislen = min_t(int, thislen, len);
1033
1034 this->spare_buf = buf;
1035 this->command(mtd, readcmd, from, mtd->oobsize);
1036
1037 onenand_update_bufferram(mtd, from, 0);
1038
1039 ret = this->wait(mtd, FL_READING);
1040 if (unlikely(ret))
1041 ret = onenand_recover_lsb(mtd, from, ret);
1042
1043 if (ret && ret != -EBADMSG) {
1044 printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
1045 break;
1046 }
1047
1048 if (mode == MTD_OOB_AUTO)
1049 onenand_transfer_auto_oob(mtd, buf, column, thislen);
1050 else
1051 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
1052
1053 read += thislen;
1054
1055 if (read == len)
1056 break;
1057
1058 buf += thislen;
1059
1060
1061 if (read < len) {
1062
1063 from += mtd->writesize;
1064 column = 0;
1065 }
1066 }
1067
1068 ops->oobretlen = read;
1069
1070 if (ret)
1071 return ret;
1072
1073 if (mtd->ecc_stats.failed - stats.failed)
1074 return -EBADMSG;
1075
1076 return 0;
1077}
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
1090 size_t * retlen, u_char * buf)
1091{
1092 struct mtd_oob_ops ops = {
1093 .len = len,
1094 .ooblen = 0,
1095 .datbuf = buf,
1096 .oobbuf = NULL,
1097 };
1098 int ret;
1099
1100 onenand_get_device(mtd, FL_READING);
1101 ret = onenand_read_ops_nolock(mtd, from, &ops);
1102 onenand_release_device(mtd);
1103
1104 *retlen = ops.retlen;
1105 return ret;
1106}
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116int onenand_read_oob(struct mtd_info *mtd, loff_t from,
1117 struct mtd_oob_ops *ops)
1118{
1119 int ret;
1120
1121 switch (ops->mode) {
1122 case MTD_OOB_PLACE:
1123 case MTD_OOB_AUTO:
1124 break;
1125 case MTD_OOB_RAW:
1126
1127 default:
1128 return -EINVAL;
1129 }
1130
1131 onenand_get_device(mtd, FL_READING);
1132 if (ops->datbuf)
1133 ret = onenand_read_ops_nolock(mtd, from, ops);
1134 else
1135 ret = onenand_read_oob_nolock(mtd, from, ops);
1136 onenand_release_device(mtd);
1137
1138 return ret;
1139}
1140
1141
1142
1143
1144
1145
1146
1147
1148static int onenand_bbt_wait(struct mtd_info *mtd, int state)
1149{
1150 struct onenand_chip *this = mtd->priv;
1151 unsigned int flags = ONENAND_INT_MASTER;
1152 unsigned int interrupt;
1153 unsigned int ctrl;
1154
1155 while (1) {
1156 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1157 if (interrupt & flags)
1158 break;
1159 }
1160
1161
1162 interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
1163 ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
1164
1165 if (interrupt & ONENAND_INT_READ) {
1166 int ecc = onenand_read_ecc(this);
1167 if (ecc & ONENAND_ECC_2BIT_ALL) {
1168 printk(KERN_INFO "onenand_bbt_wait: ecc error = 0x%04x"
1169 ", controller = 0x%04x\n", ecc, ctrl);
1170 return ONENAND_BBT_READ_ERROR;
1171 }
1172 } else {
1173 printk(KERN_ERR "onenand_bbt_wait: read timeout!"
1174 "ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
1175 return ONENAND_BBT_READ_FATAL_ERROR;
1176 }
1177
1178
1179 if (ctrl & ONENAND_CTRL_ERROR) {
1180 printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
1181 return ONENAND_BBT_READ_ERROR;
1182 }
1183
1184 return 0;
1185}
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
1196 struct mtd_oob_ops *ops)
1197{
1198 struct onenand_chip *this = mtd->priv;
1199 int read = 0, thislen, column;
1200 int ret = 0, readcmd;
1201 size_t len = ops->ooblen;
1202 u_char *buf = ops->oobbuf;
1203
1204 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len);
1205
1206 readcmd = ONENAND_IS_4KB_PAGE(this) ?
1207 ONENAND_CMD_READ : ONENAND_CMD_READOOB;
1208
1209
1210 ops->oobretlen = 0;
1211
1212
1213 if (unlikely((from + len) > mtd->size)) {
1214 printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");
1215 return ONENAND_BBT_READ_FATAL_ERROR;
1216 }
1217
1218
1219 onenand_get_device(mtd, FL_READING);
1220
1221 column = from & (mtd->oobsize - 1);
1222
1223 while (read < len) {
1224
1225 thislen = mtd->oobsize - column;
1226 thislen = min_t(int, thislen, len);
1227
1228 this->spare_buf = buf;
1229 this->command(mtd, readcmd, from, mtd->oobsize);
1230
1231 onenand_update_bufferram(mtd, from, 0);
1232
1233 ret = this->bbt_wait(mtd, FL_READING);
1234 if (unlikely(ret))
1235 ret = onenand_recover_lsb(mtd, from, ret);
1236
1237 if (ret)
1238 break;
1239
1240 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);
1241 read += thislen;
1242 if (read == len)
1243 break;
1244
1245 buf += thislen;
1246
1247
1248 if (read < len) {
1249
1250 from += this->writesize;
1251 column = 0;
1252 }
1253 }
1254
1255
1256 onenand_release_device(mtd);
1257
1258 ops->oobretlen = read;
1259 return ret;
1260}
1261
1262
1263#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
1264
1265
1266
1267
1268
1269
1270static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
1271{
1272 struct onenand_chip *this = mtd->priv;
1273 u_char *oob_buf = this->oob_buf;
1274 int status, i, readcmd;
1275
1276 readcmd = ONENAND_IS_4KB_PAGE(this) ?
1277 ONENAND_CMD_READ : ONENAND_CMD_READOOB;
1278
1279 this->command(mtd, readcmd, to, mtd->oobsize);
1280 onenand_update_bufferram(mtd, to, 0);
1281 status = this->wait(mtd, FL_READING);
1282 if (status)
1283 return status;
1284
1285 this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
1286 for (i = 0; i < mtd->oobsize; i++)
1287 if (buf[i] != 0xFF && buf[i] != oob_buf[i])
1288 return -EBADMSG;
1289
1290 return 0;
1291}
1292
1293
1294
1295
1296
1297
1298
1299
1300static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
1301{
1302 struct onenand_chip *this = mtd->priv;
1303 void __iomem *dataram;
1304 int ret = 0;
1305 int thislen, column;
1306
1307 while (len != 0) {
1308 thislen = min_t(int, this->writesize, len);
1309 column = addr & (this->writesize - 1);
1310 if (column + thislen > this->writesize)
1311 thislen = this->writesize - column;
1312
1313 this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
1314
1315 onenand_update_bufferram(mtd, addr, 0);
1316
1317 ret = this->wait(mtd, FL_READING);
1318 if (ret)
1319 return ret;
1320
1321 onenand_update_bufferram(mtd, addr, 1);
1322
1323 dataram = this->base + ONENAND_DATARAM;
1324 dataram += onenand_bufferram_offset(mtd, ONENAND_DATARAM);
1325
1326 if (memcmp(buf, dataram + column, thislen))
1327 return -EBADMSG;
1328
1329 len -= thislen;
1330 buf += thislen;
1331 addr += thislen;
1332 }
1333
1334 return 0;
1335}
1336#else
1337#define onenand_verify(...) (0)
1338#define onenand_verify_oob(...) (0)
1339#endif
1340
1341#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
1352 const u_char *buf, int column, int thislen)
1353{
1354 struct onenand_chip *this = mtd->priv;
1355 struct nand_oobfree *free;
1356 int writecol = column;
1357 int writeend = column + thislen;
1358 int lastgap = 0;
1359 unsigned int i;
1360
1361 free = this->ecclayout->oobfree;
1362 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1363 if (writecol >= lastgap)
1364 writecol += free->offset - lastgap;
1365 if (writeend >= lastgap)
1366 writeend += free->offset - lastgap;
1367 lastgap = free->offset + free->length;
1368 }
1369 free = this->ecclayout->oobfree;
1370 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
1371 int free_end = free->offset + free->length;
1372 if (free->offset < writeend && free_end > writecol) {
1373 int st = max_t(int,free->offset,writecol);
1374 int ed = min_t(int,free_end,writeend);
1375 int n = ed - st;
1376 memcpy(oob_buf + st, buf, n);
1377 buf += n;
1378 } else if (column == 0)
1379 break;
1380 }
1381 return 0;
1382}
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
1393 struct mtd_oob_ops *ops)
1394{
1395 struct onenand_chip *this = mtd->priv;
1396 int written = 0, column, thislen, subpage;
1397 int oobwritten = 0, oobcolumn, thisooblen, oobsize;
1398 size_t len = ops->len;
1399 size_t ooblen = ops->ooblen;
1400 const u_char *buf = ops->datbuf;
1401 const u_char *oob = ops->oobbuf;
1402 u_char *oobbuf;
1403 int ret = 0;
1404
1405 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
1406
1407
1408 ops->retlen = 0;
1409 ops->oobretlen = 0;
1410
1411
1412 if (unlikely((to + len) > mtd->size)) {
1413 printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
1414 return -EINVAL;
1415 }
1416
1417
1418 if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {
1419 printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
1420 return -EINVAL;
1421 }
1422
1423 if (ops->mode == MTD_OOB_AUTO)
1424 oobsize = this->ecclayout->oobavail;
1425 else
1426 oobsize = mtd->oobsize;
1427
1428 oobcolumn = to & (mtd->oobsize - 1);
1429
1430 column = to & (mtd->writesize - 1);
1431
1432
1433 while (written < len) {
1434 u_char *wbuf = (u_char *) buf;
1435
1436 thislen = min_t(int, mtd->writesize - column, len - written);
1437 thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
1438
1439 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
1440
1441
1442 subpage = thislen < mtd->writesize;
1443 if (subpage) {
1444 memset(this->page_buf, 0xff, mtd->writesize);
1445 memcpy(this->page_buf + column, buf, thislen);
1446 wbuf = this->page_buf;
1447 }
1448
1449 this->write_bufferram(mtd, to, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
1450
1451 if (oob) {
1452 oobbuf = this->oob_buf;
1453
1454
1455
1456 memset(oobbuf, 0xff, mtd->oobsize);
1457 if (ops->mode == MTD_OOB_AUTO)
1458 onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
1459 else
1460 memcpy(oobbuf + oobcolumn, oob, thisooblen);
1461
1462 oobwritten += thisooblen;
1463 oob += thisooblen;
1464 oobcolumn = 0;
1465 } else
1466 oobbuf = (u_char *) ffchars;
1467
1468 this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
1469
1470 this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
1471
1472 ret = this->wait(mtd, FL_WRITING);
1473
1474
1475 onenand_update_bufferram(mtd, to, !ret && !subpage);
1476 if (ONENAND_IS_2PLANE(this)) {
1477 ONENAND_SET_BUFFERRAM1(this);
1478 onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
1479 }
1480
1481 if (ret) {
1482 printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
1483 break;
1484 }
1485
1486
1487 ret = onenand_verify(mtd, buf, to, thislen);
1488 if (ret) {
1489 printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
1490 break;
1491 }
1492
1493 written += thislen;
1494
1495 if (written == len)
1496 break;
1497
1498 column = 0;
1499 to += thislen;
1500 buf += thislen;
1501 }
1502
1503 ops->retlen = written;
1504
1505 return ret;
1506}
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
1520 struct mtd_oob_ops *ops)
1521{
1522 struct onenand_chip *this = mtd->priv;
1523 int column, ret = 0, oobsize;
1524 int written = 0, oobcmd;
1525 u_char *oobbuf;
1526 size_t len = ops->ooblen;
1527 const u_char *buf = ops->oobbuf;
1528 mtd_oob_mode_t mode = ops->mode;
1529
1530 to += ops->ooboffs;
1531
1532 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
1533
1534
1535 ops->oobretlen = 0;
1536
1537 if (mode == MTD_OOB_AUTO)
1538 oobsize = this->ecclayout->oobavail;
1539 else
1540 oobsize = mtd->oobsize;
1541
1542 column = to & (mtd->oobsize - 1);
1543
1544 if (unlikely(column >= oobsize)) {
1545 printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");
1546 return -EINVAL;
1547 }
1548
1549
1550 if (unlikely(column + len > oobsize)) {
1551 printk(KERN_ERR "onenand_write_oob_nolock: "
1552 "Attempt to write past end of page\n");
1553 return -EINVAL;
1554 }
1555
1556
1557 if (unlikely(to >= mtd->size ||
1558 column + len > ((mtd->size >> this->page_shift) -
1559 (to >> this->page_shift)) * oobsize)) {
1560 printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");
1561 return -EINVAL;
1562 }
1563
1564 oobbuf = this->oob_buf;
1565
1566 oobcmd = ONENAND_IS_4KB_PAGE(this) ?
1567 ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
1568
1569
1570 while (written < len) {
1571 int thislen = min_t(int, oobsize, len - written);
1572
1573 this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
1574
1575
1576
1577 memset(oobbuf, 0xff, mtd->oobsize);
1578 if (mode == MTD_OOB_AUTO)
1579 onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);
1580 else
1581 memcpy(oobbuf + column, buf, thislen);
1582 this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
1583
1584 if (ONENAND_IS_4KB_PAGE(this)) {
1585
1586 memset(this->page_buf, 0xff, mtd->writesize);
1587 this->write_bufferram(mtd, 0, ONENAND_DATARAM,
1588 this->page_buf, 0, mtd->writesize);
1589 }
1590
1591 this->command(mtd, oobcmd, to, mtd->oobsize);
1592
1593 onenand_update_bufferram(mtd, to, 0);
1594 if (ONENAND_IS_2PLANE(this)) {
1595 ONENAND_SET_BUFFERRAM1(this);
1596 onenand_update_bufferram(mtd, to + this->writesize, 0);
1597 }
1598
1599 ret = this->wait(mtd, FL_WRITING);
1600 if (ret) {
1601 printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret);
1602 break;
1603 }
1604
1605 ret = onenand_verify_oob(mtd, oobbuf, to);
1606 if (ret) {
1607 printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);
1608 break;
1609 }
1610
1611 written += thislen;
1612 if (written == len)
1613 break;
1614
1615 to += mtd->writesize;
1616 buf += thislen;
1617 column = 0;
1618 }
1619
1620 ops->oobretlen = written;
1621
1622 return ret;
1623}
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
1636 size_t * retlen, const u_char * buf)
1637{
1638 struct mtd_oob_ops ops = {
1639 .len = len,
1640 .ooblen = 0,
1641 .datbuf = (u_char *) buf,
1642 .oobbuf = NULL,
1643 };
1644 int ret;
1645
1646 onenand_get_device(mtd, FL_WRITING);
1647 ret = onenand_write_ops_nolock(mtd, to, &ops);
1648 onenand_release_device(mtd);
1649
1650 *retlen = ops.retlen;
1651 return ret;
1652}
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662int onenand_write_oob(struct mtd_info *mtd, loff_t to,
1663 struct mtd_oob_ops *ops)
1664{
1665 int ret;
1666
1667 switch (ops->mode) {
1668 case MTD_OOB_PLACE:
1669 case MTD_OOB_AUTO:
1670 break;
1671 case MTD_OOB_RAW:
1672
1673 default:
1674 return -EINVAL;
1675 }
1676
1677 onenand_get_device(mtd, FL_WRITING);
1678 if (ops->datbuf)
1679 ret = onenand_write_ops_nolock(mtd, to, ops);
1680 else
1681 ret = onenand_write_oob_nolock(mtd, to, ops);
1682 onenand_release_device(mtd);
1683
1684 return ret;
1685
1686}
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
1698{
1699 struct onenand_chip *this = mtd->priv;
1700 struct bbm_info *bbm = this->bbm;
1701
1702
1703 return bbm->isbad_bbt(mtd, ofs, allowbbt);
1704}
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
1715{
1716 struct onenand_chip *this = mtd->priv;
1717 unsigned int block_size;
1718 loff_t addr = instr->addr;
1719 unsigned int len = instr->len;
1720 int ret = 0, i;
1721 struct mtd_erase_region_info *region = NULL;
1722 unsigned int region_end = 0;
1723
1724 MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",
1725 (unsigned int) addr, len);
1726
1727
1728 if (unlikely((len + addr) > mtd->size)) {
1729 MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
1730 "Erase past end of device\n");
1731 return -EINVAL;
1732 }
1733
1734 if (FLEXONENAND(this)) {
1735
1736 i = flexonenand_region(mtd, addr);
1737 region = &mtd->eraseregions[i];
1738
1739 block_size = region->erasesize;
1740 region_end = region->offset
1741 + region->erasesize * region->numblocks;
1742
1743
1744
1745
1746 if (unlikely((addr - region->offset) & (block_size - 1))) {
1747 MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
1748 " Unaligned address\n");
1749 return -EINVAL;
1750 }
1751 } else {
1752 block_size = 1 << this->erase_shift;
1753
1754
1755 if (unlikely(addr & (block_size - 1))) {
1756 MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:"
1757 "Unaligned address\n");
1758 return -EINVAL;
1759 }
1760 }
1761
1762
1763 if (unlikely(len & (block_size - 1))) {
1764 MTDDEBUG (MTD_DEBUG_LEVEL0,
1765 "onenand_erase: Length not block aligned\n");
1766 return -EINVAL;
1767 }
1768
1769 instr->fail_addr = 0xffffffff;
1770
1771
1772 onenand_get_device(mtd, FL_ERASING);
1773
1774
1775 instr->state = MTD_ERASING;
1776
1777 while (len) {
1778
1779
1780 if (instr->priv == 0 && onenand_block_isbad_nolock(mtd, addr, 0)) {
1781 printk(KERN_WARNING "onenand_erase: attempt to erase"
1782 " a bad block at addr 0x%08x\n",
1783 (unsigned int) addr);
1784 instr->state = MTD_ERASE_FAILED;
1785 goto erase_exit;
1786 }
1787
1788 this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
1789
1790 onenand_invalidate_bufferram(mtd, addr, block_size);
1791
1792 ret = this->wait(mtd, FL_ERASING);
1793
1794 if (ret) {
1795 if (ret == -EPERM)
1796 MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
1797 "Device is write protected!!!\n");
1798 else
1799 MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
1800 "Failed erase, block %d\n",
1801 onenand_block(this, addr));
1802 instr->state = MTD_ERASE_FAILED;
1803 instr->fail_addr = addr;
1804
1805 goto erase_exit;
1806 }
1807
1808 len -= block_size;
1809 addr += block_size;
1810
1811 if (addr == region_end) {
1812 if (!len)
1813 break;
1814 region++;
1815
1816 block_size = region->erasesize;
1817 region_end = region->offset
1818 + region->erasesize * region->numblocks;
1819
1820 if (len & (block_size - 1)) {
1821
1822
1823 printk("onenand_erase: Unaligned address\n");
1824 goto erase_exit;
1825 }
1826 }
1827 }
1828
1829 instr->state = MTD_ERASE_DONE;
1830
1831erase_exit:
1832
1833 ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
1834
1835 if (!ret)
1836 mtd_erase_callback(instr);
1837
1838
1839 onenand_release_device(mtd);
1840
1841 return ret;
1842}
1843
1844
1845
1846
1847
1848
1849
1850void onenand_sync(struct mtd_info *mtd)
1851{
1852 MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_sync: called\n");
1853
1854
1855 onenand_get_device(mtd, FL_SYNCING);
1856
1857
1858 onenand_release_device(mtd);
1859}
1860
1861
1862
1863
1864
1865
1866
1867
1868int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
1869{
1870 int ret;
1871
1872
1873 if (ofs > mtd->size)
1874 return -EINVAL;
1875
1876 onenand_get_device(mtd, FL_READING);
1877 ret = onenand_block_isbad_nolock(mtd,ofs, 0);
1878 onenand_release_device(mtd);
1879 return ret;
1880}
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
1891{
1892 struct onenand_chip *this = mtd->priv;
1893 struct bbm_info *bbm = this->bbm;
1894 u_char buf[2] = {0, 0};
1895 struct mtd_oob_ops ops = {
1896 .mode = MTD_OOB_PLACE,
1897 .ooblen = 2,
1898 .oobbuf = buf,
1899 .ooboffs = 0,
1900 };
1901 int block;
1902
1903
1904 block = onenand_block(this, ofs);
1905 if (bbm->bbt)
1906 bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
1907
1908
1909 ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
1910 return onenand_write_oob_nolock(mtd, ofs, &ops);
1911}
1912
1913
1914
1915
1916
1917
1918
1919
1920int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
1921{
1922 struct onenand_chip *this = mtd->priv;
1923 int ret;
1924
1925 ret = onenand_block_isbad(mtd, ofs);
1926 if (ret) {
1927
1928 if (ret > 0)
1929 return 0;
1930 return ret;
1931 }
1932
1933 ret = this->block_markbad(mtd, ofs);
1934 return ret;
1935}
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int cmd)
1947{
1948 struct onenand_chip *this = mtd->priv;
1949 int start, end, block, value, status;
1950
1951 start = onenand_block(this, ofs);
1952 end = onenand_block(this, ofs + len);
1953
1954
1955 if (this->options & ONENAND_HAS_CONT_LOCK) {
1956
1957 this->write_word(start,
1958 this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1959
1960 this->write_word(end - 1,
1961 this->base + ONENAND_REG_END_BLOCK_ADDRESS);
1962
1963 this->command(mtd, cmd, 0, 0);
1964
1965
1966 this->wait(mtd, FL_UNLOCKING);
1967
1968
1969 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
1970 & ONENAND_CTRL_ONGO)
1971 continue;
1972
1973
1974 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
1975 if (!(status & ONENAND_WP_US))
1976 printk(KERN_ERR "wp status = 0x%x\n", status);
1977
1978 return 0;
1979 }
1980
1981
1982 for (block = start; block < end; block++) {
1983
1984 value = onenand_block_address(this, block);
1985 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
1986
1987 value = onenand_bufferram_address(this, block);
1988 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
1989
1990
1991 this->write_word(block,
1992 this->base + ONENAND_REG_START_BLOCK_ADDRESS);
1993
1994 this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
1995
1996
1997 this->wait(mtd, FL_UNLOCKING);
1998
1999
2000 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2001 & ONENAND_CTRL_ONGO)
2002 continue;
2003
2004
2005 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
2006 if (!(status & ONENAND_WP_US))
2007 printk(KERN_ERR "block = %d, wp status = 0x%x\n",
2008 block, status);
2009 }
2010
2011 return 0;
2012}
2013
2014#ifdef ONENAND_LINUX
2015
2016
2017
2018
2019
2020
2021
2022
2023static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
2024{
2025 int ret;
2026
2027 onenand_get_device(mtd, FL_LOCKING);
2028 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
2029 onenand_release_device(mtd);
2030 return ret;
2031}
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
2042{
2043 int ret;
2044
2045 onenand_get_device(mtd, FL_LOCKING);
2046 ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
2047 onenand_release_device(mtd);
2048 return ret;
2049}
2050#endif
2051
2052
2053
2054
2055
2056
2057
2058static int onenand_check_lock_status(struct onenand_chip *this)
2059{
2060 unsigned int value, block, status;
2061 unsigned int end;
2062
2063 end = this->chipsize >> this->erase_shift;
2064 for (block = 0; block < end; block++) {
2065
2066 value = onenand_block_address(this, block);
2067 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
2068
2069 value = onenand_bufferram_address(this, block);
2070 this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
2071
2072 this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2073
2074
2075 status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
2076 if (!(status & ONENAND_WP_US)) {
2077 printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
2078 return 0;
2079 }
2080 }
2081
2082 return 1;
2083}
2084
2085
2086
2087
2088
2089
2090
2091static void onenand_unlock_all(struct mtd_info *mtd)
2092{
2093 struct onenand_chip *this = mtd->priv;
2094 loff_t ofs = 0;
2095 size_t len = mtd->size;
2096
2097 if (this->options & ONENAND_HAS_UNLOCK_ALL) {
2098
2099 this->write_word(0, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
2100
2101 this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
2102
2103
2104 this->wait(mtd, FL_LOCKING);
2105
2106
2107 while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
2108 & ONENAND_CTRL_ONGO)
2109 continue;
2110
2111
2112 if (onenand_check_lock_status(this))
2113 return;
2114
2115
2116 if (ONENAND_IS_DDP(this) && !FLEXONENAND(this)) {
2117
2118 ofs = this->chipsize >> 1;
2119 len = this->chipsize >> 1;
2120 }
2121 }
2122
2123 onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
2124}
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135static void onenand_check_features(struct mtd_info *mtd)
2136{
2137 struct onenand_chip *this = mtd->priv;
2138 unsigned int density, process;
2139
2140
2141 density = onenand_get_density(this->device_id);
2142 process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
2143
2144
2145 switch (density) {
2146 case ONENAND_DEVICE_DENSITY_4Gb:
2147 if (ONENAND_IS_DDP(this))
2148 this->options |= ONENAND_HAS_2PLANE;
2149 else
2150 this->options |= ONENAND_HAS_4KB_PAGE;
2151
2152 case ONENAND_DEVICE_DENSITY_2Gb:
2153
2154 if (!ONENAND_IS_DDP(this))
2155 this->options |= ONENAND_HAS_2PLANE;
2156 this->options |= ONENAND_HAS_UNLOCK_ALL;
2157
2158 case ONENAND_DEVICE_DENSITY_1Gb:
2159
2160 if (process)
2161 this->options |= ONENAND_HAS_UNLOCK_ALL;
2162 break;
2163
2164 default:
2165
2166 if (!process)
2167 this->options |= ONENAND_HAS_CONT_LOCK;
2168 break;
2169 }
2170
2171 if (ONENAND_IS_MLC(this))
2172 this->options |= ONENAND_HAS_4KB_PAGE;
2173
2174 if (ONENAND_IS_4KB_PAGE(this))
2175 this->options &= ~ONENAND_HAS_2PLANE;
2176
2177 if (FLEXONENAND(this)) {
2178 this->options &= ~ONENAND_HAS_CONT_LOCK;
2179 this->options |= ONENAND_HAS_UNLOCK_ALL;
2180 }
2181
2182 if (this->options & ONENAND_HAS_CONT_LOCK)
2183 printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
2184 if (this->options & ONENAND_HAS_UNLOCK_ALL)
2185 printk(KERN_DEBUG "Chip support all block unlock\n");
2186 if (this->options & ONENAND_HAS_2PLANE)
2187 printk(KERN_DEBUG "Chip has 2 plane\n");
2188 if (this->options & ONENAND_HAS_4KB_PAGE)
2189 printk(KERN_DEBUG "Chip has 4KiB pagesize\n");
2190
2191}
2192
2193
2194
2195
2196
2197
2198
2199char *onenand_print_device_info(int device, int version)
2200{
2201 int vcc, demuxed, ddp, density, flexonenand;
2202 char *dev_info = malloc(80);
2203 char *p = dev_info;
2204
2205 vcc = device & ONENAND_DEVICE_VCC_MASK;
2206 demuxed = device & ONENAND_DEVICE_IS_DEMUX;
2207 ddp = device & ONENAND_DEVICE_IS_DDP;
2208 density = onenand_get_density(device);
2209 flexonenand = device & DEVICE_IS_FLEXONENAND;
2210 p += sprintf(dev_info, "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
2211 demuxed ? "" : "Muxed ",
2212 flexonenand ? "Flex-" : "",
2213 ddp ? "(DDP)" : "",
2214 (16 << density), vcc ? "2.65/3.3" : "1.8", device);
2215
2216 sprintf(p, "\nOneNAND version = 0x%04x", version);
2217 printk("%s\n", dev_info);
2218
2219 return dev_info;
2220}
2221
2222static const struct onenand_manufacturers onenand_manuf_ids[] = {
2223 {ONENAND_MFR_NUMONYX, "Numonyx"},
2224 {ONENAND_MFR_SAMSUNG, "Samsung"},
2225};
2226
2227
2228
2229
2230
2231
2232
2233static int onenand_check_maf(int manuf)
2234{
2235 int size = ARRAY_SIZE(onenand_manuf_ids);
2236 int i;
2237#ifdef ONENAND_DEBUG
2238 char *name;
2239#endif
2240
2241 for (i = 0; i < size; i++)
2242 if (manuf == onenand_manuf_ids[i].id)
2243 break;
2244
2245#ifdef ONENAND_DEBUG
2246 if (i < size)
2247 name = onenand_manuf_ids[i].name;
2248 else
2249 name = "Unknown";
2250
2251 printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n", name, manuf);
2252#endif
2253
2254 return i == size;
2255}
2256
2257
2258
2259
2260
2261
2262
2263static int flexonenand_get_boundary(struct mtd_info *mtd)
2264{
2265 struct onenand_chip *this = mtd->priv;
2266 unsigned int die, bdry;
2267 int syscfg, locked;
2268
2269
2270 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
2271 this->write_word((syscfg | 0x0100), this->base + ONENAND_REG_SYS_CFG1);
2272
2273 for (die = 0; die < this->dies; die++) {
2274 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
2275 this->wait(mtd, FL_SYNCING);
2276
2277 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
2278 this->wait(mtd, FL_READING);
2279
2280 bdry = this->read_word(this->base + ONENAND_DATARAM);
2281 if ((bdry >> FLEXONENAND_PI_UNLOCK_SHIFT) == 3)
2282 locked = 0;
2283 else
2284 locked = 1;
2285 this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
2286
2287 this->command(mtd, ONENAND_CMD_RESET, 0, 0);
2288 this->wait(mtd, FL_RESETING);
2289
2290 printk(KERN_INFO "Die %d boundary: %d%s\n", die,
2291 this->boundary[die], locked ? "(Locked)" : "(Unlocked)");
2292 }
2293
2294
2295 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
2296 return 0;
2297}
2298
2299
2300
2301
2302
2303
2304
2305static void flexonenand_get_size(struct mtd_info *mtd)
2306{
2307 struct onenand_chip *this = mtd->priv;
2308 int die, i, eraseshift, density;
2309 int blksperdie, maxbdry;
2310 loff_t ofs;
2311
2312 density = onenand_get_density(this->device_id);
2313 blksperdie = ((loff_t)(16 << density) << 20) >> (this->erase_shift);
2314 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
2315 maxbdry = blksperdie - 1;
2316 eraseshift = this->erase_shift - 1;
2317
2318 mtd->numeraseregions = this->dies << 1;
2319
2320
2321 flexonenand_get_boundary(mtd);
2322 die = 0;
2323 ofs = 0;
2324 i = -1;
2325 for (; die < this->dies; die++) {
2326 if (!die || this->boundary[die-1] != maxbdry) {
2327 i++;
2328 mtd->eraseregions[i].offset = ofs;
2329 mtd->eraseregions[i].erasesize = 1 << eraseshift;
2330 mtd->eraseregions[i].numblocks =
2331 this->boundary[die] + 1;
2332 ofs += mtd->eraseregions[i].numblocks << eraseshift;
2333 eraseshift++;
2334 } else {
2335 mtd->numeraseregions -= 1;
2336 mtd->eraseregions[i].numblocks +=
2337 this->boundary[die] + 1;
2338 ofs += (this->boundary[die] + 1) << (eraseshift - 1);
2339 }
2340 if (this->boundary[die] != maxbdry) {
2341 i++;
2342 mtd->eraseregions[i].offset = ofs;
2343 mtd->eraseregions[i].erasesize = 1 << eraseshift;
2344 mtd->eraseregions[i].numblocks = maxbdry ^
2345 this->boundary[die];
2346 ofs += mtd->eraseregions[i].numblocks << eraseshift;
2347 eraseshift--;
2348 } else
2349 mtd->numeraseregions -= 1;
2350 }
2351
2352
2353 mtd->erasesize = 1 << this->erase_shift;
2354 if (mtd->numeraseregions == 1)
2355 mtd->erasesize >>= 1;
2356
2357 printk(KERN_INFO "Device has %d eraseregions\n", mtd->numeraseregions);
2358 for (i = 0; i < mtd->numeraseregions; i++)
2359 printk(KERN_INFO "[offset: 0x%08llx, erasesize: 0x%05x,"
2360 " numblocks: %04u]\n", mtd->eraseregions[i].offset,
2361 mtd->eraseregions[i].erasesize,
2362 mtd->eraseregions[i].numblocks);
2363
2364 for (die = 0, mtd->size = 0; die < this->dies; die++) {
2365 this->diesize[die] = (loff_t) (blksperdie << this->erase_shift);
2366 this->diesize[die] -= (loff_t) (this->boundary[die] + 1)
2367 << (this->erase_shift - 1);
2368 mtd->size += this->diesize[die];
2369 }
2370}
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386static int flexonenand_check_blocks_erased(struct mtd_info *mtd,
2387 int start, int end)
2388{
2389 struct onenand_chip *this = mtd->priv;
2390 int i, ret;
2391 int block;
2392 struct mtd_oob_ops ops = {
2393 .mode = MTD_OOB_PLACE,
2394 .ooboffs = 0,
2395 .ooblen = mtd->oobsize,
2396 .datbuf = NULL,
2397 .oobbuf = this->oob_buf,
2398 };
2399 loff_t addr;
2400
2401 printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end);
2402
2403 for (block = start; block <= end; block++) {
2404 addr = flexonenand_addr(this, block);
2405 if (onenand_block_isbad_nolock(mtd, addr, 0))
2406 continue;
2407
2408
2409
2410
2411
2412 ret = onenand_read_oob_nolock(mtd, addr, &ops);
2413 if (ret)
2414 return ret;
2415
2416 for (i = 0; i < mtd->oobsize; i++)
2417 if (this->oob_buf[i] != 0xff)
2418 break;
2419
2420 if (i != mtd->oobsize) {
2421 printk(KERN_WARNING "Block %d not erased.\n", block);
2422 return 1;
2423 }
2424 }
2425
2426 return 0;
2427}
2428
2429
2430
2431
2432
2433int flexonenand_set_boundary(struct mtd_info *mtd, int die,
2434 int boundary, int lock)
2435{
2436 struct onenand_chip *this = mtd->priv;
2437 int ret, density, blksperdie, old, new, thisboundary;
2438 loff_t addr;
2439
2440 if (die >= this->dies)
2441 return -EINVAL;
2442
2443 if (boundary == this->boundary[die])
2444 return 0;
2445
2446 density = onenand_get_density(this->device_id);
2447 blksperdie = ((16 << density) << 20) >> this->erase_shift;
2448 blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
2449
2450 if (boundary >= blksperdie) {
2451 printk("flexonenand_set_boundary:"
2452 "Invalid boundary value. "
2453 "Boundary not changed.\n");
2454 return -EINVAL;
2455 }
2456
2457
2458 old = this->boundary[die] + (die * this->density_mask);
2459 new = boundary + (die * this->density_mask);
2460 ret = flexonenand_check_blocks_erased(mtd, min(old, new)
2461 + 1, max(old, new));
2462 if (ret) {
2463 printk(KERN_ERR "flexonenand_set_boundary: Please erase blocks before boundary change\n");
2464 return ret;
2465 }
2466
2467 this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
2468 this->wait(mtd, FL_SYNCING);
2469
2470
2471 this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
2472 ret = this->wait(mtd, FL_READING);
2473
2474 thisboundary = this->read_word(this->base + ONENAND_DATARAM);
2475 if ((thisboundary >> FLEXONENAND_PI_UNLOCK_SHIFT) != 3) {
2476 printk(KERN_ERR "flexonenand_set_boundary: boundary locked\n");
2477 goto out;
2478 }
2479
2480 printk(KERN_INFO "flexonenand_set_boundary: Changing die %d boundary: %d%s\n",
2481 die, boundary, lock ? "(Locked)" : "(Unlocked)");
2482
2483 boundary &= FLEXONENAND_PI_MASK;
2484 boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
2485
2486 addr = die ? this->diesize[0] : 0;
2487 this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
2488 ret = this->wait(mtd, FL_ERASING);
2489 if (ret) {
2490 printk("flexonenand_set_boundary:"
2491 "Failed PI erase for Die %d\n", die);
2492 goto out;
2493 }
2494
2495 this->write_word(boundary, this->base + ONENAND_DATARAM);
2496 this->command(mtd, ONENAND_CMD_PROG, addr, 0);
2497 ret = this->wait(mtd, FL_WRITING);
2498 if (ret) {
2499 printk("flexonenand_set_boundary:"
2500 "Failed PI write for Die %d\n", die);
2501 goto out;
2502 }
2503
2504 this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0);
2505 ret = this->wait(mtd, FL_WRITING);
2506out:
2507 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND);
2508 this->wait(mtd, FL_RESETING);
2509 if (!ret)
2510
2511 flexonenand_get_size(mtd);
2512
2513 return ret;
2514}
2515
2516
2517
2518
2519
2520
2521
2522
2523static int onenand_chip_probe(struct mtd_info *mtd)
2524{
2525 struct onenand_chip *this = mtd->priv;
2526 int bram_maf_id, bram_dev_id, maf_id, dev_id;
2527 int syscfg;
2528
2529
2530 syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
2531
2532
2533 this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ),
2534 this->base + ONENAND_REG_SYS_CFG1);
2535
2536
2537 this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
2538
2539
2540 bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
2541 bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
2542
2543
2544 this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
2545
2546
2547 this->wait(mtd, FL_RESETING);
2548
2549
2550 this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
2551
2552
2553 if (onenand_check_maf(bram_maf_id))
2554 return -ENXIO;
2555
2556
2557 maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
2558 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
2559
2560
2561 if (maf_id != bram_maf_id || dev_id != bram_dev_id)
2562 return -ENXIO;
2563
2564 return 0;
2565}
2566
2567
2568
2569
2570
2571
2572
2573
2574int onenand_probe(struct mtd_info *mtd)
2575{
2576 struct onenand_chip *this = mtd->priv;
2577 int dev_id, ver_id;
2578 int density;
2579 int ret;
2580
2581 ret = this->chip_probe(mtd);
2582 if (ret)
2583 return ret;
2584
2585
2586 dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
2587 ver_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
2588 this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
2589
2590
2591 mtd->name = onenand_print_device_info(dev_id, ver_id);
2592 this->device_id = dev_id;
2593 this->version_id = ver_id;
2594
2595
2596 onenand_check_features(mtd);
2597
2598 density = onenand_get_density(dev_id);
2599 if (FLEXONENAND(this)) {
2600 this->dies = ONENAND_IS_DDP(this) ? 2 : 1;
2601
2602 mtd->numeraseregions = this->dies << 1;
2603 mtd->eraseregions = malloc(sizeof(struct mtd_erase_region_info)
2604 * (this->dies << 1));
2605 if (!mtd->eraseregions)
2606 return -ENOMEM;
2607 }
2608
2609
2610
2611
2612
2613 this->chipsize = (16 << density) << 20;
2614
2615
2616
2617 mtd->writesize =
2618 this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
2619
2620 if (ONENAND_IS_4KB_PAGE(this))
2621 mtd->writesize <<= 1;
2622
2623 mtd->oobsize = mtd->writesize >> 5;
2624
2625 mtd->erasesize = mtd->writesize << 6;
2626
2627
2628
2629
2630
2631 if (FLEXONENAND(this))
2632 mtd->erasesize <<= 1;
2633
2634 this->erase_shift = ffs(mtd->erasesize) - 1;
2635 this->page_shift = ffs(mtd->writesize) - 1;
2636 this->ppb_shift = (this->erase_shift - this->page_shift);
2637 this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
2638
2639 if (ONENAND_IS_DDP(this))
2640 this->density_mask = this->chipsize >> (this->erase_shift + 1);
2641
2642 this->writesize = mtd->writesize;
2643
2644
2645
2646 if (FLEXONENAND(this))
2647 flexonenand_get_size(mtd);
2648 else
2649 mtd->size = this->chipsize;
2650
2651 mtd->flags = MTD_CAP_NANDFLASH;
2652 mtd->erase = onenand_erase;
2653 mtd->read = onenand_read;
2654 mtd->write = onenand_write;
2655 mtd->read_oob = onenand_read_oob;
2656 mtd->write_oob = onenand_write_oob;
2657 mtd->sync = onenand_sync;
2658 mtd->block_isbad = onenand_block_isbad;
2659 mtd->block_markbad = onenand_block_markbad;
2660
2661 return 0;
2662}
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674int onenand_scan(struct mtd_info *mtd, int maxchips)
2675{
2676 int i;
2677 struct onenand_chip *this = mtd->priv;
2678
2679 if (!this->read_word)
2680 this->read_word = onenand_readw;
2681 if (!this->write_word)
2682 this->write_word = onenand_writew;
2683
2684 if (!this->command)
2685 this->command = onenand_command;
2686 if (!this->wait)
2687 this->wait = onenand_wait;
2688 if (!this->bbt_wait)
2689 this->bbt_wait = onenand_bbt_wait;
2690
2691 if (!this->read_bufferram)
2692 this->read_bufferram = onenand_read_bufferram;
2693 if (!this->write_bufferram)
2694 this->write_bufferram = onenand_write_bufferram;
2695
2696 if (!this->chip_probe)
2697 this->chip_probe = onenand_chip_probe;
2698
2699 if (!this->block_markbad)
2700 this->block_markbad = onenand_default_block_markbad;
2701 if (!this->scan_bbt)
2702 this->scan_bbt = onenand_default_bbt;
2703
2704 if (onenand_probe(mtd))
2705 return -ENXIO;
2706
2707
2708 if (this->mmcontrol) {
2709 printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
2710 this->read_bufferram = onenand_sync_read_bufferram;
2711 }
2712
2713
2714 if (!this->page_buf) {
2715 this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
2716 if (!this->page_buf) {
2717 printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n");
2718 return -ENOMEM;
2719 }
2720 this->options |= ONENAND_PAGEBUF_ALLOC;
2721 }
2722 if (!this->oob_buf) {
2723 this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
2724 if (!this->oob_buf) {
2725 printk(KERN_ERR "onenand_scan: Can't allocate oob_buf\n");
2726 if (this->options & ONENAND_PAGEBUF_ALLOC) {
2727 this->options &= ~ONENAND_PAGEBUF_ALLOC;
2728 kfree(this->page_buf);
2729 }
2730 return -ENOMEM;
2731 }
2732 this->options |= ONENAND_OOBBUF_ALLOC;
2733 }
2734
2735 this->state = FL_READY;
2736
2737
2738
2739
2740 switch (mtd->oobsize) {
2741 case 128:
2742 this->ecclayout = &onenand_oob_128;
2743 mtd->subpage_sft = 0;
2744 break;
2745
2746 case 64:
2747 this->ecclayout = &onenand_oob_64;
2748 mtd->subpage_sft = 2;
2749 break;
2750
2751 case 32:
2752 this->ecclayout = &onenand_oob_32;
2753 mtd->subpage_sft = 1;
2754 break;
2755
2756 default:
2757 printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n",
2758 mtd->oobsize);
2759 mtd->subpage_sft = 0;
2760
2761 this->ecclayout = &onenand_oob_32;
2762 break;
2763 }
2764
2765 this->subpagesize = mtd->writesize >> mtd->subpage_sft;
2766
2767
2768
2769
2770
2771 this->ecclayout->oobavail = 0;
2772 for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
2773 this->ecclayout->oobfree[i].length; i++)
2774 this->ecclayout->oobavail +=
2775 this->ecclayout->oobfree[i].length;
2776 mtd->oobavail = this->ecclayout->oobavail;
2777
2778 mtd->ecclayout = this->ecclayout;
2779
2780
2781 onenand_unlock_all(mtd);
2782
2783 return this->scan_bbt(mtd);
2784}
2785
2786
2787
2788
2789
2790void onenand_release(struct mtd_info *mtd)
2791{
2792}
2793