All of lore.kernel.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.