OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [mtd/] [devices/] [doc2001plus.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Linux driver for Disk-On-Chip Millennium Plus
3
 *
4
 * (c) 2002-2003 Greg Ungerer <gerg@snapgear.com>
5
 * (c) 2002-2003 SnapGear Inc
6
 * (c) 1999 Machine Vision Holdings, Inc.
7
 * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
8
 *
9
 * $Id: doc2001plus.c,v 1.14 2005/11/07 11:14:24 gleixner Exp $
10
 *
11
 * Released under GPL
12
 */
13
 
14
#include <linux/kernel.h>
15
#include <linux/module.h>
16
#include <asm/errno.h>
17
#include <asm/io.h>
18
#include <asm/uaccess.h>
19
#include <linux/miscdevice.h>
20
#include <linux/delay.h>
21
#include <linux/slab.h>
22
#include <linux/init.h>
23
#include <linux/types.h>
24
#include <linux/bitops.h>
25
 
26
#include <linux/mtd/mtd.h>
27
#include <linux/mtd/nand.h>
28
#include <linux/mtd/doc2000.h>
29
 
30
/* #define ECC_DEBUG */
31
 
32
/* I have no idea why some DoC chips can not use memcop_form|to_io().
33
 * This may be due to the different revisions of the ASIC controller built-in or
34
 * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment
35
 * this:*/
36
#undef USE_MEMCPY
37
 
38
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
39
                size_t *retlen, u_char *buf);
40
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
41
                size_t *retlen, const u_char *buf);
42
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
43
                        struct mtd_oob_ops *ops);
44
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
45
                         struct mtd_oob_ops *ops);
46
static int doc_erase (struct mtd_info *mtd, struct erase_info *instr);
47
 
48
static struct mtd_info *docmilpluslist = NULL;
49
 
50
 
51
/* Perform the required delay cycles by writing to the NOP register */
52
static void DoC_Delay(void __iomem * docptr, int cycles)
53
{
54
        int i;
55
 
56
        for (i = 0; (i < cycles); i++)
57
                WriteDOC(0, docptr, Mplus_NOP);
58
}
59
 
60
#define CDSN_CTRL_FR_B_MASK     (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
61
 
62
/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
63
static int _DoC_WaitReady(void __iomem * docptr)
64
{
65
        unsigned int c = 0xffff;
66
 
67
        DEBUG(MTD_DEBUG_LEVEL3,
68
              "_DoC_WaitReady called for out-of-line wait\n");
69
 
70
        /* Out-of-line routine to wait for chip response */
71
        while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c)
72
                ;
73
 
74
        if (c == 0)
75
                DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
76
 
77
        return (c == 0);
78
}
79
 
80
static inline int DoC_WaitReady(void __iomem * docptr)
81
{
82
        /* This is inline, to optimise the common case, where it's ready instantly */
83
        int ret = 0;
84
 
85
        /* read form NOP register should be issued prior to the read from CDSNControl
86
           see Software Requirement 11.4 item 2. */
87
        DoC_Delay(docptr, 4);
88
 
89
        if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
90
                /* Call the out-of-line routine to wait */
91
                ret = _DoC_WaitReady(docptr);
92
 
93
        return ret;
94
}
95
 
96
/* For some reason the Millennium Plus seems to occassionally put itself
97
 * into reset mode. For me this happens randomly, with no pattern that I
98
 * can detect. M-systems suggest always check this on any block level
99
 * operation and setting to normal mode if in reset mode.
100
 */
101
static inline void DoC_CheckASIC(void __iomem * docptr)
102
{
103
        /* Make sure the DoC is in normal mode */
104
        if ((ReadDOC(docptr, Mplus_DOCControl) & DOC_MODE_NORMAL) == 0) {
105
                WriteDOC((DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_DOCControl);
106
                WriteDOC(~(DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_CtrlConfirm);
107
        }
108
}
109
 
110
/* DoC_Command: Send a flash command to the flash chip through the Flash
111
 * command register. Need 2 Write Pipeline Terminates to complete send.
112
 */
113
static void DoC_Command(void __iomem * docptr, unsigned char command,
114
                               unsigned char xtraflags)
115
{
116
        WriteDOC(command, docptr, Mplus_FlashCmd);
117
        WriteDOC(command, docptr, Mplus_WritePipeTerm);
118
        WriteDOC(command, docptr, Mplus_WritePipeTerm);
119
}
120
 
121
/* DoC_Address: Set the current address for the flash chip through the Flash
122
 * Address register. Need 2 Write Pipeline Terminates to complete send.
123
 */
124
static inline void DoC_Address(struct DiskOnChip *doc, int numbytes,
125
                               unsigned long ofs, unsigned char xtraflags1,
126
                               unsigned char xtraflags2)
127
{
128
        void __iomem * docptr = doc->virtadr;
129
 
130
        /* Allow for possible Mill Plus internal flash interleaving */
131
        ofs >>= doc->interleave;
132
 
133
        switch (numbytes) {
134
        case 1:
135
                /* Send single byte, bits 0-7. */
136
                WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress);
137
                break;
138
        case 2:
139
                /* Send bits 9-16 followed by 17-23 */
140
                WriteDOC((ofs >> 9)  & 0xff, docptr, Mplus_FlashAddress);
141
                WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress);
142
                break;
143
        case 3:
144
                /* Send 0-7, 9-16, then 17-23 */
145
                WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress);
146
                WriteDOC((ofs >> 9)  & 0xff, docptr, Mplus_FlashAddress);
147
                WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress);
