public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* pre-CFI sharp driver
@ 2004-04-22  1:54 John Lenz
  0 siblings, 0 replies; only message in thread
From: John Lenz @ 2004-04-22  1:54 UTC (permalink / raw)
  To: linux-mtd

[-- Attachment #1: Type: text/plain, Size: 2325 bytes --]

The device I am developing for is the Sharp Zaurus SL5500 (which is  
codenamed collie).  I am currently working on porting the kernel used  
for www.openzaurus.org from 2.4 to 2.6.  In 2.4, we used the pre-CFI  
sharp driver.  NOTE: the root filesystem is located on the flash  
device.  I am using the maps/sa1100-flash.c map.

I have tried using the Intel/Sharp flash chips (cfi_cmdset_0001.c) and  
cfi_probe and have had some success.

1) On a stock 2.6.5, doesn't work
2) On a 2.6.5 with the mtd cvs code using the Intel CFI driver and  
using cfi_probe, I am able to mount the root filesystem (jffs2) and am  
able to log in and busybox works and such.  When booting tho, there are  
a bunch of errors like
jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00a00000:  
0x8080 instead.
I get around 50-60 of these messages at different addresses.
Note, the address given there is near the end of the flash.

But ignoring those, the root fs is still mounted.

But when I try and write a file, jffs2_flash_writev returns -15.  i.e.  
I get a "Write of x bytes at x failed.  returned -15, retlen 0" error.

The sharp device also starts up completly locked, and I have to add the  
following code to the maps/sa1100-collie.c after cfi_probe has been  
called.
{ int k;
for (k = 0; k < sa[i].mtd->numeraseregions; k++) {
	int retval;
	retval = sa[i].mtd->unlock(sa[i].mtd, sa[i].mtd->eraseregions 
[k].offset,
			sa[i].mtd->eraseregions[k].erasesize);
	if (retval)
		printk(KERN_WARNING "SA1100 flash: Error while  
unlocking region 0x%08x\n",
				sa[i].mtd->eraseregions[k].offset);
} }

It could be possible that since the 0x00a0000 is past the end of the  
last erase block (we create the jffs2 filesystem with the --pad  
option), they are still locked?  but why would that impact the  
scanning?

I am able to mount the root filesystem and write files and everything  
works with the attached patch  I don't even need the mtd cvs code, it  
works with just the stock 2.6.5 kernel.  This is just a forward port of  
the changes we had to sharp.c  note that we have defined AUTOUNLOCK.

This is difficult to debug, because I do not have any specs for the  
device.  The only reference we have is the code that sharp has  
released, which uses the pre-CFI device with the same changes I have  
attached.

John


[-- Attachment #2: sharp.diff --]
[-- Type: text/x-patch, Size: 9064 bytes --]

--- linux-2.6.5/drivers/mtd/chips/sharp.c	2004-04-03 21:37:23.000000000 -0600
+++ linux-2.6.5-zaurus/drivers/mtd/chips/sharp.c	2004-04-21 16:47:49.000000000 -0500
@@ -25,6 +25,7 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
+#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
@@ -58,9 +59,12 @@
 
 #define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT)
 
+#define BLOCK_MASK		0xfffe0000
+
 /* Configuration options */
 
-#undef AUTOUNLOCK  /* automatically unlocks blocks before erasing */
+//#undef AUTOUNLOCK  /* automatically unlocks blocks before erasing */
+#define AUTOUNLOCK
 
 struct mtd_info *sharp_probe(struct map_info *);
 
@@ -81,7 +85,7 @@
 static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
 	unsigned long adr);
 #ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
+static inline void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
 	unsigned long adr);
 #endif
 
@@ -104,6 +108,13 @@
 	.module		= THIS_MODULE
 };
 
+static void sharp_udelay(unsigned long i) {
+	if (in_interrupt()) {
+		udelay(i);
+	} else {
+		schedule();
+	}
+}
 
 struct mtd_info *sharp_probe(struct map_info *map)
 {
@@ -129,6 +140,7 @@
 		kfree(sharp);
 		return NULL;
 	}
+	//MSC0 = 0xfff8fff8;
 
 	mtd->priv = map;
 	mtd->type = MTD_NORFLASH;
@@ -142,7 +154,8 @@
 	mtd->name = map->name;
 
 	memset(sharp, 0, sizeof(*sharp));
-	sharp->chipshift = 23;
+	//sharp->chipshift = 23;
+	sharp->chipshift = 24;
 	sharp->numchips = 1;
 	sharp->chips[0].start = 0;
 	sharp->chips[0].state = FL_READY;
@@ -171,8 +184,9 @@
 
 	read0=map_read32(map, base+0);
 	read4=map_read32(map, base+4);
