diff options
| -rw-r--r-- | target/linux/linux-2.4/patches/brcm/001-bcm47xx.patch | 920 | 
1 files changed, 0 insertions, 920 deletions
diff --git a/target/linux/linux-2.4/patches/brcm/001-bcm47xx.patch b/target/linux/linux-2.4/patches/brcm/001-bcm47xx.patch index 5d162c43d..762676139 100644 --- a/target/linux/linux-2.4/patches/brcm/001-bcm47xx.patch +++ b/target/linux/linux-2.4/patches/brcm/001-bcm47xx.patch @@ -12914,926 +12914,6 @@ diff -urN linux-2.4.30/drivers/char/serial.c linux-2.4.30.dev/drivers/char/seria   	if (doflow)   		state->flags |= ASYNC_CONS_FLOW;   	info = &async_sercons; -diff -urN linux-2.4.30/drivers/mtd/chips/Config.in linux-2.4.30.dev/drivers/mtd/chips/Config.in ---- linux-2.4.30/drivers/mtd/chips/Config.in	2003-06-13 16:51:34.000000000 +0200 -+++ linux-2.4.30.dev/drivers/mtd/chips/Config.in	2005-08-22 01:34:46.435134440 +0200 -@@ -45,6 +45,7 @@ - dep_tristate '  Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_GEN_PROBE - dep_tristate '  Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE - dep_tristate '  Support for ST (Advanced Architecture) flash chips' CONFIG_MTD_CFI_STAA $CONFIG_MTD_GEN_PROBE -+dep_tristate '  Support for SST flash chips' CONFIG_MTD_CFI_SSTSTD $CONFIG_MTD_GEN_PROBE -  - dep_tristate '  Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD - dep_tristate '  Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD -diff -urN linux-2.4.30/drivers/mtd/chips/Makefile linux-2.4.30.dev/drivers/mtd/chips/Makefile ---- linux-2.4.30/drivers/mtd/chips/Makefile	2003-06-13 16:51:34.000000000 +0200 -+++ linux-2.4.30.dev/drivers/mtd/chips/Makefile	2005-08-22 01:34:46.458130944 +0200 -@@ -18,6 +18,7 @@ - obj-$(CONFIG_MTD_AMDSTD)	+= amd_flash.o  - obj-$(CONFIG_MTD_CFI)		+= cfi_probe.o - obj-$(CONFIG_MTD_CFI_STAA)	+= cfi_cmdset_0020.o -+obj-$(CONFIG_MTD_CFI_SSTSTD)   += cfi_cmdset_0701.o - obj-$(CONFIG_MTD_CFI_AMDSTD)	+= cfi_cmdset_0002.o - obj-$(CONFIG_MTD_CFI_INTELEXT)	+= cfi_cmdset_0001.o - obj-$(CONFIG_MTD_GEN_PROBE)	+= gen_probe.o -diff -urN linux-2.4.30/drivers/mtd/chips/cfi_cmdset_0701.c linux-2.4.30.dev/drivers/mtd/chips/cfi_cmdset_0701.c ---- linux-2.4.30/drivers/mtd/chips/cfi_cmdset_0701.c	1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.dev/drivers/mtd/chips/cfi_cmdset_0701.c	2005-08-22 01:34:46.433134744 +0200 -@@ -0,0 +1,855 @@ -+/* -+ * Common Flash Interface support: -+ *   SST Standard Vendor Command Set (ID 0x0701) -+ * -+ * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp> -+ * -+ * 2_by_8 routines added by Simon Munton -+ * -+ * This code is GPL -+ * -+ * $Id: cfi_cmdset_0701.c,v 1.1 2005/03/16 13:50:00 wbx Exp $ -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/sched.h> -+#include <asm/io.h> -+#include <asm/byteorder.h> -+ -+#include <linux/errno.h> -+#include <linux/slab.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/cfi.h> -+ -+static int cfi_sststd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); -+static int cfi_sststd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); -+static int cfi_sststd_erase_onesize(struct mtd_info *, struct erase_info *); -+static int cfi_sststd_erase_varsize(struct mtd_info *, struct erase_info *); -+static void cfi_sststd_sync (struct mtd_info *); -+static int cfi_sststd_suspend (struct mtd_info *); -+static void cfi_sststd_resume (struct mtd_info *); -+ -+static void cfi_sststd_destroy(struct mtd_info *); -+ -+struct mtd_info *cfi_cmdset_0701(struct map_info *, int); -+static struct mtd_info *cfi_sststd_setup (struct map_info *); -+ -+ -+static struct mtd_chip_driver cfi_sststd_chipdrv = { -+	probe: NULL, /* Not usable directly */ -+	destroy: cfi_sststd_destroy, -+	name: "cfi_cmdset_0701", -+	module: THIS_MODULE -+}; -+ -+struct mtd_info *cfi_cmdset_0701(struct map_info *map, int primary) -+{ -+	struct cfi_private *cfi = map->fldrv_priv; -+	int ofs_factor = cfi->interleave * cfi->device_type; -+	int i; -+	__u8 major, minor; -+	__u32 base = cfi->chips[0].start; -+ -+	if (cfi->cfi_mode==1){ -+		__u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; -+ -+		cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); -+		cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); -+		cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); -+		 -+		major = cfi_read_query(map, base + (adr+3)*ofs_factor); -+		minor = cfi_read_query(map, base + (adr+4)*ofs_factor); -+		 -+		printk(" SST Query Table v%c.%c at 0x%4.4X\n", -+		       major, minor, adr); -+		cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL); -+		 -+		cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); -+		cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); -+		cfi_send_gen_cmd(0x90, 0x5555, base, map, cfi, cfi->device_type, NULL); -+		cfi->mfr = cfi_read_query(map, base); -+		cfi->id = cfi_read_query(map, base + ofs_factor); -+ -+		cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); -+		cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); -+		cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); -+		 -+		switch (cfi->device_type) { -+		case CFI_DEVICETYPE_X16: -+			cfi->addr_unlock1 = 0x5555; -+			cfi->addr_unlock2 = 0x2AAA; -+			break; -+		default: -+			printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0701 device type %d\n", cfi->device_type); -+			return NULL; -+		} -+	} /* CFI mode */ -+ -+	for (i=0; i< cfi->numchips; i++) { -+		cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; -+		cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; -+		cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; -+	}		 -+	 -+	map->fldrv = &cfi_sststd_chipdrv; -+	MOD_INC_USE_COUNT; -+ -+	cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL); -+	return cfi_sststd_setup(map); -+} -+ -+static struct mtd_info *cfi_sststd_setup(struct map_info *map) -+{ -+	struct cfi_private *cfi = map->fldrv_priv; -+	struct mtd_info *mtd; -+	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave; -+ -+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); -+	printk("number of %s chips: %d\n", (cfi->cfi_mode)?"JEDEC":"CFI",cfi->numchips); -+ -+	if (!mtd) { -+	  printk("Failed to allocate memory for MTD device\n"); -+	  kfree(cfi->cmdset_priv); -+	  return NULL; -+	} -+ -+	memset(mtd, 0, sizeof(*mtd)); -+	mtd->priv = map; -+	mtd->type = MTD_NORFLASH; -+	/* Also select the correct geometry setup too */  -+	mtd->size = devsize * cfi->numchips; -+	 -+	if (cfi->cfiq->NumEraseRegions == 1) { -+		/* No need to muck about with multiple erase sizes */ -+		mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave; -+	} else { -+		unsigned long offset = 0; -+		int i,j; -+ -+		mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; -+		mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); -+		if (!mtd->eraseregions) {  -+			printk("Failed to allocate memory for MTD erase region info\n"); -+			kfree(cfi->cmdset_priv); -+			return NULL; -+		} -+			 -+		for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { -+			unsigned long ernum, ersize; -+			ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave; -+			ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1; -+			 -+			if (mtd->erasesize < ersize) { -+				mtd->erasesize = ersize; -+			} -+			for (j=0; j<cfi->numchips; j++) { -+				mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset; -+				mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize; -+				mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; -+			} -+			offset += (ersize * ernum); -+		} -+ -+		// debug -+		for (i=0; i<mtd->numeraseregions;i++){ -+			printk("%d: offset=0x%x,size=0x%x,blocks=%d\n", -+			       i,mtd->eraseregions[i].offset, -+			       mtd->eraseregions[i].erasesize, -+			       mtd->eraseregions[i].numblocks); -+		} -+	} -+ -+	switch (CFIDEV_BUSWIDTH) -+	{ -+	case 1: -+	case 2: -+	case 4: -+		if (mtd->numeraseregions > 1) -+			mtd->erase = cfi_sststd_erase_varsize; -+		else -+			mtd->erase = cfi_sststd_erase_onesize; -+		mtd->read = cfi_sststd_read; -+		mtd->write = cfi_sststd_write; -+		break; -+ -+	default: -+	        printk("Unsupported buswidth\n"); -+		kfree(mtd); -+		kfree(cfi->cmdset_priv); -+		return NULL; -+		break; -+	} -+	mtd->sync = cfi_sststd_sync; -+	mtd->suspend = cfi_sststd_suspend; -+	mtd->resume = cfi_sststd_resume; -+	mtd->flags = MTD_CAP_NORFLASH; -+	map->fldrv = &cfi_sststd_chipdrv; -+	mtd->name = map->name; -+	MOD_INC_USE_COUNT; -+	return mtd; -+} -+ -+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) -+{ -+	DECLARE_WAITQUEUE(wait, current); -+	unsigned long timeo = jiffies + HZ; -+ -+ retry: -+	cfi_spin_lock(chip->mutex); -+ -+	if (chip->state != FL_READY){ -+	        printk("Waiting for chip to read, status = %d\n", chip->state); -+		set_current_state(TASK_UNINTERRUPTIBLE); -+		add_wait_queue(&chip->wq, &wait); -+                 -+		cfi_spin_unlock(chip->mutex); -+ -+		schedule(); -+		remove_wait_queue(&chip->wq, &wait); -+		timeo = jiffies + HZ; -+ -+		goto retry; -+	}	 -+ -+	adr += chip->start; -+ -+	chip->state = FL_READY; -+ -+	map->copy_from(map, buf, adr, len); -+ -+	wake_up(&chip->wq); -+	cfi_spin_unlock(chip->mutex); -+ -+	return 0; -+} -+ -+static int cfi_sststd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -+{ -+	struct map_info *map = mtd->priv; -+	struct cfi_private *cfi = map->fldrv_priv; -+	unsigned long ofs; -+	int chipnum; -+	int ret = 0; -+ -+	/* ofs: offset within the first chip that the first read should start */ -+ -+	chipnum = (from >> cfi->chipshift); -+	ofs = from - (chipnum <<  cfi->chipshift); -+ -+ -+	*retlen = 0; -+ -+	while (len) { -+		unsigned long thislen; -+ -+		if (chipnum >= cfi->numchips) -+			break; -+ -+		if ((len + ofs -1) >> cfi->chipshift) -+			thislen = (1<<cfi->chipshift) - ofs; -+		else -+			thislen = len; -+ -+		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf); -+		if (ret) -+			break; -+ -+		*retlen += thislen; -+		len -= thislen; -+		buf += thislen; -+ -+		ofs = 0; -+		chipnum++; -+	} -+	return ret; -+} -+ -+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast) -+{ -+	unsigned long timeo = jiffies + HZ; -+	unsigned int Last[4]; -+	unsigned long Count = 0; -+	struct cfi_private *cfi = map->fldrv_priv; -+	DECLARE_WAITQUEUE(wait, current); -+	int ret = 0; -+ -+ retry: -+	cfi_spin_lock(chip->mutex); -+ -+	if (chip->state != FL_READY){ -+	        printk("Waiting for chip to write, status = %d\n", chip->state); -+		set_current_state(TASK_UNINTERRUPTIBLE); -+		add_wait_queue(&chip->wq, &wait); -+                 -+		cfi_spin_unlock(chip->mutex); -+ -+		schedule(); -+		remove_wait_queue(&chip->wq, &wait); -+		printk("Wake up to write:\n"); -+		timeo = jiffies + HZ; -+ -+		goto retry; -+	}	 -+ -+	chip->state = FL_WRITING; -+ -+	adr += chip->start; -+	ENABLE_VPP(map); -+    cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); -+    cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); -+    cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); -+ -+	cfi_write(map, datum, adr); -+ -+	cfi_spin_unlock(chip->mutex); -+	cfi_udelay(chip->word_write_time); -+	cfi_spin_lock(chip->mutex); -+ -+	Last[0] = cfi_read(map, adr); -+	//	printk("Last[0] is %x\n", Last[0]); -+	Last[1] = cfi_read(map, adr); -+	//	printk("Last[1] is %x\n", Last[1]); -+	Last[2] = cfi_read(map, adr); -+	//	printk("Last[2] is %x\n", Last[2]); -+ -+	for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){ -+		cfi_spin_unlock(chip->mutex); -+		cfi_udelay(10); -+		cfi_spin_lock(chip->mutex); -+		 -+	        Last[Count % 4] = cfi_read(map, adr); -+		//		printk("Last[%d%%4] is %x\n", Count, Last[Count%4]); -+	} -+	 -+	if (Last[(Count - 1) % 4] != datum){ -+		printk("Last[%ld] is %x, datum is %x\n",(Count - 1) % 4,Last[(Count - 1) % 4],datum); -+	        cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL); -+		DISABLE_VPP(map); -+		ret = -EIO; -+	}        -+	DISABLE_VPP(map); -+	chip->state = FL_READY; -+	wake_up(&chip->wq); -+	cfi_spin_unlock(chip->mutex); -+	 -+	return ret; -+} -+ -+static int cfi_sststd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf) -+{ -+	struct map_info *map = mtd->priv; -+	struct cfi_private *cfi = map->fldrv_priv; -+	int ret = 0; -+	int chipnum; -+	unsigned long ofs, chipstart; -+ -+	*retlen = 0; -+	if (!len) -+		return 0; -+ -+	chipnum = to >> cfi->chipshift; -+	ofs = to  - (chipnum << cfi->chipshift); -+	chipstart = cfi->chips[chipnum].start; -+ -+	/* If it's not bus-aligned, do the first byte write */ -+	if (ofs & (CFIDEV_BUSWIDTH-1)) { -+		unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1); -+		int i = ofs - bus_ofs; -+		int n = 0; -+		u_char tmp_buf[4]; -+		__u32 datum; -+ -+		map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); -+		while (len && i < CFIDEV_BUSWIDTH) -+			tmp_buf[i++] = buf[n++], len--; -+ -+		if (cfi_buswidth_is_2()) { -+			datum = *(__u16*)tmp_buf; -+		} else if (cfi_buswidth_is_4()) { -+			datum = *(__u32*)tmp_buf; -+		} else { -+			return -EINVAL;  /* should never happen, but be safe */ -+		} -+ -+		ret = do_write_oneword(map, &cfi->chips[chipnum],  -+				bus_ofs, datum, 0); -+		if (ret)  -+			return ret; -+		 -+		ofs += n; -+		buf += n; -+		(*retlen) += n; -+ -+		if (ofs >> cfi->chipshift) { -+			chipnum ++;  -+			ofs = 0; -+			if (chipnum == cfi->numchips) -+				return 0; -+		} -+	} -+	 -+	/* We are now aligned, write as much as possible */ -+	while(len >= CFIDEV_BUSWIDTH) { -+		__u32 datum; -+ -+		if (cfi_buswidth_is_1()) { -+			datum = *(__u8*)buf; -+		} else if (cfi_buswidth_is_2()) { -+			datum = *(__u16*)buf; -+		} else if (cfi_buswidth_is_4()) { -+			datum = *(__u32*)buf; -+		} else { -+			return -EINVAL; -+		} -+		ret = do_write_oneword(map, &cfi->chips[chipnum], -+				       ofs, datum, cfi->fast_prog); -+		if (ret) { -+			return ret; -+		} -+ -+		ofs += CFIDEV_BUSWIDTH; -+		buf += CFIDEV_BUSWIDTH; -+		(*retlen) += CFIDEV_BUSWIDTH; -+		len -= CFIDEV_BUSWIDTH; -+ -+		if (ofs >> cfi->chipshift) { -+			chipnum ++;  -+			ofs = 0; -+			if (chipnum == cfi->numchips) -+				return 0; -+			chipstart = cfi->chips[chipnum].start; -+		} -+	} -+ -+	if (len & (CFIDEV_BUSWIDTH-1)) { -+		int i = 0, n = 0; -+		u_char tmp_buf[4]; -+		__u32 datum; -+ -+		map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); -+		while (len--) -+			tmp_buf[i++] = buf[n++]; -+ -+		if (cfi_buswidth_is_2()) { -+			datum = *(__u16*)tmp_buf; -+		} else if (cfi_buswidth_is_4()) { -+			datum = *(__u32*)tmp_buf; -+		} else { -+			return -EINVAL;  /* should never happen, but be safe */ -+		} -+ -+		ret = do_write_oneword(map, &cfi->chips[chipnum],  -+				ofs, datum, 0); -+		if (ret)  -+			return ret; -+		 -+		(*retlen) += n; -+	} -+ -+	return 0; -+} -+ -+static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) -+{ -+	unsigned int status; -+	unsigned long timeo = jiffies + HZ; -+	struct cfi_private *cfi = map->fldrv_priv; -+	unsigned int rdy_mask; -+	DECLARE_WAITQUEUE(wait, current); -+ -+ retry: -+	cfi_spin_lock(chip->mutex); -+ -+	if (chip->state != FL_READY){ -+		set_current_state(TASK_UNINTERRUPTIBLE); -+		add_wait_queue(&chip->wq, &wait); -+                 -+		cfi_spin_unlock(chip->mutex); -+ -+		schedule(); -+		remove_wait_queue(&chip->wq, &wait); -+		timeo = jiffies + HZ; -+ -+		goto retry; -+	}	 -+ -+	chip->state = FL_ERASING; -+ -+	adr += chip->start; -+	ENABLE_VPP(map); -+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); -+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); -+	cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); -+	cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); -+	cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL); -+	cfi_write(map, CMD(0x30), adr); -+	 -+	timeo = jiffies + (HZ*20); -+ -+	cfi_spin_unlock(chip->mutex); -+	schedule_timeout(HZ); -+	cfi_spin_lock(chip->mutex); -+	 -+	rdy_mask = CMD(0x80); -+ -+	/* Once the state machine's known to be working I'll do that */ -+ -+	while ( ( (status = cfi_read(map,adr)) & rdy_mask ) != rdy_mask ) { -+		static int z=0; -+ -+		if (chip->state != FL_ERASING) { -+			/* Someone's suspended the erase. Sleep */ -+			set_current_state(TASK_UNINTERRUPTIBLE); -+			add_wait_queue(&chip->wq, &wait); -+			 -+			cfi_spin_unlock(chip->mutex); -+			printk("erase suspended. Sleeping\n"); -+			 -+			schedule(); -+			remove_wait_queue(&chip->wq, &wait); -+			timeo = jiffies + (HZ*2);  -+			cfi_spin_lock(chip->mutex); -+			continue; -+		} -+ -+		/* OK Still waiting */ -+		if (time_after(jiffies, timeo)) { -+			chip->state = FL_READY; -+			cfi_spin_unlock(chip->mutex); -+			printk("waiting for erase to complete timed out."); -+			DISABLE_VPP(map); -+			return -EIO; -+		} -+		 -+		/* Latency issues. Drop the lock, wait a while and retry */ -+		cfi_spin_unlock(chip->mutex); -+ -+		z++; -+		if ( 0 && !(z % 100 ))  -+			printk("chip not ready yet after erase. looping\n"); -+ -+		cfi_udelay(1); -+		 -+		cfi_spin_lock(chip->mutex); -+		continue; -+	} -+	 -+	/* Done and happy. */ -+	DISABLE_VPP(map); -+	chip->state = FL_READY; -+	wake_up(&chip->wq); -+	cfi_spin_unlock(chip->mutex); -+	return 0; -+} -+ -+static int cfi_sststd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) -+{ -+	struct map_info *map = mtd->priv; -+	struct cfi_private *cfi = map->fldrv_priv; -+	unsigned long adr, len; -+	int chipnum, ret = 0; -+	int i, first; -+	struct mtd_erase_region_info *regions = mtd->eraseregions; -+ -+	if (instr->addr > mtd->size) -+		return -EINVAL; -+ -+	if ((instr->len + instr->addr) > mtd->size) -+		return -EINVAL; -+ -+	/* Check that both start and end of the requested erase are -+	 * aligned with the erasesize at the appropriate addresses. -+	 */ -+ -+	i = 0; -+ -+	/* Skip all erase regions which are ended before the start of  -+	   the requested erase. Actually, to save on the calculations, -+	   we skip to the first erase region which starts after the -+	   start of the requested erase, and then go back one. -+	*/ -+	 -+	while (i < mtd->numeraseregions && instr->addr >= regions[i].offset) -+	       i++; -+	i--; -+ -+	/* OK, now i is pointing at the erase region in which this  -+	   erase request starts. Check the start of the requested -+	   erase range is aligned with the erase size which is in -+	   effect here. -+	*/ -+ -+	if (instr->addr & (regions[i].erasesize-1)) -+		return -EINVAL; -+ -+	/* Remember the erase region we start on */ -+	first = i; -+ -+	/* Next, check that the end of the requested erase is aligned -+	 * with the erase region at that address. -+	 */ -+ -+	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset) -+		i++; -+ -+	/* As before, drop back one to point at the region in which -+	   the address actually falls -+	*/ -+	i--; -+	 -+	if ((instr->addr + instr->len) & (regions[i].erasesize-1)) -+		return -EINVAL; -+	 -+	chipnum = instr->addr >> cfi->chipshift; -+	adr = instr->addr - (chipnum << cfi->chipshift); -+	len = instr->len; -+ -+	i=first; -+ -+	while(len) { -+		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); -+ -+		if (ret) -+			return ret; -+ -+		adr += regions[i].erasesize; -+		len -= regions[i].erasesize; -+ -+		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift))) -+			i++; -+ -+		if (adr >> cfi->chipshift) { -+			adr = 0; -+			chipnum++; -+			 -+			if (chipnum >= cfi->numchips) -+			break; -+		} -+	} -+ -+	instr->state = MTD_ERASE_DONE; -+	if (instr->callback) -+		instr->callback(instr); -+	 -+	return 0; -+} -+ -+static int cfi_sststd_erase_onesize(struct mtd_info *mtd, struct erase_info *instr) -+{ -+	struct map_info *map = mtd->priv; -+	struct cfi_private *cfi = map->fldrv_priv; -+	unsigned long adr, len; -+	int chipnum, ret = 0; -+ -+	if (instr->addr & (mtd->erasesize - 1)) -+		return -EINVAL; -+ -+	if (instr->len & (mtd->erasesize -1)) -+		return -EINVAL; -+ -+	if ((instr->len + instr->addr) > mtd->size) -+		return -EINVAL; -+ -+	chipnum = instr->addr >> cfi->chipshift; -+	adr = instr->addr - (chipnum << cfi->chipshift); -+	len = instr->len; -+ -+	while(len) { -+		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); -+ -+		if (ret) -+			return ret; -+ -+		adr += mtd->erasesize; -+		len -= mtd->erasesize; -+ -+		if (adr >> cfi->chipshift) { -+			adr = 0; -+			chipnum++; -+			 -+			if (chipnum >= cfi->numchips) -+			break; -+		} -+	} -+		 -+	instr->state = MTD_ERASE_DONE; -+	if (instr->callback) -+		instr->callback(instr); -+	 -+	return 0; -+} -+ -+static void cfi_sststd_sync (struct mtd_info *mtd) -+{ -+	struct map_info *map = mtd->priv; -+	struct cfi_private *cfi = map->fldrv_priv; -+	int i; -+	struct flchip *chip; -+	int ret = 0; -+	DECLARE_WAITQUEUE(wait, current); -+ -+	for (i=0; !ret && i<cfi->numchips; i++) { -+		chip = &cfi->chips[i]; -+ -+	retry: -+		cfi_spin_lock(chip->mutex); -+ -+		switch(chip->state) { -+		case FL_READY: -+		case FL_STATUS: -+		case FL_CFI_QUERY: -+		case FL_JEDEC_QUERY: -+			chip->oldstate = chip->state; -+			chip->state = FL_SYNCING; -+			/* No need to wake_up() on this state change -  -+			 * as the whole point is that nobody can do anything -+			 * with the chip now anyway. -+			 */ -+		case FL_SYNCING: -+			cfi_spin_unlock(chip->mutex); -+			break; -+ -+		default: -+			/* Not an idle state */ -+			add_wait_queue(&chip->wq, &wait); -+			 -+			cfi_spin_unlock(chip->mutex); -+ -+			schedule(); -+ -+		        remove_wait_queue(&chip->wq, &wait); -+			 -+			goto retry; -+		} -+	} -+ -+	/* Unlock the chips again */ -+ -+	for (i--; i >=0; i--) { -+		chip = &cfi->chips[i]; -+ -+		cfi_spin_lock(chip->mutex); -+		 -+		if (chip->state == FL_SYNCING) { -+			chip->state = chip->oldstate; -+			wake_up(&chip->wq); -+		} -+		cfi_spin_unlock(chip->mutex); -+	} -+} -+ -+ -+static int cfi_sststd_suspend(struct mtd_info *mtd) -+{ -+	struct map_info *map = mtd->priv; -+	struct cfi_private *cfi = map->fldrv_priv; -+	int i; -+	struct flchip *chip; -+	int ret = 0; -+//printk("suspend\n"); -+ -+	for (i=0; !ret && i<cfi->numchips; i++) { -+		chip = &cfi->chips[i]; -+ -+		cfi_spin_lock(chip->mutex); -+ -+		switch(chip->state) { -+		case FL_READY: -+		case FL_STATUS: -+		case FL_CFI_QUERY: -+		case FL_JEDEC_QUERY: -+			chip->oldstate = chip->state; -+			chip->state = FL_PM_SUSPENDED; -+			/* No need to wake_up() on this state change -  -+			 * as the whole point is that nobody can do anything -+			 * with the chip now anyway. -+			 */ -+		case FL_PM_SUSPENDED: -+			break; -+ -+		default: -+			ret = -EAGAIN; -+			break; -+		} -+		cfi_spin_unlock(chip->mutex); -+	} -+ -+	/* Unlock the chips again */ -+ -+	if (ret) { -+    		for (i--; i >=0; i--) { -+			chip = &cfi->chips[i]; -+ -+			cfi_spin_lock(chip->mutex); -+		 -+			if (chip->state == FL_PM_SUSPENDED) { -+				chip->state = chip->oldstate; -+				wake_up(&chip->wq); -+			} -+			cfi_spin_unlock(chip->mutex); -+		} -+	} -+	 -+	return ret; -+} -+ -+static void cfi_sststd_resume(struct mtd_info *mtd) -+{ -+	struct map_info *map = mtd->priv; -+	struct cfi_private *cfi = map->fldrv_priv; -+	int i; -+	struct flchip *chip; -+//printk("resume\n"); -+ -+	for (i=0; i<cfi->numchips; i++) { -+	 -+		chip = &cfi->chips[i]; -+ -+		cfi_spin_lock(chip->mutex); -+		 -+		if (chip->state == FL_PM_SUSPENDED) { -+			chip->state = FL_READY; -+			cfi_write(map, CMD(0xF0), chip->start); -+			wake_up(&chip->wq); -+		} -+		else -+			printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n"); -+ -+		cfi_spin_unlock(chip->mutex); -+	} -+} -+ -+static void cfi_sststd_destroy(struct mtd_info *mtd) -+{ -+	struct map_info *map = mtd->priv; -+	struct cfi_private *cfi = map->fldrv_priv; -+	kfree(cfi->cmdset_priv); -+	kfree(cfi); -+} -+ -+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE) -+#define cfi_sststd_init init_module -+#define cfi_sststd_exit cleanup_module -+#endif -+ -+static char im_name[]="cfi_cmdset_0701"; -+ -+mod_init_t cfi_sststd_init(void) -+{ -+	inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0701); -+	return 0; -+} -+ -+mod_exit_t cfi_sststd_exit(void) -+{ -+	inter_module_unregister(im_name); -+} -+ -+module_init(cfi_sststd_init); -+module_exit(cfi_sststd_exit); -+ -diff -urN linux-2.4.30/drivers/mtd/chips/cfi_probe.c linux-2.4.30.dev/drivers/mtd/chips/cfi_probe.c ---- linux-2.4.30/drivers/mtd/chips/cfi_probe.c	2003-06-13 16:51:34.000000000 +0200 -+++ linux-2.4.30.dev/drivers/mtd/chips/cfi_probe.c	2005-08-22 01:34:46.434134592 +0200 -@@ -67,8 +67,15 @@ - 	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - 	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); -  --	if (!qry_present(map,base,cfi)) --		return 0; -+	if (!qry_present(map,base,cfi)) { -+		/* rather broken SST cfi probe (requires SST unlock) */ -+		cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); -+		cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL); -+		cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL); -+		cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL); -+		if (!qry_present(map,base,cfi)) -+			return 0; -+	} -  - 	if (!cfi->numchips) { - 		/* This is the first time we're called. Set up the CFI  -diff -urN linux-2.4.30/drivers/mtd/chips/gen_probe.c linux-2.4.30.dev/drivers/mtd/chips/gen_probe.c ---- linux-2.4.30/drivers/mtd/chips/gen_probe.c	2003-08-25 13:44:42.000000000 +0200 -+++ linux-2.4.30.dev/drivers/mtd/chips/gen_probe.c	2005-08-22 01:34:46.436134288 +0200 -@@ -332,9 +332,13 @@ - 		return cfi_cmdset_0002(map, primary); - #endif - #ifdef CONFIG_MTD_CFI_STAA --        case 0x0020: -+	case 0x0020: - 		return cfi_cmdset_0020(map, primary); - #endif -+#ifdef CONFIG_MTD_CFI_SSTSTD -+	case 0x0701: -+		return cfi_cmdset_0701(map, primary); -+#endif - 	} -  - 	return cfi_cmdset_unknown(map, primary);  diff -urN linux-2.4.30/drivers/mtd/maps/Config.in linux-2.4.30.dev/drivers/mtd/maps/Config.in  --- linux-2.4.30/drivers/mtd/maps/Config.in	2005-08-22 01:29:09.605340352 +0200  +++ linux-2.4.30.dev/drivers/mtd/maps/Config.in	2005-08-22 01:34:46.460130640 +0200  | 