148
                break;
149
        default:
150
                return;
151
        }
152
 
153
        WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
154
        WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
155
}
156
 
157
/* DoC_SelectChip: Select a given flash chip within the current floor */
158
static int DoC_SelectChip(void __iomem * docptr, int chip)
159
{
160
        /* No choice for flash chip on Millennium Plus */
161
        return 0;
162
}
163
 
164
/* DoC_SelectFloor: Select a given floor (bank of flash chips) */
165
static int DoC_SelectFloor(void __iomem * docptr, int floor)
166
{
167
        WriteDOC((floor & 0x3), docptr, Mplus_DeviceSelect);
168
        return 0;
169
}
170
 
171
/*
172
 * Translate the given offset into the appropriate command and offset.
173
 * This does the mapping using the 16bit interleave layout defined by
174
 * M-Systems, and looks like this for a sector pair:
175
 *  +-----------+-------+-------+-------+--------------+---------+-----------+
176
 *  | 0 --- 511 |512-517|518-519|520-521| 522 --- 1033 |1034-1039|1040 - 1055|
177
 *  +-----------+-------+-------+-------+--------------+---------+-----------+
178
 *  | Data 0    | ECC 0 |Flags0 |Flags1 | Data 1       |ECC 1    | OOB 1 + 2 |
179
 *  +-----------+-------+-------+-------+--------------+---------+-----------+
180
 */
181
/* FIXME: This lives in INFTL not here. Other users of flash devices
182
   may not want it */
183
static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from)
184
{
185
        struct DiskOnChip *this = mtd->priv;
186
 
187
        if (this->interleave) {
188
                unsigned int ofs = *from & 0x3ff;
189
                unsigned int cmd;
190
 
191
                if (ofs < 512) {
192
                        cmd = NAND_CMD_READ0;
193
                        ofs &= 0x1ff;
194
                } else if (ofs < 1014) {
195
                        cmd = NAND_CMD_READ1;
196
                        ofs = (ofs & 0x1ff) + 10;
197
                } else {
198
                        cmd = NAND_CMD_READOOB;
199
                        ofs = ofs - 1014;
200
                }
201
 
202
                *from = (*from & ~0x3ff) | ofs;
203
                return cmd;
204
        } else {
205
                /* No interleave */
206
                if ((*from) & 0x100)
207
                        return NAND_CMD_READ1;
208
                return NAND_CMD_READ0;
209
        }
210
}
211
 
212
static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from)
213
{
214
        unsigned int ofs, cmd;
215
 
216
        if (*from & 0x200) {
217
                cmd = NAND_CMD_READOOB;
218
                ofs = 10 + (*from & 0xf);
219
        } else {
220
                cmd = NAND_CMD_READ1;
221
                ofs = (*from & 0xf);
222
        }
223
 
224
        *from = (*from & ~0x3ff) | ofs;
225
        return cmd;
226
}
227
 
228
static unsigned int DoC_GetFlagsOffset(struct mtd_info *mtd, loff_t *from)
229
{
230
        unsigned int ofs, cmd;
231
 
232
        cmd = NAND_CMD_READ1;
233
        ofs = (*from & 0x200) ? 8 : 6;
234
        *from = (*from & ~0x3ff) | ofs;
235
        return cmd;
236
}
237
 
238
static unsigned int DoC_GetHdrOffset(struct mtd_info *mtd, loff_t *from)
239
{
240
        unsigned int ofs, cmd;
241
 
242
        cmd = NAND_CMD_READOOB;
243
        ofs = (*from & 0x200) ? 24 : 16;
244
        *from = (*from & ~0x3ff) | ofs;
245
        return cmd;
246
}
247
 
248
static inline void MemReadDOC(void __iomem * docptr, unsigned char *buf, int len)
249
{
250
#ifndef USE_MEMCPY
251
        int i;
252
        for (i = 0; i < len; i++)
253
                buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
254
#else
255
        memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len);
256
#endif
257
}
258
 
259
static inline void MemWriteDOC(void __iomem * docptr, unsigned char *buf, int len)
260
{
261
#ifndef USE_MEMCPY
262
        int i;
263
        for (i = 0; i < len; i++)
264
                WriteDOC(buf[i], docptr, Mil_CDSN_IO + i);
265
#else
266
        memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len);
267
#endif
268
}
269
 
