diff --git a/openwrt/target/linux/linux-2.4/patches/brcm/001-bcm47xx.patch b/openwrt/target/linux/linux-2.4/patches/brcm/001-bcm47xx.patch index 5d162c43d..762676139 100644 --- a/openwrt/target/linux/linux-2.4/patches/brcm/001-bcm47xx.patch +++ b/openwrt/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. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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<cfiq->WordWriteTimeoutTyp; -+ cfi->chips[i].buffer_write_time = 1<cfiq->BufWriteTimeoutTyp; -+ cfi->chips[i].erase_time = 1<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<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; icfiq->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; jnumchips; 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; inumeraseregions;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<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 (inumeraseregions && (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 && inumchips; 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 && inumchips; 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; inumchips; 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