1/*======================================================================
2
3  $Id: doc1000.c,v 1.1.1.1 2008/10/15 03:26:35 james26_jang 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
33static u_long base              = 0xe0000;
34static int erase_timeout	= 10*HZ;	/* in ticks */
35static int retry_limit		= 4;		/* write retries */
36static u_long max_tries       	= 4096;		/* status polling */
37
38MODULE_PARM(base,"l");
39MODULE_PARM(erase_timeout, "i");
40MODULE_PARM(retry_limit, "i");
41MODULE_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
48static struct mtd_info *mymtd;
49static 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
59struct 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
72static void flashcard_periodic(u_long data);
73static int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr);
74static int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
75static int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
76static void flashcard_sync (struct mtd_info *mtd);
77
78static inline void resume_erase(volatile u_char *addr);
79static inline int suspend_erase(volatile u_char *addr);
80static inline int byte_write (volatile u_char *addr, u_char byte);
81static inline int word_write (volatile u_char *addr, __u16 word);
82static inline int check_write(volatile u_char *addr);
83static inline void block_erase (volatile u_char *addr);
84static 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
90static 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
103void 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
114int 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
143int 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
209int 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
286static 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
307static 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
327static inline void block_erase (volatile u_char *addr)
328{
329	writew(IF_BLOCK_ERASE, addr);
330	writew(IF_CONFIRM, addr);
331}
332
333
334static 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
355static 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
375static 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
387static 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
404static 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
432static 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 (time_after(jiffies, erase->time + erase_timeout))
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
513int __init init_doc1000(void)
514{
515	struct mypriv *priv;
516
517	if (!base)
518	{
519		printk(KERN_NOTICE "flashcard: No start address for memory device.\n");
520		return -EINVAL;
521	}
522
523	mymtd  = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
524
525	if (!mymtd)
526	{
527		printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device.\n");
528		return -ENOMEM;
529	}
530
531	memset(mymtd,0,sizeof(struct mtd_info));
532
533	mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL);
534	if (!mymtd->priv)
535	  {
536	    kfree(mymtd);
537	    printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device's private data.\n");
538	    return -ENOMEM;
539	  }
540
541
542
543
544	priv=mymtd->priv;
545	init_waitqueue_head(&priv->wq);
546
547	memset (priv,0,sizeof(struct mypriv));
548
549	priv->baseaddr = phys_to_virt(base);
550	priv->numdevices = 4;
551
552	mymtd->name = "M-Systems DiskOnChip 1000";
553
554	mymtd->size = 0x100000;
555	mymtd->flags = MTD_CLEAR_BITS | MTD_ERASEABLE;
556        mymtd->erase = flashcard_erase;
557	mymtd->point = NULL;
558	mymtd->unpoint = NULL;
559	mymtd->read = flashcard_read;
560	mymtd->write = flashcard_write;
561
562	mymtd->sync = flashcard_sync;
563	mymtd->erasesize = 0x10000;
564	//	mymtd->interleave = 2;
565	priv->devshift =  24;
566	mymtd->type = MTD_NORFLASH;
567
568	if (add_mtd_device(mymtd))
569	{
570		printk(KERN_NOTICE "MTD device registration failed!\n");
571		kfree(mymtd->priv);
572		kfree(mymtd);
573		return -EAGAIN;
574	}
575
576	init_timer(&flashcard_timer);
577	flashcard_timer.function = flashcard_periodic;
578	flashcard_timer.data = (u_long)mymtd;
579	return 0;
580}
581
582static void __init cleanup_doc1000(void)
583{
584	kfree (mymtd->priv);
585	del_mtd_device(mymtd);
586	kfree(mymtd);
587}
588
589module_init(init_doc1000);
590module_exit(cleanup_doc1000);
591
592MODULE_LICENSE("GPL");
593MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
594MODULE_DESCRIPTION("MTD driver for DiskOnChip 1000");
595
596