270
/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */
271
static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
272
{
273
        int mfr, id, i, j;
274
        volatile char dummy;
275
        void __iomem * docptr = doc->virtadr;
276
 
277
        /* Page in the required floor/chip */
278
        DoC_SelectFloor(docptr, floor);
279
        DoC_SelectChip(docptr, chip);
280
 
281
        /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
282
        WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
283
 
284
        /* Reset the chip, see Software Requirement 11.4 item 1. */
285
        DoC_Command(docptr, NAND_CMD_RESET, 0);
286
        DoC_WaitReady(docptr);
287
 
288
        /* Read the NAND chip ID: 1. Send ReadID command */
289
        DoC_Command(docptr, NAND_CMD_READID, 0);
290
 
291
        /* Read the NAND chip ID: 2. Send address byte zero */
292
        DoC_Address(doc, 1, 0x00, 0, 0x00);
293
 
294
        WriteDOC(0, docptr, Mplus_FlashControl);
295
        DoC_WaitReady(docptr);
296
 
297
        /* Read the manufacturer and device id codes of the flash device through
298
           CDSN IO register see Software Requirement 11.4 item 5.*/
299
        dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
300
        dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
301
 
302
        mfr = ReadDOC(docptr, Mil_CDSN_IO);
303
        if (doc->interleave)
304
                dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
305
 
306
        id  = ReadDOC(docptr, Mil_CDSN_IO);
307
        if (doc->interleave)
308
                dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
309
 
310
        dummy = ReadDOC(docptr, Mplus_LastDataRead);
311
        dummy = ReadDOC(docptr, Mplus_LastDataRead);
312
 
313
        /* Disable flash internally */
314
        WriteDOC(0, docptr, Mplus_FlashSelect);
315
 
316
        /* No response - return failure */
317
        if (mfr == 0xff || mfr == 0)
318
                return 0;
319
 
320
        for (i = 0; nand_flash_ids[i].name != NULL; i++) {
321
                if (id == nand_flash_ids[i].id) {
322
                        /* Try to identify manufacturer */
323
                        for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
324
                                if (nand_manuf_ids[j].id == mfr)
325
                                        break;
326
                        }
327
                        printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
328
                               "Chip ID: %2.2X (%s:%s)\n", mfr, id,
329
                               nand_manuf_ids[j].name, nand_flash_ids[i].name);
330
                        doc->mfr = mfr;
331
                        doc->id = id;
332
                        doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
333
                        doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave;
334
                        break;
335
                }
336
        }
337
 
338
        if (nand_flash_ids[i].name == NULL)
339
                return 0;
340
        return 1;
341
}
342
 
343
/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
344
static void DoC_ScanChips(struct DiskOnChip *this)
345
{
346
        int floor, chip;
347
        int numchips[MAX_FLOORS_MPLUS];
348
        int ret;
349
 
350
        this->numchips = 0;
351
        this->mfr = 0;
352
        this->id = 0;
353
 
354
        /* Work out the intended interleave setting */
355
        this->interleave = 0;
356
        if (this->ChipID == DOC_ChipID_DocMilPlus32)
357
                this->interleave = 1;
358
 
359
        /* Check the ASIC agrees */
360
        if ( (this->interleave << 2) !=
361
             (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) {
362
                u_char conf = ReadDOC(this->virtadr, Mplus_Configuration);
363
                printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n",
364
                       this->interleave?"on (16-bit)":"off (8-bit)");
365
                conf ^= 4;
366
                WriteDOC(conf, this->virtadr, Mplus_Configuration);
367
        }
368
 
369
        /* For each floor, find the number of valid chips it contains */
370
        for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) {
371
                numchips[floor] = 0;
372
                for (chip = 0; chip < MAX_CHIPS_MPLUS && ret != 0; chip++) {
373
                        ret = DoC_IdentChip(this, floor, chip);
374
                        if (ret) {
375
                                numchips[floor]++;
376
                                this->numchips++;
377
                        }
378
                }
379
        }
380
        /* If there are none at all that we recognise, bail */
381
        if (!this->numchips) {
382
                printk("No flash chips recognised.\n");
383
                return;
384
        }
385
 
386
        /* Allocate an array to hold the information for each chip */
387
        this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL);
388
        if (!this->chips){
389
                printk("MTD: No memory for allocating chip info structures\n");
390
                return;
391
        }
392
 
393
        /* Fill out the chip array with {floor, chipno} for each
394
         * detected chip in the device. */
395
        for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) {
396
                for (chip = 0 ; chip < numchips[floor] ; chip++) {
397
                        this->chips[ret].floor = floor;
398
                        this->chips[ret].chip = chip;
399
                        this->chips[ret].curadr = 0;
400
                        this->chips[ret].curmode = 0x50;
401
                        ret++;
402
                }
403
        }
404
 
405
        /* Calculate and print the total size of the device */
406
        this->totlen = this->numchips * (1 << this->chipshift);
407
        printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n",
408
               this->numchips ,this->totlen >> 20);
409
}
410
 
411
static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
412
{
413
        int tmp1, tmp2, retval;
414
 
415
        if (doc1->physadr == doc2->physadr)
416
                return 1;
417
 
418
        /* Use the alias resolution register which was set aside for this
419
         * purpose. If it's value is the same on both chips, they might
420
         * be the same chip, and we write to one and check for a change in
421
         * the other. It's unclear if this register is usuable in the
422
         * DoC 2000 (it's in the Millennium docs), but it seems to work. */
423
        tmp1 = ReadDOC(doc1->virtadr, Mplus_AliasResolution);
424
        tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
425
        if (tmp1 != tmp2)
426
                return 0;
427
 
428
        WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution);
