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