original comment: +Wilson03172004,marked due to this pci host does not support MWI
[linux-2.4.git] / drivers / mtd / devices / doc1000.c
1 /*======================================================================
2
3   $Id: doc1000.c,v 1.17 2003/01/24 13:33:20 dwmw2 Exp $
4
5 ======================================================================*/
6
7
8 #include <linux/config.h>
9 #include <linux/module.h>
10 #include <asm/uaccess.h>
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/ptrace.h>
15 #include <linux/slab.h>
16 #include <linux/string.h>
17 #include <linux/timer.h>
18 #include <linux/major.h>
19 #include <linux/fs.h>
20 #include <linux/ioctl.h>
21 #include <asm/io.h>
22 #include <asm/system.h>
23 #include <linux/delay.h>
24 #include <linux/init.h>
25
26 #include <linux/mtd/mtd.h>
27 #include <linux/mtd/iflash.h>
28
29 /* Parameters that can be set with 'insmod' */
30
31 static u_long base              = 0xe0000;
32 static int erase_timeout        = 10*HZ;        /* in ticks */
33 static int retry_limit          = 4;            /* write retries */
34 static u_long max_tries         = 4096;         /* status polling */
35
36 MODULE_PARM(base,"l");
37 MODULE_PARM(erase_timeout, "i");
38 MODULE_PARM(retry_limit, "i");
39 MODULE_PARM(max_tries, "i");
40
41 #define WINDOW_SIZE 0x2000
42 #define WINDOW_MASK (WINDOW_SIZE - 1)
43 #define PAGEREG_LO (WINDOW_SIZE)
44 #define PAGEREG_HI (WINDOW_SIZE + 2)
45
46 static struct mtd_info *mymtd;
47 static struct timer_list flashcard_timer;
48
49 #define MAX_CELLS               32
50 #define MAX_FLASH_DEVICES       8
51
52 /* A flash region is composed of one or more "cells", where we allow
53    simultaneous erases if they are in different cells */
54
55
56
57 struct mypriv {
58         u_char *baseaddr;
59         u_short curpage;
60         u_char locked;
61         u_short numdevices;
62         u_char interleave;
63         struct erase_info *cur_erases;
64         wait_queue_head_t wq;
65         u_char devstat[MAX_FLASH_DEVICES];
66         u_long devshift;
67 };
68
69
70 static void flashcard_periodic(u_long data);
71 static int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr);
72 static int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
73 static int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
74 static void flashcard_sync (struct mtd_info *mtd);
75
76 static inline void resume_erase(volatile u_char *addr);
77 static inline int suspend_erase(volatile u_char *addr);
78 static inline int byte_write (volatile u_char *addr, u_char byte);
79 static inline int word_write (volatile u_char *addr, __u16 word);
80 static inline int check_write(volatile u_char *addr);
81 static inline void block_erase (volatile u_char *addr);
82 static inline int check_erase(volatile u_char *addr);
83
84 #ifdef CONFIG_SMP
85 #warning This is definitely not SMP safe. Lock the paging mechanism.
86 #endif
87
88 static u_char *pagein(struct mtd_info *mtd, u_long addr)
89 {
90   struct mypriv *priv=mtd->priv;
91   u_short page = addr >> 13;
92
93   priv->baseaddr[PAGEREG_LO] = page & 0xff;
94   priv->baseaddr[PAGEREG_HI] = page >> 8;
95   priv->curpage = page;
96   
97   return &priv->baseaddr[addr & WINDOW_MASK];
98 }
99
100
101 void flashcard_sync (struct mtd_info *mtd)
102 {
103         struct mypriv *priv=mtd->priv;
104
105         flashcard_periodic((u_long) mtd);
106         printk("sync...");
107         if (priv->cur_erases)
108                 interruptible_sleep_on(&priv->wq);
109         printk("Done.\n");
110 }
111
112 int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr)
113 {
114         u_char *pageaddr;
115         struct mypriv *priv=mtd->priv;
116         struct erase_info **tmp=&priv->cur_erases;
117         
118         if (instr->len != mtd->erasesize)
119                 return -EINVAL;
120         if (instr->addr + instr->len > mtd->size)
121                 return -EINVAL;
122
123         pageaddr=pagein(mtd,instr->addr);
124         instr->mtd = mtd;
125         instr->dev = instr->addr >> priv->devshift;
126         instr->cell = (instr->addr - (instr->dev << priv->devshift)) / mtd->erasesize;
127         instr->next = NULL;
128         instr->state = MTD_ERASE_PENDING;
129         
130         while (*tmp)
131         {
132                 tmp = &((*tmp) -> next);
133         }
134         
135         *tmp = instr;
136         flashcard_periodic((u_long)mtd);
137         return 0;
138 }
139
140 static inline int suspend_erase(volatile u_char *addr)
141 {
142         __u16 status;
143         u_long i = 0;
144         
145         writew(IF_ERASE_SUSPEND, addr);
146         writew(IF_READ_CSR, addr);
147         
148         do {
149                 status = readw(addr);
150                 if ((status & CSR_WR_READY) == CSR_WR_READY)
151                         return 0;
152                 i++;
153         } while(i < max_tries);
154
155         printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status);
156         return -EIO;
157
158 }
159
160 static inline void resume_erase(volatile u_char *addr)
161 {
162         __u16 status;
163         
164         writew(IF_READ_CSR, addr);
165         status = readw(addr);
166         
167         /* Only give resume signal if the erase is really suspended */
168         if (status & CSR_ERA_SUSPEND)
169                 writew(IF_CONFIRM, addr);
170 }
171
172 static inline int byte_write (volatile u_char *addr, u_char byte)
173 {
174         register u_char status;
175         register u_short i = 0;
176
177         do {
178                 status = readb(addr);
179                 if (status & CSR_WR_READY)
180                 {
181                         writeb(IF_WRITE & 0xff, addr);
182                         writeb(byte, addr);
183                         return 0;
184                 }
185                 i++;
186         } while(i < max_tries);
187
188                 
189         printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%x\n",status);
190         return -EIO;
191 }
192
193 static inline int word_write (volatile u_char *addr, __u16 word)
194 {
195         register u_short status;
196         register u_short i = 0;
197         
198         do {
199                 status = readw(addr);
200                 if ((status & CSR_WR_READY) == CSR_WR_READY)
201                 {
202                         writew(IF_WRITE, addr);
203                         writew(word, addr);
204                         return 0;
205                 }
206                 i++;
207         } while(i < max_tries);
208                 
209         printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%x\n", addr, status);
210         return -EIO;
211 }
212
213 static inline void reset_block(volatile u_char *addr)
214 {
215         u_short i;
216         __u16 status;
217
218         writew(IF_CLEAR_CSR, addr);
219
220         for (i = 0; i < 100; i++) {
221                 writew(IF_READ_CSR, addr);
222                 status = readw(addr);
223                 if (status != 0xffff) break;
224                 udelay(1000);
225         }
226
227         writew(IF_READ_CSR, addr);
228 }
229
230 static inline int check_write(volatile u_char *addr)
231 {
232         u_short status, i = 0;
233         
234         writew(IF_READ_CSR, addr);
235         
236         do {
237                 status = readw(addr);
238                 if (status & (CSR_WR_ERR | CSR_VPP_LOW))
239                 {
240                         printk(KERN_NOTICE "flashcard: write failure at %p, status 0x%x\n", addr, status);
241                         reset_block(addr);
242                         return -EIO;
243                 }
244                 if ((status & CSR_WR_READY) == CSR_WR_READY)
245                         return 0;
246                 i++;
247         } while (i < max_tries);
248
249         printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%x\n", addr, status);
250         return -EIO;
251 }
252
253
254 int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
255 {
256         u_char *pageaddr=pagein(mtd,from);
257         struct mypriv *priv=mtd->priv;
258         u_char device = from >> priv->devshift;
259         u_char cell = (int) (from - (device << priv->devshift)) / mtd->erasesize;
260         int ret = 0, timeron = 0;
261
262         if ((from & WINDOW_MASK) + len <= WINDOW_SIZE)
263                 *retlen = len;
264         else
265                 *retlen = WINDOW_SIZE - (from & WINDOW_MASK);
266
267         if (priv->devstat[device])
268         {
269                 
270                 /* There is an erase in progress or pending for this device. Stop it */
271                 timeron = del_timer(&flashcard_timer);
272                 
273                 if (priv->cur_erases && priv->cur_erases->cell == cell) 
274                         
275                 {
276                         /* The erase is on the current cell. Just return all 0xff */ 
277                         add_timer(&flashcard_timer);
278                         
279                         
280                         printk("Cell %d currently erasing. Setting to all 0xff\n",cell);
281                         memset(buf, 0xff, *retlen);
282                         return 0;
283                 }
284                 if (priv->devstat[device] == MTD_ERASING)
285                 {
286                         ret = suspend_erase(pageaddr);
287                         priv->devstat[device] = MTD_ERASE_SUSPEND;
288                        
289                         if (ret) 
290                         {
291                                 printk("flashcard: failed to suspend erase\n");
292                                 add_timer (&flashcard_timer);
293                                 return ret;
294                         }
295                 }
296
297         }
298
299         writew(IF_READ_ARRAY, (u_long)pageaddr & ~1);
300         
301         ret = 0;
302         memcpy (buf, pageaddr, *retlen);
303         
304         writew(IF_READ_CSR, (u_long)pageaddr & ~1);
305         
306         
307         if (priv->devstat[device] & MTD_ERASE_SUSPEND)
308         {
309                 resume_erase(pageaddr);
310                 priv->devstat[device]=MTD_ERASING;
311         }
312
313
314         if (timeron) add_timer (&flashcard_timer);
315                 
316         return ret;
317 }
318
319
320 int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
321 {
322         struct mypriv *priv = (struct mypriv *)mtd->priv;
323         u_char *endaddr, *startaddr;
324         register u_char *pageaddr;
325         u_char device = to >> priv->devshift;
326 /*      jiffies_t oldj=jiffies;*/
327         int ret;
328
329         while (priv->devstat[device])
330         {
331                 flashcard_sync(mtd);
332         }
333
334         if ((to & WINDOW_MASK) + len <= WINDOW_SIZE)
335                 *retlen = len;
336         else
337                 *retlen = WINDOW_SIZE - (to & WINDOW_MASK);
338         
339         pageaddr = pagein(mtd, to);
340         startaddr = (u_char *)((u_long) pageaddr & ~1);
341         endaddr = pageaddr+(*retlen);
342
343
344
345         /* Set up to read */
346         writew(IF_READ_CSR, startaddr);
347         
348         /* Make sure it's aligned by reading the first byte if necessary */
349         if (to & 1)
350         {
351                 /* Unaligned access */
352
353                 u_char cbuf;
354
355                 cbuf = *buf;
356
357                 if (!((u_long)pageaddr & 0xf))
358                         schedule();
359                         
360                 ret = byte_write(pageaddr, cbuf);
361                 if (ret) return ret;
362
363                 pageaddr++; buf++;
364         }
365
366
367         for ( ; pageaddr + 1 < endaddr; buf += 2, pageaddr += 2)
368                 {
369                         /* if ((u_long)pageaddr & 0xf) schedule();*/
370                         
371                         ret = word_write(pageaddr, *(__u16 *)buf);
372                         if (ret) 
373                                 return ret;
374                 }
375         
376         if (pageaddr != endaddr)
377         {
378                 /* One more byte to write at the end. */
379                 u_char cbuf;
380
381                 cbuf = *buf;
382
383                 ret = byte_write(pageaddr, cbuf);
384
385                 if (ret) return ret;
386         }
387
388         return check_write(startaddr);
389 /*      printk("Time taken in flashcard_write: %lx jiffies\n",jiffies - oldj);*/
390 }
391
392
393
394
395 /*====================================================================*/
396
397 static inline void block_erase (volatile u_char *addr)
398 {
399         writew(IF_BLOCK_ERASE, addr);
400         writew(IF_CONFIRM, addr);
401 }
402
403
404 static inline int check_erase(volatile u_char *addr)
405 {
406         __u16 status;
407         
408 /*      writew(IF_READ_CSR, addr);*/
409         status = readw(addr);
410         
411
412         if ((status & CSR_WR_READY) != CSR_WR_READY)
413                 return -EBUSY;
414         
415         if (status & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR)) 
416         {
417                 printk(KERN_NOTICE "flashcard: erase failed, status 0x%x\n",
418                        status);
419                 return -EIO;
420         }
421         
422         return 0;
423 }
424
425 /*====================================================================*/
426
427
428
429 static void flashcard_periodic(unsigned long data)
430 {
431         register struct mtd_info *mtd = (struct mtd_info *)data;
432         register struct mypriv *priv = mtd->priv;
433         struct erase_info *erase = priv->cur_erases;
434         u_char *pageaddr;
435
436         del_timer (&flashcard_timer);
437
438         if (!erase)
439                 return;
440
441         pageaddr = pagein(mtd, erase->addr);
442         
443         if (erase->state == MTD_ERASE_PENDING)
444         {
445                 block_erase(pageaddr);
446                 priv->devstat[erase->dev] = erase->state = MTD_ERASING;
447                 erase->time = jiffies;
448                 erase->retries = 0;
449         }
450         else if (erase->state == MTD_ERASING)
451         {
452                 /* It's trying to erase. Check whether it's finished */
453
454                 int ret = check_erase(pageaddr);
455
456                 if (!ret)
457                 {
458                         /* It's finished OK */
459                         priv->devstat[erase->dev] = 0;
460                         priv->cur_erases = erase->next;
461                         erase->state = MTD_ERASE_DONE;
462                         if (erase->callback)
463                                 (*(erase->callback))(erase);
464                         else
465                                 kfree(erase);
466                 }
467                 else if (ret == -EIO)
468                 {
469                         if (++erase->retries > retry_limit)
470                         {
471                                 printk("Failed too many times. Giving up\n");
472                                 priv->cur_erases = erase->next;
473                                 priv->devstat[erase->dev] = 0;
474                                 erase->state = MTD_ERASE_FAILED;
475                                 if (erase->callback)
476                                         (*(erase->callback))(erase);
477                                 else
478                                         kfree(erase);
479                         }
480                         else
481                                 priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING;
482                 }
483                 else if (time_after(jiffies, erase->time + erase_timeout))
484                 {
485                         printk("Flash erase timed out. The world is broken.\n");
486
487                         /* Just ignore and hope it goes away. For a while, read ops will give the CSR
488                            and writes won't work. */
489
490                         priv->cur_erases = erase->next;
491                         priv->devstat[erase->dev] = 0;
492                         erase->state = MTD_ERASE_FAILED;
493                         if (erase->callback)
494                                         (*(erase->callback))(erase);
495                                 else
496                                         kfree(erase);
497                 }
498         }
499
500         if (priv->cur_erases)
501         {
502                 flashcard_timer.expires = jiffies + HZ;
503                 add_timer (&flashcard_timer);
504         }
505         else 
506                 wake_up_interruptible(&priv->wq);
507
508 }
509
510 int __init init_doc1000(void)
511 {
512         struct mypriv *priv;
513
514         if (!base)
515         {
516                 printk(KERN_NOTICE "flashcard: No start address for memory device.\n");
517                 return -EINVAL;
518         }
519
520         mymtd  = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
521
522         if (!mymtd)
523         {
524                 printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device.\n");
525                 return -ENOMEM;
526         }
527
528         memset(mymtd,0,sizeof(struct mtd_info));
529
530         mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL);
531         if (!mymtd->priv)
532           {
533             kfree(mymtd);
534             printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device's private data.\n");
535             return -ENOMEM;
536           }
537         
538
539
540
541         priv=mymtd->priv;
542         init_waitqueue_head(&priv->wq);
543
544         memset (priv,0,sizeof(struct mypriv));
545
546         priv->baseaddr = phys_to_virt(base);
547         priv->numdevices = 4;
548         
549         mymtd->name = "M-Systems DiskOnChip 1000";
550
551         mymtd->size = 0x100000;
552         mymtd->flags = MTD_CLEAR_BITS | MTD_ERASEABLE;
553         mymtd->erase = flashcard_erase;
554         mymtd->point = NULL;
555         mymtd->unpoint = NULL;
556         mymtd->read = flashcard_read;
557         mymtd->write = flashcard_write;
558
559         mymtd->sync = flashcard_sync;
560         mymtd->erasesize = 0x10000;
561         //      mymtd->interleave = 2;
562         priv->devshift =  24;
563         mymtd->type = MTD_NORFLASH;
564         
565         if (add_mtd_device(mymtd))
566         {
567                 printk(KERN_NOTICE "MTD device registration failed!\n");
568                 kfree(mymtd->priv);
569                 kfree(mymtd);
570                 return -EAGAIN;
571         }
572         
573         init_timer(&flashcard_timer);
574         flashcard_timer.function = flashcard_periodic;
575         flashcard_timer.data = (u_long)mymtd;
576         return 0;
577 }
578
579 static void __init cleanup_doc1000(void)
580 {
581         kfree (mymtd->priv);
582         del_mtd_device(mymtd);
583         kfree(mymtd);
584 }
585
586 module_init(init_doc1000);
587 module_exit(cleanup_doc1000);
588
589 MODULE_LICENSE("GPL");
590 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
591 MODULE_DESCRIPTION("MTD driver for DiskOnChip 1000");
592