429
        tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
430
        if (tmp2 == (tmp1+1) % 0xff)
431
                retval = 1;
432
        else
433
                retval = 0;
434
 
435
        /* Restore register contents.  May not be necessary, but do it just to
436
         * be safe. */
437
        WriteDOC(tmp1, doc1->virtadr, Mplus_AliasResolution);
438
 
439
        return retval;
440
}
441
 
442
/* This routine is found from the docprobe code by symbol_get(),
443
 * which will bump the use count of this module. */
444
void DoCMilPlus_init(struct mtd_info *mtd)
445
{
446
        struct DiskOnChip *this = mtd->priv;
447
        struct DiskOnChip *old = NULL;
448
 
449
        /* We must avoid being called twice for the same device. */
450
        if (docmilpluslist)
451
                old = docmilpluslist->priv;
452
 
453
        while (old) {
454
                if (DoCMilPlus_is_alias(this, old)) {
455
                        printk(KERN_NOTICE "Ignoring DiskOnChip Millennium "
456
                                "Plus at 0x%lX - already configured\n",
457
                                this->physadr);
458
                        iounmap(this->virtadr);
459
                        kfree(mtd);
460
                        return;
461
                }
462
                if (old->nextdoc)
463
                        old = old->nextdoc->priv;
464
                else
465
                        old = NULL;
466
        }
467
 
468
        mtd->name = "DiskOnChip Millennium Plus";
469
        printk(KERN_NOTICE "DiskOnChip Millennium Plus found at "
470
                "address 0x%lX\n", this->physadr);
471
 
472
        mtd->type = MTD_NANDFLASH;
473
        mtd->flags = MTD_CAP_NANDFLASH;
474
        mtd->size = 0;
475
 
476
        mtd->erasesize = 0;
477
        mtd->writesize = 512;
478
        mtd->oobsize = 16;
479
        mtd->owner = THIS_MODULE;
480
        mtd->erase = doc_erase;
481
        mtd->point = NULL;
482
        mtd->unpoint = NULL;
483
        mtd->read = doc_read;
484
        mtd->write = doc_write;
485
        mtd->read_oob = doc_read_oob;
486
        mtd->write_oob = doc_write_oob;
487
        mtd->sync = NULL;
488
 
489
        this->totlen = 0;
490
        this->numchips = 0;
491
        this->curfloor = -1;
492
        this->curchip = -1;
493
 
494
        /* Ident all the chips present. */
495
        DoC_ScanChips(this);
496
 
497
        if (!this->totlen) {
498
                kfree(mtd);
499
                iounmap(this->virtadr);
500
        } else {
501
                this->nextdoc = docmilpluslist;
502
                docmilpluslist = mtd;
503
                mtd->size  = this->totlen;
504
                mtd->erasesize = this->erasesize;
505
                add_mtd_device(mtd);
506
                return;
507
        }
508
}
509
EXPORT_SYMBOL_GPL(DoCMilPlus_init);
510
 
511
#if 0
512
static int doc_dumpblk(struct mtd_info *mtd, loff_t from)
513
{
514
        int i;
515
        loff_t fofs;
516
        struct DiskOnChip *this = mtd->priv;
517
        void __iomem * docptr = this->virtadr;
518
        struct Nand *mychip = &this->chips[from >> (this->chipshift)];
519
        unsigned char *bp, buf[1056];
520
        char c[32];
521
 
522
        from &= ~0x3ff;
523
 
524
        /* Don't allow read past end of device */
525
        if (from >= this->totlen)
526
                return -EINVAL;
527
 
528
        DoC_CheckASIC(docptr);
529
 
530
        /* Find the chip which is to be used and select it */
531
        if (this->curfloor != mychip->floor) {
532
                DoC_SelectFloor(docptr, mychip->floor);
533
                DoC_SelectChip(docptr, mychip->chip);
534
        } else if (this->curchip != mychip->chip) {
535
                DoC_SelectChip(docptr, mychip->chip);
536
        }
537
        this->curfloor = mychip->floor;
538
        this->curchip = mychip->chip;
539
 
540
        /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
541
        WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
542
 
543
        /* Reset the chip, see Software Requirement 11.4 item 1. */
544
        DoC_Command(docptr, NAND_CMD_RESET, 0);
545
        DoC_WaitReady(docptr);
546
 
547
        fofs = from;
548
        DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0);
549
        DoC_Address(this, 3, fofs, 0, 0x00);
550
        WriteDOC(0, docptr, Mplus_FlashControl);
551
        DoC_WaitReady(docptr);
552
 
553
        /* disable the ECC engine */
554
        WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
555
 
556
        ReadDOC(docptr, Mplus_ReadPipeInit);
557
        ReadDOC(docptr, Mplus_ReadPipeInit);
558
 
559
        /* Read the data via the internal pipeline through CDSN IO
560
           register, see Pipelined Read Operations 11.3 */
561
        MemReadDOC(docptr, buf, 1054);
562
        buf[1054] = ReadDOC(docptr, Mplus_LastDataRead);
563
        buf[1055] = ReadDOC(docptr, Mplus_LastDataRead);
564
 
565
        memset(&c[0], 0, sizeof(c));
566
        printk("DUMP OFFSET=%x:\n", (int)from);
567
 
568
        for (i = 0, bp = &buf[0]; (i < 1056); i++) {
569
                if ((i % 16) == 0)
570
                        printk("%08x: ", i);
571
                printk(" %02x", *bp);
572
                c[(i & 0xf)] = ((*bp >= 0x20) && (*bp <= 0x7f)) ? *bp : '.';
573
                bp++;
574
                if (((i + 1) % 16) == 0)
575
                        printk("    %s\n", c);
576
        }
577
        printk("\n");
578
 
579
        /* Disable flash internally */
580
        WriteDOC(0, docptr, Mplus_FlashSelect);
581
 
582
        return 0;
583
}
584
#endif
585
 
586
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
587
                    size_t *retlen, u_char *buf)
588
{
589
        int ret, i;
590
        volatile char dummy;
591
        loff_t fofs;
592
        unsigned char syndrome[6], eccbuf[6];
593
        struct DiskOnChip *this = mtd->priv;
594
        void __iomem * docptr = this->virtadr;
595
        struct Nand *mychip = &this->chips[from >> (this->chipshift)];
596
 
597
        /* Don't allow read past end of device */
598
        if (from >= this->totlen)
599
                return -EINVAL;
600
 
601
        /* Don't allow a single read to cross a 512-byte block boundary */
602
        if (from + len > ((from | 0x1ff) + 1))
603
                len = ((from | 0x1ff) + 1) - from;
604
 
605
        DoC_CheckASIC(docptr);
606
 
607
        /* Find the chip which is to be used and select it */
608
        if (this->curfloor != mychip->floor) {
609
                DoC_SelectFloor(docptr, mychip->floor);
610
                DoC_SelectChip(docptr, mychip->chip);
611
        } else if (this->curchip != mychip->chip) {
612
                DoC_SelectChip(docptr, mychip->chip);
613
        }
614
        this->curfloor = mychip->floor;
615
        this->curchip = mychip->chip;
616
 
617
        /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
618
        WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
619
 
620
        /* Reset the chip, see Software Requirement 11.4 item 1. */
621
        DoC_Command(docptr, NAND_CMD_RESET, 0);
622
        DoC_WaitReady(docptr);
623
 
624
        fofs = from;
625
        DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0);
626
        DoC_Address(this, 3, fofs, 0, 0x00);
627
        WriteDOC(0, docptr, Mplus_FlashControl);
628
        DoC_WaitReady(docptr);
629
 
630
        /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
631
        WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
632
        WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
633
 
634
        /* Let the caller know we completed it */
635
        *retlen = len;
636
        ret = 0;
637
 
638
        ReadDOC(docptr, Mplus_ReadPipeInit);
639
        ReadDOC(docptr, Mplus_ReadPipeInit);
640
 
641
        /* Read the data via the internal pipeline through CDSN IO
642
           register, see Pipelined Read Operations 11.3 */
643
        MemReadDOC(docptr, buf, len);
644
 
645
        /* Read the ECC data following raw data */
646
        MemReadDOC(docptr, eccbuf, 4);
647
        eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
648
        eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
649
 
650
        /* Flush the pipeline */
651
        dummy = ReadDOC(docptr, Mplus_ECCConf);
652
        dummy = ReadDOC(docptr, Mplus_ECCConf);
653
 
654
        /* Check the ECC Status */
655
        if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
656
                int nb_errors;
657
                /* There was an ECC error */
658
#ifdef ECC_DEBUG
659
                printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
660
#endif
661
                /* Read the ECC syndrom through the DiskOnChip ECC logic.
662
                   These syndrome will be all ZERO when there is no error */
663
                for (i = 0; i < 6; i++)
664
                        syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
665
 
666
                nb_errors = doc_decode_ecc(buf, syndrome);
667
#ifdef ECC_DEBUG
668
                printk("ECC Errors corrected: %x\n", nb_errors);
669
#endif
670
                if (nb_errors < 0) {
671
                        /* We return error, but have actually done the
672
                           read. Not that this can be told to user-space, via
673
                           sys_read(), but at least MTD-aware stuff can know
674
                           about it by checking *retlen */
675
#ifdef ECC_DEBUG
676
                        printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n",
677
                                __FILE__, __LINE__, (int)from);
678
                        printk("        syndrome= %02x:%02x:%02x:%02x:%02x:"
679
                                "%02x\n",
680
                                syndrome[0], syndrome[1], syndrome[2],
681
                                syndrome[3], syndrome[4], syndrome[5]);
682
                        printk("          eccbuf= %02x:%02x:%02x:%02x:%02x:"
683
                                "%02x\n",
684
                                eccbuf[0], eccbuf[1], eccbuf[2],
685
                                eccbuf[3], eccbuf[4], eccbuf[5]);
686
#endif
687
                                ret = -EIO;
688
                }
689
        }
690
 
691
#ifdef PSYCHO_DEBUG
692
        printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
693
               (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
694
               eccbuf[4], eccbuf[5]);
695
#endif
696
        /* disable the ECC engine */
697
        WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
698
 
699
        /* Disable flash internally */
700
        WriteDOC(0, docptr, Mplus_FlashSelect);
701
 
702
        return ret;
703
}
704
 
705
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
706
                     size_t *retlen, const u_char *buf)
707
{
708
        int i, before, ret = 0;
709
        loff_t fto;
710
        volatile char dummy;
711
        char eccbuf[6];
712
        struct DiskOnChip *this = mtd->priv;
713
        void __iomem * docptr = this->virtadr;
714
        struct Nand *mychip = &this->chips[to >> (this->chipshift)];
715
 
716
        /* Don't allow write past end of device */
717
        if (to >= this->totlen)
718
                return -EINVAL;
719
 
720
        /* Don't allow writes which aren't exactly one block (512 bytes) */
721
        if ((to & 0x1ff) || (len != 0x200))
722
                return -EINVAL;
723
 
724
        /* Determine position of OOB flags, before or after data */
725
        before = (this->interleave && (to & 0x200));
726
 
727
        DoC_CheckASIC(docptr);
728
 
729
        /* Find the chip which is to be used and select it */
730
        if (this->curfloor != mychip->floor) {
731
                DoC_SelectFloor(docptr, mychip->floor);
732
                DoC_SelectChip(docptr, mychip->chip);
733
        } else if (this->curchip != mychip->chip) {
734
                DoC_SelectChip(docptr, mychip->chip);
735
        }
736
        this->curfloor = mychip->floor;
737
        this->curchip = mychip->chip;
738
 
739
        /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
740
        WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
741
 
742
        /* Reset the chip, see Software Requirement 11.4 item 1. */
743
        DoC_Command(docptr, NAND_CMD_RESET, 0);
744
        DoC_WaitReady(docptr);
745
 
746
        /* Set device to appropriate plane of flash */
747
        fto = to;
748
        WriteDOC(DoC_GetDataOffset(mtd, &fto), docptr, Mplus_FlashCmd);
749
 
750
        /* On interleaved devices the flags for 2nd half 512 are before data */
751
        if (eccbuf && before)
752
                fto -= 2;
753
 
754
        /* issue the Serial Data In command to initial the Page Program process */
755
        DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
756
        DoC_Address(this, 3, fto, 0x00, 0x00);
757
 
758
        /* Disable the ECC engine */
759
        WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
760
 
761
        if (before) {
762
                /* Write the block status BLOCK_USED (0x5555) */
763
                WriteDOC(0x55, docptr, Mil_CDSN_IO);
764
                WriteDOC(0x55, docptr, Mil_CDSN_IO);
765
        }
766
 
767
        /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
768
        WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
769
 
770
        MemWriteDOC(docptr, (unsigned char *) buf, len);
771
 
772
        /* Write ECC data to flash, the ECC info is generated by
773
           the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
774
        DoC_Delay(docptr, 3);
775
 
776
        /* Read the ECC data through the DiskOnChip ECC logic */
777
        for (i = 0; i < 6; i++)
778
                eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
779
 
780
        /* disable the ECC engine */
781
        WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
782
 
783
        /* Write the ECC data to flash */
784
        MemWriteDOC(docptr, eccbuf, 6);
785
 
786
        if (!before) {
787
                /* Write the block status BLOCK_USED (0x5555) */
788
                WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
789
                WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
790
        }
791
 
792
#ifdef PSYCHO_DEBUG
793
        printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
794
               (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
795
               eccbuf[4], eccbuf[5]);
796
#endif
797
 
798
        WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
799
        WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
800
 
801
        /* Commit the Page Program command and wait for ready
802
           see Software Requirement 11.4 item 1.*/
803
        DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
804
        DoC_WaitReady(docptr);
805
 
806
        /* Read the status of the flash device through CDSN IO register
807
           see Software Requirement 11.4 item 5.*/
808
        DoC_Command(docptr, NAND_CMD_STATUS, 0);
809
        dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
810
        dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
811
        DoC_Delay(docptr, 2);
812
        if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
813
                printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to);
814
                /* Error in programming
815
                   FIXME: implement Bad Block Replacement (in nftl.c ??) */
816
                *retlen = 0;
817
                ret = -EIO;
818
        }
819
        dummy = ReadDOC(docptr, Mplus_LastDataRead);
820
 
821
        /* Disable flash internally */
822
        WriteDOC(0, docptr, Mplus_FlashSelect);
823
 
824
        /* Let the caller know we completed it */
825
        *retlen = len;
826
 
827
        return ret;
828
}
829
 
830
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
831
                        struct mtd_oob_ops *ops)