-	if(read0 == 0x89898989){
-		printk("Looks like sharp flash\n");
+	//if(read0 == 0x89898989){
+	if (read0 == 0x00b000b0) {
+		//printk("Looks like sharp flash\n");
 		switch(read4){
 		case 0xaaaaaaaa:
 		case 0xa0a0a0a0:
@@ -187,6 +201,11 @@
 			mtd->erasesize = 0x10000 * width;
 			mtd->size = 0x100000 * width;
 			return width;
+		case 0x00b000b0:
+			/* a6 - LH28F640BFHE 8 64k * 2 chip blocks*/
+			mtd->erasesize = 0x10000 * width / 2;
+			mtd->size = 0x800000 * width / 2;
+			return width;
 #if 0
 		case 0x00000000: /* unknown */
 			/* XX - LH28F004SCT 512kx8, 8 64k blocks*/
@@ -213,7 +232,7 @@
 /* This function returns with the chip->mutex lock held. */
 static int sharp_wait(struct map_info *map, struct flchip *chip)
 {
-	__u16 status;
+	__u32 status;
 	unsigned long timeo = jiffies + HZ;
 	DECLARE_WAITQUEUE(wait, current);
 	int adr = 0;
@@ -227,23 +246,35 @@
 		chip->state = FL_STATUS;
 	case FL_STATUS:
 		status = map_read32(map,adr);
+		if ((status & SR_READY) == SR_READY)
+			break;
+		spin_unlock_bh(chip->mutex);
+		if (time_after(jiffies, timeo)) {
+			printk("Waiting for chip to be ready timed out in erase\n");
+			return -EIO;
+		}
+		sharp_udelay(1);
+		goto retry;
 //printk("status=%08x\n",status);
 
-		udelay(100);
-		if((status & SR_READY)!=SR_READY){
+		//udelay(100);
+		//if((status & SR_READY)!=SR_READY){
 //printk(".status=%08x\n",status);
-			udelay(100);
-		}
-		break;
+		//	udelay(100);
+		//}
+		//break;
 	default:
-		printk("Waiting for chip\n");
+		//printk("Waiting for chip\n");
 
 		set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
 
 		spin_unlock_bh(chip->mutex);
 
-		schedule();
+		//schedule();
+		sharp_udelay(1);
+
+		set_current_state(TASK_RUNNING);
 		remove_wait_queue(&chip->wq, &wait);
 
 		if(signal_pending(current))
@@ -348,12 +379,13 @@
 	unsigned long adr, __u32 datum)
 {
 	int ret;
-	int timeo;
 	int try;
 	int i;
-	int status = 0;
+	u32 status = 0;
 
 	ret = sharp_wait(map,chip);
+	if (ret < 0)
+		return ret;
 
 	for(try=0;try<10;try++){
 		map_write32(map,CMD_BYTE_WRITE,adr);
@@ -362,14 +394,21 @@
 
 		chip->state = FL_WRITING;
 
-		timeo = jiffies + (HZ/2);
-
 		map_write32(map,CMD_READ_STATUS,adr);
 		for(i=0;i<100;i++){
 			status = map_read32(map,adr);
 			if((status & SR_READY)==SR_READY)
 				break;
 		}
+#ifdef AUTOUNLOCK
+		if (status & SR_PROTECT) { /* lock block */
+			map_write32(map, CMD_CLEAR_STATUS, adr);
+			sharp_unlock_oneblock(map,chip,adr);
+			map_write32(map, CMD_CLEAR_STATUS, adr);
+			map_write32(map, CMD_RESET, adr);
+			continue;
+		}
+#endif
 		if(i==100){
 			printk("sharp: timed out writing\n");
 		}
@@ -384,8 +423,7 @@
 	map_write32(map,CMD_RESET,adr);
 	chip->state = FL_READY;
 
-	wake_up(&chip->wq);
-	spin_unlock_bh(chip->mutex);
+	sharp_release(chip);
 
 	return 0;
 }
@@ -413,8 +451,13 @@
 		ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr);
 		if(ret)return ret;
 
-		adr += mtd->erasesize;
-		len -= mtd->erasesize;
+		if (adr >= 0xfe0000) {
+			adr += mtd->erasesize / 8;
+			len -= mtd->erasesize / 8;
+		} else {
+			adr += mtd->erasesize;
+			len -= mtd->erasesize;
+		}
 		if(adr >> sharp->chipshift){
 			adr = 0;
 			chipnum++;
@@ -430,7 +473,7 @@
 	return 0;
 }
 
-static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
+static inline int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
 	unsigned long adr)
 {
 	int ret;
@@ -441,7 +484,7 @@
 	map_write32(map,CMD_READ_STATUS,adr);
 	status = map_read32(map,adr);
 
-	timeo = jiffies + HZ;
+	timeo = jiffies + HZ * 10;
 
 	while(time_before(jiffies, timeo)){
 		map_write32(map,CMD_READ_STATUS,adr);
@@ -453,18 +496,22 @@
 		set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&chip->wq, &wait);
 
-		//spin_unlock_bh(chip->mutex);
+		spin_unlock_bh(chip->mutex);
 
 		schedule_timeout(1);
 		schedule();
-		remove_wait_queue(&chip->wq, &wait);
 
-		//spin_lock_bh(chip->mutex);
+		spin_lock_bh(chip->mutex);
+
+		remove_wait_queue(&chip->wq, &wait);
+		set_current_state(TASK_RUNNING);
 		
+#if 0
 		if (signal_pending(current)){
 			ret = -EINTR;
 			goto out;
 		}
+#endif
 		
 	}
 	ret = -ETIME;
@@ -477,11 +524,15 @@
 {
 	int ret;
 	//int timeo;
-	int status;
+	u32 status;
 	//int i;
 
 //printk("sharp_erase_oneblock()\n");
 
+	ret = sharp_wait(map,chip);
+	if (ret < 0)
+		return ret;
+
 #ifdef AUTOUNLOCK
 	/* This seems like a good place to do an unlock */
 	sharp_unlock_oneblock(map,chip,adr);
@@ -493,7 +544,10 @@
 	chip->state = FL_ERASING;
 
 	ret = sharp_do_wait_for_ready(map,chip,adr);
-	if(ret<0)return ret;
+	if(ret<0) {
+		spin_unlock_bh(chip->mutex);
+		return ret;
+	}
 
 	map_write32(map,CMD_READ_STATUS,adr);
 	status = map_read32(map,adr);
@@ -501,43 +555,30 @@
 	if(!(status&SR_ERRORS)){
 		map_write32(map,CMD_RESET,adr);
 		chip->state = FL_READY;
-		//spin_unlock_bh(chip->mutex);
+		spin_unlock_bh(chip->mutex);
 		return 0;
 	}
 
 	printk("sharp: error erasing block at addr=%08lx status=%08x\n",adr,status);
 	map_write32(map,CMD_CLEAR_STATUS,adr);
 
-	//spin_unlock_bh(chip->mutex);
+	sharp_release(chip);
 
 	return -EIO;
 }
 
 #ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
+static inline void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
 	unsigned long adr)
 {
-	int i;
-	int status;
+	u32 status;
 
-	map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr);
-	map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr);
+	map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr & BLOCK_MASK);
+	map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr & BLOCK_MASK);
 
