cleanup
[linux-2.4.21-pre4.git] / drivers / mtd / devices / doc1000.c
1 /*======================================================================
2
3   $Id: doc1000.c,v 1.1.1.1 2005/04/11 02:50:26 jack 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
141 int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
142 {
143         u_char *pageaddr=pagein(mtd,from);
144         struct mypriv *priv=mtd->priv;
145         u_char device = from >> priv->devshift;
146         u_char cell = (int) (from - (device << priv->devshift)) / mtd->erasesize;
147         int ret = 0, timeron = 0;
148
149         if ((from & WINDOW_MASK) + len <= WINDOW_SIZE)
150                 *retlen = len;
151         else
152                 *retlen = WINDOW_SIZE - (from & WINDOW_MASK);
153
154         if (priv->devstat[device])
155         {
156                 
157                 /* There is an erase in progress or pending for this device. Stop it */
158                 timeron = del_timer(&flashcard_timer);
159                 
160                 if (priv->cur_erases && priv->cur_erases->cell == cell) 
161                         
162                 {
163                         /* The erase is on the current cell. Just return all 0xff */ 
164                         add_timer(&flashcard_timer);
165                         
166                         
167                         printk("Cell %d currently erasing. Setting to all 0xff\n",cell);
168                         memset(buf, 0xff, *retlen);
169                         return 0;
170                 }
171                 if (priv->devstat[device] == MTD_ERASING)
172                 {
173                         ret = suspend_erase(pageaddr);
174                         priv->devstat[device] = MTD_ERASE_SUSPEND;
175                        
176                         if (ret) 
177                         {
178                                 printk("flashcard: failed to suspend erase\n");
179                                 add_timer (&flashcard_timer);
180                                 return ret;
181                         }
182                 }
183
184         }
185
186         writew(IF_READ_ARRAY, (u_long)pageaddr & ~1);
187         
188         ret = 0;
189         memcpy (buf, pageaddr, *retlen);
190         
191         writew(IF_READ_CSR, (u_long)pageaddr & ~1);
192         
193         
194         if (priv->devstat[device] & MTD_ERASE_SUSPEND)
195         {
196                 resume_erase(pageaddr);
197                 priv->devstat[device]=MTD_ERASING;
198         }
199
200
201         if (timeron) add_timer (&flashcard_timer);
202                 
203         return ret;
204 }
205
206
207 int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
208 {
209         struct mypriv *priv = (struct mypriv *)mtd->priv;
210         u_char *endaddr, *startaddr;
211         register u_char *pageaddr;
212         u_char device = to >> priv->devshift;
213 /*      jiffies_t oldj=jiffies;*/
214         int ret;
215
216         while (priv->devstat[device])
217         {
218                 flashcard_sync(mtd);
219         }
220
221         if ((to & WINDOW_MASK) + len <= WINDOW_SIZE)
222                 *retlen = len;
223         else
224                 *retlen = WINDOW_SIZE - (to & WINDOW_MASK);
225         
226         pageaddr = pagein(mtd, to);
227         startaddr = (u_char *)((u_long) pageaddr & ~1);
228         endaddr = pageaddr+(*retlen);
229
230
231
232         /* Set up to read */
233         writew(IF_READ_CSR, startaddr);
234         
235         /* Make sure it's aligned by reading the first byte if necessary */
236         if (to & 1)
237         {
238                 /* Unaligned access */
239
240                 u_char cbuf;
241
242                 cbuf = *buf;
243
244                 if (!((u_long)pageaddr & 0xf))
245                         schedule();
246                         
247                 ret = byte_write(pageaddr, cbuf);
248                 if (ret) return ret;
249
250                 pageaddr++; buf++;
251         }
252
253
254         for ( ; pageaddr + 1 < endaddr; buf += 2, pageaddr += 2)
255                 {
256                         /* if ((u_long)pageaddr & 0xf) schedule();*/
257                         
258                         ret = word_write(pageaddr, *(__u16 *)buf);
259                         if (ret) 
260                                 return ret;
261                 }
262         
263         if (pageaddr != endaddr)
264         {
265                 /* One more byte to write at the end. */
266                 u_char cbuf;
267
268                 cbuf = *buf;
269
270                 ret = byte_write(pageaddr, cbuf);
271
272                 if (ret) return ret;
273         }
274
275         return check_write(startaddr);
276 /*      printk("Time taken in flashcard_write: %lx jiffies\n",jiffies - oldj);*/
277 }
278
279
280
281
282 /*====================================================================*/
283
284 static inline int byte_write (volatile u_char *addr, u_char byte)
285 {
286         register u_char status;
287         register u_short i = 0;
288
289         do {
290                 status = readb(addr);
291                 if (status & CSR_WR_READY)
292                 {
293                         writeb(IF_WRITE & 0xff, addr);
294                         writeb(byte, addr);
295                         return 0;
296                 }
297                 i++;
298         } while(i < max_tries);
299
300                 
301         printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%x\n",status);
302         return -EIO;
303 }
304
305 static inline int word_write (volatile u_char *addr, __u16 word)
306 {
307         register u_short status;
308         register u_short i = 0;
309         
310         do {
311                 status = readw(addr);
312                 if ((status & CSR_WR_READY) == CSR_WR_READY)
313                 {
314                         writew(IF_WRITE, addr);
315                         writew(word, addr);
316                         return 0;
317                 }
318                 i++;
319         } while(i < max_tries);
320                 
321         printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%x\n", addr, status);
322         return -EIO;
323 }
324
325 static inline void block_erase (volatile u_char *addr)
326 {
327         writew(IF_BLOCK_ERASE, addr);
328         writew(IF_CONFIRM, addr);
329 }
330
331
332 static inline int check_erase(volatile u_char *addr)
333 {
334         __u16 status;
335         
336 /*      writew(IF_READ_CSR, addr);*/
337         status = readw(addr);
338         
339
340         if ((status & CSR_WR_READY) != CSR_WR_READY)
341                 return -EBUSY;
342         
343         if (status & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR)) 
344         {
345                 printk(KERN_NOTICE "flashcard: erase failed, status 0x%x\n",
346                        status);
347                 return -EIO;
348         }
349         
350         return 0;
351 }
352
353 static inline int suspend_erase(volatile u_char *addr)
354 {
355         __u16 status;
356         u_long i = 0;
357         
358         writew(IF_ERASE_SUSPEND, addr);
359         writew(IF_READ_CSR, addr);
360         
361         do {
362                 status = readw(addr);
363                 if ((status & CSR_WR_READY) == CSR_WR_READY)
364                         return 0;
365                 i++;
366         } while(i < max_tries);
367
368         printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status);
369         return -EIO;
370
371 }
372
373 static inline void resume_erase(volatile u_char *addr)
374 {
375         __u16 status;
376         
377         writew(IF_READ_CSR, addr);
378         status = readw(addr);
379         
380         /* Only give resume signal if the erase is really suspended */
381         if (status & CSR_ERA_SUSPEND)
382                 writew(IF_CONFIRM, addr);
383 }
384
385 static inline void reset_block(volatile u_char *addr)
386 {
387         u_short i;
388         __u16 status;
389
390         writew(IF_CLEAR_CSR, addr);
391
392         for (i = 0; i < 100; i++) {
393                 writew(IF_READ_CSR, addr);
394                 status = readw(addr);
395                 if (status != 0xffff) break;
396                 udelay(1000);
397         }
398
399         writew(IF_READ_CSR, addr);
400 }
401
402 static inline int check_write(volatile u_char *addr)
403 {
404         u_short status, i = 0;
405         
406         writew(IF_READ_CSR, addr);
407         
408         do {
409                 status = readw(addr);
410                 if (status & (CSR_WR_ERR | CSR_VPP_LOW))
411                 {
412                         printk(KERN_NOTICE "flashcard: write failure at %p, status 0x%x\n", addr, status);
413                         reset_block(addr);
414                         return -EIO;
415                 }
416                 if ((status & CSR_WR_READY) == CSR_WR_READY)
417                         return 0;
418                 i++;
419         } while (i < max_tries);
420
421         printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%x\n", addr, status);
422         return -EIO;
423 }
424
425
426 /*====================================================================*/
427
428
429
430 static void flashcard_periodic(unsigned long data)
431 {
432         register struct mtd_info *mtd = (struct mtd_info *)data;
433         register struct mypriv *priv = mtd->priv;
434         struct erase_info *erase = priv->cur_erases;
435         u_char *pageaddr;
436
437         del_timer (&flashcard_timer);
438
439         if (!erase)
440                 return;
441
442         pageaddr = pagein(mtd, erase->addr);
443         
444         if (erase->state == MTD_ERASE_PENDING)
445         {
446                 block_erase(pageaddr);
447                 priv->devstat[erase->dev] = erase->state = MTD_ERASING;
448                 erase->time = jiffies;
449                 erase->retries = 0;
450         }
451         else if (erase->state == MTD_ERASING)
452         {
453                 /* It's trying to erase. Check whether it's finished */
454
455                 int ret = check_erase(pageaddr);
456
457                 if (!ret)
458                 {
459                         /* It's finished OK */
460                         priv->devstat[erase->dev] = 0;
461                         priv->cur_erases = erase->next;
462                         erase->state = MTD_ERASE_DONE;
463                         if (erase->callback)
464                                 (*(erase->callback))(erase);
465                         else
466                                 kfree(erase);
467                 }
468                 else if (ret == -EIO)
469                 {
470                         if (++erase->retries > retry_limit)
471                         {
472                                 printk("Failed too many times. Giving up\n");
473                                 priv->cur_erases = erase->next;
474                                 priv->devstat[erase->dev] = 0;
475                                 erase->state = MTD_ERASE_FAILED;
476                                 if (erase->callback)
477                                         (*(erase->callback))(erase);
478                                 else
479                                         kfree(erase);
480                         }
481                         else
482                                 priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING;
483                 }
484                 else if (time_after(jiffies, erase->time + erase_timeout))
485                 {
486                         printk("Flash erase timed out. The world is broken.\n");
487
488                         /* Just ignore and hope it goes away. For a while, read ops will give the CSR
489                            and writes won't work. */
490
491                         priv->cur_erases = erase->next;
492                         priv->devstat[erase->dev] = 0;
493                         erase->state = MTD_ERASE_FAILED;
494                         if (erase->callback)
495                                         (*(erase->callback))(erase);
496                                 else
497                                         kfree(erase);
498                 }
499         }
500
501         if (priv->cur_erases)
502         {
503                 flashcard_timer.expires = jiffies + HZ;
504                 add_timer (&flashcard_timer);
505         }
506         else 
507                 wake_up_interruptible(&priv->wq);
508
509 }
510
511 int __init init_doc1000(void)
512 {
513         struct mypriv *priv;
514
515         if (!base)
516         {
517                 printk(KERN_NOTICE "flashcard: No start address for memory device.\n");
518                 return -EINVAL;
519         }
520
521         mymtd  = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
522
523         if (!mymtd)
524         {
525                 printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device.\n");
526                 return -ENOMEM;
527         }
528
529         memset(mymtd,0,sizeof(struct mtd_info));
530
531         mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL);
532         if (!mymtd->priv)
533           {
534             kfree(mymtd);
535             printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device's private data.\n");
536             return -ENOMEM;
537           }
538         
539
540
541
542         priv=mymtd->priv;
543         init_waitqueue_head(&priv->wq);
544
545         memset (priv,0,sizeof(struct mypriv));
546
547         priv->baseaddr = phys_to_virt(base);
548         priv->numdevices = 4;
549         
550         mymtd->name = "M-Systems DiskOnChip 1000";
551
552         mymtd->size = 0x100000;
553         mymtd->flags = MTD_CLEAR_BITS | MTD_ERASEABLE;
554         mymtd->erase = flashcard_erase;
555         mymtd->point = NULL;
556         mymtd->unpoint = NULL;
557         mymtd->read = flashcard_read;
558         mymtd->write = flashcard_write;
559
560         mymtd->sync = flashcard_sync;
561         mymtd->erasesize = 0x10000;
562         //      mymtd->interleave = 2;
563         priv->devshift =  24;
564         mymtd->type = MTD_NORFLASH;
565         
566         if (add_mtd_device(mymtd))
567         {
568                 printk(KERN_NOTICE "MTD device registration failed!\n");
569                 kfree(mymtd->priv);
570                 kfree(mymtd);
571                 return -EAGAIN;
572         }
573         
574         init_timer(&flashcard_timer);
575         flashcard_timer.function = flashcard_periodic;
576         flashcard_timer.data = (u_long)mymtd;
577         return 0;
578 }
579
580 static void __init cleanup_doc1000(void)
581 {
582         kfree (mymtd->priv);
583         del_mtd_device(mymtd);
584         kfree(mymtd);
585 }
586
587 module_init(init_doc1000);
588 module_exit(cleanup_doc1000);
589
590 MODULE_LICENSE("GPL");
591 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
592 MODULE_DESCRIPTION("MTD driver for DiskOnChip 1000");
593