832
{
833
        loff_t fofs, base;
834
        struct DiskOnChip *this = mtd->priv;
835
        void __iomem * docptr = this->virtadr;
836
        struct Nand *mychip = &this->chips[ofs >> this->chipshift];
837
        size_t i, size, got, want;
838
        uint8_t *buf = ops->oobbuf;
839
        size_t len = ops->len;
840
 
841
        BUG_ON(ops->mode != MTD_OOB_PLACE);
842
 
843
        ofs += ops->ooboffs;
844
 
845
        DoC_CheckASIC(docptr);
846
 
847
        /* Find the chip which is to be used and select it */
848
        if (this->curfloor != mychip->floor) {
849
                DoC_SelectFloor(docptr, mychip->floor);
850
                DoC_SelectChip(docptr, mychip->chip);
851
        } else if (this->curchip != mychip->chip) {
852
                DoC_SelectChip(docptr, mychip->chip);
853
        }
854
        this->curfloor = mychip->floor;
855
        this->curchip = mychip->chip;
856
 
857
        /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
858
        WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect);
859
 
860
        /* disable the ECC engine */
861
        WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
862
        DoC_WaitReady(docptr);
863
 
864
        /* Maximum of 16 bytes in the OOB region, so limit read to that */
865
        if (len > 16)
866
                len = 16;
867
        got = 0;
868
        want = len;
869
 
870
        for (i = 0; ((i < 3) && (want > 0)); i++) {
871
                /* Figure out which region we are accessing... */
872
                fofs = ofs;
873
                base = ofs & 0xf;
874
                if (!this->interleave) {
875
                        DoC_Command(docptr, NAND_CMD_READOOB, 0);
876
                        size = 16 - base;
877
                } else if (base < 6) {
878
                        DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0);
879
                        size = 6 - base;
880
                } else if (base < 8) {
881
                        DoC_Command(docptr, DoC_GetFlagsOffset(mtd, &fofs), 0);
882
                        size = 8 - base;
883
                } else {
884
                        DoC_Command(docptr, DoC_GetHdrOffset(mtd, &fofs), 0);
885
                        size = 16 - base;
886
                }
887
                if (size > want)
888
                        size = want;
889
 
890
                /* Issue read command */
891
                DoC_Address(this, 3, fofs, 0, 0x00);
892
                WriteDOC(0, docptr, Mplus_FlashControl);
893
                DoC_WaitReady(docptr);
894
 
895
                ReadDOC(docptr, Mplus_ReadPipeInit);
896
                ReadDOC(docptr, Mplus_ReadPipeInit);
897
                MemReadDOC(docptr, &buf[got], size - 2);
898
                buf[got + size - 2] = ReadDOC(docptr, Mplus_LastDataRead);
899
                buf[got + size - 1] = ReadDOC(docptr, Mplus_LastDataRead);
900
 
901
                ofs += size;
902
                got += size;
903
                want -= size;
904
        }
905
 
906
        /* Disable flash internally */
907
        WriteDOC(0, docptr, Mplus_FlashSelect);
908
 
909
        ops->retlen = len;
910
        return 0;
911
}
912
 
913
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
914
                         struct mtd_oob_ops *ops)
915
{
916
        volatile char dummy;
917
        loff_t fofs, base;
918
        struct DiskOnChip *this = mtd->priv;
919
        void __iomem * docptr = this->virtadr;
920
        struct Nand *mychip = &this->chips[ofs >> this->chipshift];
921
        size_t i, size, got, want;
922
        int ret = 0;
923
        uint8_t *buf = ops->oobbuf;
924
        size_t len = ops->len;
925
 
926
        BUG_ON(ops->mode != MTD_OOB_PLACE);
927
 
928
        ofs += ops->ooboffs;
929
 
930
        DoC_CheckASIC(docptr);
931
 
932
        /* Find the chip which is to be used and select it */
933
        if (this->curfloor != mychip->floor) {
934
                DoC_SelectFloor(docptr, mychip->floor);
935
                DoC_SelectChip(docptr, mychip->chip);
936
        } else if (this->curchip != mychip->chip) {
937
                DoC_SelectChip(docptr, mychip->chip);
938
        }
939
        this->curfloor = mychip->floor;
940
        this->curchip = mychip->chip;
941
 
942
        /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
943
        WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
944
 
945
 
946
        /* Maximum of 16 bytes in the OOB region, so limit write to that */
947
        if (len > 16)
948
                len = 16;
949
        got = 0;
950
        want = len;
951
 
952
        for (i = 0; ((i < 3) && (want > 0)); i++) {
953
                /* Reset the chip, see Software Requirement 11.4 item 1. */
954
                DoC_Command(docptr, NAND_CMD_RESET, 0);
955
                DoC_WaitReady(docptr);
956
 
957
                /* Figure out which region we are accessing... */
958
                fofs = ofs;
959
                base = ofs & 0x0f;
960
                if (!this->interleave) {
961
                        WriteDOC(NAND_CMD_READOOB, docptr, Mplus_FlashCmd);
962
                        size = 16 - base;
963
                } else if (base < 6) {
964
                        WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
965
                        size = 6 - base;
966
                } else if (base < 8) {
967
                        WriteDOC(DoC_GetFlagsOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
968
                        size = 8 - base;
969
                } else {
970
                        WriteDOC(DoC_GetHdrOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
971
                        size = 16 - base;
972
                }
973
                if (size > want)
974
                        size = want;
975
 
976
                /* Issue the Serial Data In command to initial the Page Program process */
977
                DoC_Command(docptr, NAND_CMD_SEQIN, 0x00);
978
                DoC_Address(this, 3, fofs, 0, 0x00);
979
 
980
                /* Disable the ECC engine */
981
                WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
982
 
983
                /* Write the data via the internal pipeline through CDSN IO
984
                   register, see Pipelined Write Operations 11.2 */
985
                MemWriteDOC(docptr, (unsigned char *) &buf[got], size);
986
                WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
987
                WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
988
 
989
                /* Commit the Page Program command and wait for ready
990
                   see Software Requirement 11.4 item 1.*/
991
                DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00);
992
                DoC_WaitReady(docptr);
993
 
994
                /* Read the status of the flash device through CDSN IO register
995
                   see Software Requirement 11.4 item 5.*/
996
                DoC_Command(docptr, NAND_CMD_STATUS, 0x00);
997
                dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
998
                dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
999
                DoC_Delay(docptr, 2);
1000
                if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
1001
                        printk("MTD: Error 0x%x programming oob at 0x%x\n",
1002
                                dummy, (int)ofs);
1003
                        /* FIXME: implement Bad Block Replacement */
1004
                        ops->retlen = 0;
1005
                        ret = -EIO;
1006
                }
1007
                dummy = ReadDOC(docptr, Mplus_LastDataRead);
1008
 
1009
                ofs += size;
1010
                got += size;
1011
                want -= size;
1012
        }
1013
 
1014
        /* Disable flash internally */
1015
        WriteDOC(0, docptr, Mplus_FlashSelect);
1016
 
1017
        ops->retlen = len;
1018
        return ret;
1019
}
1020
 