-	udelay(100);
+	sharp_do_wait_for_ready(map,chip,adr);
 
 	status = map_read32(map,adr);
-	printk("status=%08x\n",status);
-
-	for(i=0;i<1000;i++){
-		//map_write32(map,CMD_READ_STATUS,adr);
-		status = map_read32(map,adr);
-		if((status & SR_READY)==SR_READY)
-			break;
-		udelay(100);
-	}
-	if(i==1000){
-		printk("sharp: timed out unlocking block\n");
-	}
 
 	if(!(status&SR_ERRORS)){
 		map_write32(map,CMD_RESET,adr);
@@ -557,20 +598,55 @@
 
 static int sharp_suspend(struct mtd_info *mtd)
 {
-	printk("sharp_suspend()\n");
-	return -EINVAL;
+	struct map_info *map = mtd->priv;
+	struct sharp_info *sharp = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+	int ret = 0;
+
+	for (i = 0; !ret && i < sharp->numchips; i++) {
+		chip = &sharp->chips[i];
+		ret = sharp_wait(map,chip);
+
+		if (ret) {
+			ret = -EAGAIN;
+		} else {
+			chip->state = FL_PM_SUSPENDED;
+			spin_unlock_bh(chip->mutex);
+		}
+	}
+	return ret;
 }
 
 static void sharp_resume(struct mtd_info *mtd)
 {
-	printk("sharp_resume()\n");
-	
+	struct map_info *map = mtd->priv;
+	struct sharp_info *sharp = map->fldrv_priv;
+	int i;
+	struct flchip *chip;
+
+	for (i = 0; i < sharp->numchips; i++) {
+		chip = &sharp->chips[i];
+
+		spin_lock_bh(chip->mutex);
+
+		if (chip->state == FL_PM_SUSPENDED) {
+			/* We need to force it back to a known state */
+			map_write32(map, CMD_RESET, chip->start);
+			chip->state = FL_READY;
+			wake_up(&chip->wq);
+		}
+
+		spin_unlock_bh(chip->mutex);
+	}
 }
 
 static void sharp_destroy(struct mtd_info *mtd)
 {
-	printk("sharp_destroy()\n");
+	struct map_info *map = mtd->priv;
+	struct sharp_info *sharp = map->fldrv_priv;
 
+	kfree(sharp);
 }
 
 int __init sharp_probe_init(void)

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2004-04-22  1:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-04-22  1:54 pre-CFI sharp driver John Lenz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox