1
2
3
4
5
6
7
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <asm/errno.h>
11#include <asm/io.h>
12#include <asm/uaccess.h>
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/init.h>
16#include <linux/types.h>
17#include <linux/bitops.h>
18
19#include <linux/mtd/mtd.h>
20#include <linux/mtd/nand.h>
21#include <linux/mtd/doc2000.h>
22
23
24
25
26
27
28
29#undef USE_MEMCPY
30
31static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
32 size_t *retlen, u_char *buf);
33static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
34 size_t *retlen, const u_char *buf);
35static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
36 struct mtd_oob_ops *ops);
37static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
38 struct mtd_oob_ops *ops);
39static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
40
41static struct mtd_info *docmillist = NULL;
42
43
44static void DoC_Delay(void __iomem * docptr, unsigned short cycles)
45{
46 volatile char dummy;
47 int i;
48
49 for (i = 0; i < cycles; i++)
50 dummy = ReadDOC(docptr, NOP);
51}
52
53
54static int _DoC_WaitReady(void __iomem * docptr)
55{
56 unsigned short c = 0xffff;
57
58 DEBUG(MTD_DEBUG_LEVEL3,
59 "_DoC_WaitReady called for out-of-line wait\n");
60
61
62 while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c)
63 ;
64
65 if (c == 0)
66 DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
67
68 return (c == 0);
69}
70
71static inline int DoC_WaitReady(void __iomem * docptr)
72{
73
74 int ret = 0;
75
76
77
78 DoC_Delay(docptr, 4);
79
80 if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
81
82 ret = _DoC_WaitReady(docptr);
83
84
85
86 DoC_Delay(docptr, 2);
87
88 return ret;
89}
90
91
92
93
94
95static void DoC_Command(void __iomem * docptr, unsigned char command,
96 unsigned char xtraflags)
97{
98
99 WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl);
100 DoC_Delay(docptr, 4);
101
102
103 WriteDOC(command, docptr, Mil_CDSN_IO);
104 WriteDOC(0x00, docptr, WritePipeTerm);
105
106
107 WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
108 DoC_Delay(docptr, 4);
109}
110
111
112
113
114
115static inline void DoC_Address(void __iomem * docptr, int numbytes, unsigned long ofs,
116 unsigned char xtraflags1, unsigned char xtraflags2)
117{
118
119 WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl);
120 DoC_Delay(docptr, 4);
121
122
123 switch (numbytes)
124 {
125 case 1:
126
127 WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO);
128 WriteDOC(0x00, docptr, WritePipeTerm);
129 break;
130 case 2:
131
132 WriteDOC((ofs >> 9) & 0xff, docptr, Mil_CDSN_IO);
133 WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO);
134 WriteDOC(0x00, docptr, WritePipeTerm);
135 break;
136 case 3:
137
138 WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO);
139 WriteDOC((ofs >> 9) & 0xff, docptr, Mil_CDSN_IO);
140 WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO);
141 WriteDOC(0x00, docptr, WritePipeTerm);
142 break;
143 default:
144 return;
145 }
146
147
148 WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl);
149 DoC_Delay(docptr, 4);
150}
151
152
153static int DoC_SelectChip(void __iomem * docptr, int chip)
154{
155
156 WriteDOC(chip, docptr, CDSNDeviceSelect);
157 DoC_Delay(docptr, 4);
158
159
160 return DoC_WaitReady(docptr);
161}
162
163
164static int DoC_SelectFloor(void __iomem * docptr, int floor)
165{
166
167 WriteDOC(floor, docptr, FloorSelect);
168
169
170 return DoC_WaitReady(docptr);
171}
172
173
174static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
175{
176 int mfr, id, i, j;
177 volatile char dummy;
178
179
180
181 DoC_SelectFloor(doc->virtadr, floor);
182 DoC_SelectChip(doc->virtadr, chip);
183
184
185 DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP);
186 DoC_WaitReady(doc->virtadr);
187
188
189 DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP);
190
191
192 DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00);
193
194
195
196 dummy = ReadDOC(doc->virtadr, ReadPipeInit);
197 DoC_Delay(doc->virtadr, 2);
198 mfr = ReadDOC(doc->virtadr, Mil_CDSN_IO);
199
200 DoC_Delay(doc->virtadr, 2);
201 id = ReadDOC(doc->virtadr, Mil_CDSN_IO);
202 dummy = ReadDOC(doc->virtadr, LastDataRead);
203
204
205 if (mfr == 0xff || mfr == 0)
206 return 0;
207
208
209 for (i = 0; nand_flash_ids[i].name != NULL; i++) {
210 if ( id == nand_flash_ids[i].id) {
211
212 for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
213 if (nand_manuf_ids[j].id == mfr)
214 break;
215 }
216 printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
217 "Chip ID: %2.2X (%s:%s)\n",
218 mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
219 doc->mfr = mfr;
220 doc->id = id;
221 doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
222 break;
223 }
224 }
225
226 if (nand_flash_ids[i].name == NULL)
227 return 0;
228 else
229 return 1;
230}
231
232
233static void DoC_ScanChips(struct DiskOnChip *this)
234{
235 int floor, chip;
236 int numchips[MAX_FLOORS_MIL];
237 int ret;
238
239 this->numchips = 0;
240 this->mfr = 0;
241 this->id = 0;
242
243
244 for (floor = 0,ret = 1; floor < MAX_FLOORS_MIL; floor++) {
245 numchips[floor] = 0;
246 for (chip = 0; chip < MAX_CHIPS_MIL && ret != 0; chip++) {
247 ret = DoC_IdentChip(this, floor, chip);
248 if (ret) {
249 numchips[floor]++;
250 this->numchips++;
251 }
252 }
253 }
254
255 if (!this->numchips) {
256 printk("No flash chips recognised.\n");
257 return;
258 }
259
260
261 this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL);
262 if (!this->chips){
263 printk("No memory for allocating chip info structures\n");
264 return;
265 }
266
267
268
269 for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) {
270 for (chip = 0 ; chip < numchips[floor] ; chip++) {
271 this->chips[ret].floor = floor;
272 this->chips[ret].chip = chip;
273 this->chips[ret].curadr = 0;
274 this->chips[ret].curmode = 0x50;
275 ret++;
276 }
277 }
278
279
280 this->totlen = this->numchips * (1 << this->chipshift);
281 printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n",
282 this->numchips ,this->totlen >> 20);
283}
284
285static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
286{
287 int tmp1, tmp2, retval;
288
289 if (doc1->physadr == doc2->physadr)
290 return 1;
291
292
293
294
295
296
297 tmp1 = ReadDOC(doc1->virtadr, AliasResolution);
298 tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
299 if (tmp1 != tmp2)
300 return 0;
301
302 WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution);
303 tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
304 if (tmp2 == (tmp1+1) % 0xff)
305 retval = 1;
306 else
307 retval = 0;
308
309
310
311 WriteDOC(tmp1, doc1->virtadr, AliasResolution);
312
313 return retval;
314}
315
316
317
318void DoCMil_init(struct mtd_info *mtd)
319{
320 struct DiskOnChip *this = mtd->priv;
321 struct DiskOnChip *old = NULL;
322
323
324 if (docmillist)
325 old = docmillist->priv;
326
327 while (old) {
328 if (DoCMil_is_alias(this, old)) {
329 printk(KERN_NOTICE "Ignoring DiskOnChip Millennium at "
330 "0x%lX - already configured\n", this->physadr);
331 iounmap(this->virtadr);
332 kfree(mtd);
333 return;
334 }
335 if (old->nextdoc)
336 old = old->nextdoc->priv;
337 else
338 old = NULL;
339 }
340
341 mtd->name = "DiskOnChip Millennium";
342 printk(KERN_NOTICE "DiskOnChip Millennium found at address 0x%lX\n",
343 this->physadr);
344
345 mtd->type = MTD_NANDFLASH;
346 mtd->flags = MTD_CAP_NANDFLASH;
347 mtd->size = 0;
348
349
350 mtd->erasesize = 0x2000;
351
352 mtd->writesize = 512;
353 mtd->oobsize = 16;
354 mtd->owner = THIS_MODULE;
355 mtd->erase = doc_erase;
356 mtd->point = NULL;
357 mtd->unpoint = NULL;
358 mtd->read = doc_read;
359 mtd->write = doc_write;
360 mtd->read_oob = doc_read_oob;
361 mtd->write_oob = doc_write_oob;
362 mtd->sync = NULL;
363
364 this->totlen = 0;
365 this->numchips = 0;
366 this->curfloor = -1;
367 this->curchip = -1;
368
369
370 DoC_ScanChips(this);
371
372 if (!this->totlen) {
373 kfree(mtd);
374 iounmap(this->virtadr);
375 } else {
376 this->nextdoc = docmillist;
377 docmillist = mtd;
378 mtd->size = this->totlen;
379 add_mtd_device(mtd);
380 return;
381 }
382}
383EXPORT_SYMBOL_GPL(DoCMil_init);
384
385static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
386 size_t *retlen, u_char *buf)
387{
388 int i, ret;
389 volatile char dummy;
390 unsigned char syndrome[6], eccbuf[6];
391 struct DiskOnChip *this = mtd->priv;
392 void __iomem *docptr = this->virtadr;
393 struct Nand *mychip = &this->chips[from >> (this->chipshift)];
394
395
396 if (from >= this->totlen)
397 return -EINVAL;
398
399
400 if (from + len > ((from | 0x1ff) + 1))
401 len = ((from | 0x1ff) + 1) - from;
402
403
404 if (this->curfloor != mychip->floor) {
405 DoC_SelectFloor(docptr, mychip->floor);
406 DoC_SelectChip(docptr, mychip->chip);
407 } else if (this->curchip != mychip->chip) {
408 DoC_SelectChip(docptr, mychip->chip);
409 }
410 this->curfloor = mychip->floor;
411 this->curchip = mychip->chip;
412
413
414
415
416 DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP);
417 DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00);
418 DoC_WaitReady(docptr);
419
420
421 WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
422 WriteDOC (DOC_ECC_EN, docptr, ECCConf);
423
424
425
426 dummy = ReadDOC(docptr, ReadPipeInit);
427#ifndef USE_MEMCPY
428 for (i = 0; i < len-1; i++) {
429
430
431 buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
432 }
433#else
434 memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);
435#endif
436 buf[len - 1] = ReadDOC(docptr, LastDataRead);
437
438
439 *retlen = len;
440 ret = 0;
441
442
443
444 dummy = ReadDOC(docptr, ReadPipeInit);
445#ifndef USE_MEMCPY
446 for (i = 0; i < 5; i++) {
447
448
449 eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
450 }
451#else
452 memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);
453#endif
454 eccbuf[5] = ReadDOC(docptr, LastDataRead);
455
456
457 dummy = ReadDOC(docptr, ECCConf);
458 dummy = ReadDOC(docptr, ECCConf);
459
460
461 if (ReadDOC(docptr, ECCConf) & 0x80) {
462 int nb_errors;
463
464#ifdef ECC_DEBUG
465 printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
466#endif
467
468
469 for (i = 0; i < 6; i++) {
470 syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i);
471 }
472 nb_errors = doc_decode_ecc(buf, syndrome);
473#ifdef ECC_DEBUG
474 printk("ECC Errors corrected: %x\n", nb_errors);
475#endif
476 if (nb_errors < 0) {
477
478
479
480 ret = -EIO;
481 }
482 }
483
484#ifdef PSYCHO_DEBUG
485 printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
486 (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
487 eccbuf[4], eccbuf[5]);
488#endif
489
490
491 WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
492
493 return ret;
494}
495
496static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
497 size_t *retlen, const u_char *buf)
498{
499 int i,ret = 0;
500 char eccbuf[6];
501 volatile char dummy;
502 struct DiskOnChip *this = mtd->priv;
503 void __iomem *docptr = this->virtadr;
504 struct Nand *mychip = &this->chips[to >> (this->chipshift)];
505
506
507 if (to >= this->totlen)
508 return -EINVAL;
509
510#if 0
511
512 if (to + len > ( (to | 0x1ff) + 1))
513 len = ((to | 0x1ff) + 1) - to;
514#else
515
516 if (to & 0x1ff || len != 0x200)
517 return -EINVAL;
518#endif
519
520
521 if (this->curfloor != mychip->floor) {
522 DoC_SelectFloor(docptr, mychip->floor);
523 DoC_SelectChip(docptr, mychip->chip);
524 } else if (this->curchip != mychip->chip) {
525 DoC_SelectChip(docptr, mychip->chip);
526 }
527 this->curfloor = mychip->floor;
528 this->curchip = mychip->chip;
529
530
531 DoC_Command(docptr, NAND_CMD_RESET, 0x00);
532 DoC_WaitReady(docptr);
533
534 DoC_Command(docptr, NAND_CMD_READ0, 0x00);
535
536
537 DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
538 DoC_Address(docptr, 3, to, 0x00, 0x00);
539 DoC_WaitReady(docptr);
540
541
542 WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
543 WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
544
545
546
547#ifndef USE_MEMCPY
548 for (i = 0; i < len; i++) {
549
550
551 WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
552 }
553#else
554 memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
555#endif
556 WriteDOC(0x00, docptr, WritePipeTerm);
557
558
559
560 WriteDOC(0, docptr, NOP);
561 WriteDOC(0, docptr, NOP);
562 WriteDOC(0, docptr, NOP);
563
564
565 for (i = 0; i < 6; i++) {
566 eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i);
567 }
568
569
570 WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
571
572#ifndef USE_MEMCPY
573
574 for (i = 0; i < 6; i++) {
575
576
577 WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i);
578 }
579#else
580 memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);
581#endif
582
583
584
585
586 WriteDOC(0x55, docptr, Mil_CDSN_IO);
587 WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
588
589 WriteDOC(0x00, docptr, WritePipeTerm);
590
591#ifdef PSYCHO_DEBUG
592 printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
593 (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
594 eccbuf[4], eccbuf[5]);
595#endif
596
597
598
599 DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
600 DoC_WaitReady(docptr);
601
602
603
604 DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
605 dummy = ReadDOC(docptr, ReadPipeInit);
606 DoC_Delay(docptr, 2);
607 if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
608 printk("Error programming flash\n");
609
610
611 *retlen = 0;
612 ret = -EIO;
613 }
614 dummy = ReadDOC(docptr, LastDataRead);
615
616
617 *retlen = len;
618
619 return ret;
620}
621
622static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
623 struct mtd_oob_ops *ops)
624{
625#ifndef USE_MEMCPY
626 int i;
627#endif
628 volatile char dummy;
629 struct DiskOnChip *this = mtd->priv;
630 void __iomem *docptr = this->virtadr;
631 struct Nand *mychip = &this->chips[ofs >> this->chipshift];
632 uint8_t *buf = ops->oobbuf;
633 size_t len = ops->len;
634
635 BUG_ON(ops->mode != MTD_OOB_PLACE);
636
637 ofs += ops->ooboffs;
638
639
640 if (this->curfloor != mychip->floor) {
641 DoC_SelectFloor(docptr, mychip->floor);
642 DoC_SelectChip(docptr, mychip->chip);
643 } else if (this->curchip != mychip->chip) {
644 DoC_SelectChip(docptr, mychip->chip);
645 }
646 this->curfloor = mychip->floor;
647 this->curchip = mychip->chip;
648
649
650 WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
651 WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
652
653
654
655
656 DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
657 DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0x00);
658 DoC_WaitReady(docptr);
659
660
661
662 dummy = ReadDOC(docptr, ReadPipeInit);
663#ifndef USE_MEMCPY
664 for (i = 0; i < len-1; i++) {
665
666
667 buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
668 }
669#else
670 memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len - 1);
671#endif
672 buf[len - 1] = ReadDOC(docptr, LastDataRead);
673
674 ops->retlen = len;
675
676 return 0;
677}
678
679static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
680 struct mtd_oob_ops *ops)
681{
682#ifndef USE_MEMCPY
683 int i;
684#endif
685 volatile char dummy;
686 int ret = 0;
687 struct DiskOnChip *this = mtd->priv;
688 void __iomem *docptr = this->virtadr;
689 struct Nand *mychip = &this->chips[ofs >> this->chipshift];
690 uint8_t *buf = ops->oobbuf;
691 size_t len = ops->len;
692
693 BUG_ON(ops->mode != MTD_OOB_PLACE);
694
695 ofs += ops->ooboffs;
696
697
698 if (this->curfloor != mychip->floor) {
699 DoC_SelectFloor(docptr, mychip->floor);
700 DoC_SelectChip(docptr, mychip->chip);
701 } else if (this->curchip != mychip->chip) {
702 DoC_SelectChip(docptr, mychip->chip);
703 }
704 this->curfloor = mychip->floor;
705 this->curchip = mychip->chip;
706
707
708 WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
709 WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
710
711
712 DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP);
713 DoC_WaitReady(docptr);
714
715 DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP);
716
717
718 DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
719 DoC_Address(docptr, 3, ofs, 0x00, 0x00);
720
721
722
723#ifndef USE_MEMCPY
724 for (i = 0; i < len; i++) {
725
726
727 WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
728 }
729#else
730 memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
731#endif
732 WriteDOC(0x00, docptr, WritePipeTerm);
733
734
735
736 DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
737 DoC_WaitReady(docptr);
738
739
740
741 DoC_Command(docptr, NAND_CMD_STATUS, 0x00);
742 dummy = ReadDOC(docptr, ReadPipeInit);
743 DoC_Delay(docptr, 2);
744 if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
745 printk("Error programming oob data\n");
746
747 ops->retlen = 0;
748 ret = -EIO;
749 }
750 dummy = ReadDOC(docptr, LastDataRead);
751
752 ops->retlen = len;
753
754 return ret;
755}
756
757int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
758{
759 volatile char dummy;
760 struct DiskOnChip *this = mtd->priv;
761 __u32 ofs = instr->addr;
762 __u32 len = instr->len;
763 void __iomem *docptr = this->virtadr;
764 struct Nand *mychip = &this->chips[ofs >> this->chipshift];
765
766 if (len != mtd->erasesize)
767 printk(KERN_WARNING "Erase not right size (%x != %x)n",
768 len, mtd->erasesize);
769
770
771 if (this->curfloor != mychip->floor) {
772 DoC_SelectFloor(docptr, mychip->floor);
773 DoC_SelectChip(docptr, mychip->chip);
774 } else if (this->curchip != mychip->chip) {
775 DoC_SelectChip(docptr, mychip->chip);
776 }
777 this->curfloor = mychip->floor;
778 this->curchip = mychip->chip;
779
780 instr->state = MTD_ERASE_PENDING;
781
782
783 DoC_Command(docptr, NAND_CMD_ERASE1, 0x00);
784 DoC_Address(docptr, 2, ofs, 0x00, 0x00);
785
786
787
788 DoC_Command(docptr, NAND_CMD_ERASE2, 0x00);
789 DoC_WaitReady(docptr);
790
791 instr->state = MTD_ERASING;
792
793
794
795
796
797 DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP);
798 dummy = ReadDOC(docptr, ReadPipeInit);
799 DoC_Delay(docptr, 2);
800 if (ReadDOC(docptr, Mil_CDSN_IO) & 1) {
801 printk("Error Erasing at 0x%x\n", ofs);
802
803
804 instr->state = MTD_ERASE_FAILED;
805 } else
806 instr->state = MTD_ERASE_DONE;
807 dummy = ReadDOC(docptr, LastDataRead);
808
809 mtd_erase_callback(instr);
810
811 return 0;
812}
813
814
815
816
817
818
819
820static void __exit cleanup_doc2001(void)
821{
822 struct mtd_info *mtd;
823 struct DiskOnChip *this;
824
825 while ((mtd=docmillist)) {
826 this = mtd->priv;
827 docmillist = this->nextdoc;
828
829 del_mtd_device(mtd);
830
831 iounmap(this->virtadr);
832 kfree(this->chips);
833 kfree(mtd);
834 }
835}
836
837module_exit(cleanup_doc2001);
838
839MODULE_LICENSE("GPL");
840MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
841MODULE_DESCRIPTION("Alternative driver for DiskOnChip Millennium");
842