1021
int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
1022
{
1023
        volatile char dummy;
1024
        struct DiskOnChip *this = mtd->priv;
1025
        __u32 ofs = instr->addr;
1026
        __u32 len = instr->len;
1027
        void __iomem * docptr = this->virtadr;
1028
        struct Nand *mychip = &this->chips[ofs >> this->chipshift];
1029
 
1030
        DoC_CheckASIC(docptr);
1031
 
1032
        if (len != mtd->erasesize)
1033
                printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n",
1034
                       len, mtd->erasesize);
1035
 
1036
        /* Find the chip which is to be used and select it */
1037
        if (this->curfloor != mychip->floor) {
1038
                DoC_SelectFloor(docptr, mychip->floor);
1039
                DoC_SelectChip(docptr, mychip->chip);
1040
        } else if (this->curchip != mychip->chip) {
1041
                DoC_SelectChip(docptr, mychip->chip);
1042
        }
1043
        this->curfloor = mychip->floor;
1044
        this->curchip = mychip->chip;
1045
 
1046
        instr->state = MTD_ERASE_PENDING;
1047
 
1048
        /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */
1049
        WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect);
1050
 
1051
        DoC_Command(docptr, NAND_CMD_RESET, 0x00);
1052
        DoC_WaitReady(docptr);
1053
 
1054
        DoC_Command(docptr, NAND_CMD_ERASE1, 0);
1055
        DoC_Address(this, 2, ofs, 0, 0x00);
1056
        DoC_Command(docptr, NAND_CMD_ERASE2, 0);
1057
        DoC_WaitReady(docptr);
1058
        instr->state = MTD_ERASING;
1059
 
1060
        /* Read the status of the flash device through CDSN IO register
1061
           see Software Requirement 11.4 item 5. */
1062
        DoC_Command(docptr, NAND_CMD_STATUS, 0);
1063
        dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
1064
        dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
1065
        if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) {
1066
                printk("MTD: Error 0x%x erasing at 0x%x\n", dummy, ofs);
1067
                /* FIXME: implement Bad Block Replacement (in nftl.c ??) */
1068
                instr->state = MTD_ERASE_FAILED;
1069
        } else {
1070
                instr->state = MTD_ERASE_DONE;
1071
        }
1072
        dummy = ReadDOC(docptr, Mplus_LastDataRead);
1073
 
1074
        /* Disable flash internally */
1075
        WriteDOC(0, docptr, Mplus_FlashSelect);
1076
 
1077
        mtd_erase_callback(instr);
1078
 
1079
        return 0;
1080
}
1081
 
1082
/****************************************************************************
1083
 *
1084
 * Module stuff
1085
 *
1086
 ****************************************************************************/
1087
 
1088
static void __exit cleanup_doc2001plus(void)
1089
{
1090
        struct mtd_info *mtd;
1091
        struct DiskOnChip *this;
1092
 
1093
        while ((mtd=docmilpluslist)) {
1094
                this = mtd->priv;
1095
                docmilpluslist = this->nextdoc;
1096
 
1097
                del_mtd_device(mtd);
1098
 
1099
                iounmap(this->virtadr);
1100
                kfree(this->chips);
1101
                kfree(mtd);
1102
        }
1103
}
1104
 
1105
module_exit(cleanup_doc2001plus);
1106
 
1107
MODULE_LICENSE("GPL");
1108
MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com> et al.");
1109
MODULE_DESCRIPTION("Driver for DiskOnChip Millennium Plus");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.