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