Merge master.kernel.org:/pub/scm/linux/kernel/git/tglx/mtd-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Mon, 11 Jul 2005 17:18:18 +0000 (10:18 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 11 Jul 2005 17:18:18 +0000 (10:18 -0700)
83 files changed:
drivers/mtd/chips/Kconfig
drivers/mtd/chips/amd_flash.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/fwh_lock.h
drivers/mtd/chips/gen_probe.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/ms02-nv.c
drivers/mtd/devices/mtdram.c
drivers/mtd/devices/phram.c
drivers/mtd/devices/slram.c
drivers/mtd/ftl.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/alchemy-flash.c [new file with mode: 0644]
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/bast-flash.c
drivers/mtd/maps/db1550-flash.c [deleted file]
drivers/mtd/maps/db1x00-flash.c [deleted file]
drivers/mtd/maps/elan-104nc.c [deleted file]
drivers/mtd/maps/ichxrom.c
drivers/mtd/maps/ixp2000.c
drivers/mtd/maps/mainstone-flash.c [new file with mode: 0644]
drivers/mtd/maps/map_funcs.c
drivers/mtd/maps/omap_nor.c [new file with mode: 0644]
drivers/mtd/maps/pb1550-flash.c [deleted file]
drivers/mtd/maps/pb1xxx-flash.c [deleted file]
drivers/mtd/maps/pci.c
drivers/mtd/maps/plat-ram.c [new file with mode: 0644]
drivers/mtd/maps/scb2_flash.c
drivers/mtd/maps/sharpsl-flash.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/rtc_from4.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sharpsl.c [changed mode: 0755->0644]
drivers/mtd/nand/tx4925ndfmc.c [deleted file]
drivers/mtd/nand/tx4938ndfmc.c [deleted file]
fs/Kconfig
fs/jffs2/Makefile
fs/jffs2/README.Locking
fs/jffs2/background.c
fs/jffs2/build.c
fs/jffs2/compr_zlib.c
fs/jffs2/dir.c
fs/jffs2/erase.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/gc.c
fs/jffs2/nodelist.c
fs/jffs2/nodelist.h
fs/jffs2/nodemgmt.c
fs/jffs2/os-linux.h
fs/jffs2/read.c
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/super.c
fs/jffs2/symlink.c
fs/jffs2/wbuf.c
fs/jffs2/write.c
include/asm-arm/arch-pxa/mtd-xip.h [new file with mode: 0644]
include/asm-arm/arch-sa1100/mtd-xip.h [new file with mode: 0644]
include/asm-arm/mtd-xip.h [new file with mode: 0644]
include/linux/jffs2_fs_sb.h
include/linux/mtd/cfi.h
include/linux/mtd/flashchip.h
include/linux/mtd/inftl.h
include/linux/mtd/map.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/plat-ram.h [new file with mode: 0644]
include/linux/mtd/xip.h
include/mtd/mtd-abi.h

index d682dbc8157e4030a641a245b305ea7d112593e2..b5dc59389bb363886f4b6023ca54a3106da2d31c 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $
+# $Id: Kconfig,v 1.15 2005/06/06 23:04:35 tpoynor Exp $
 
 menu "RAM/ROM/Flash chip drivers"
        depends on MTD!=n
@@ -155,6 +155,31 @@ config MTD_CFI_I8
          If your flash chips are interleaved in eights - i.e. you have eight
          flash chips addressed by each bus cycle, then say 'Y'.
 
+config MTD_OTP
+       bool "Protection Registers aka one-time programmable (OTP) bits"
+       depends on MTD_CFI_ADV_OPTIONS
+       default n
+       help
+         This enables support for reading, writing and locking so called
+         "Protection Registers" present on some flash chips.
+         A subset of them are pre-programmed at the factory with a
+         unique set of values. The rest is user-programmable.
+
+         The user-programmable Protection Registers contain one-time
+         programmable (OTP) bits; when programmed, register bits cannot be
+         erased. Each Protection Register can be accessed multiple times to
+         program individual bits, as long as the register remains unlocked.
+
+         Each Protection Register has an associated Lock Register bit. When a
+         Lock Register bit is programmed, the associated Protection Register
+         can only be read; it can no longer be programmed. Additionally,
+         because the Lock Register bits themselves are OTP, when programmed,
+         Lock Register bits cannot be erased. Therefore, when a Protection
+         Register is locked, it cannot be unlocked.
+
+         This feature should therefore be used with extreme care. Any mistake
+         in the programming of OTP bits will waste them.
+
 config MTD_CFI_INTELEXT
        tristate "Support for Intel/Sharp flash chips"
        depends on MTD_GEN_PROBE
@@ -275,7 +300,7 @@ config MTD_JEDEC
 
 config MTD_XIP
        bool "XIP aware MTD support"
-       depends on !SMP && MTD_CFI_INTELEXT && EXPERIMENTAL
+       depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL
        default y if XIP_KERNEL
        help
          This allows MTD support to work with flash memory which is also
index 41e2e3e31603cc9dd7cd5c412c81add96137b170..2dafeba3f3d5afb9ce165794e86286da7b064e77 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Author: Jonas Holmberg <jonas.holmberg@axis.com>
  *
- * $Id: amd_flash.c,v 1.26 2004/11/20 12:49:04 dwmw2 Exp $
+ * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $
  *
  * Copyright (c) 2001 Axis Communications AB
  *
@@ -67,7 +67,6 @@
 #define AM29LV160DT    0x22C4
 #define AM29LV160DB    0x2249
 #define AM29BDS323D     0x22D1
-#define AM29BDS643D    0x227E
 
 /* Atmel */
 #define AT49xV16x      0x00C0
@@ -617,17 +616,6 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
                        { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
                        { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks =  8 },
                }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29BDS643D,
-               .name = "AMD AM29BDS643D",
-               .size = 0x00800000,
-               .numeraseregions = 3,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 },
-                       { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks =  8 },
-               }
        }, {
                .mfr_id = MANUFACTURER_ATMEL,
                .dev_id = AT49xV16x,
index c268bcd7172025a5312960f338903085086cc366..0cfcd88468e0ed3c2db5da780bc3d7e428c3ab3c 100644 (file)
@@ -4,7 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.164 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $
  *
  * 
  * 10/10/2000  Nicolas Pitre <nico@cam.org>
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/reboot.h>
 #include <linux/mtd/xip.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
 #define M50LPW080       0x002F
 
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-//static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-//static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
 static void cfi_intelext_sync (struct mtd_info *);
 static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
 static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+#ifdef CONFIG_MTD_OTP
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t);
+static int cfi_intelext_get_fact_prot_info (struct mtd_info *,
+                                           struct otp_info *, size_t);
+static int cfi_intelext_get_user_prot_info (struct mtd_info *,
+                                           struct otp_info *, size_t);
+#endif
 static int cfi_intelext_suspend (struct mtd_info *);
 static void cfi_intelext_resume (struct mtd_info *);
+static int cfi_intelext_reboot (struct notifier_block *, unsigned long, void *);
 
 static void cfi_intelext_destroy(struct mtd_info *);
 
@@ -252,7 +262,8 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                int nb_parts, i;
 
                /* Protection Register info */
-               extra_size += (extp->NumProtectionFields - 1) * (4 + 6);
+               extra_size += (extp->NumProtectionFields - 1) *
+                             sizeof(struct cfi_intelext_otpinfo);
 
                /* Burst Read info */
                extra_size += 6;
@@ -324,7 +335,9 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
        mtd->resume  = cfi_intelext_resume;
        mtd->flags   = MTD_CAP_NORFLASH;
        mtd->name    = map->name;
-       
+
+       mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
+
        if (cfi->cfi_mode == CFI_MODE_CFI) {
                /* 
                 * It's a real CFI chip, not one for which the probe
@@ -422,9 +435,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
                       mtd->eraseregions[i].numblocks);
        }
 
-#if 0
-       mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+#ifdef CONFIG_MTD_OTP
        mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
+       mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+       mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
+       mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
+       mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info;
+       mtd->get_user_prot_info = cfi_intelext_get_user_prot_info;
 #endif
 
        /* This function has the potential to distort the reality
@@ -433,6 +450,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
                goto setup_err;
 
        __module_get(THIS_MODULE);
+       register_reboot_notifier(&mtd->reboot_notifier);
        return mtd;
 
  setup_err:
@@ -471,7 +489,8 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
                int offs, numregions, numparts, partshift, numvirtchips, i, j;
 
                /* Protection Register info */
-               offs = (extp->NumProtectionFields - 1) * (4 + 6);
+               offs = (extp->NumProtectionFields - 1) *
+                      sizeof(struct cfi_intelext_otpinfo);
 
                /* Burst Read info */
                offs += 6;
@@ -563,7 +582,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
  resettime:
        timeo = jiffies + HZ;
  retry:
-       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) {
+       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) {
                /*
                 * OK. We have possibility for contension on the write/erase
                 * operations which are global to the real chip and not per
@@ -807,10 +826,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
  * assembly to make sure inline functions were actually inlined and that gcc
  * didn't emit calls to its own support functions). Also configuring MTD CFI
  * support to a single buswidth and a single interleave is also recommended.
- * Note that not only IRQs are disabled but the preemption count is also
- * increased to prevent other locking primitives (namely spin_unlock) from
- * decrementing the preempt count to zero and scheduling the CPU away while
- * not in array mode.
  */
 
 static void xip_disable(struct map_info *map, struct flchip *chip,
@@ -818,7 +833,6 @@ static void xip_disable(struct map_info *map, struct flchip *chip,
 {
        /* TODO: chips with no XIP use should ignore and return */
        (void) map_read(map, adr); /* ensure mmu mapping is up to date */
-       preempt_disable();
        local_irq_disable();
 }
 
@@ -831,9 +845,8 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
                chip->state = FL_READY;
        }
        (void) map_read(map, adr);
-       asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */
+       xip_iprefetch();
        local_irq_enable();
-       preempt_enable();
 }
 
 /*
@@ -909,7 +922,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
                        (void) map_read(map, adr);
                        asm volatile (".rep 8; nop; .endr");
                        local_irq_enable();
-                       preempt_enable();
+                       spin_unlock(chip->mutex);
                        asm volatile (".rep 8; nop; .endr");
                        cond_resched();
 
@@ -919,15 +932,15 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
                         * a suspended erase state.  If so let's wait
                         * until it's done.
                         */
-                       preempt_disable();
+                       spin_lock(chip->mutex);
                        while (chip->state != newstate) {
                                DECLARE_WAITQUEUE(wait, current);
                                set_current_state(TASK_UNINTERRUPTIBLE);
                                add_wait_queue(&chip->wq, &wait);
-                               preempt_enable();
+                               spin_unlock(chip->mutex);
                                schedule();
                                remove_wait_queue(&chip->wq, &wait);
-                               preempt_disable();
+                               spin_lock(chip->mutex);
                        }
                        /* Disallow XIP again */
                        local_irq_disable();
@@ -956,12 +969,14 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
  * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
  * the flash is actively programming or erasing since we have to poll for
  * the operation to complete anyway.  We can't do that in a generic way with
- * a XIP setup so do it before the actual flash operation in this case.
+ * a XIP setup so do it before the actual flash operation in this case
+ * and stub it out from INVALIDATE_CACHE_UDELAY.
  */
-#undef INVALIDATE_CACHED_RANGE
-#define INVALIDATE_CACHED_RANGE(x...)
-#define XIP_INVAL_CACHED_RANGE(map, from, size) \
-       do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
+#define XIP_INVAL_CACHED_RANGE(map, from, size)  \
+       INVALIDATE_CACHED_RANGE(map, from, size)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
+       UDELAY(map, chip, adr, usec)
 
 /*
  * Extra notes:
@@ -984,11 +999,23 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
 
 #define xip_disable(map, chip, adr)
 #define xip_enable(map, chip, adr)
-
-#define UDELAY(map, chip, adr, usec)  cfi_udelay(usec)
-
 #define XIP_INVAL_CACHED_RANGE(x...)
 
+#define UDELAY(map, chip, adr, usec)  \
+do {  \
+       spin_unlock(chip->mutex);  \
+       cfi_udelay(usec);  \
+       spin_lock(chip->mutex);  \
+} while (0)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
+do {  \
+       spin_unlock(chip->mutex);  \
+       INVALIDATE_CACHED_RANGE(map, adr, len);  \
+       cfi_udelay(usec);  \
+       spin_lock(chip->mutex);  \
+} while (0)
+
 #endif
 
 static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
@@ -1176,111 +1203,11 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz
        return ret;
 }
 
-#if 0
-static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd,
-                                               loff_t from, size_t len,
-                                               size_t *retlen,
-                                               u_char *buf,
-                                               int base_offst, int reg_sz)
-{
-       struct map_info *map = mtd->priv;
-       struct cfi_private *cfi = map->fldrv_priv;
-       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
-       struct flchip *chip;
-       int ofs_factor = cfi->interleave * cfi->device_type;
-       int count = len;
-       int chip_num, offst;
-       int ret;
-
-       chip_num = ((unsigned int)from/reg_sz);
-       offst = from - (reg_sz*chip_num)+base_offst;
-
-       while (count) {
-       /* Calculate which chip & protection register offset we need */
-
-               if (chip_num >= cfi->numchips)
-                       goto out;
-
-               chip = &cfi->chips[chip_num];
-               
-               spin_lock(chip->mutex);
-               ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
-               if (ret) {
-                       spin_unlock(chip->mutex);
-                       return (len-count)?:ret;
-               }
-
-               xip_disable(map, chip, chip->start);
-
-               if (chip->state != FL_JEDEC_QUERY) {
-                       map_write(map, CMD(0x90), chip->start);
-                       chip->state = FL_JEDEC_QUERY;
-               }
-
-               while (count && ((offst-base_offst) < reg_sz)) {
-                       *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
-                       buf++;
-                       offst++;
-                       count--;
-               }
-
-               xip_enable(map, chip, chip->start);
-               put_chip(map, chip, chip->start);
-               spin_unlock(chip->mutex);
-
-               /* Move on to the next chip */
-               chip_num++;
-               offst = base_offst;
-       }
-       
- out:  
-       return len-count;
-}
-       
-static int cfi_intelext_read_user_prot_reg (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;
-       struct cfi_pri_intelext *extp=cfi->cmdset_priv;
-       int base_offst,reg_sz;
-       
-       /* Check that we actually have some protection registers */
-       if(!extp || !(extp->FeatureSupport&64)){
-               printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
-               return 0;
-       }
-
-       base_offst=(1<<extp->FactProtRegSize);
-       reg_sz=(1<<extp->UserProtRegSize);
-
-       return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
-}
-
-static int cfi_intelext_read_fact_prot_reg (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;
-       struct cfi_pri_intelext *extp=cfi->cmdset_priv;
-       int base_offst,reg_sz;
-       
-       /* Check that we actually have some protection registers */
-       if(!extp || !(extp->FeatureSupport&64)){
-               printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
-               return 0;
-       }
-
-       base_offst=0;
-       reg_sz=(1<<extp->FactProtRegSize);
-
-       return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
-}
-#endif
-
 static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
-                                    unsigned long adr, map_word datum)
+                                    unsigned long adr, map_word datum, int mode)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       map_word status, status_OK;
+       map_word status, status_OK, write_cmd;
        unsigned long timeo;
        int z, ret=0;
 
@@ -1288,9 +1215,14 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 
        /* Let's determine this according to the interleave only once */
        status_OK = CMD(0x80);
+       switch (mode) {
+       case FL_WRITING:   write_cmd = CMD(0x40); break;
+       case FL_OTP_WRITE: write_cmd = CMD(0xc0); break;
+       default: return -EINVAL;
+       }
 
        spin_lock(chip->mutex);
-       ret = get_chip(map, chip, adr, FL_WRITING);
+       ret = get_chip(map, chip, adr, mode);
        if (ret) {
                spin_unlock(chip->mutex);
                return ret;
@@ -1299,19 +1231,18 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
        XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
        ENABLE_VPP(map);
        xip_disable(map, chip, adr);
-       map_write(map, CMD(0x40), adr);
+       map_write(map, write_cmd, adr);
        map_write(map, datum, adr);
-       chip->state = FL_WRITING;
+       chip->state = mode;
 
-       spin_unlock(chip->mutex);
-       INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
-       UDELAY(map, chip, adr, chip->word_write_time);
-       spin_lock(chip->mutex);
+       INVALIDATE_CACHE_UDELAY(map, chip,
+                               adr, map_bankwidth(map),
+                               chip->word_write_time);
 
        timeo = jiffies + (HZ/2);
        z = 0;
        for (;;) {
-               if (chip->state != FL_WRITING) {
+               if (chip->state != mode) {
                        /* Someone's suspended the write. Sleep */
                        DECLARE_WAITQUEUE(wait, current);
 
@@ -1339,10 +1270,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
                }
 
                /* Latency issues. Drop the lock, wait a while and retry */
-               spin_unlock(chip->mutex);
                z++;
                UDELAY(map, chip, adr, 1);
-               spin_lock(chip->mutex);
        }
        if (!z) {
                chip->word_write_time--;
@@ -1399,7 +1328,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                datum = map_word_load_partial(map, datum, buf, gap, n);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
-                                              bus_ofs, datum);
+                                              bus_ofs, datum, FL_WRITING);
                if (ret) 
                        return ret;
 
@@ -1420,7 +1349,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                map_word datum = map_word_load(map, buf);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
-                               ofs, datum);
+                                      ofs, datum, FL_WRITING);
                if (ret)
                        return ret;
 
@@ -1444,7 +1373,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                datum = map_word_load_partial(map, datum, buf, 0, len);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
-                                              ofs, datum);
+                                      ofs, datum, FL_WRITING);
                if (ret) 
                        return ret;
                
@@ -1506,9 +1435,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
 
-               spin_unlock(chip->mutex);
                UDELAY(map, chip, cmd_adr, 1);
-               spin_lock(chip->mutex);
 
                if (++z > 20) {
                        /* Argh. Not ready for write to buffer */
@@ -1554,10 +1481,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        map_write(map, CMD(0xd0), cmd_adr);
        chip->state = FL_WRITING;
 
-       spin_unlock(chip->mutex);
-       INVALIDATE_CACHED_RANGE(map, adr, len);
-       UDELAY(map, chip, cmd_adr, chip->buffer_write_time);
-       spin_lock(chip->mutex);
+       INVALIDATE_CACHE_UDELAY(map, chip, 
+                               cmd_adr, len,
+                               chip->buffer_write_time);
 
        timeo = jiffies + (HZ/2);
        z = 0;
@@ -1589,10 +1515,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                }
                
                /* Latency issues. Drop the lock, wait a while and retry */
-               spin_unlock(chip->mutex);
-               UDELAY(map, chip, cmd_adr, 1);
                z++;
-               spin_lock(chip->mutex);
+               UDELAY(map, chip, cmd_adr, 1);
        }
        if (!z) {
                chip->buffer_write_time--;
@@ -1720,10 +1644,9 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
        chip->state = FL_ERASING;
        chip->erase_suspended = 0;
 
-       spin_unlock(chip->mutex);
-       INVALIDATE_CACHED_RANGE(map, adr, len);
-       UDELAY(map, chip, adr, chip->erase_time*1000/2);
-       spin_lock(chip->mutex);
+       INVALIDATE_CACHE_UDELAY(map, chip,
+                               adr, len,
+                               chip->erase_time*1000/2);
 
        /* FIXME. Use a timer to check this, and return immediately. */
        /* Once the state machine's known to be working I'll do that */
@@ -1768,9 +1691,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
                }
                
                /* Latency issues. Drop the lock, wait a while and retry */
-               spin_unlock(chip->mutex);
                UDELAY(map, chip, adr, 1000000/HZ);
-               spin_lock(chip->mutex);
        }
 
        /* We've broken this before. It doesn't hurt to be safe */
@@ -1780,44 +1701,34 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
 
        /* check for lock bit */
        if (map_word_bitsset(map, status, CMD(0x3a))) {
-               unsigned char chipstatus;
+               unsigned long chipstatus;
 
                /* Reset the error bits */
                map_write(map, CMD(0x50), adr);
                map_write(map, CMD(0x70), adr);
                xip_enable(map, chip, adr);
 
-               chipstatus = status.x[0];
-               if (!map_word_equal(map, status, CMD(chipstatus))) {
-                       int i, w;
-                       for (w=0; w<map_words(map); w++) {
-                               for (i = 0; i<cfi_interleave(cfi); i++) {
-                                       chipstatus |= status.x[w] >> (cfi->device_type * 8);
-                               }
-                       }
-                       printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
-                              status.x[0], chipstatus);
-               }
+               chipstatus = MERGESTATUS(status);
 
                if ((chipstatus & 0x30) == 0x30) {
-                       printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
+                       printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus);
                        ret = -EIO;
                } else if (chipstatus & 0x02) {
                        /* Protection bit set */
                        ret = -EROFS;
                } else if (chipstatus & 0x8) {
                        /* Voltage */
-                       printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus);
+                       printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%lx\n", chipstatus);
                        ret = -EIO;
                } else if (chipstatus & 0x20) {
                        if (retries--) {
-                               printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
+                               printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
                                timeo = jiffies + HZ;
                                put_chip(map, chip, adr);
                                spin_unlock(chip->mutex);
                                goto retry;
                        }
-                       printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
+                       printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx\n", adr, chipstatus);
                        ret = -EIO;
                }
        } else {
@@ -1882,6 +1793,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
                
                if (chip->state == FL_SYNCING) {
                        chip->state = chip->oldstate;
+                       chip->oldstate = FL_READY;
                        wake_up(&chip->wq);
                }
                spin_unlock(chip->mutex);
@@ -1897,8 +1809,9 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map,
        struct cfi_private *cfi = map->fldrv_priv;
        int status, ofs_factor = cfi->interleave * cfi->device_type;
 
+       adr += chip->start;
        xip_disable(map, chip, adr+(2*ofs_factor));
-       cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+       map_write(map, CMD(0x90), adr+(2*ofs_factor));
        chip->state = FL_JEDEC_QUERY;
        status = cfi_read_query(map, adr+(2*ofs_factor));
        xip_enable(map, chip, 0);
@@ -1915,6 +1828,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
                                       unsigned long adr, int len, void *thunk)
 {
        struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
        map_word status, status_OK;
        unsigned long timeo = jiffies + HZ;
        int ret;
@@ -1944,9 +1858,13 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
        } else
                BUG();
 
-       spin_unlock(chip->mutex);
-       UDELAY(map, chip, adr, 1000000/HZ);
-       spin_lock(chip->mutex);
+       /*
+        * If Instant Individual Block Locking supported then no need
+        * to delay.
+        */
+
+       if (!extp || !(extp->FeatureSupport & (1 << 5)))
+               UDELAY(map, chip, adr, 1000000/HZ);
 
        /* FIXME. Use a timer to check this, and return immediately. */
        /* Once the state machine's known to be working I'll do that */
@@ -1973,9 +1891,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
                }
                
                /* Latency issues. Drop the lock, wait a while and retry */
-               spin_unlock(chip->mutex);
                UDELAY(map, chip, adr, 1);
-               spin_lock(chip->mutex);
        }
        
        /* Done and happy. */
@@ -2034,6 +1950,274 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
        return ret;
 }
 
+#ifdef CONFIG_MTD_OTP
+
+typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, 
+                       u_long data_offset, u_char *buf, u_int size,
+                       u_long prot_offset, u_int groupno, u_int groupsize);
+
+static int __xipram
+do_otp_read(struct map_info *map, struct flchip *chip, u_long offset,
+           u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       int ret;
+
+       spin_lock(chip->mutex);
+       ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
+       if (ret) {
+               spin_unlock(chip->mutex);
+               return ret;
+       }
+
+       /* let's ensure we're not reading back cached data from array mode */
+       INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
+
+       xip_disable(map, chip, chip->start);
+       if (chip->state != FL_JEDEC_QUERY) {
+               map_write(map, CMD(0x90), chip->start);
+               chip->state = FL_JEDEC_QUERY;
+       }
+       map_copy_from(map, buf, chip->start + offset, size);
+       xip_enable(map, chip, chip->start);
+
+       /* then ensure we don't keep OTP data in the cache */
+       INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
+
+       put_chip(map, chip, chip->start);
+       spin_unlock(chip->mutex);
+       return 0;
+}
+
+static int
+do_otp_write(struct map_info *map, struct flchip *chip, u_long offset,
+            u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+       int ret;
+
+       while (size) {
+               unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1);
+               int gap = offset - bus_ofs;
+               int n = min_t(int, size, map_bankwidth(map)-gap);
+               map_word datum = map_word_ff(map);
+
+               datum = map_word_load_partial(map, datum, buf, gap, n);
+               ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
+               if (ret) 
+                       return ret;
+
+               offset += n;
+               buf += n;
+               size -= n;
+       }
+
+       return 0;
+}
+
+static int
+do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset,
+           u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       map_word datum;
+
+       /* make sure area matches group boundaries */
+       if (size != grpsz)
+               return -EXDEV;
+
+       datum = map_word_ff(map);
+       datum = map_word_clr(map, datum, CMD(1 << grpno));
+       return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);
+}
+
+static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
+                                size_t *retlen, u_char *buf,
+                                otp_op_t action, int user_regs)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+       struct flchip *chip;
+       struct cfi_intelext_otpinfo *otp;
+       u_long devsize, reg_prot_offset, data_offset;
+       u_int chip_num, chip_step, field, reg_fact_size, reg_user_size;
+       u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups;
+       int ret;
+
+       *retlen = 0;
+
+       /* Check that we actually have some OTP registers */
+       if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields)
+               return -ENODATA;
+
+       /* we need real chips here not virtual ones */
+       devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;
+       chip_step = devsize >> cfi->chipshift;
+       chip_num = 0;
+
+       /* Some chips have OTP located in the _top_ partition only.
+          For example: Intel 28F256L18T (T means top-parameter device) */
+       if (cfi->mfr == MANUFACTURER_INTEL) {
+               switch (cfi->id) {
+               case 0x880b:
+               case 0x880c:
+               case 0x880d:
+                       chip_num = chip_step - 1;
+               }
+       }
+
+       for ( ; chip_num < cfi->numchips; chip_num += chip_step) {
+               chip = &cfi->chips[chip_num];
+               otp = (struct cfi_intelext_otpinfo *)&extp->extra[0];
+
+               /* first OTP region */
+               field = 0;
+               reg_prot_offset = extp->ProtRegAddr;
+               reg_fact_groups = 1;
+               reg_fact_size = 1 << extp->FactProtRegSize;
+               reg_user_groups = 1;
+               reg_user_size = 1 << extp->UserProtRegSize;
+
+               while (len > 0) {
+                       /* flash geometry fixup */
+                       data_offset = reg_prot_offset + 1;
+                       data_offset *= cfi->interleave * cfi->device_type;
+                       reg_prot_offset *= cfi->interleave * cfi->device_type;
+                       reg_fact_size *= cfi->interleave;
+                       reg_user_size *= cfi->interleave;
+
+                       if (user_regs) {
+                               groups = reg_user_groups;
+                               groupsize = reg_user_size;
+                               /* skip over factory reg area */
+                               groupno = reg_fact_groups;
+                               data_offset += reg_fact_groups * reg_fact_size;
+                       } else {
+                               groups = reg_fact_groups;
+                               groupsize = reg_fact_size;
+                               groupno = 0;
+                       }
+
+                       while (len > 0 && groups > 0) {
+                               if (!action) {
+                                       /*
+                                        * Special case: if action is NULL
+                                        * we fill buf with otp_info records.
+                                        */
+                                       struct otp_info *otpinfo;
+                                       map_word lockword;
+                                       len -= sizeof(struct otp_info);
+                                       if (len <= 0)
+                                               return -ENOSPC;
+                                       ret = do_otp_read(map, chip,
+                                                         reg_prot_offset,
+                                                         (u_char *)&lockword,
+                                                         map_bankwidth(map),
+                                                         0, 0,  0);
+                                       if (ret)
+                                               return ret;
+                                       otpinfo = (struct otp_info *)buf;
+                                       otpinfo->start = from;
+                                       otpinfo->length = groupsize;
+                                       otpinfo->locked =
+                                          !map_word_bitsset(map, lockword,
+                                                            CMD(1 << groupno));
+                                       from += groupsize;
+                                       buf += sizeof(*otpinfo);
+                                       *retlen += sizeof(*otpinfo);
+                               } else if (from >= groupsize) {
+                                       from -= groupsize;
+                                       data_offset += groupsize;
+                               } else {
+                                       int size = groupsize;
+                                       data_offset += from;
+                                       size -= from;
+                                       from = 0;
+                                       if (size > len)
+                                               size = len;
+                                       ret = action(map, chip, data_offset,
+                                                    buf, size, reg_prot_offset,
+                                                    groupno, groupsize);
+                                       if (ret < 0)
+                                               return ret;
+                                       buf += size;
+                                       len -= size;
+                                       *retlen += size;
+                                       data_offset += size;
+                               }
+                               groupno++;
+                               groups--;
+                       }
+
+                       /* next OTP region */
+                       if (++field == extp->NumProtectionFields)
+                               break;
+                       reg_prot_offset = otp->ProtRegAddr;
+                       reg_fact_groups = otp->FactGroups;
+                       reg_fact_size = 1 << otp->FactProtRegSize;
+                       reg_user_groups = otp->UserGroups;
+                       reg_user_size = 1 << otp->UserProtRegSize;
+                       otp++;
+               }
+       }
+
+       return 0;
+}
+
+static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
+                                          size_t len, size_t *retlen,
+                                           u_char *buf)
+{
+       return cfi_intelext_otp_walk(mtd, from, len, retlen,
+                                    buf, do_otp_read, 0);
+}
+
+static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
+                                          size_t len, size_t *retlen,
+                                           u_char *buf)
+{
+       return cfi_intelext_otp_walk(mtd, from, len, retlen,
+                                    buf, do_otp_read, 1);
+}
+
+static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
+                                           size_t len, size_t *retlen,
+                                            u_char *buf)
+{
+       return cfi_intelext_otp_walk(mtd, from, len, retlen,
+                                    buf, do_otp_write, 1);
+}
+
+static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
+                                          loff_t from, size_t len)
+{
+       size_t retlen;
+       return cfi_intelext_otp_walk(mtd, from, len, &retlen,
+                                    NULL, do_otp_lock, 1);
+}
+
+static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, 
+                                          struct otp_info *buf, size_t len)
+{
+       size_t retlen;
+       int ret;
+
+       ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
+       return ret ? : retlen;
+}
+
+static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
+                                          struct otp_info *buf, size_t len)
+{
+       size_t retlen;
+       int ret;
+
+       ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
+       return ret ? : retlen;
+}
+
+#endif
+
 static int cfi_intelext_suspend(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
@@ -2125,10 +2309,46 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
        }
 }
 
+static int cfi_intelext_reset(struct mtd_info *mtd)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       int i, ret;
+
+       for (i=0; i < cfi->numchips; i++) {
+               struct flchip *chip = &cfi->chips[i];
+
+               /* force the completion of any ongoing operation
+                  and switch to array mode so any bootloader in 
+                  flash is accessible for soft reboot. */
+               spin_lock(chip->mutex);
+               ret = get_chip(map, chip, chip->start, FL_SYNCING);
+               if (!ret) {
+                       map_write(map, CMD(0xff), chip->start);
+                       chip->state = FL_READY;
+               }
+               spin_unlock(chip->mutex);
+       }
+
+       return 0;
+}
+
+static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val,
+                              void *v)
+{
+       struct mtd_info *mtd;
+
+       mtd = container_of(nb, struct mtd_info, reboot_notifier);
+       cfi_intelext_reset(mtd);
+       return NOTIFY_DONE;
+}
+
 static void cfi_intelext_destroy(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
+       cfi_intelext_reset(mtd);
+       unregister_reboot_notifier(&mtd->reboot_notifier);
        kfree(cfi->cmdset_priv);
        kfree(cfi->cfiq);
        kfree(cfi->chips[0].priv);
index fca8ff6f7e140eb0518be9a6a9b96b9ee9ccb146..8505f118f2dbfcd8d7275c3cb1af5292eaaaca0d 100644 (file)
@@ -4,16 +4,20 @@
  *
  * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
  * Copyright (C) 2004 Arcom Control Systems Ltd <linux@arcom.com>
+ * Copyright (C) 2005 MontaVista Software Inc. <source@mvista.com>
  *
  * 2_by_8 routines added by Simon Munton
  *
  * 4_by_16 work by Carolyn J. Smith
  *
+ * XIP support hooks by Vitaly Wool (based on code for Intel flash 
+ * by Nicolas Pitre)
+ * 
  * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
  *
  * This code is GPL
  *
- * $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.118 2005/07/04 22:34:29 gleixner Exp $
  *
  */
 
@@ -34,6 +38,7 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/cfi.h>
+#include <linux/mtd/xip.h>
 
 #define AMD_BOOTLOC_BUG
 #define FORCE_WORD_WRITE 0
@@ -43,6 +48,7 @@
 #define MANUFACTURER_AMD       0x0001
 #define MANUFACTURER_SST       0x00BF
 #define SST49LF004B            0x0060
+#define SST49LF008A            0x005a
 
 static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -191,6 +197,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
 };
 static struct cfi_fixup jedec_fixup_table[] = {
        { MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
+       { MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, },
        { 0, 0, NULL, NULL }
 };
 
@@ -391,7 +398,7 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
  * correctly and is therefore not done (particulary with interleaved chips
  * as each chip must be checked independantly of the others).
  */
-static int chip_ready(struct map_info *map, unsigned long addr)
+static int __xipram chip_ready(struct map_info *map, unsigned long addr)
 {
        map_word d, t;
 
@@ -401,6 +408,32 @@ static int chip_ready(struct map_info *map, unsigned long addr)
        return map_word_equal(map, d, t);
 }
 
+/*
+ * Return true if the chip is ready and has the correct value.
+ *
+ * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
+ * non-suspended sector) and it is indicated by no bits toggling.
+ *
+ * Error are indicated by toggling bits or bits held with the wrong value,
+ * or with bits toggling.
+ *
+ * Note that anything more complicated than checking if no bits are toggling
+ * (including checking DQ5 for an error status) is tricky to get working
+ * correctly and is therefore not done (particulary with interleaved chips
+ * as each chip must be checked independantly of the others).
+ *
+ */
+static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected)
+{
+       map_word oldd, curd;
+
+       oldd = map_read(map, addr);
+       curd = map_read(map, addr);
+
+       return  map_word_equal(map, oldd, curd) && 
+               map_word_equal(map, curd, expected);
+}
+
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
 {
        DECLARE_WAITQUEUE(wait, current);
@@ -420,12 +453,12 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
 
                        if (time_after(jiffies, timeo)) {
                                printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
-                               cfi_spin_unlock(chip->mutex);
+                               spin_unlock(chip->mutex);
                                return -EIO;
                        }
-                       cfi_spin_unlock(chip->mutex);
+                       spin_unlock(chip->mutex);
                        cfi_udelay(1);
-                       cfi_spin_lock(chip->mutex);
+                       spin_lock(chip->mutex);
                        /* Someone else might have been playing with it. */
                        goto retry;
                }
@@ -473,15 +506,23 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                                return -EIO;
                        }
                        
-                       cfi_spin_unlock(chip->mutex);
+                       spin_unlock(chip->mutex);
                        cfi_udelay(1);
-                       cfi_spin_lock(chip->mutex);
+                       spin_lock(chip->mutex);
                        /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
                           So we can just loop here. */
                }
                chip->state = FL_READY;
                return 0;
 
+       case FL_XIP_WHILE_ERASING:
+               if (mode != FL_READY && mode != FL_POINT &&
+                   (!cfip || !(cfip->EraseSuspend&2)))
+                       goto sleep;
+               chip->oldstate = chip->state;
+               chip->state = FL_READY;
+               return 0;
+
        case FL_POINT:
                /* Only if there's no operation suspended... */
                if (mode == FL_READY && chip->oldstate == FL_READY)
@@ -491,10 +532,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
        sleep:
                set_current_state(TASK_UNINTERRUPTIBLE);
                add_wait_queue(&chip->wq, &wait);
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
                schedule();
                remove_wait_queue(&chip->wq, &wait);
-               cfi_spin_lock(chip->mutex);
+               spin_lock(chip->mutex);
                goto resettime;
        }
 }
@@ -512,6 +553,11 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
                chip->state = FL_ERASING;
                break;
 
+       case FL_XIP_WHILE_ERASING:
+               chip->state = chip->oldstate;
+               chip->oldstate = FL_READY;
+               break;
+
        case FL_READY:
        case FL_STATUS:
                /* We should really make set_vpp() count, rather than doing this */
@@ -523,6 +569,198 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
        wake_up(&chip->wq);
 }
 
+#ifdef CONFIG_MTD_XIP
+
+/*
+ * No interrupt what so ever can be serviced while the flash isn't in array
+ * mode.  This is ensured by the xip_disable() and xip_enable() functions
+ * enclosing any code path where the flash is known not to be in array mode.
+ * And within a XIP disabled code path, only functions marked with __xipram
+ * may be called and nothing else (it's a good thing to inspect generated
+ * assembly to make sure inline functions were actually inlined and that gcc
+ * didn't emit calls to its own support functions). Also configuring MTD CFI
+ * support to a single buswidth and a single interleave is also recommended.
+ */
+
+static void xip_disable(struct map_info *map, struct flchip *chip,
+                       unsigned long adr)
+{
+       /* TODO: chips with no XIP use should ignore and return */
+       (void) map_read(map, adr); /* ensure mmu mapping is up to date */
+       local_irq_disable();
+}
+
+static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
+                               unsigned long adr)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+
+       if (chip->state != FL_POINT && chip->state != FL_READY) {
+               map_write(map, CMD(0xf0), adr);
+               chip->state = FL_READY;
+       }
+       (void) map_read(map, adr);
+       xip_iprefetch();
+       local_irq_enable();
+}
+
+/*
+ * When a delay is required for the flash operation to complete, the
+ * xip_udelay() function is polling for both the given timeout and pending
+ * (but still masked) hardware interrupts.  Whenever there is an interrupt
+ * pending then the flash erase operation is suspended, array mode restored 
+ * and interrupts unmasked.  Task scheduling might also happen at that
+ * point.  The CPU eventually returns from the interrupt or the call to
+ * schedule() and the suspended flash operation is resumed for the remaining
+ * of the delay period.
+ *
+ * Warning: this function _will_ fool interrupt latency tracing tools.
+ */
+
+static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
+                               unsigned long adr, int usec)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+       map_word status, OK = CMD(0x80);
+       unsigned long suspended, start = xip_currtime();
+       flstate_t oldstate;
+
+       do {
+               cpu_relax();
+               if (xip_irqpending() && extp &&
+                   ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) &&
+                   (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
+                       /*
+                        * Let's suspend the erase operation when supported.  
+                        * Note that we currently don't try to suspend 
+                        * interleaved chips if there is already another 
+                        * operation suspended (imagine what happens
+                        * when one chip was already done with the current
+                        * operation while another chip suspended it, then
+                        * we resume the whole thing at once).  Yes, it
+                        * can happen!
+                        */
+                       map_write(map, CMD(0xb0), adr);
+                       usec -= xip_elapsed_since(start);
+                       suspended = xip_currtime();
+                       do {
+                               if (xip_elapsed_since(suspended) > 100000) {
+                                       /*
+                                        * The chip doesn't want to suspend
+                                        * after waiting for 100 msecs.
+                                        * This is a critical error but there
+                                        * is not much we can do here.
+                                        */
+                                       return;
+                               }
+                               status = map_read(map, adr);
+                       } while (!map_word_andequal(map, status, OK, OK));
+
+                       /* Suspend succeeded */
+                       oldstate = chip->state;
+                       if (!map_word_bitsset(map, status, CMD(0x40)))
+                               break;
+                       chip->state = FL_XIP_WHILE_ERASING;
+                       chip->erase_suspended = 1;
+                       map_write(map, CMD(0xf0), adr);
+                       (void) map_read(map, adr);
+                       asm volatile (".rep 8; nop; .endr");
+                       local_irq_enable();
+                       spin_unlock(chip->mutex);
+                       asm volatile (".rep 8; nop; .endr");
+                       cond_resched();
+
+                       /*
+                        * We're back.  However someone else might have
+                        * decided to go write to the chip if we are in
+                        * a suspended erase state.  If so let's wait
+                        * until it's done.
+                        */
+                       spin_lock(chip->mutex);
+                       while (chip->state != FL_XIP_WHILE_ERASING) {
+                               DECLARE_WAITQUEUE(wait, current);
+                               set_current_state(TASK_UNINTERRUPTIBLE);
+                               add_wait_queue(&chip->wq, &wait);
+                               spin_unlock(chip->mutex);
+                               schedule();
+                               remove_wait_queue(&chip->wq, &wait);
+                               spin_lock(chip->mutex);
+                       }
+                       /* Disallow XIP again */
+                       local_irq_disable();
+
+                       /* Resume the write or erase operation */
+                       map_write(map, CMD(0x30), adr);
+                       chip->state = oldstate;
+                       start = xip_currtime();
+               } else if (usec >= 1000000/HZ) {
+                       /*
+                        * Try to save on CPU power when waiting delay
+                        * is at least a system timer tick period.
+                        * No need to be extremely accurate here.
+                        */
+                       xip_cpu_idle();
+               }
+               status = map_read(map, adr);
+       } while (!map_word_andequal(map, status, OK, OK)
+                && xip_elapsed_since(start) < usec);
+}
+
+#define UDELAY(map, chip, adr, usec)  xip_udelay(map, chip, adr, usec)
+
+/*
+ * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
+ * the flash is actively programming or erasing since we have to poll for
+ * the operation to complete anyway.  We can't do that in a generic way with
+ * a XIP setup so do it before the actual flash operation in this case
+ * and stub it out from INVALIDATE_CACHE_UDELAY.
+ */
+#define XIP_INVAL_CACHED_RANGE(map, from, size)  \
+       INVALIDATE_CACHED_RANGE(map, from, size)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
+       UDELAY(map, chip, adr, usec)
+
+/*
+ * Extra notes:
+ *
+ * Activating this XIP support changes the way the code works a bit.  For
+ * example the code to suspend the current process when concurrent access
+ * happens is never executed because xip_udelay() will always return with the
+ * same chip state as it was entered with.  This is why there is no care for
+ * the presence of add_wait_queue() or schedule() calls from within a couple
+ * xip_disable()'d  areas of code, like in do_erase_oneblock for example.
+ * The queueing and scheduling are always happening within xip_udelay().
+ *
+ * Similarly, get_chip() and put_chip() just happen to always be executed
+ * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state
+ * is in array mode, therefore never executing many cases therein and not
+ * causing any problem with XIP.
+ */
+
+#else
+
+#define xip_disable(map, chip, adr)
+#define xip_enable(map, chip, adr)
+#define XIP_INVAL_CACHED_RANGE(x...)
+
+#define UDELAY(map, chip, adr, usec)  \
+do {  \
+       spin_unlock(chip->mutex);  \
+       cfi_udelay(usec);  \
+       spin_lock(chip->mutex);  \
+} while (0)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
+do {  \
+       spin_unlock(chip->mutex);  \
+       INVALIDATE_CACHED_RANGE(map, adr, len);  \
+       cfi_udelay(usec);  \
+       spin_lock(chip->mutex);  \
+} while (0)
+
+#endif
 
 static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
 {
@@ -535,10 +773,10 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
        /* Ensure cmd read/writes are aligned. */ 
        cmd_addr = adr & ~(map_bankwidth(map)-1); 
 
-       cfi_spin_lock(chip->mutex);
+       spin_lock(chip->mutex);
        ret = get_chip(map, chip, cmd_addr, FL_READY);
        if (ret) {
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
                return ret;
        }
 
@@ -551,7 +789,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
 
        put_chip(map, chip, cmd_addr);
 
-       cfi_spin_unlock(chip->mutex);
+       spin_unlock(chip->mutex);
        return 0;
 }
 
@@ -605,7 +843,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
        struct cfi_private *cfi = map->fldrv_priv;
 
  retry:
-       cfi_spin_lock(chip->mutex);
+       spin_lock(chip->mutex);
 
        if (chip->state != FL_READY){
 #if 0
@@ -614,7 +852,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
                set_current_state(TASK_UNINTERRUPTIBLE);
                add_wait_queue(&chip->wq, &wait);
                
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
 
                schedule();
                remove_wait_queue(&chip->wq, &wait);
@@ -643,7 +881,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
        cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        
        wake_up(&chip->wq);
-       cfi_spin_unlock(chip->mutex);
+       spin_unlock(chip->mutex);
 
        return 0;
 }
@@ -692,7 +930,7 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,
 }
 
 
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
+static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        unsigned long timeo = jiffies + HZ;
@@ -712,10 +950,10 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
 
        adr += chip->start;
 
-       cfi_spin_lock(chip->mutex);
+       spin_lock(chip->mutex);
        ret = get_chip(map, chip, adr, FL_WRITING);
        if (ret) {
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
                return ret;
        }
 
@@ -735,7 +973,9 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
                goto op_done;
        }
 
+       XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
        ENABLE_VPP(map);
+       xip_disable(map, chip, adr);
  retry:
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
@@ -743,9 +983,9 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
        map_write(map, datum, adr);
        chip->state = FL_WRITING;
 
-       cfi_spin_unlock(chip->mutex);
-       cfi_udelay(chip->word_write_time);
-       cfi_spin_lock(chip->mutex);
+       INVALIDATE_CACHE_UDELAY(map, chip,
+                               adr, map_bankwidth(map),
+                               chip->word_write_time);
 
        /* See comment above for timeout value. */
        timeo = jiffies + uWriteTimeout; 
@@ -756,39 +996,43 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
 
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        add_wait_queue(&chip->wq, &wait);
-                       cfi_spin_unlock(chip->mutex);
+                       spin_unlock(chip->mutex);
                        schedule();
                        remove_wait_queue(&chip->wq, &wait);
                        timeo = jiffies + (HZ / 2); /* FIXME */
-                       cfi_spin_lock(chip->mutex);
+                       spin_lock(chip->mutex);
                        continue;
                }
 
                if (chip_ready(map, adr))
-                       goto op_done;
+                       break;
 
-               if (time_after(jiffies, timeo))
+               if (time_after(jiffies, timeo)) {
+                       xip_enable(map, chip, adr);
+                       printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
+                       xip_disable(map, chip, adr);
                         break;
+               }
 
                /* Latency issues. Drop the lock, wait a while and retry */
-               cfi_spin_unlock(chip->mutex);
-               cfi_udelay(1);
-               cfi_spin_lock(chip->mutex);
+               UDELAY(map, chip, adr, 1);
        }
+       /* Did we succeed? */
+       if (!chip_good(map, adr, datum)) {
+               /* reset on all failures. */
+               map_write( map, CMD(0xF0), chip->start );
+               /* FIXME - should have reset delay before continuing */
 
-       printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
-
-       /* reset on all failures. */
-       map_write( map, CMD(0xF0), chip->start );
-       /* FIXME - should have reset delay before continuing */
-       if (++retry_cnt <= MAX_WORD_RETRIES) 
-               goto retry;
+               if (++retry_cnt <= MAX_WORD_RETRIES) 
+                       goto retry;
 
-       ret = -EIO;
+               ret = -EIO;
+       }
+       xip_enable(map, chip, adr);
  op_done:
        chip->state = FL_READY;
        put_chip(map, chip, adr);
-       cfi_spin_unlock(chip->mutex);
+       spin_unlock(chip->mutex);
 
        return ret;
 }
@@ -820,7 +1064,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
                map_word tmp_buf;
 
  retry:
-               cfi_spin_lock(cfi->chips[chipnum].mutex);
+               spin_lock(cfi->chips[chipnum].mutex);
 
                if (cfi->chips[chipnum].state != FL_READY) {
 #if 0
@@ -829,7 +1073,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        add_wait_queue(&cfi->chips[chipnum].wq, &wait);
 
-                       cfi_spin_unlock(cfi->chips[chipnum].mutex);
+                       spin_unlock(cfi->chips[chipnum].mutex);
 
                        schedule();
                        remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
@@ -843,7 +1087,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
                /* Load 'tmp_buf' with old contents of flash */
                tmp_buf = map_read(map, bus_ofs+chipstart);
 
-               cfi_spin_unlock(cfi->chips[chipnum].mutex);
+               spin_unlock(cfi->chips[chipnum].mutex);
 
                /* Number of bytes to copy from buffer */
                n = min_t(int, len, map_bankwidth(map)-i);
@@ -898,7 +1142,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
                map_word tmp_buf;
 
  retry1:
-               cfi_spin_lock(cfi->chips[chipnum].mutex);
+               spin_lock(cfi->chips[chipnum].mutex);
 
                if (cfi->chips[chipnum].state != FL_READY) {
 #if 0
@@ -907,7 +1151,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        add_wait_queue(&cfi->chips[chipnum].wq, &wait);
 
-                       cfi_spin_unlock(cfi->chips[chipnum].mutex);
+                       spin_unlock(cfi->chips[chipnum].mutex);
 
                        schedule();
                        remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
@@ -920,7 +1164,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
 
                tmp_buf = map_read(map, ofs + chipstart);
 
-               cfi_spin_unlock(cfi->chips[chipnum].mutex);
+               spin_unlock(cfi->chips[chipnum].mutex);
 
                tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
        
@@ -939,8 +1183,9 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
 /*
  * FIXME: interleaved mode not tested, and probably not supported!
  */
-static inline int do_write_buffer(struct map_info *map, struct flchip *chip, 
-                                 unsigned long adr, const u_char *buf, int len)
+static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
+                                   unsigned long adr, const u_char *buf, 
+                                   int len)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        unsigned long timeo = jiffies + HZ;
@@ -954,10 +1199,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
        adr += chip->start;
        cmd_adr = adr;
 
-       cfi_spin_lock(chip->mutex);
+       spin_lock(chip->mutex);
        ret = get_chip(map, chip, adr, FL_WRITING);
        if (ret) {
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
                return ret;
        }
 
@@ -966,7 +1211,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
        DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
               __func__, adr, datum.x[0] );
 
+       XIP_INVAL_CACHED_RANGE(map, adr, len);
        ENABLE_VPP(map);
+       xip_disable(map, chip, cmd_adr);
+       
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
@@ -996,9 +1244,9 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
        map_write(map, CMD(0x29), cmd_adr);
        chip->state = FL_WRITING;
 
-       cfi_spin_unlock(chip->mutex);
-       cfi_udelay(chip->buffer_write_time);
-       cfi_spin_lock(chip->mutex);
+       INVALIDATE_CACHE_UDELAY(map, chip,
+                               adr, map_bankwidth(map),
+                               chip->word_write_time);
 
        timeo = jiffies + uWriteTimeout; 
                
@@ -1009,38 +1257,39 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
 
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        add_wait_queue(&chip->wq, &wait);
-                       cfi_spin_unlock(chip->mutex);
+                       spin_unlock(chip->mutex);
                        schedule();
                        remove_wait_queue(&chip->wq, &wait);
                        timeo = jiffies + (HZ / 2); /* FIXME */
-                       cfi_spin_lock(chip->mutex);
+                       spin_lock(chip->mutex);
                        continue;
                }
 
-               if (chip_ready(map, adr))
+               if (chip_ready(map, adr)) {
+                       xip_enable(map, chip, adr);
                        goto op_done;
+               }
                    
                if( time_after(jiffies, timeo))
                        break;
 
                /* Latency issues. Drop the lock, wait a while and retry */
-               cfi_spin_unlock(chip->mutex);
-               cfi_udelay(1);
-               cfi_spin_lock(chip->mutex);
+               UDELAY(map, chip, adr, 1);
        }
 
-       printk(KERN_WARNING "MTD %s(): software timeout\n",
-              __func__ );
-
        /* reset on all failures. */
        map_write( map, CMD(0xF0), chip->start );
+       xip_enable(map, chip, adr);
        /* FIXME - should have reset delay before continuing */
 
+       printk(KERN_WARNING "MTD %s(): software timeout\n",
+              __func__ );
+
        ret = -EIO;
  op_done:
        chip->state = FL_READY;
        put_chip(map, chip, adr);
-       cfi_spin_unlock(chip->mutex);
+       spin_unlock(chip->mutex);
 
        return ret;
 }
@@ -1130,7 +1379,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
  * Handle devices with one erase region, that only implement
  * the chip erase command.
  */
-static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
+static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        unsigned long timeo = jiffies + HZ;
@@ -1140,17 +1389,20 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
 
        adr = cfi->addr_unlock1;
 
-       cfi_spin_lock(chip->mutex);
+       spin_lock(chip->mutex);
        ret = get_chip(map, chip, adr, FL_WRITING);
        if (ret) {
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
                return ret;
        }
 
        DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
               __func__, chip->start );
 
+       XIP_INVAL_CACHED_RANGE(map, adr, map->size);
        ENABLE_VPP(map);
+       xip_disable(map, chip, adr);
+
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
@@ -1162,9 +1414,9 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
        chip->erase_suspended = 0;
        chip->in_progress_block_addr = adr;
 
-       cfi_spin_unlock(chip->mutex);
-       msleep(chip->erase_time/2);
-       cfi_spin_lock(chip->mutex);
+       INVALIDATE_CACHE_UDELAY(map, chip,
+                               adr, map->size,
+                               chip->erase_time*500);
 
        timeo = jiffies + (HZ*20);
 
@@ -1173,10 +1425,10 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
                        /* Someone's suspended the erase. Sleep */
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        add_wait_queue(&chip->wq, &wait);
-                       cfi_spin_unlock(chip->mutex);
+                       spin_unlock(chip->mutex);
                        schedule();
                        remove_wait_queue(&chip->wq, &wait);
-                       cfi_spin_lock(chip->mutex);
+                       spin_lock(chip->mutex);
                        continue;
                }
                if (chip->erase_suspended) {
@@ -1187,36 +1439,36 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
                }
 
                if (chip_ready(map, adr))
-                       goto op_done;
+                       break;
 
-               if (time_after(jiffies, timeo))
+               if (time_after(jiffies, timeo)) {
+                       printk(KERN_WARNING "MTD %s(): software timeout\n",
+                               __func__ );
                        break;
+               }
 
                /* Latency issues. Drop the lock, wait a while and retry */
-               cfi_spin_unlock(chip->mutex);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
-               cfi_spin_lock(chip->mutex);
+               UDELAY(map, chip, adr, 1000000/HZ);
        }
+       /* Did we succeed? */
+       if (!chip_good(map, adr, map_word_ff(map))) {
+               /* reset on all failures. */
+               map_write( map, CMD(0xF0), chip->start );
+               /* FIXME - should have reset delay before continuing */
 
-       printk(KERN_WARNING "MTD %s(): software timeout\n",
-              __func__ );
-
-       /* reset on all failures. */
-       map_write( map, CMD(0xF0), chip->start );
-       /* FIXME - should have reset delay before continuing */
+               ret = -EIO;
+       }
 
-       ret = -EIO;
- op_done:
        chip->state = FL_READY;
+       xip_enable(map, chip, adr);
        put_chip(map, chip, adr);
-       cfi_spin_unlock(chip->mutex);
+       spin_unlock(chip->mutex);
 
        return ret;
 }
 
 
-static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk)
+static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        unsigned long timeo = jiffies + HZ;
@@ -1225,17 +1477,20 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
 
        adr += chip->start;
 
-       cfi_spin_lock(chip->mutex);
+       spin_lock(chip->mutex);
        ret = get_chip(map, chip, adr, FL_ERASING);
        if (ret) {
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
                return ret;
        }
 
        DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
               __func__, adr );
 
+       XIP_INVAL_CACHED_RANGE(map, adr, len);
        ENABLE_VPP(map);
+       xip_disable(map, chip, adr);
+
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
@@ -1246,10 +1501,10 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
        chip->state = FL_ERASING;
        chip->erase_suspended = 0;
        chip->in_progress_block_addr = adr;
-       
-       cfi_spin_unlock(chip->mutex);
-       msleep(chip->erase_time/2);
-       cfi_spin_lock(chip->mutex);
+
+       INVALIDATE_CACHE_UDELAY(map, chip,
+                               adr, len,
+                               chip->erase_time*500);
 
        timeo = jiffies + (HZ*20);
 
@@ -1258,10 +1513,10 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
                        /* Someone's suspended the erase. Sleep */
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        add_wait_queue(&chip->wq, &wait);
-                       cfi_spin_unlock(chip->mutex);
+                       spin_unlock(chip->mutex);
                        schedule();
                        remove_wait_queue(&chip->wq, &wait);
-                       cfi_spin_lock(chip->mutex);
+                       spin_lock(chip->mutex);
                        continue;
                }
                if (chip->erase_suspended) {
@@ -1271,31 +1526,33 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
                        chip->erase_suspended = 0;
                }
 
-               if (chip_ready(map, adr))
-                       goto op_done;
+               if (chip_ready(map, adr)) {
+                       xip_enable(map, chip, adr);
+                       break;
+               }
 
-               if (time_after(jiffies, timeo))
+               if (time_after(jiffies, timeo)) {
+                       xip_enable(map, chip, adr);
+                       printk(KERN_WARNING "MTD %s(): software timeout\n",
+                               __func__ );
                        break;
+               }
 
                /* Latency issues. Drop the lock, wait a while and retry */
-               cfi_spin_unlock(chip->mutex);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
-               cfi_spin_lock(chip->mutex);
+               UDELAY(map, chip, adr, 1000000/HZ);
+       }
+       /* Did we succeed? */
+       if (!chip_good(map, adr, map_word_ff(map))) {
+               /* reset on all failures. */
+               map_write( map, CMD(0xF0), chip->start );
+               /* FIXME - should have reset delay before continuing */
+
+               ret = -EIO;
        }
-       
-       printk(KERN_WARNING "MTD %s(): software timeout\n",
-              __func__ );
-       
-       /* reset on all failures. */
-       map_write( map, CMD(0xF0), chip->start );
-       /* FIXME - should have reset delay before continuing */
 
-       ret = -EIO;
- op_done:
        chip->state = FL_READY;
        put_chip(map, chip, adr);
-       cfi_spin_unlock(chip->mutex);
+       spin_unlock(chip->mutex);
        return ret;
 }
 
@@ -1355,7 +1612,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
                chip = &cfi->chips[i];
 
        retry:
-               cfi_spin_lock(chip->mutex);
+               spin_lock(chip->mutex);
 
                switch(chip->state) {
                case FL_READY:
@@ -1369,14 +1626,14 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
                         * with the chip now anyway.
                         */
                case FL_SYNCING:
-                       cfi_spin_unlock(chip->mutex);
+                       spin_unlock(chip->mutex);
                        break;
 
                default:
                        /* Not an idle state */
                        add_wait_queue(&chip->wq, &wait);
                        
-                       cfi_spin_unlock(chip->mutex);
+                       spin_unlock(chip->mutex);
 
                        schedule();
 
@@ -1391,13 +1648,13 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
        for (i--; i >=0; i--) {
                chip = &cfi->chips[i];
 
-               cfi_spin_lock(chip->mutex);
+               spin_lock(chip->mutex);
                
                if (chip->state == FL_SYNCING) {
                        chip->state = chip->oldstate;
                        wake_up(&chip->wq);
                }
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
        }
 }
 
@@ -1413,7 +1670,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
        for (i=0; !ret && i<cfi->numchips; i++) {
                chip = &cfi->chips[i];
 
-               cfi_spin_lock(chip->mutex);
+               spin_lock(chip->mutex);
 
                switch(chip->state) {
                case FL_READY:
@@ -1433,7 +1690,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
                        ret = -EAGAIN;
                        break;
                }
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
        }
 
        /* Unlock the chips again */
@@ -1442,13 +1699,13 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
                for (i--; i >=0; i--) {
                        chip = &cfi->chips[i];
 
-                       cfi_spin_lock(chip->mutex);
+                       spin_lock(chip->mutex);
                
                        if (chip->state == FL_PM_SUSPENDED) {
                                chip->state = chip->oldstate;
                                wake_up(&chip->wq);
                        }
-                       cfi_spin_unlock(chip->mutex);
+                       spin_unlock(chip->mutex);
                }
        }
        
@@ -1467,7 +1724,7 @@ static void cfi_amdstd_resume(struct mtd_info *mtd)
        
                chip = &cfi->chips[i];
 
-               cfi_spin_lock(chip->mutex);
+               spin_lock(chip->mutex);
                
                if (chip->state == FL_PM_SUSPENDED) {
                        chip->state = FL_READY;
@@ -1477,7 +1734,7 @@ static void cfi_amdstd_resume(struct mtd_info *mtd)
                else
                        printk(KERN_ERR "Argh. Chip not in PM_SUSPENDED state upon resume()\n");
 
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
        }
 }
 
index fbf44708a861f95998876fffa527a80c229020b1..e1a5b76596c577a2b2325071cc8988755772449e 100644 (file)
@@ -58,10 +58,10 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
         * to flash memory - that means that we don't have to check status
         * and timeout.
         */
-       cfi_spin_lock(chip->mutex);
+       spin_lock(chip->mutex);
        ret = get_chip(map, chip, adr, FL_LOCKING);
        if (ret) {
-               cfi_spin_unlock(chip->mutex);
+               spin_unlock(chip->mutex);
                return ret;
        }
 
@@ -71,7 +71,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
        /* Done and happy. */
        chip->state = FL_READY;
        put_chip(map, chip, adr);
-       cfi_spin_unlock(chip->mutex);
+       spin_unlock(chip->mutex);
        return 0;
 }
 
index fc982c4671f0cb7a976ce355cc01ecfb4eb6d5c6..dc065b22f79ece4ee37440038c965766cfcaa8d4 100644 (file)
@@ -2,7 +2,7 @@
  * Routines common to all CFI-type probes.
  * (C) 2001-2003 Red Hat, Inc.
  * GPL'd
- * $Id: gen_probe.c,v 1.21 2004/08/14 15:14:05 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $
  */
 
 #include <linux/kernel.h>
@@ -162,7 +162,7 @@ static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
        int max_chips = map_bankwidth(map); /* And minimum 1 */
        int nr_chips, type;
 
-       for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) {
+       for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
 
                if (!cfi_interleave_supported(nr_chips))
                    continue;
index 30325a25ab953e3f4bdc18515af0dfae4e83b4c9..30da428eb7b99e0c9a265928d8d4303654a21264 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $
+   $Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $
    See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
    for the standard this probe goes back to.
 
 #define SST29LE512     0x003d
 #define SST39LF800     0x2781
 #define SST39LF160     0x2782
+#define SST39VF1601    0x234b
 #define SST39LF512     0x00D4
 #define SST39LF010     0x00D5
 #define SST39LF020     0x00D6
@@ -1448,6 +1449,21 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x1000,256),
                        ERASEINFO(0x1000,256)
                }
+       }, {
+               .mfr_id         = MANUFACTURER_SST,     /* should be CFI */
+               .dev_id         = SST39VF1601,
+               .name           = "SST 39VF1601",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
+                       [1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
+               },
+               .DevSize        = SIZE_2MiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 2,
+               .regions        = {
+                       ERASEINFO(0x1000,256),
+                       ERASEINFO(0x1000,256)
+               }
 
        }, {
                .mfr_id         = MANUFACTURER_ST,      /* FIXME - CFI device? */
@@ -1856,6 +1872,16 @@ static inline int jedec_match( __u32 base,
        case CFI_DEVICETYPE_X8:
                mfr = (__u8)finfo->mfr_id;
                id = (__u8)finfo->dev_id;
+
+               /* bjd: it seems that if we do this, we can end up
+                * detecting 16bit flashes as an 8bit device, even though
+                * there aren't.
+                */
+               if (finfo->dev_id > 0xff) {
+                       DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n",
+                              __func__);
+                       goto match_done;
+               }
                break;
        case CFI_DEVICETYPE_X16:
                mfr = (__u16)finfo->mfr_id;
index 60ab4b89a2f93d7f78f439e62d6d6a3ce0977366..ef24837019d3e4e8f4961035a62d1198beb039fb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
+ * $Id: cmdlinepart.c,v 1.18 2005/06/07 15:04:26 joern Exp $
  *
  * Read flash partition table from command line
  *
@@ -239,7 +239,8 @@ static int mtdpart_setup_real(char *s)
                                &num_parts,     /* out: number of parts */
                                0,              /* first partition */
                                (unsigned char**)&this_mtd, /* out: extra mem */
-                               mtd_id_len + 1 + sizeof(*this_mtd));
+                               mtd_id_len + 1 + sizeof(*this_mtd) + 
+                               sizeof(void*)-1 /*alignment*/);
                if(!parts)
                {
                        /*
@@ -252,6 +253,9 @@ static int mtdpart_setup_real(char *s)
                         return 0;
                 }
 
+               /* align this_mtd */
+               this_mtd = (struct cmdline_mtd_partition *) 
+                       ALIGN((unsigned long)this_mtd, sizeof(void*));
                /* enter results */         
                this_mtd->parts = parts;
                this_mtd->num_parts = num_parts;
index cfe6ccf07972e26c3c8ae186016117b381d0e627..4a7a805e7564c4d359f9049daf1ebc54a284c39b 100644 (file)
@@ -1,10 +1,9 @@
 /*
- * $Id: block2mtd.c,v 1.23 2005/01/05 17:05:46 dwmw2 Exp $
+ * $Id: block2mtd.c,v 1.28 2005/03/19 22:40:44 gleixner Exp $
  *
  * block2mtd.c - create an mtd from a block device
  *
  * Copyright (C) 2001,2002     Simon Evans <spse@secret.org.uk>
- * Copyright (C) 2004          Gareth Bult <Gareth@Encryptec.net>
  * Copyright (C) 2004,2005     Jörn Engel <joern@wh.fh-wedel.de>
  *
  * Licence: GPL
@@ -20,7 +19,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/buffer_head.h>
 
-#define VERSION "$Revision: 1.23 $"
+#define VERSION "$Revision: 1.28 $"
 
 
 #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
@@ -89,7 +88,6 @@ void cache_readahead(struct address_space *mapping, int index)
 static struct page* page_readahead(struct address_space *mapping, int index)
 {
        filler_t *filler = (filler_t*)mapping->a_ops->readpage;
-       //do_page_cache_readahead(mapping, index, XXX, 64);
        cache_readahead(mapping, index);
        return read_cache_page(mapping, index, filler, NULL);
 }
@@ -157,7 +155,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
        struct block2mtd_dev *dev = mtd->priv;
        struct page *page;
        int index = from >> PAGE_SHIFT;
-       int offset = from & (PAGE_SHIFT-1);
+       int offset = from & (PAGE_SIZE-1);
        int cpylen;
 
        if (from > mtd->size)
@@ -370,16 +368,16 @@ static int ustrtoul(const char *cp, char **endp, unsigned int base)
 }
 
 
-static int parse_num32(u32 *num32, const char *token)
+static int parse_num(size_t *num, const char *token)
 {
        char *endp;
-       unsigned long n;
+       size_t n;
 
-       n = ustrtoul(token, &endp, 0);
+       n = (size_t) ustrtoul(token, &endp, 0);
        if (*endp)
                return -EINVAL;
 
-       *num32 = n;
+       *num = n;
        return 0;
 }
 
@@ -422,7 +420,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
        char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */
        char *token[2];
        char *name;
-       u32 erase_size = PAGE_SIZE;
+       size_t erase_size = PAGE_SIZE;
        int i, ret;
 
        if (strnlen(val, sizeof(buf)) >= sizeof(buf))
@@ -449,7 +447,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
                return 0;
 
        if (token[1]) {
-               ret = parse_num32(&erase_size, token[1]);
+               ret = parse_num(&erase_size, token[1]);
                if (ret)
                        parse_err("illegal erase size");
        }
index 380ff08d29e4a668e9a3f087586172259372b5da..f5026cee087fa22925365d0b662267ba1b73f8e9 100644 (file)
@@ -6,7 +6,7 @@
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- *     $Id: ms02-nv.c,v 1.8 2005/01/05 18:05:12 dwmw2 Exp $
+ *     $Id: ms02-nv.c,v 1.10 2005/06/20 12:24:41 macro Exp $
  */
 
 #include <linux/init.h>
@@ -99,8 +99,8 @@ static inline uint ms02nv_probe_one(ulong addr)
         * The firmware writes MS02NV_ID at MS02NV_MAGIC and also
         * a diagnostic status at MS02NV_DIAG.
         */
-       ms02nv_diagp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_DIAG));
-       ms02nv_magicp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_MAGIC));
+       ms02nv_diagp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_DIAG));
+       ms02nv_magicp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_MAGIC));
        err = get_dbe(ms02nv_magic, ms02nv_magicp);
        if (err)
                return 0;
@@ -233,7 +233,7 @@ static int __init ms02nv_init_one(ulong addr)
                goto err_out_csr_res;
        }
 
-       printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMiB.\n",
+       printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %zuMiB.\n",
                mtd->index, ms02nv_name, addr, size >> 20);
 
        mp->next = root_ms02nv_mtd;
index edac4156d69c86003385ba4cdbc4a83ee63f2074..bb713fed2f373c66fd13e8f29be3abbc733963bb 100644 (file)
@@ -1,9 +1,10 @@
 /*
  * mtdram - a test mtd device
- * $Id: mtdram.c,v 1.35 2005/01/05 18:05:12 dwmw2 Exp $
+ * $Id: mtdram.c,v 1.37 2005/04/21 03:42:11 joern Exp $
  * Author: Alexander Larsson <alex@cendio.se>
  *
  * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
+ * Copyright (c) 2005 Joern Engel <joern@wh.fh-wedel.de>
  *
  * This code is GPL
  *
 #include <linux/mtd/compatmac.h>
 #include <linux/mtd/mtd.h>
 
-#ifndef CONFIG_MTDRAM_ABS_POS
-  #define CONFIG_MTDRAM_ABS_POS 0
-#endif
-
-#if CONFIG_MTDRAM_ABS_POS > 0
-  #include <asm/io.h>
-#endif
-
-#ifdef MODULE
 static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
 static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
-module_param(total_size,ulong,0);
-MODULE_PARM_DESC(total_size, "Total device size in KiB");
-module_param(erase_size,ulong,0);
-MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
 #define MTDRAM_TOTAL_SIZE (total_size * 1024)
 #define MTDRAM_ERASE_SIZE (erase_size * 1024)
-#else
-#define MTDRAM_TOTAL_SIZE (CONFIG_MTDRAM_TOTAL_SIZE * 1024)
-#define MTDRAM_ERASE_SIZE (CONFIG_MTDRAM_ERASE_SIZE * 1024)
-#endif
 
+#ifdef MODULE
+module_param(total_size, ulong, 0);
+MODULE_PARM_DESC(total_size, "Total device size in KiB");
+module_param(erase_size, ulong, 0);
+MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
+#endif
 
 // We could store these in the mtd structure, but we only support 1 device..
 static struct mtd_info *mtd_info;
 
-
-static int
-ram_erase(struct mtd_info *mtd, struct erase_info *instr)
+static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
-  DEBUG(MTD_DEBUG_LEVEL2, "ram_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len);
-  if (instr->addr + instr->len > mtd->size) {
-    DEBUG(MTD_DEBUG_LEVEL1, "ram_erase() out of bounds (%ld > %ld)\n", (long)(instr->addr + instr->len), (long)mtd->size);
-    return -EINVAL;
-  }
-       
-  memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
-       
-  instr->state = MTD_ERASE_DONE;
-  mtd_erase_callback(instr);
-
-  return 0;
+       if (instr->addr + instr->len > mtd->size)
+               return -EINVAL;
+
+       memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
+
+       instr->state = MTD_ERASE_DONE;
+       mtd_erase_callback(instr);
+
+       return 0;
 }
 
-static int ram_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, u_char **mtdbuf)
 {
-  if (from + len > mtd->size)
-    return -EINVAL;
-       
-  *mtdbuf = mtd->priv + from;
-  *retlen = len;
-  return 0;
+       if (from + len > mtd->size)
+               return -EINVAL;
+
+       *mtdbuf = mtd->priv + from;
+       *retlen = len;
+       return 0;
 }
 
-static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
-                        size_t len)
+static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
+               size_t len)
 {
-  DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n");
 }
 
 static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
-            size_t *retlen, u_char *buf)
+               size_t *retlen, u_char *buf)
 {
-  DEBUG(MTD_DEBUG_LEVEL2, "ram_read(pos:%ld, len:%ld)\n", (long)from, (long)len);
-  if (from + len > mtd->size) {
-    DEBUG(MTD_DEBUG_LEVEL1, "ram_read() out of bounds (%ld > %ld)\n", (long)(from + len), (long)mtd->size);
-    return -EINVAL;
-  }
+       if (from + len > mtd->size)
+               return -EINVAL;
 
-  memcpy(buf, mtd->priv + from, len);
+       memcpy(buf, mtd->priv + from, len);
 
-  *retlen=len;
-  return 0;
+       *retlen = len;
+       return 0;
 }
 
 static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
-             size_t *retlen, const u_char *buf)
+               size_t *retlen, const u_char *buf)
 {
-  DEBUG(MTD_DEBUG_LEVEL2, "ram_write(pos:%ld, len:%ld)\n", (long)to, (long)len);
-  if (to + len > mtd->size) {
-    DEBUG(MTD_DEBUG_LEVEL1, "ram_write() out of bounds (%ld > %ld)\n", (long)(to + len), (long)mtd->size);
-    return -EINVAL;
-  }
+       if (to + len > mtd->size)
+               return -EINVAL;
 
-  memcpy ((char *)mtd->priv + to, buf, len);
+       memcpy((char *)mtd->priv + to, buf, len);
 
-  *retlen=len;
-  return 0;
+       *retlen = len;
+       return 0;
 }
 
 static void __exit cleanup_mtdram(void)
 {
-  if (mtd_info) {
-    del_mtd_device(mtd_info);
-#if CONFIG_MTDRAM_TOTAL_SIZE > 0
-    if (mtd_info->priv)
-#if CONFIG_MTDRAM_ABS_POS > 0
-      iounmap(mtd_info->priv);
-#else
-      vfree(mtd_info->priv);
-#endif 
-#endif
-    kfree(mtd_info);
-  }
-}
-
-int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 
-                       unsigned long size, char *name)
-{
-   memset(mtd, 0, sizeof(*mtd));
-
-   /* Setup the MTD structure */
-   mtd->name = name;
-   mtd->type = MTD_RAM;
-   mtd->flags = MTD_CAP_RAM;
-   mtd->size = size;
-   mtd->erasesize = MTDRAM_ERASE_SIZE;
-   mtd->priv = mapped_address;
-
-   mtd->owner = THIS_MODULE;
-   mtd->erase = ram_erase;
-   mtd->point = ram_point;
-   mtd->unpoint = ram_unpoint;
-   mtd->read = ram_read;
-   mtd->write = ram_write;
-
-   if (add_mtd_device(mtd)) {
-     return -EIO;
-   }
-   
-   return 0;
-}
-
-#if CONFIG_MTDRAM_TOTAL_SIZE > 0
-#if CONFIG_MTDRAM_ABS_POS > 0
-static int __init init_mtdram(void)
-{
-  void *addr;
-  int err;
-  /* Allocate some memory */
-   mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-   if (!mtd_info)
-     return -ENOMEM;
-   
-  addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
-  if (!addr) {
-    DEBUG(MTD_DEBUG_LEVEL1, 
-          "Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n", 
-          (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
-    kfree(mtd_info);
-    mtd_info = NULL;
-    return -ENOMEM;
-  }
-  err = mtdram_init_device(mtd_info, addr, 
-                           MTDRAM_TOTAL_SIZE, "mtdram test device");
-  if (err) 
-  {
-    iounmap(addr);
-    kfree(mtd_info);
-    mtd_info = NULL;
-    return err;
-  }
-  memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
-  return err;
+       if (mtd_info) {
+               del_mtd_device(mtd_info);
+               if (mtd_info->priv)
+                       vfree(mtd_info->priv);
+               kfree(mtd_info);
+       }
 }
 
-#else /* CONFIG_MTDRAM_ABS_POS > 0 */
-
-static int __init init_mtdram(void)
+int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
+               unsigned long size, char *name)
 {
-  void *addr;
-  int err;
-  /* Allocate some memory */
-   mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-   if (!mtd_info)
-     return -ENOMEM;
-
-  addr = vmalloc(MTDRAM_TOTAL_SIZE);
-  if (!addr) {
-    DEBUG(MTD_DEBUG_LEVEL1, 
-          "Failed to vmalloc memory region of size %ld\n", 
-          (long)MTDRAM_TOTAL_SIZE);
-    kfree(mtd_info);
-    mtd_info = NULL;
-    return -ENOMEM;
-  }
-  err = mtdram_init_device(mtd_info, addr, 
-                           MTDRAM_TOTAL_SIZE, "mtdram test device");
-  if (err) 
-  {
-    vfree(addr);
-    kfree(mtd_info);
-    mtd_info = NULL;
-    return err;
-  }
-  memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
-  return err;
+       memset(mtd, 0, sizeof(*mtd));
+
+       /* Setup the MTD structure */
+       mtd->name = name;
+       mtd->type = MTD_RAM;
+       mtd->flags = MTD_CAP_RAM;
+       mtd->size = size;
+       mtd->erasesize = MTDRAM_ERASE_SIZE;
+       mtd->priv = mapped_address;
+
+       mtd->owner = THIS_MODULE;
+       mtd->erase = ram_erase;
+       mtd->point = ram_point;
+       mtd->unpoint = ram_unpoint;
+       mtd->read = ram_read;
+       mtd->write = ram_write;
+
+       if (add_mtd_device(mtd)) {
+               return -EIO;
+       }
+
+       return 0;
 }
-#endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */
-
-#else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */
 
 static int __init init_mtdram(void)
 {
-  return 0;
+       void *addr;
+       int err;
+
+       if (!total_size)
+               return -EINVAL;
+
+       /* Allocate some memory */
+       mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+       if (!mtd_info)
+               return -ENOMEM;
+
+       addr = vmalloc(MTDRAM_TOTAL_SIZE);
+       if (!addr) {
+               kfree(mtd_info);
+               mtd_info = NULL;
+               return -ENOMEM;
+       }
+       err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device");
+       if (err) {
+               vfree(addr);
+               kfree(mtd_info);
+               mtd_info = NULL;
+               return err;
+       }
+       memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+       return err;
 }
-#endif /* !(CONFIG_MTDRAM_TOTAL_SIZE > 0) */
 
 module_init(init_mtdram);
 module_exit(cleanup_mtdram);
@@ -232,4 +160,3 @@ module_exit(cleanup_mtdram);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>");
 MODULE_DESCRIPTION("Simulated MTD driver for testing");
-
index 5f8e164ddb710fa9d219845e1623c35bae73783b..a423a382095a7231f23391979df5f9a6145af580 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * $Id: phram.c,v 1.11 2005/01/05 18:05:13 dwmw2 Exp $
+ * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $
  *
  * Copyright (c) ????          Jochen Schäuble <psionic@psionic.de>
  * Copyright (c) 2003-2004     Jörn Engel <joern@wh.fh-wedel.de>
@@ -15,9 +15,7 @@
  *
  * Example:
  *     phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
- *
  */
-
 #include <asm/io.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -36,7 +34,6 @@ struct phram_mtd_list {
 static LIST_HEAD(phram_list);
 
 
-
 static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
        u_char *start = mtd->priv;
@@ -71,7 +68,8 @@ static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
        return 0;
 }
 
-static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from,
+               size_t len)
 {
 }
 
@@ -80,8 +78,11 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
 {
        u_char *start = mtd->priv;
 
-       if (from + len > mtd->size)
+       if (from >= mtd->size)
                return -EINVAL;
+
+       if (len > mtd->size - from)
+               len = mtd->size - from;
        
        memcpy(buf, start + from, len);
 
@@ -94,8 +95,11 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
 {
        u_char *start = mtd->priv;
 
-       if (to + len > mtd->size)
+       if (to >= mtd->size)
                return -EINVAL;
+
+       if (len > mtd->size - to)
+               len = mtd->size - to;
        
        memcpy(start + to, buf, len);
 
@@ -107,9 +111,9 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
 
 static void unregister_devices(void)
 {
-       struct phram_mtd_list *this;
+       struct phram_mtd_list *this, *safe;
 
-       list_for_each_entry(this, &phram_list, list) {
+       list_for_each_entry_safe(this, safe, &phram_list, list) {
                del_mtd_device(&this->mtd);
                iounmap(this->mtd.priv);
                kfree(this);
@@ -145,7 +149,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
        new->mtd.write = phram_write;
        new->mtd.owner = THIS_MODULE;
        new->mtd.type = MTD_RAM;
-       new->mtd.erasesize = 0;
+       new->mtd.erasesize = PAGE_SIZE;
 
        ret = -EAGAIN;
        if (add_mtd_device(&new->mtd)) {
@@ -214,6 +218,15 @@ static int parse_name(char **pname, const char *token)
        return 0;
 }
 
+
+static inline void kill_final_newline(char *str)
+{
+       char *newline = strrchr(str, '\n');
+       if (newline && !newline[1])
+               *newline = 0;
+}
+
+
 #define parse_err(fmt, args...) do {   \
        ERROR(fmt , ## args);   \
        return 0;               \
@@ -232,6 +245,7 @@ static int phram_setup(const char *val, struct kernel_param *kp)
                parse_err("parameter too long\n");
 
        strcpy(str, val);
+       kill_final_newline(str);
 
        for (i=0; i<3; i++)
                token[i] = strsep(&str, ",");
index 5ab15e643be789485b48bcd3d92b7c6da12199f6..84fa91392a8c7180b5113a15a290e76f49f4a50a 100644 (file)
@@ -1,6 +1,6 @@
 /*======================================================================
 
-  $Id: slram.c,v 1.33 2005/01/05 18:05:13 dwmw2 Exp $
+  $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $
 
   This driver provides a method to access memory not used by the kernel
   itself (i.e. if the kernel commandline mem=xxx is used). To actually
@@ -50,6 +50,7 @@
 #include <linux/mtd/mtd.h>
 
 #define SLRAM_MAX_DEVICES_PARAMS 6             /* 3 parameters / device */
+#define SLRAM_BLK_SZ 0x4000
 
 #define T(fmt, args...) printk(KERN_DEBUG fmt, ## args)
 #define E(fmt, args...) printk(KERN_NOTICE fmt, ## args)
@@ -108,6 +109,9 @@ static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
 {
        slram_priv_t *priv = mtd->priv;
 
+       if (from + len > mtd->size)
+               return -EINVAL;
+
        *mtdbuf = priv->start + from;
        *retlen = len;
        return(0);
@@ -121,7 +125,13 @@ static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char *buf)
 {
        slram_priv_t *priv = mtd->priv;
-       
+
+       if (from > mtd->size)
+               return -EINVAL;
+
+       if (from + len > mtd->size)
+               len = mtd->size - from;
+
        memcpy(buf, priv->start + from, len);
 
        *retlen = len;
@@ -133,6 +143,9 @@ static int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
 {
        slram_priv_t *priv = mtd->priv;
 
+       if (to + len > mtd->size)
+               return -EINVAL;
+
        memcpy(priv->start + to, buf, len);
 
        *retlen = len;
@@ -188,7 +201,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
        (*curmtd)->mtdinfo->name = name;
        (*curmtd)->mtdinfo->size = length;
        (*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS |
-                                       MTD_WRITEB_WRITEABLE | MTD_VOLATILE;
+                                       MTD_WRITEB_WRITEABLE | MTD_VOLATILE | MTD_CAP_RAM;
         (*curmtd)->mtdinfo->erase = slram_erase;
        (*curmtd)->mtdinfo->point = slram_point;
        (*curmtd)->mtdinfo->unpoint = slram_unpoint;
@@ -196,7 +209,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
        (*curmtd)->mtdinfo->write = slram_write;
        (*curmtd)->mtdinfo->owner = THIS_MODULE;
        (*curmtd)->mtdinfo->type = MTD_RAM;
-       (*curmtd)->mtdinfo->erasesize = 0x0;
+       (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
 
        if (add_mtd_device((*curmtd)->mtdinfo)) {
                E("slram: Failed to register new device\n");
@@ -261,7 +274,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength)
        }
        T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n",
                        devname, devstart, devlength);
-       if ((devstart < 0) || (devlength < 0)) {
+       if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) {
                E("slram: Illegal start / length parameter.\n");
                return(-EINVAL);
        }
index 18cc8846e7337015609eb1c0ff449dc5ebaf2d1e..d9ab60b36fd43d571995165d3df190fdbebbb01b 100644 (file)
@@ -1,5 +1,5 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $
+ * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -357,6 +357,7 @@ static int erase_xfer(partition_t *part,
     if (!erase) 
             return -ENOMEM;
 
+    erase->mtd = part->mbd.mtd;
     erase->callback = ftl_erase_callback;
     erase->addr = xfer->Offset;
     erase->len = 1 << part->header.EraseUnitSize;
@@ -1096,7 +1097,7 @@ struct mtd_blktrans_ops ftl_tr = {
 
 int init_ftl(void)
 {
-       DEBUG(0, "$Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $\n");
+       DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n");
 
        return register_mtd_blktrans(&ftl_tr);
 }
index 2bea2e0b06f26819d3526c1c2c2d9e6e8c34c13b..44781a83b2e78b79b953d21f60bbf4fe12294466 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.42 2005/01/05 16:59:50 dwmw2 Exp $
+# $Id: Kconfig,v 1.55 2005/07/02 01:53:24 tpoynor Exp $
 
 menu "Mapping drivers for chip access"
        depends on MTD!=n
@@ -122,16 +122,6 @@ config MTD_SBC_GXX
          More info at
          <http://www.arcomcontrols.com/products/icp/pc104/processors/SBC_GX1.htm>.
 
-config MTD_ELAN_104NC
-       tristate "CFI Flash device mapped on Arcom ELAN-104NC"
-       depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS
-       help
-         This provides a driver for the on-board flash of the Arcom Control
-         System's ELAN-104NC development board. By default the flash
-         is split into 3 partitions which are accessed as separate MTD
-         devices. This board utilizes Intel StrataFlash. More info at
-         <http://www.arcomcontrols.com/products/icp/pc104/processors/ELAN104NC.htm>.
-
 config MTD_LUBBOCK
        tristate "CFI Flash device mapped on Intel Lubbock XScale eval board"
        depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS
@@ -139,6 +129,14 @@ config MTD_LUBBOCK
          This provides a driver for the on-board flash of the Intel
          'Lubbock' XScale evaluation board.
 
+config MTD_MAINSTONE
+       tristate "CFI Flash device mapped on Intel Mainstone XScale eval board"
+       depends on MACH_MAINSTONE && MTD_CFI_INTELEXT
+       select MTD_PARTITIONS
+       help
+         This provides a driver for the on-board flash of the Intel
+         'Mainstone PXA27x evaluation board.
+
 config MTD_OCTAGON
        tristate "JEDEC Flash device mapped on Octagon 5066 SBC"
        depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
@@ -213,74 +211,11 @@ config MTD_NETtel
        help
          Support for flash chips on NETtel/SecureEdge/SnapGear boards.
 
-config MTD_PB1XXX
-       tristate "Flash devices on Alchemy PB1xxx boards"
-       depends on MIPS && ( MIPS_PB1000 || MIPS_PB1100 || MIPS_PB1500 )
-       help
-         Flash memory access on Alchemy Pb1000/Pb1100/Pb1500 boards
-
-config MTD_PB1XXX_BOOT
-       bool "PB1x00 boot flash device"
-       depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 )
-       help
-         Use the first of the two 32MiB flash banks on Pb1100/Pb1500 board.
-         You can say 'Y' to both this and 'MTD_PB1XXX_USER' below, to use
-         both banks.
-
-config MTD_PB1XXX_USER
-       bool "PB1x00 user flash device"
-       depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 )
-       default y if MTD_PB1XX_BOOT = n
-       help
-         Use the second of the two 32MiB flash banks on Pb1100/Pb1500 board.
-         You can say 'Y' to both this and 'MTD_PB1XXX_BOOT' above, to use
-         both banks.
-
-config MTD_PB1550
-       tristate "Flash devices on Alchemy PB1550 board"
-       depends on MIPS && MIPS_PB1550
-       help
-         Flash memory access on Alchemy Pb1550 board
-
-config MTD_PB1550_BOOT
-       bool "PB1550 boot flash device"
-       depends on MTD_PB1550
+config MTD_ALCHEMY
+       tristate '  AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' 
+       depends on MIPS && SOC_AU1X00
        help
-         Use the first of the two 64MiB flash banks on Pb1550 board.
-         You can say 'Y' to both this and 'MTD_PB1550_USER' below, to use
-         both banks.
-
-config MTD_PB1550_USER
-       bool "PB1550 user flash device"
-       depends on MTD_PB1550
-       default y if MTD_PB1550_BOOT = n
-       help
-         Use the second of the two 64MiB flash banks on Pb1550 board.
-         You can say 'Y' to both this and 'MTD_PB1550_BOOT' above, to use
-         both banks.
-
-config MTD_DB1550
-       tristate "Flash devices on Alchemy DB1550 board"
-       depends on MIPS && MIPS_DB1550
-       help
-         Flash memory access on Alchemy Db1550 board
-
-config MTD_DB1550_BOOT
-       bool "DB1550 boot flash device"
-       depends on MTD_DB1550
-       help
-         Use the first of the two 64MiB flash banks on Db1550 board.
-         You can say 'Y' to both this and 'MTD_DB1550_USER' below, to use
-         both banks.
-
-config MTD_DB1550_USER
-       bool "DB1550 user flash device"
-       depends on MTD_DB1550
-       default y if MTD_DB1550_BOOT = n
-       help
-         Use the second of the two 64MiB flash banks on Db1550 board.
-         You can say 'Y' to both this and 'MTD_DB1550_BOOT' above, to use
-         both banks.
+         Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
 
 config MTD_DILNETPC
        tristate "CFI Flash device mapped on DIL/Net PC"
@@ -588,6 +523,15 @@ config MTD_MPC1211
          This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02).
          If you have such a board, say 'Y'.
 
+config MTD_OMAP_NOR
+       tristate "TI OMAP board mappings"
+       depends on MTD_CFI && ARCH_OMAP
+       help
+         This enables access to the NOR flash chips on TI OMAP-based
+         boards defining flash platform devices and flash platform data.
+         These boards include the Innovator, H2, H3, OSK, Perseus2, and
+         more.  If you have such a board, say 'Y'.
+
 # This needs CFI or JEDEC, depending on the cards found.
 config MTD_PCI
        tristate "PCI MTD driver"
@@ -647,13 +591,14 @@ config MTD_DMV182
           Map driver for Dy-4 SVME/DMV-182 board.
 
 config MTD_BAST
-       tristate "Map driver for Simtec BAST (EB2410ITX)"
-       depends on ARCH_BAST
+       tristate "Map driver for Simtec BAST (EB2410ITX) or Thorcom VR1000"
+       depends on ARCH_BAST || MACH_VR1000
        select MTD_PARTITIONS
        select MTD_MAP_BANK_WIDTH_16
        select MTD_JEDECPROBE
        help
-         Map driver for NOR flash on the Simtec BAST (EB2410ITX).
+         Map driver for NOR flash on the Simtec BAST (EB2410ITX), or the
+         Thorcom VR1000
 
          Note, this driver *cannot* over-ride the WP link on the
          board, or currently detect the state of the link.
@@ -669,5 +614,15 @@ config MTD_SHARP_SL
        help
          This enables access to the flash chip on the Sharp SL Series of PDAs.
 
+config MTD_PLATRAM
+       tristate "Map driver for platform device RAM (mtd-ram)"
+       depends on MTD
+       select MTD_RAM
+       help
+         Map driver for RAM areas described via the platform device
+         system.
+
+         This selection automatically selects the map_ram driver.
+
 endmenu
 
index 7ffe02b85301657650be057ab40949ce1fdec675..7bcbc49e329f24c94ec7d1ee714c29e8ecab1a5f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # linux/drivers/maps/Makefile
 #
-# $Id: Makefile.common,v 1.23 2005/01/05 17:06:36 dwmw2 Exp $
+# $Id: Makefile.common,v 1.30 2005/07/02 01:53:24 tpoynor Exp $
 
 ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
 obj-$(CONFIG_MTD)              += map_funcs.o
@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
 obj-$(CONFIG_MTD_CSTM_MIPS_IXX)        += cstm_mips_ixx.o
 obj-$(CONFIG_MTD_DC21285)      += dc21285.o
 obj-$(CONFIG_MTD_DILNETPC)     += dilnetpc.o
-obj-$(CONFIG_MTD_ELAN_104NC)   += elan-104nc.o
 obj-$(CONFIG_MTD_EPXA10DB)     += epxa10db-flash.o
 obj-$(CONFIG_MTD_IQ80310)      += iq80310.o
 obj-$(CONFIG_MTD_L440GX)       += l440gx.o
@@ -23,6 +22,7 @@ obj-$(CONFIG_MTD_AMD76XROM)   += amd76xrom.o
 obj-$(CONFIG_MTD_ICHXROM)      += ichxrom.o
 obj-$(CONFIG_MTD_TSUNAMI)      += tsunami_flash.o
 obj-$(CONFIG_MTD_LUBBOCK)      += lubbock-flash.o
+obj-$(CONFIG_MTD_MAINSTONE)    += mainstone-flash.o
 obj-$(CONFIG_MTD_MBX860)       += mbx860.o
 obj-$(CONFIG_MTD_CEIVA)                += ceiva.o
 obj-$(CONFIG_MTD_OCTAGON)      += octagon-5066.o
@@ -44,10 +44,7 @@ obj-$(CONFIG_MTD_DBOX2)              += dbox2-flash.o
 obj-$(CONFIG_MTD_OCELOT)       += ocelot.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)          += pci.o
-obj-$(CONFIG_MTD_PB1XXX)       += pb1xxx-flash.o
-obj-$(CONFIG_MTD_DB1X00)        += db1x00-flash.o
-obj-$(CONFIG_MTD_PB1550)        += pb1550-flash.o
-obj-$(CONFIG_MTD_DB1550)        += db1550-flash.o
+obj-$(CONFIG_MTD_ALCHEMY)       += alchemy-flash.o
 obj-$(CONFIG_MTD_LASAT)                += lasat.o
 obj-$(CONFIG_MTD_AUTCPU12)     += autcpu12-nvram.o
 obj-$(CONFIG_MTD_EDB7312)      += edb7312.o
@@ -71,3 +68,5 @@ obj-$(CONFIG_MTD_IXP2000)     += ixp2000.o
 obj-$(CONFIG_MTD_WRSBC8260)    += wr_sbc82xx_flash.o
 obj-$(CONFIG_MTD_DMV182)       += dmv182.o
 obj-$(CONFIG_MTD_SHARP_SL)     += sharpsl-flash.o
+obj-$(CONFIG_MTD_PLATRAM)      += plat-ram.o
+obj-$(CONFIG_MTD_OMAP_NOR)     += omap_nor.o
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
new file mode 100644 (file)
index 0000000..27fd2a3
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Flash memory access on AMD Alchemy evaluation boards
+ * 
+ * $Id: alchemy-flash.c,v 1.1 2005/02/27 21:50:21 ppopov Exp $
+ *
+ * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+#ifdef         DEBUG_RW
+#define        DBG(x...)       printk(x)
+#else
+#define        DBG(x...)       
+#endif
+
+#ifdef CONFIG_MIPS_PB1000
+#define BOARD_MAP_NAME "Pb1000 Flash"
+#define BOARD_FLASH_SIZE 0x00800000 /* 8MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1500
+#define BOARD_MAP_NAME "Pb1500 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1100
+#define BOARD_MAP_NAME "Pb1100 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1550
+#define BOARD_MAP_NAME "Pb1550 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1200
+#define BOARD_MAP_NAME "Pb1200 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1000
+#define BOARD_MAP_NAME "Db1000 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1500
+#define BOARD_MAP_NAME "Db1500 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1100
+#define BOARD_MAP_NAME "Db1100 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1550
+#define BOARD_MAP_NAME "Db1550 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1200
+#define BOARD_MAP_NAME "Db1200 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_HYDROGEN3
+#define BOARD_MAP_NAME "Hydrogen3 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#define USE_LOCAL_ACCESSORS /* why? */
+#endif
+
+#ifdef CONFIG_MIPS_BOSPORUS
+#define BOARD_MAP_NAME "Bosporus Flash"
+#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_MIRAGE
+#define BOARD_MAP_NAME "Mirage Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#define USE_LOCAL_ACCESSORS /* why? */
+#endif
+
+static struct map_info alchemy_map = {
+       .name = BOARD_MAP_NAME,
+};
+
+static struct mtd_partition alchemy_partitions[] = {
+        {
+                .name = "User FS",
+                .size = BOARD_FLASH_SIZE - 0x00400000,
+                .offset = 0x0000000
+        },{
+                .name = "YAMON",
+                .size = 0x0100000,
+               .offset = MTDPART_OFS_APPEND,
+                .mask_flags = MTD_WRITEABLE
+        },{
+                .name = "raw kernel",
+               .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
+               .offset = MTDPART_OFS_APPEND,
+        }
+};
+
+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
+
+static struct mtd_info *mymtd;
+
+int __init alchemy_mtd_init(void)
+{
+       struct mtd_partition *parts;
+       int nb_parts = 0;
+       unsigned long window_addr;
+       unsigned long window_size;
+       
+       /* Default flash buswidth */
+       alchemy_map.bankwidth = BOARD_FLASH_WIDTH;
+
+       window_addr = 0x20000000 - BOARD_FLASH_SIZE;
+       window_size = BOARD_FLASH_SIZE;
+#ifdef CONFIG_MIPS_MIRAGE_WHY
+       /* Boot ROM flash bank only; no user bank */
+       window_addr = 0x1C000000;
+       window_size = 0x04000000;
+       /* USERFS from 0x1C00 0000 to 0x1FC00000 */
+       alchemy_partitions[0].size = 0x03C00000;
+#endif
+
+       /*
+        * Static partition definition selection
+        */
+       parts = alchemy_partitions;
+       nb_parts = NB_OF(alchemy_partitions);
+       alchemy_map.size = window_size;
+
+       /*
+        * Now let's probe for the actual flash.  Do it here since
+        * specific machine settings might have been set above.
+        */
+       printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n", 
+                       alchemy_map.bankwidth*8);
+       alchemy_map.virt = ioremap(window_addr, window_size);
+       mymtd = do_map_probe("cfi_probe", &alchemy_map);
+       if (!mymtd) {
+               iounmap(alchemy_map.virt);
+               return -ENXIO;
+       }
+       mymtd->owner = THIS_MODULE;
+
+       add_mtd_partitions(mymtd, parts, nb_parts);
+       return 0;
+}
+
+static void __exit alchemy_mtd_cleanup(void)
+{
+       if (mymtd) {
+               del_mtd_partitions(mymtd);
+               map_destroy(mymtd);
+               iounmap(alchemy_map.virt);
+       }
+}
+
+module_init(alchemy_mtd_init);
+module_exit(alchemy_mtd_cleanup);
+
+MODULE_AUTHOR("Embedded Alley Solutions, Inc");
+MODULE_DESCRIPTION(BOARD_MAP_NAME " MTD driver");
+MODULE_LICENSE("GPL");
index 51e97b05304e4ee37f5bf8a6e3d0b3e0269cde8b..e8a900a77685e4bb024a3c510a2b3e5dc3d11c1b 100644 (file)
@@ -2,7 +2,7 @@
  * amd76xrom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 dwmw2 Exp $
+ * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $
  */
 
 #include <linux/module.h>
@@ -314,7 +314,7 @@ static int __init init_amd76xrom(void)
        }
        return -ENXIO;
 #if 0
-       return pci_module_init(&amd76xrom_driver);
+       return pci_register_driver(&amd76xrom_driver);
 #endif
 }
 
index 44de3a81b2774e026d628dca870caf49b3e770b9..0c45464e3f7b8636f6d816b280a150e930dea6de 100644 (file)
@@ -1,14 +1,15 @@
 /* linux/drivers/mtd/maps/bast_flash.c
  *
- * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
  *
  * Simtec Bast (EB2410ITX) NOR MTD Mapping driver
  *
  * Changelog:
  *     20-Sep-2004  BJD  Initial version
+ *     17-Jan-2005  BJD  Add whole device if no partitions found
  *
- * $Id: bast-flash.c,v 1.1 2004/09/21 14:29:04 bjd Exp $
+ * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -46,9 +47,9 @@
 #include <asm/arch/bast-cpld.h>
 
 #ifdef CONFIG_MTD_BAST_MAXSIZE
-#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * (1024*1024))
+#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M)
 #else
-#define AREA_MAXSIZE (32*1024*1024)
+#define AREA_MAXSIZE (32 * SZ_1M)
 #endif
 
 #define PFX "bast-flash: "
@@ -189,6 +190,8 @@ static int bast_flash_probe(struct device *dev)
                err = add_mtd_partitions(info->mtd, info->partitions, err);
                if (err) 
                        printk(KERN_ERR PFX "cannot add/parse partitions\n");
+       } else {
+               err = add_mtd_device(info->mtd);
        }
 
        if (err == 0)
diff --git a/drivers/mtd/maps/db1550-flash.c b/drivers/mtd/maps/db1550-flash.c
deleted file mode 100644 (file)
index d213888..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Flash memory access on Alchemy Db1550 board
- * 
- * $Id: db1550-flash.c,v 1.7 2004/11/04 13:24:14 gleixner Exp $
- *
- * (C) 2004 Embedded Edge, LLC, based on db1550-flash.c:
- * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
- * 
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef         DEBUG_RW
-#define        DBG(x...)       printk(x)
-#else
-#define        DBG(x...)       
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-
-
-static struct map_info db1550_map = {
-       .name = "Db1550 flash",
-};
-
-static unsigned char flash_bankwidth = 4;
-
-/* 
- * Support only 64MB NOR Flash parts
- */
-
-#if defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_BOTH_BANKS
-#elif defined(CONFIG_MTD_DB1550_BOOT) && !defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_BOOT_ONLY
-#elif !defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_USER_ONLY
-#endif
-
-#ifdef DB1550_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first 
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition db1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-        * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size =   (0x1FC00000 - 0x18000000),
-                .offset = 0x0000000
-        },{
-                .name = "yamon",
-                .size = 0x0100000,
-               .offset = MTDPART_OFS_APPEND,
-                .mask_flags = MTD_WRITEABLE
-        },{
-                .name = "raw kernel",
-               .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(DB1550_BOOT_ONLY)
-static struct mtd_partition db1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size =   0x03c00000,
-                .offset = 0x0000000
-        },{
-                .name = "yamon",
-                .size = 0x0100000,
-               .offset = MTDPART_OFS_APPEND,
-                .mask_flags = MTD_WRITEABLE
-        },{
-                .name = "raw kernel",
-               .size = (0x300000-0x40000), /* last 256KB is yamon env */
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(DB1550_USER_ONLY)
-static struct mtd_partition db1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
-                .offset = 0x0000000
-        },{
-                .name = "raw kernel",
-               .size = MTDPART_SIZ_FULL,
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#else
-#error MTD_DB1550 define combo error /* should never happen */
-#endif
-
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
-static struct mtd_info *mymtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
-#if defined(DB1550_BOTH_BANKS)
-                       window_addr = 0x18000000;
-                       window_size = 0x8000000; 
-#elif defined(DB1550_BOOT_ONLY)
-                       window_addr = 0x1C000000;
-                       window_size = 0x4000000; 
-#else /* USER ONLY */
-                       window_addr = 0x18000000;
-                       window_size = 0x4000000; 
-#endif
-       return 0;
-}
-
-int __init db1550_mtd_init(void)
-{
-       struct mtd_partition *parts;
-       int nb_parts = 0;
-       
-       /* Default flash bankwidth */
-       db1550_map.bankwidth = flash_bankwidth;
-
-       if (setup_flash_params()) 
-               return -ENXIO;
-
-       /*
-        * Static partition definition selection
-        */
-       parts = db1550_partitions;
-       nb_parts = NB_OF(db1550_partitions);
-       db1550_map.size = window_size;
-
-       /*
-        * Now let's probe for the actual flash.  Do it here since
-        * specific machine settings might have been set above.
-        */
-       printk(KERN_NOTICE "Db1550 flash: probing %d-bit flash bus\n", 
-                       db1550_map.bankwidth*8);
-       db1550_map.virt = ioremap(window_addr, window_size);
-       mymtd = do_map_probe("cfi_probe", &db1550_map);
-       if (!mymtd) return -ENXIO;
-       mymtd->owner = THIS_MODULE;
-
-       add_mtd_partitions(mymtd, parts, nb_parts);
-       return 0;
-}
-
-static void __exit db1550_mtd_cleanup(void)
-{
-       if (mymtd) {
-               del_mtd_partitions(mymtd);
-               map_destroy(mymtd);
-               iounmap((void *) db1550_map.virt);
-       }
-}
-
-module_init(db1550_mtd_init);
-module_exit(db1550_mtd_cleanup);
-
-MODULE_AUTHOR("Embedded Edge, LLC");
-MODULE_DESCRIPTION("Db1550 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/db1x00-flash.c b/drivers/mtd/maps/db1x00-flash.c
deleted file mode 100644 (file)
index faa68ec..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Flash memory access on Alchemy Db1xxx boards
- * 
- * $Id: db1x00-flash.c,v 1.6 2004/11/04 13:24:14 gleixner Exp $
- *
- * (C) 2003 Pete Popov <ppopov@embeddedalley.com>
- * 
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef         DEBUG_RW
-#define        DBG(x...)       printk(x)
-#else
-#define        DBG(x...)       
-#endif
-
-/* MTD CONFIG OPTIONS */
-#if defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_BOTH_BANKS
-#elif defined(CONFIG_MTD_DB1X00_BOOT) && !defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_BOOT_ONLY
-#elif !defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_USER_ONLY
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-static unsigned long flash_size;
-
-static unsigned short *bcsr = (unsigned short *)0xAE000000;
-static unsigned char flash_bankwidth = 4;
-
-/* 
- * The Db1x boards support different flash densities. We setup
- * the mtd_partition structures below for default of 64Mbit 
- * flash densities, and override the partitions sizes, if
- * necessary, after we check the board status register.
- */
-
-#ifdef DB1X00_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first 
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition db1x00_partitions[] = {
-        {
-                .name         =  "User FS",
-                .size         =  0x1c00000,
-                .offset       =  0x0000000
-        },{
-                .name         =  "yamon",
-                .size         =  0x0100000,
-               .offset       =  MTDPART_OFS_APPEND,
-                .mask_flags   =  MTD_WRITEABLE
-        },{
-                .name         =  "raw kernel",
-               .size         =  (0x300000-0x40000), /* last 256KB is env */
-               .offset       =  MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(DB1X00_BOOT_ONLY)
-static struct mtd_partition db1x00_partitions[] = {
-        {
-                .name         =  "User FS",
-                .size         =  0x00c00000,
-                .offset       =  0x0000000
-        },{
-                .name         =  "yamon",
-                .size         =  0x0100000,
-               .offset       =  MTDPART_OFS_APPEND,
-                .mask_flags   =  MTD_WRITEABLE
-        },{
-                .name         =  "raw kernel",
-               .size         =  (0x300000-0x40000), /* last 256KB is env */
-               .offset       =  MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(DB1X00_USER_ONLY)
-static struct mtd_partition db1x00_partitions[] = {
-        {
-                .name         =  "User FS",
-                .size         =  0x0e00000,
-                .offset       =  0x0000000
-        },{
-                .name         =  "raw kernel",
-               .size         =  MTDPART_SIZ_FULL,
-               .offset       =  MTDPART_OFS_APPEND,
-        }
-};
-#else
-#error MTD_DB1X00 define combo error /* should never happen */
-#endif
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
-#define NAME           "Db1x00 Linux Flash"
-
-static struct map_info db1xxx_mtd_map = {
-       .name           = NAME,
-};
-
-static struct mtd_partition *parsed_parts;
-static struct mtd_info *db1xxx_mtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
-       switch ((bcsr[2] >> 14) & 0x3) {
-               case 0: /* 64Mbit devices */
-                       flash_size = 0x800000; /* 8MB per part */
-#if defined(DB1X00_BOTH_BANKS)
-                       window_addr = 0x1E000000;
-                       window_size = 0x2000000; 
-#elif defined(DB1X00_BOOT_ONLY)
-                       window_addr = 0x1F000000;
-                       window_size = 0x1000000; 
-#else /* USER ONLY */
-                       window_addr = 0x1E000000;
-                       window_size = 0x1000000; 
-#endif
-                       break;
-               case 1:
-                       /* 128 Mbit devices */
-                       flash_size = 0x1000000; /* 16MB per part */
-#if defined(DB1X00_BOTH_BANKS)
-                       window_addr = 0x1C000000;
-                       window_size = 0x4000000;
-                       /* USERFS from 0x1C00 0000 to 0x1FC0 0000 */
-                       db1x00_partitions[0].size = 0x3C00000;
-#elif defined(DB1X00_BOOT_ONLY)
-                       window_addr = 0x1E000000;
-                       window_size = 0x2000000;
-                       /* USERFS from 0x1E00 0000 to 0x1FC0 0000 */
-                       db1x00_partitions[0].size = 0x1C00000;
-#else /* USER ONLY */
-                       window_addr = 0x1C000000;
-                       window_size = 0x2000000;
-                       /* USERFS from 0x1C00 0000 to 0x1DE00000 */
-                       db1x00_partitions[0].size = 0x1DE0000;
-#endif
-                       break;
-               case 2:
-                       /* 256 Mbit devices */
-                       flash_size = 0x4000000; /* 64MB per part */
-#if defined(DB1X00_BOTH_BANKS)
-                       return 1;
-#elif defined(DB1X00_BOOT_ONLY)
-                       /* Boot ROM flash bank only; no user bank */
-                       window_addr = 0x1C000000;
-                       window_size = 0x4000000;
-                       /* USERFS from 0x1C00 0000 to 0x1FC00000 */
-                       db1x00_partitions[0].size = 0x3C00000;
-#else /* USER ONLY */
-                       return 1;
-#endif
-                       break;
-               default:
-                       return 1;
-       }
-       db1xxx_mtd_map.size = window_size;
-       db1xxx_mtd_map.bankwidth = flash_bankwidth;
-       db1xxx_mtd_map.phys = window_addr;
-       db1xxx_mtd_map.bankwidth = flash_bankwidth;
-       return 0;
-}
-
-int __init db1x00_mtd_init(void)
-{
-       struct mtd_partition *parts;
-       int nb_parts = 0;
-       
-       if (setup_flash_params()) 
-               return -ENXIO;
-
-       /*
-        * Static partition definition selection
-        */
-       parts = db1x00_partitions;
-       nb_parts = NB_OF(db1x00_partitions);
-
-       /*
-        * Now let's probe for the actual flash.  Do it here since
-        * specific machine settings might have been set above.
-        */
-       printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n", 
-                       db1xxx_mtd_map.bankwidth*8);
-       db1xxx_mtd_map.virt = ioremap(window_addr, window_size);
-       db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map);
-       if (!db1xxx_mtd) return -ENXIO;
-       db1xxx_mtd->owner = THIS_MODULE;
-
-       add_mtd_partitions(db1xxx_mtd, parts, nb_parts);
-       return 0;
-}
-
-static void __exit db1x00_mtd_cleanup(void)
-{
-       if (db1xxx_mtd) {
-               del_mtd_partitions(db1xxx_mtd);
-               map_destroy(db1xxx_mtd);
-               if (parsed_parts)
-                       kfree(parsed_parts);
-       }
-}
-
-module_init(db1x00_mtd_init);
-module_exit(db1x00_mtd_cleanup);
-
-MODULE_AUTHOR("Pete Popov");
-MODULE_DESCRIPTION("Db1x00 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c
deleted file mode 100644 (file)
index e9465f5..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-/* elan-104nc.c -- MTD map driver for Arcom Control Systems ELAN-104NC
-   Copyright (C) 2000 Arcom Control System Ltd
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-
-   $Id: elan-104nc.c,v 1.25 2004/11/28 09:40:39 dwmw2 Exp $
-
-The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
-mode.  This drivers uses the CFI probe and Intel Extended Command Set drivers.
-
-The flash is accessed as follows:
-
-   32 kbyte memory window at 0xb0000-0xb7fff
-   
-   16 bit I/O port (0x22) for some sort of paging.
-
-The single flash device is divided into 3 partition which appear as separate
-MTD devices.
-
-Linux thinks that the I/O port is used by the PIC and hence check_region() will
-always fail.  So we don't do it.  I just hope it doesn't break anything.
-*/
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-
-#define WINDOW_START 0xb0000
-/* Number of bits in offset. */
-#define WINDOW_SHIFT 15
-#define WINDOW_LENGTH (1 << WINDOW_SHIFT)
-/* The bits for the offset into the window. */
-#define WINDOW_MASK (WINDOW_LENGTH-1)
-#define PAGE_IO 0x22
-#define PAGE_IO_SIZE 2
-
-static volatile int page_in_window = -1; // Current page in window.
-static void __iomem *iomapadr;
-static DEFINE_SPINLOCK(elan_104nc_spin);
-
-/* partition_info gives details on the logical partitions that the split the 
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
-static struct mtd_partition partition_info[]={
-    { .name = "ELAN-104NC flash boot partition", 
-      .offset = 0, 
-      .size = 640*1024 },
-    { .name = "ELAN-104NC flash partition 1", 
-      .offset = 640*1024, 
-      .size = 896*1024 },
-    { .name = "ELAN-104NC flash partition 2", 
-      .offset = (640+896)*1024 }
-};
-#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
-
-/*
- * If no idea what is going on here.  This is taken from the FlashFX stuff.
- */
-#define ROMCS 1
-
-static inline void elan_104nc_setup(void)
-{
-    u16 t;
-
-    outw( 0x0023 + ROMCS*2, PAGE_IO );
-    t=inb( PAGE_IO+1 );
-
-    t=(t & 0xf9) | 0x04;
-
-    outw( ((0x0023 + ROMCS*2) | (t << 8)), PAGE_IO );
-}
-
-static inline void elan_104nc_page(struct map_info *map, unsigned long ofs)
-{
-       unsigned long page = ofs >> WINDOW_SHIFT;
-       
-       if( page!=page_in_window ) {
-               int cmd1;
-               int cmd2;
-
-               cmd1=(page & 0x700) + 0x0833 + ROMCS*0x4000;
-               cmd2=((page & 0xff) << 8) + 0x0032;
-
-               outw( cmd1, PAGE_IO );
-               outw( cmd2, PAGE_IO );
-
-               page_in_window = page;
-       }
-}
-
-
-static map_word elan_104nc_read16(struct map_info *map, unsigned long ofs)
-{
-       map_word ret;
-       spin_lock(&elan_104nc_spin);
-       elan_104nc_page(map, ofs);
-       ret.x[0] = readw(iomapadr + (ofs & WINDOW_MASK));
-       spin_unlock(&elan_104nc_spin);
-       return ret;
-}
-
-static void elan_104nc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-       while (len) {
-               unsigned long thislen = len;
-               if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
-                       thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-               
-               spin_lock(&elan_104nc_spin);
-               elan_104nc_page(map, from);
-               memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen);
-               spin_unlock(&elan_104nc_spin);
-               to += thislen;
-               from += thislen;
-               len -= thislen;
-       }
-}
-
-static void elan_104nc_write16(struct map_info *map, map_word d, unsigned long adr)
-{
-       spin_lock(&elan_104nc_spin);
-       elan_104nc_page(map, adr);
-       writew(d.x[0], iomapadr + (adr & WINDOW_MASK));
-       spin_unlock(&elan_104nc_spin);
-}
-
-static void elan_104nc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{      
-       while(len) {
-               unsigned long thislen = len;
-               if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
-                       thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-               
-               spin_lock(&elan_104nc_spin);
-               elan_104nc_page(map, to);
-               memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen);
-               spin_unlock(&elan_104nc_spin);
-               to += thislen;
-               from += thislen;
-               len -= thislen;
-       }
-}
-
-static struct map_info elan_104nc_map = {
-       .name = "ELAN-104NC flash",
-       .phys = NO_XIP,
-       .size = 8*1024*1024, /* this must be set to a maximum possible amount
-                       of flash so the cfi probe routines find all
-                       the chips */
-       .bankwidth = 2,
-       .read = elan_104nc_read16,
-       .copy_from = elan_104nc_copy_from,
-       .write = elan_104nc_write16,
-       .copy_to = elan_104nc_copy_to
-};
-
-/* MTD device for all of the flash. */
-static struct mtd_info *all_mtd;
-
-static void cleanup_elan_104nc(void)
-{
-       if( all_mtd ) {
-               del_mtd_partitions( all_mtd );
-               map_destroy( all_mtd );
-       }
-
-       iounmap(iomapadr);
-}
-
-static int __init init_elan_104nc(void)
-{
-       /* Urg! We use I/O port 0x22 without request_region()ing it,
-          because it's already allocated to the PIC. */
-
-       iomapadr = ioremap(WINDOW_START, WINDOW_LENGTH);
-       if (!iomapadr) {
-               printk( KERN_ERR"%s: failed to ioremap memory region\n",
-                       elan_104nc_map.name );
-               return -EIO;
-       }
-
-       printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
-               elan_104nc_map.name,
-               PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1,
-               WINDOW_START, WINDOW_START+WINDOW_LENGTH-1 );
-
-       elan_104nc_setup();
-
-       /* Probe for chip. */
-       all_mtd = do_map_probe("cfi_probe",  &elan_104nc_map );
-       if( !all_mtd ) {
-               cleanup_elan_104nc();
-               return -ENXIO;
-       }
-       
-       all_mtd->owner = THIS_MODULE;
-
-       /* Create MTD devices for each partition. */
-       add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS );
-
-       return 0;
-}
-
-module_init(init_elan_104nc);
-module_exit(cleanup_elan_104nc);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Arcom Control Systems Ltd.");
-MODULE_DESCRIPTION("MTD map driver for Arcom Control Systems ELAN-104NC");
index 29d1cc1bb426c112f5dc8e7a88c1e2680e2778a8..e505207cd4892918b27c59a3ccc2f00afc0c3c59 100644 (file)
@@ -2,7 +2,7 @@
  * ichxrom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 dwmw2 Exp $
+ * $Id: ichxrom.c,v 1.18 2005/07/07 10:26:20 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -338,9 +338,9 @@ static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
        { 0, },
 };
 
+#if 0
 MODULE_DEVICE_TABLE(pci, ichxrom_pci_tbl);
 
-#if 0
 static struct pci_driver ichxrom_driver = {
        .name =         MOD_NAME,
        .id_table =     ichxrom_pci_tbl,
@@ -366,7 +366,7 @@ static int __init init_ichxrom(void)
        }
        return -ENXIO;
 #if 0
-       return pci_module_init(&ichxrom_driver);
+       return pci_register_driver(&ichxrom_driver);
 #endif
 }
 
index c5b5f447e34b6a72c14f35e6eb7dcf3d315c8175..3e94b616743d0cec3cc123fb8952b2aedf4f236b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ixp2000.c,v 1.5 2004/11/16 17:15:48 dsaxena Exp $
+ * $Id: ixp2000.c,v 1.6 2005/03/18 14:07:46 gleixner Exp $
  *
  * drivers/mtd/maps/ixp2000.c
  *
@@ -216,11 +216,6 @@ static int ixp2000_flash_probe(struct device *_dev)
                goto Error;
        }
 
-       /*
-        * Setup read mode for FLASH
-        */
-       *IXP2000_SLOWPORT_FRM = 1;
-
 #if defined(__ARMEB__)
        /*
         * Enable erratum 44 workaround for NPUs with broken slowport
diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c
new file mode 100644 (file)
index 0000000..87e93fa
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * $Id:  $
+ *
+ * Map driver for the Mainstone developer platform.
+ *
+ * Author:     Nicolas Pitre
+ * Copyright:  (C) 2001 MontaVista Software Inc.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+
+
+#define ROM_ADDR       0x00000000
+#define FLASH_ADDR     0x04000000
+
+#define WINDOW_SIZE    0x04000000
+
+static void mainstone_map_inval_cache(struct map_info *map, unsigned long from,
+                                     ssize_t len)
+{
+       consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+}
+
+static struct map_info mainstone_maps[2] = { {
+       .size =         WINDOW_SIZE,
+       .phys =         PXA_CS0_PHYS,
+       .inval_cache =  mainstone_map_inval_cache,
+}, {
+       .size =         WINDOW_SIZE,
+       .phys =         PXA_CS1_PHYS,
+       .inval_cache =  mainstone_map_inval_cache,
+} };
+
+static struct mtd_partition mainstone_partitions[] = {
+       {
+               .name =         "Bootloader",
+               .size =         0x00040000,
+               .offset =       0,
+               .mask_flags =   MTD_WRITEABLE  /* force read-only */
+       },{
+               .name =         "Kernel",
+               .size =         0x00400000,
+               .offset =       0x00040000,
+       },{
+               .name =         "Filesystem",
+               .size =         MTDPART_SIZ_FULL,
+               .offset =       0x00440000
+       }
+};
+
+static struct mtd_info *mymtds[2];
+static struct mtd_partition *parsed_parts[2];
+static int nr_parsed_parts[2];
+
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+
+static int __init init_mainstone(void)
+{
+       int SW7 = 0;  /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
+       int ret = 0, i;
+
+       mainstone_maps[0].bankwidth = (BOOT_DEF & 1) ? 2 : 4;
+       mainstone_maps[1].bankwidth = 4;
+
+       /* Compensate for SW7 which swaps the flash banks */
+       mainstone_maps[SW7].name = "processor flash";
+       mainstone_maps[SW7 ^ 1].name = "main board flash";
+
+       printk(KERN_NOTICE "Mainstone configured to boot from %s\n",
+              mainstone_maps[0].name);
+
+       for (i = 0; i < 2; i++) {
+               mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys,
+                                                WINDOW_SIZE);
+               if (!mainstone_maps[i].virt) {
+                       printk(KERN_WARNING "Failed to ioremap %s\n", 
+                              mainstone_maps[i].name);
+                       if (!ret)
+                               ret = -ENOMEM;
+                       continue;
+               }
+               mainstone_maps[i].cached = 
+                       ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE);
+               if (!mainstone_maps[i].cached)
+                       printk(KERN_WARNING "Failed to ioremap cached %s\n",
+                              mainstone_maps[i].name);
+               simple_map_init(&mainstone_maps[i]);
+
+               printk(KERN_NOTICE 
+                      "Probing %s at physical address 0x%08lx"
+                      " (%d-bit bankwidth)\n",
+                      mainstone_maps[i].name, mainstone_maps[i].phys, 
+                      mainstone_maps[i].bankwidth * 8);
+
+               mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]);
+               
+               if (!mymtds[i]) {
+                       iounmap((void *)mainstone_maps[i].virt);
+                       if (mainstone_maps[i].cached)
+                               iounmap(mainstone_maps[i].cached);
+                       if (!ret)
+                               ret = -EIO;
+                       continue;
+               }
+               mymtds[i]->owner = THIS_MODULE;
+
+               ret = parse_mtd_partitions(mymtds[i], probes,
+                                          &parsed_parts[i], 0);
+
+               if (ret > 0)
+                       nr_parsed_parts[i] = ret;
+       }
+
+       if (!mymtds[0] && !mymtds[1])
+               return ret;
+       
+       for (i = 0; i < 2; i++) {
+               if (!mymtds[i]) {
+                       printk(KERN_WARNING "%s is absent. Skipping\n", 
+                              mainstone_maps[i].name);
+               } else if (nr_parsed_parts[i]) {
+                       add_mtd_partitions(mymtds[i], parsed_parts[i], 
+                                          nr_parsed_parts[i]);
+               } else if (!i) {
+                       printk("Using static partitions on %s\n",
+                              mainstone_maps[i].name);
+                       add_mtd_partitions(mymtds[i], mainstone_partitions, 
+                                          ARRAY_SIZE(mainstone_partitions));
+               } else {
+                       printk("Registering %s as whole device\n", 
+                              mainstone_maps[i].name);
+                       add_mtd_device(mymtds[i]);
+               }
+       }
+       return 0;
+}
+
+static void __exit cleanup_mainstone(void)
+{
+       int i;
+       for (i = 0; i < 2; i++) {
+               if (!mymtds[i])
+                       continue;
+
+               if (nr_parsed_parts[i] || !i)
+                       del_mtd_partitions(mymtds[i]);
+               else
+                       del_mtd_device(mymtds[i]);
+
+               map_destroy(mymtds[i]);
+               iounmap((void *)mainstone_maps[i].virt);
+               if (mainstone_maps[i].cached)
+                       iounmap(mainstone_maps[i].cached);
+               kfree(parsed_parts[i]);
+       }
+}
+
+module_init(init_mainstone);
+module_exit(cleanup_mainstone);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
+MODULE_DESCRIPTION("MTD map driver for Intel Mainstone");
index 38f6a7af53f8f6e85fd786f04764e1bbaaedd447..9105e6ca0aa61de3be27f9063464e1c3372a9a25 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: map_funcs.c,v 1.9 2004/07/13 22:33:15 dwmw2 Exp $
+ * $Id: map_funcs.c,v 1.10 2005/06/06 23:04:36 tpoynor Exp $
  *
  * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS
  * is enabled.
@@ -9,23 +9,24 @@
 #include <linux/module.h>
 
 #include <linux/mtd/map.h>
+#include <linux/mtd/xip.h>
 
-static map_word simple_map_read(struct map_info *map, unsigned long ofs)
+static map_word __xipram simple_map_read(struct map_info *map, unsigned long ofs)
 {
        return inline_map_read(map, ofs);
 }
 
-static void simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
+static void __xipram simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
 {
        inline_map_write(map, datum, ofs);
 }
 
-static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+static void __xipram simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
 {
        inline_map_copy_from(map, to, from, len);
 }
 
-static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+static void __xipram simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
 {
        inline_map_copy_to(map, to, from, len);
 }
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c
new file mode 100644 (file)
index 0000000..8cc7140
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Flash memory support for various TI OMAP boards
+ *
+ * Copyright (C) 2001-2002 MontaVista Software Inc.
+ * Copyright (C) 2003-2004 Texas Instruments
+ * Copyright (C) 2004 Nokia Corporation 
+ *
+ *     Assembled using driver code copyright the companies above
+ *     and written by David Brownell, Jian Zhang <jzhang@ti.com>,
+ *     Tony Lindgren <tony@atomide.com> and others.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/flash.h>
+#include <asm/arch/tc.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL };
+#endif
+
+struct omapflash_info {
+       struct mtd_partition    *parts;
+       struct mtd_info         *mtd;
+       struct map_info         map;
+};
+
+static void omap_set_vpp(struct map_info *map, int enable)
+{
+       static int      count;
+
+       if (enable) {
+               if (count++ == 0)
+                       OMAP_EMIFS_CONFIG_REG |= OMAP_EMIFS_CONFIG_WP;
+       } else {
+               if (count && (--count == 0))
+                       OMAP_EMIFS_CONFIG_REG &= ~OMAP_EMIFS_CONFIG_WP;
+       }
+}
+
+static int __devinit omapflash_probe(struct device *dev)
+{
+       int err;
+       struct omapflash_info *info;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct flash_platform_data *pdata = pdev->dev.platform_data;
+       struct resource *res = pdev->resource;
+       unsigned long size = res->end - res->start + 1;
+
+       info = kmalloc(sizeof(struct omapflash_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       memset(info, 0, sizeof(struct omapflash_info));
+
+       if (!request_mem_region(res->start, size, "flash")) {
+               err = -EBUSY;
+               goto out_free_info;
+       }
+
+       info->map.virt          = ioremap(res->start, size);
+       if (!info->map.virt) {
+               err = -ENOMEM;
+               goto out_release_mem_region;
+       }
+       info->map.name          = pdev->dev.bus_id;
+       info->map.phys          = res->start;
+       info->map.size          = size;
+       info->map.bankwidth     = pdata->width;
+       info->map.set_vpp       = omap_set_vpp;
+
+       simple_map_init(&info->map);
+       info->mtd = do_map_probe(pdata->map_name, &info->map);
+       if (!info->mtd) {
+               err = -EIO;
+               goto out_iounmap;
+       }
+       info->mtd->owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       err = parse_mtd_partitions(info->mtd, part_probes, &info->parts, 0);
+       if (err > 0)
+               add_mtd_partitions(info->mtd, info->parts, err);
+       else if (err < 0 && pdata->parts)
+               add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts);
+       else
+#endif
+               add_mtd_device(info->mtd);
+
+       dev_set_drvdata(&pdev->dev, info);
+
+       return 0;
+
+out_iounmap:
+       iounmap(info->map.virt);
+out_release_mem_region:
+       release_mem_region(res->start, size);
+out_free_info:
+       kfree(info);
+
+       return err;
+}
+
+static int __devexit omapflash_remove(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct omapflash_info *info = dev_get_drvdata(&pdev->dev);
+
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       if (info) {
+               if (info->parts) {
+                       del_mtd_partitions(info->mtd);
+                       kfree(info->parts);
+               } else
+                       del_mtd_device(info->mtd);
+               map_destroy(info->mtd);
+               release_mem_region(info->map.phys, info->map.size);
+               iounmap((void __iomem *) info->map.virt);
+               kfree(info);
+       }
+
+       return 0;
+}
+
+static struct device_driver omapflash_driver = {
+       .name   = "omapflash",
+       .bus    = &platform_bus_type,
+       .probe  = omapflash_probe,
+       .remove = __devexit_p(omapflash_remove),
+};
+
+static int __init omapflash_init(void)
+{
+       return driver_register(&omapflash_driver);
+}
+
+static void __exit omapflash_exit(void)
+{
+       driver_unregister(&omapflash_driver);
+}
+
+module_init(omapflash_init);
+module_exit(omapflash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MTD NOR map driver for TI OMAP boards");
+
diff --git a/drivers/mtd/maps/pb1550-flash.c b/drivers/mtd/maps/pb1550-flash.c
deleted file mode 100644 (file)
index 1424726..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Flash memory access on Alchemy Pb1550 board
- * 
- * $Id: pb1550-flash.c,v 1.6 2004/11/04 13:24:15 gleixner Exp $
- *
- * (C) 2004 Embedded Edge, LLC, based on pb1550-flash.c:
- * (C) 2003 Pete Popov <ppopov@pacbell.net>
- * 
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/au1000.h>
-#include <asm/pb1550.h>
-
-#ifdef         DEBUG_RW
-#define        DBG(x...)       printk(x)
-#else
-#define        DBG(x...)       
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-
-
-static struct map_info pb1550_map = {
-       .name = "Pb1550 flash",
-};
-
-static unsigned char flash_bankwidth = 4;
-
-/* 
- * Support only 64MB NOR Flash parts
- */
-
-#ifdef PB1550_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first 
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition pb1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-        * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size =   (0x1FC00000 - 0x18000000),
-                .offset = 0x0000000
-        },{
-                .name = "yamon",
-                .size = 0x0100000,
-               .offset = MTDPART_OFS_APPEND,
-                .mask_flags = MTD_WRITEABLE
-        },{
-                .name = "raw kernel",
-               .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(PB1550_BOOT_ONLY)
-static struct mtd_partition pb1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size =   0x03c00000,
-                .offset = 0x0000000
-        },{
-                .name = "yamon",
-                .size = 0x0100000,
-               .offset = MTDPART_OFS_APPEND,
-                .mask_flags = MTD_WRITEABLE
-        },{
-                .name = "raw kernel",
-               .size = (0x300000-0x40000), /* last 256KB is yamon env */
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(PB1550_USER_ONLY)
-static struct mtd_partition pb1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
-                .offset = 0x0000000
-        },{
-                .name = "raw kernel",
-               .size = MTDPART_SIZ_FULL,
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#else
-#error MTD_PB1550 define combo error /* should never happen */
-#endif
-
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
-static struct mtd_info *mymtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
-       u16 boot_swapboot;
-       boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | 
-               ((bcsr->status >> 6)  & 0x1);
-       printk("Pb1550 MTD: boot:swap %d\n", boot_swapboot);
-
-       switch (boot_swapboot) {
-               case 0: /* 512Mbit devices, both enabled */
-               case 1: 
-               case 8:
-               case 9: 
-#if defined(PB1550_BOTH_BANKS)
-                       window_addr = 0x18000000;
-                       window_size = 0x8000000; 
-#elif defined(PB1550_BOOT_ONLY)
-                       window_addr = 0x1C000000;
-                       window_size = 0x4000000; 
-#else /* USER ONLY */
-                       window_addr = 0x1E000000;
-                       window_size = 0x4000000; 
-#endif
-                       break;
-               case 0xC:
-               case 0xD:
-               case 0xE:
-               case 0xF: 
-                       /* 64 MB Boot NOR Flash is disabled */
-                       /* and the start address is moved to 0x0C00000 */
-                       window_addr = 0x0C000000;
-                       window_size = 0x4000000; 
-               default:
-                       printk("Pb1550 MTD: unsupported boot:swap setting\n");
-                       return 1;
-       }
-       return 0;
-}
-
-int __init pb1550_mtd_init(void)
-{
-       struct mtd_partition *parts;
-       int nb_parts = 0;
-       
-       /* Default flash bankwidth */
-       pb1550_map.bankwidth = flash_bankwidth;
-
-       if (setup_flash_params()) 
-               return -ENXIO;
-
-       /*
-        * Static partition definition selection
-        */
-       parts = pb1550_partitions;
-       nb_parts = NB_OF(pb1550_partitions);
-       pb1550_map.size = window_size;
-
-       /*
-        * Now let's probe for the actual flash.  Do it here since
-        * specific machine settings might have been set above.
-        */
-       printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n", 
-                       pb1550_map.bankwidth*8);
-       pb1550_map.virt = ioremap(window_addr, window_size);
-       mymtd = do_map_probe("cfi_probe", &pb1550_map);
-       if (!mymtd) return -ENXIO;
-       mymtd->owner = THIS_MODULE;
-
-       add_mtd_partitions(mymtd, parts, nb_parts);
-       return 0;
-}
-
-static void __exit pb1550_mtd_cleanup(void)
-{
-       if (mymtd) {
-               del_mtd_partitions(mymtd);
-               map_destroy(mymtd);
-       }
-}
-
-module_init(pb1550_mtd_init);
-module_exit(pb1550_mtd_cleanup);
-
-MODULE_AUTHOR("Embedded Edge, LLC");
-MODULE_DESCRIPTION("Pb1550 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/pb1xxx-flash.c b/drivers/mtd/maps/pb1xxx-flash.c
deleted file mode 100644 (file)
index 06e7315..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Flash memory access on Alchemy Pb1xxx boards
- * 
- * (C) 2001 Pete Popov <ppopov@mvista.com>
- * 
- * $Id: pb1xxx-flash.c,v 1.14 2004/11/04 13:24:15 gleixner Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef         DEBUG_RW
-#define        DBG(x...)       printk(x)
-#else
-#define        DBG(x...)       
-#endif
-
-#ifdef CONFIG_MIPS_PB1000
-
-#define WINDOW_ADDR 0x1F800000
-#define WINDOW_SIZE 0x800000
-
-static struct mtd_partition pb1xxx_partitions[] = {
-        {
-                .name         =  "yamon env",
-                .size         =   0x00020000,
-                .offset       =   0,
-                .mask_flags   =   MTD_WRITEABLE},
-       {
-                .name         =   "User FS",
-                .size         =   0x003e0000,
-                .offset       =   0x20000,},
-       {
-                .name         =   "boot code",
-                .size         =   0x100000,
-                .offset       =   0x400000,
-                .mask_flags   =   MTD_WRITEABLE},
-       {
-                .name         =   "raw/kernel",
-                .size         =   0x300000,
-                .offset       =   0x500000}
-};
-
-#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
-
-#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-/* both 32MB banks will be used. Combine the first 32MB bank and the
- * first 28MB of the second bank together into a single jffs/jffs2
- * partition.
- */
-#define WINDOW_ADDR 0x1C000000
-#define WINDOW_SIZE 0x4000000
-static struct mtd_partition pb1xxx_partitions[] = {
-        {
-                .name         =   "User FS",
-                .size         =   0x3c00000,
-                .offset       =   0x0000000
-        },{
-                .name         =   "yamon",
-                .size         =   0x0100000,
-                .offset       =   0x3c00000,
-                .mask_flags   =   MTD_WRITEABLE
-        },{
-                .name         =   "raw kernel",
-                .size         =   0x02c0000,
-                .offset       =   0x3d00000
-        }
-};
-#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER)
-#define WINDOW_ADDR 0x1E000000
-#define WINDOW_SIZE 0x2000000
-static struct mtd_partition pb1xxx_partitions[] = {
-        {
-                .name         =   "User FS",
-                .size         =   0x1c00000,
-                .offset       =   0x0000000
-        },{
-                .name         =   "yamon",
-                .size         =   0x0100000,
-                .offset       =   0x1c00000,
-                .mask_flags   =   MTD_WRITEABLE
-        },{
-                .name         =   "raw kernel",
-                .size         =   0x02c0000,
-                .offset       =   0x1d00000
-        }
-};
-#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-#define WINDOW_ADDR 0x1C000000
-#define WINDOW_SIZE 0x2000000
-static struct mtd_partition pb1xxx_partitions[] = {
-        {
-                .name         =   "User FS",
-                .size         =    0x1e00000,
-                .offset       =    0x0000000
-        },{
-                .name         =    "raw kernel",
-                .size         =    0x0200000,
-                .offset       =    0x1e00000,
-        }
-};
-#else
-#error MTD_PB1500 define combo error /* should never happen */
-#endif
-#else
-#error Unsupported board
-#endif
-
-#define NAME           "Pb1x00 Linux Flash"
-#define PADDR          WINDOW_ADDR
-#define BUSWIDTH       4
-#define SIZE           WINDOW_SIZE
-#define PARTITIONS     4
-
-static struct map_info pb1xxx_mtd_map = {
-       .name           = NAME,
-       .size           = SIZE,
-       .bankwidth      = BUSWIDTH,
-       .phys           = PADDR,
-};
-
-static struct mtd_info *pb1xxx_mtd;
-
-int __init pb1xxx_mtd_init(void)
-{
-       struct mtd_partition *parts;
-       int nb_parts = 0;
-       char *part_type;
-       
-       /*
-        * Static partition definition selection
-        */
-       part_type = "static";
-       parts = pb1xxx_partitions;
-       nb_parts = ARRAY_SIZE(pb1xxx_partitions);
-
-       /*
-        * Now let's probe for the actual flash.  Do it here since
-        * specific machine settings might have been set above.
-        */
-       printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", 
-                       BUSWIDTH*8);
-       pb1xxx_mtd_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
-       simple_map_init(&pb1xxx_mtd_map);
-
-       pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map);
-       if (!pb1xxx_mtd) return -ENXIO;
-       pb1xxx_mtd->owner = THIS_MODULE;
-
-       add_mtd_partitions(pb1xxx_mtd, parts, nb_parts);
-       return 0;
-}
-
-static void __exit pb1xxx_mtd_cleanup(void)
-{
-       if (pb1xxx_mtd) {
-               del_mtd_partitions(pb1xxx_mtd);
-               map_destroy(pb1xxx_mtd);
-               iounmap((void *) pb1xxx_mtd_map.virt);
-       }
-}
-
-module_init(pb1xxx_mtd_init);
-module_exit(pb1xxx_mtd_cleanup);
-
-MODULE_AUTHOR("Pete Popov");
-MODULE_DESCRIPTION("Pb1xxx CFI map driver");
-MODULE_LICENSE("GPL");
index 08b60bdc53812949939c4aa4fed79638bd2125a0..18dbd3af1eaa652a34d4677a97f1742d4851d74c 100644 (file)
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  $Id: pci.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $
+ *  $Id: pci.c,v 1.10 2005/03/18 14:04:35 gleixner Exp $
  * 
  * Generic PCI memory map driver.  We support the following boards:
  *  - Intel IQ80310 ATU.
@@ -370,7 +370,7 @@ static struct pci_driver mtd_pci_driver = {
 
 static int __init mtd_pci_maps_init(void)
 {
-       return pci_module_init(&mtd_pci_driver);
+       return pci_register_driver(&mtd_pci_driver);
 }
 
 static void __exit mtd_pci_maps_exit(void)
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
new file mode 100644 (file)
index 0000000..118b045
--- /dev/null
@@ -0,0 +1,278 @@
+/* drivers/mtd/maps/plat-ram.c
+ *
+ * (c) 2004-2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/SWLINUX/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Generic platfrom device based RAM map
+ *
+ * $Id: plat-ram.c,v 1.3 2005/03/19 22:41:27 gleixner Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/plat-ram.h>
+
+#include <asm/io.h>
+
+/* private structure for each mtd platform ram device created */
+
+struct platram_info {
+       struct device           *dev;
+       struct mtd_info         *mtd;
+       struct map_info          map;
+       struct mtd_partition    *partitions;
+       struct resource         *area;
+       struct platdata_mtd_ram *pdata;
+};
+
+/* to_platram_info()
+ *
+ * device private data to struct platram_info conversion
+*/
+
+static inline struct platram_info *to_platram_info(struct device *dev)
+{
+       return (struct platram_info *)dev_get_drvdata(dev);
+}
+
+/* platram_setrw
+ *
+ * call the platform device's set rw/ro control
+ *
+ * to = 0 => read-only
+ *    = 1 => read-write
+*/
+
+static inline void platram_setrw(struct platram_info *info, int to)
+{
+       if (info->pdata == NULL)
+               return;
+
+       if (info->pdata->set_rw != NULL)
+               (info->pdata->set_rw)(info->dev, to);
+}
+
+/* platram_remove
+ *
+ * called to remove the device from the driver's control
+*/
+
+static int platram_remove(struct device *dev)
+{
+       struct platram_info *info = to_platram_info(dev);
+
+       dev_set_drvdata(dev, NULL);
+
+       dev_dbg(dev, "removing device\n");
+
+       if (info == NULL) 
+               return 0;
+
+       if (info->mtd) {
+#ifdef CONFIG_MTD_PARTITIONS
+               if (info->partitions) {
+                       del_mtd_partitions(info->mtd);
+                       kfree(info->partitions);
+               }
+#endif
+               del_mtd_device(info->mtd);
+               map_destroy(info->mtd);
+       }
+
+       /* ensure ram is left read-only */
+
+       platram_setrw(info, PLATRAM_RO);
+
+       /* release resources */
+
+       if (info->area) {
+               release_resource(info->area);
+               kfree(info->area);
+       }
+
+       if (info->map.virt != NULL)
+               iounmap(info->map.virt);
+       
+       kfree(info);
+
+       return 0;
+}
+
+/* platram_probe
+ *
+ * called from device drive system when a device matching our
+ * driver is found.
+*/
+
+static int platram_probe(struct device *dev)
+{
+       struct platform_device *pd = to_platform_device(dev);
+       struct platdata_mtd_ram *pdata;
+       struct platram_info *info;
+       struct resource *res;
+       int err = 0;
+
+       dev_dbg(dev, "probe entered\n");
+       
+       if (dev->platform_data == NULL) {
+               dev_err(dev, "no platform data supplied\n");
+               err = -ENOENT;
+               goto exit_error;
+       }
+
+       pdata = dev->platform_data;
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (info == NULL) {
+               dev_err(dev, "no memory for flash info\n");
+               err = -ENOMEM;
+               goto exit_error;
+       }
+
+       memset(info, 0, sizeof(*info));
+       dev_set_drvdata(dev, info);
+
+       info->dev = dev;
+       info->pdata = pdata;
+
+       /* get the resource for the memory mapping */
+
+       res = platform_get_resource(pd, IORESOURCE_MEM, 0);
+
+       if (res == NULL) {
+               dev_err(dev, "no memory resource specified\n");
+               err = -ENOENT;
+               goto exit_free;
+       }
+
+       dev_dbg(dev, "got platform resource %p (0x%lx)\n", res, res->start);
+
+       /* setup map parameters */
+
+       info->map.phys = res->start;
+       info->map.size = (res->end - res->start) + 1;
+       info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name;
+       info->map.bankwidth = pdata->bankwidth;
+
+       /* register our usage of the memory area */
+
+       info->area = request_mem_region(res->start, info->map.size, pd->name);
+       if (info->area == NULL) {
+               dev_err(dev, "failed to request memory region\n");
+               err = -EIO;
+               goto exit_free;
+       }
+
+       /* remap the memory area */
+
+       info->map.virt = ioremap(res->start, info->map.size);
+       dev_dbg(dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size);
+
+       if (info->map.virt == NULL) {
+               dev_err(dev, "failed to ioremap() region\n");
+               err = -EIO;
+               goto exit_free;
+       }
+
+       simple_map_init(&info->map);
+
+       dev_dbg(dev, "initialised map, probing for mtd\n");
+
+       /* probe for the right mtd map driver */
+
+       info->mtd = do_map_probe("map_ram" , &info->map);
+       if (info->mtd == NULL) {
+               dev_err(dev, "failed to probe for map_ram\n");
+               err = -ENOMEM;
+               goto exit_free;
+       }
+
+       info->mtd->owner = THIS_MODULE;
+
+       platram_setrw(info, PLATRAM_RW);
+
+       /* check to see if there are any available partitions, or wether
+        * to add this device whole */
+
+#ifdef CONFIG_MTD_PARTITIONS
+       if (pdata->nr_partitions > 0) {
+               const char **probes = { NULL };
+
+               if (pdata->probes)
+                       probes = (const char **)pdata->probes;
+
+               err = parse_mtd_partitions(info->mtd, probes,
+                                          &info->partitions, 0);
+               if (err > 0) {
+                       err = add_mtd_partitions(info->mtd, info->partitions,
+                                                err);
+               }
+       }
+#endif /* CONFIG_MTD_PARTITIONS */
+
+       if (add_mtd_device(info->mtd)) {
+               dev_err(dev, "add_mtd_device() failed\n");
+               err = -ENOMEM;
+       }
+       
+       dev_info(dev, "registered mtd device\n");
+       return err;
+
+ exit_free:
+       platram_remove(dev);
+ exit_error:
+       return err;
+}
+
+/* device driver info */
+
+static struct device_driver platram_driver = {
+       .name           = "mtd-ram",
+       .bus            = &platform_bus_type,
+       .probe          = platram_probe,
+       .remove         = platram_remove,
+};
+
+/* module init/exit */
+
+static int __init platram_init(void)
+{
+       printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n");
+       return driver_register(&platram_driver);
+}
+
+static void __exit platram_exit(void)
+{
+       driver_unregister(&platram_driver);
+}
+
+module_init(platram_init);
+module_exit(platram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("MTD platform RAM map driver");
index 5bb3b600e5d0cc8ab3e827e303a7a3b719a3347f..97a8dfd69258188a29bea7afd3c64c08a594fbbe 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * MTD map driver for BIOS Flash on Intel SCB2 boards
- * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $
+ * $Id: scb2_flash.c,v 1.12 2005/03/18 14:04:35 gleixner Exp $
  * Copyright (C) 2002 Sun Microsystems, Inc.
  * Tim Hockin <thockin@sun.com>
  *
@@ -238,7 +238,7 @@ static struct pci_driver scb2_flash_driver = {
 static int __init
 scb2_flash_init(void)
 {
-       return pci_module_init(&scb2_flash_driver);
+       return pci_register_driver(&scb2_flash_driver);
 }
 
 static void __exit
index b3b39cb7c608f6f2c0b871d00422cd1e4db6e75f..d15da6fd84c10fce1c41aaba3f96a87afe997816 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2001 Lineo Japan, Inc.
  * Copyright (C) 2002  SHARP
  *
- * $Id: sharpsl-flash.c,v 1.2 2004/11/24 20:38:06 rpurdie Exp $
+ * $Id: sharpsl-flash.c,v 1.5 2005/03/21 08:42:11 rpurdie Exp $
  *
  * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp
  *          Handle mapping of the flash on the RPX Lite and CLLF boards
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
 
 #define WINDOW_ADDR 0x00000000
-#define WINDOW_SIZE 0x01000000
+#define WINDOW_SIZE 0x00800000
 #define BANK_WIDTH 2
 
 static struct mtd_info *mymtd;
@@ -44,9 +45,7 @@ struct map_info sharpsl_map = {
 
 static struct mtd_partition sharpsl_partitions[1] = {
        {
-               name:           "Filesystem",
-               size:           0x006d0000,
-               offset:         0x00120000
+               name:           "Boot PROM Filesystem",
        }
 };
 
@@ -58,12 +57,16 @@ int __init init_sharpsl(void)
        int nb_parts = 0;
        char *part_type = "static";
 
-       printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+       printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", 
+               WINDOW_SIZE, WINDOW_ADDR);
        sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
        if (!sharpsl_map.virt) {
                printk("Failed to ioremap\n");
                return -EIO;
        }
+
+       simple_map_init(&sharpsl_map);
+
        mymtd = do_map_probe("map_rom", &sharpsl_map);
        if (!mymtd) {
                iounmap(sharpsl_map.virt);
@@ -72,6 +75,22 @@ int __init init_sharpsl(void)
 
        mymtd->owner = THIS_MODULE;
 
+       if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() 
+               || machine_is_poodle()) {
+               sharpsl_partitions[0].size=0x006d0000;
+               sharpsl_partitions[0].offset=0x00120000;
+       } else if (machine_is_tosa()) {
+               sharpsl_partitions[0].size=0x006a0000;
+               sharpsl_partitions[0].offset=0x00160000;
+       } else if (machine_is_spitz()) {
+               sharpsl_partitions[0].size=0x006b0000;
+               sharpsl_partitions[0].offset=0x00140000;
+       } else {
+               map_destroy(mymtd);
+               iounmap(sharpsl_map.virt);      
+               return -ENODEV;
+       }
+       
        parts = sharpsl_partitions;
        nb_parts = NB_OF(sharpsl_partitions);
 
index 510ad78312cc67155a22813b8c893c8ad4011004..1ed602a0f24cb617fd06cc27fd70d72399380b67 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdchar.c,v 1.66 2005/01/05 18:05:11 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.73 2005/07/04 17:36:41 gleixner Exp $
  *
  * Character-device access to raw MTD devices.
  *
 #include <linux/fs.h>
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
+#include <linux/device.h>
+
+static struct class *mtd_class;
 
 static void mtd_notify_add(struct mtd_info* mtd)
 {
        if (!mtd)
                return;
 
-       devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
-                     S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
-               
-       devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
-                     S_IFCHR | S_IRUGO, "mtd/%dro", mtd->index);
+       class_device_create(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
+                           NULL, "mtd%d", mtd->index);
+       
+       class_device_create(mtd_class, 
+                           MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
+                           NULL, "mtd%dro", mtd->index);
 }
 
 static void mtd_notify_remove(struct mtd_info* mtd)
 {
        if (!mtd)
                return;
-       devfs_remove("mtd/%d", mtd->index);
-       devfs_remove("mtd/%dro", mtd->index);
+
+       class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
+       class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
 }
 
 static struct mtd_notifier notifier = {
@@ -43,25 +46,25 @@ static struct mtd_notifier notifier = {
        .remove = mtd_notify_remove,
 };
 
-static inline void mtdchar_devfs_init(void)
-{
-       devfs_mk_dir("mtd");
-       register_mtd_user(&notifier);
-}
+/*
+ * We use file->private_data to store a pointer to the MTDdevice.
+ * Since alighment is at least 32 bits, we have 2 bits free for OTP
+ * modes as well.
+ */
 
-static inline void mtdchar_devfs_exit(void)
-{
-       unregister_mtd_user(&notifier);
-       devfs_remove("mtd");
-}
-#else /* !DEVFS */
-#define mtdchar_devfs_init() do { } while(0)
-#define mtdchar_devfs_exit() do { } while(0)
-#endif
+#define TO_MTD(file) (struct mtd_info *)((long)((file)->private_data) & ~3L)
+
+#define MTD_MODE_OTP_FACT      1
+#define MTD_MODE_OTP_USER      2
+#define MTD_MODE(file)         ((long)((file)->private_data) & 3)
+
+#define SET_MTD_MODE(file, mode) \
+       do { long __p = (long)((file)->private_data); \
+            (file)->private_data = (void *)((__p & ~3L) | mode); } while (0)
 
 static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
 {
-       struct mtd_info *mtd = file->private_data;
+       struct mtd_info *mtd = TO_MTD(file);
 
        switch (orig) {
        case 0:
@@ -134,7 +137,7 @@ static int mtd_close(struct inode *inode, struct file *file)
 
        DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
 
-       mtd = file->private_data;
+       mtd = TO_MTD(file);
        
        if (mtd->sync)
                mtd->sync(mtd);
@@ -151,7 +154,7 @@ static int mtd_close(struct inode *inode, struct file *file)
 
 static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
 {
-       struct mtd_info *mtd = file->private_data;
+       struct mtd_info *mtd = TO_MTD(file);
        size_t retlen=0;
        size_t total_retlen=0;
        int ret=0;
@@ -178,7 +181,16 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
                if (!kbuf)
                        return -ENOMEM;
                
-               ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+               switch (MTD_MODE(file)) {
+               case MTD_MODE_OTP_FACT:
+                       ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+                       break;
+               case MTD_MODE_OTP_USER:
+                       ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+                       break;
+               default:
+                       ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+               }
                /* Nand returns -EBADMSG on ecc errors, but it returns
                 * the data. For our userspace tools it is important
                 * to dump areas with ecc errors ! 
@@ -196,6 +208,8 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
 
                        count -= retlen;
                        buf += retlen;
+                       if (retlen == 0)
+                               count = 0;
                }
                else {
                        kfree(kbuf);
@@ -210,7 +224,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
 
 static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
 {
-       struct mtd_info *mtd = file->private_data;
+       struct mtd_info *mtd = TO_MTD(file);
        char *kbuf;
        size_t retlen;
        size_t total_retlen=0;
@@ -245,7 +259,20 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
                        return -EFAULT;
                }
                
-               ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
+               switch (MTD_MODE(file)) {
+               case MTD_MODE_OTP_FACT:
+                       ret = -EROFS;
+                       break;
+               case MTD_MODE_OTP_USER:
+                       if (!mtd->write_user_prot_reg) {
+                               ret = -EOPNOTSUPP;
+                               break;
+                       }
+                       ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+                       break;
+               default:
+                       ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
+               }
                if (!ret) {
                        *ppos += retlen;
                        total_retlen += retlen;
@@ -276,7 +303,7 @@ static void mtdchar_erase_callback (struct erase_info *instr)
 static int mtd_ioctl(struct inode *inode, struct file *file,
                     u_int cmd, u_long arg)
 {
-       struct mtd_info *mtd = file->private_data;
+       struct mtd_info *mtd = TO_MTD(file);
        void __user *argp = (void __user *)arg;
        int ret = 0;
        u_long size;
@@ -518,6 +545,80 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                break;
        }
 
+#ifdef CONFIG_MTD_OTP
+       case OTPSELECT:
+       {
+               int mode;
+               if (copy_from_user(&mode, argp, sizeof(int)))
+                       return -EFAULT;
+               SET_MTD_MODE(file, 0);
+               switch (mode) {
+               case MTD_OTP_FACTORY:
+                       if (!mtd->read_fact_prot_reg)
+                               ret = -EOPNOTSUPP;
+                       else
+                               SET_MTD_MODE(file, MTD_MODE_OTP_FACT);
+                       break;
+               case MTD_OTP_USER:
+                       if (!mtd->read_fact_prot_reg)
+                               ret = -EOPNOTSUPP;
+                       else
+                               SET_MTD_MODE(file, MTD_MODE_OTP_USER);
+                       break;
+               default:
+                       ret = -EINVAL;
+               case MTD_OTP_OFF:
+                       break;
+               }
+               file->f_pos = 0;
+               break;
+       }
+
+       case OTPGETREGIONCOUNT:
+       case OTPGETREGIONINFO:
+       {
+               struct otp_info *buf = kmalloc(4096, GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+               ret = -EOPNOTSUPP;
+               switch (MTD_MODE(file)) {
+               case MTD_MODE_OTP_FACT:
+                       if (mtd->get_fact_prot_info)
+                               ret = mtd->get_fact_prot_info(mtd, buf, 4096);
+                       break;
+               case MTD_MODE_OTP_USER:
+                       if (mtd->get_user_prot_info)
+                               ret = mtd->get_user_prot_info(mtd, buf, 4096);
+                       break;
+               }
+               if (ret >= 0) {
+                       if (cmd == OTPGETREGIONCOUNT) {
+                               int nbr = ret / sizeof(struct otp_info);
+                               ret = copy_to_user(argp, &nbr, sizeof(int));
+                       } else
+                               ret = copy_to_user(argp, buf, ret);
+                       if (ret)
+                               ret = -EFAULT;
+               }
+               kfree(buf);
+               break;
+       }
+
+       case OTPLOCK:
+       {
+               struct otp_info info;
+
+               if (MTD_MODE(file) != MTD_MODE_OTP_USER)
+                       return -EINVAL;
+               if (copy_from_user(&info, argp, sizeof(info)))
+                       return -EFAULT;
+               if (!mtd->lock_user_prot_reg)
+                       return -EOPNOTSUPP;
+               ret = mtd->lock_user_prot_reg(mtd, info.start, info.length);
+               break;
+       }
+#endif
+
        default:
                ret = -ENOTTY;
        }
@@ -543,13 +644,22 @@ static int __init init_mtdchar(void)
                return -EAGAIN;
        }
 
-       mtdchar_devfs_init();
+       mtd_class = class_create(THIS_MODULE, "mtd");
+
+       if (IS_ERR(mtd_class)) {
+               printk(KERN_ERR "Error creating mtd class.\n");
+               unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
+               return PTR_ERR(mtd_class);
+       }
+
+       register_mtd_user(&notifier);
        return 0;
 }
 
 static void __exit cleanup_mtdchar(void)
 {
-       mtdchar_devfs_exit();
+       unregister_mtd_user(&notifier);
+       class_destroy(mtd_class);
        unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
 }
 
index 9c0315d1b1c4f59fa7ffd123b2c0e9063ea529b5..dc86df18e94b72768ce0d7beaaf06e629c9217a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdcore.c,v 1.44 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $
  *
  * Core registration and callback routines for MTD
  * drivers and users.
@@ -149,8 +149,8 @@ void register_mtd_user (struct mtd_notifier *new)
 }
 
 /**
- *     register_mtd_user - unregister a 'user' of MTD devices.
- *     @new: pointer to notifier info structure
+ *     unregister_mtd_user - unregister a 'user' of MTD devices.
+ *     @old: pointer to notifier info structure
  *
  *     Removes a callback function pair from the list of 'users' to be
  *     notified upon addition or removal of MTD devices. Causes the
index 96ebb52f24b1cdb4ea4cd2a6499d8fd9aef0bd86..b92e6bfffaf2afa78cf3aad8fe38d7248509200c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.51 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $
  *
  *     02-21-2002      Thomas Gleixner <gleixner@autronix.de>
  *                     added support for read_oob, write_oob
@@ -116,6 +116,13 @@ static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
                                        len, retlen, buf);
 }
 
+static int part_get_user_prot_info (struct mtd_info *mtd,
+                                   struct otp_info *buf, size_t len)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->get_user_prot_info (part->master, buf, len);
+}
+
 static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
                        size_t *retlen, u_char *buf)
 {
@@ -124,6 +131,13 @@ static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
                                        len, retlen, buf);
 }
 
+static int part_get_fact_prot_info (struct mtd_info *mtd,
+                                   struct otp_info *buf, size_t len)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->get_fact_prot_info (part->master, buf, len);
+}
+
 static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
                        size_t *retlen, const u_char *buf)
 {
@@ -182,6 +196,12 @@ static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t l
                                        len, retlen, buf);
 }
 
+static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) 
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->lock_user_prot_reg (part->master, from, len);
+}
+
 static int part_writev (struct mtd_info *mtd,  const struct kvec *vecs,
                         unsigned long count, loff_t to, size_t *retlen)
 {
@@ -409,6 +429,12 @@ int add_mtd_partitions(struct mtd_info *master,
                        slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
                if(master->write_user_prot_reg)
                        slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
+               if(master->lock_user_prot_reg)
+                       slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
+               if(master->get_user_prot_info)
+                       slave->mtd.get_user_prot_info = part_get_user_prot_info;
+               if(master->get_fact_prot_info)
+                       slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
                if (master->sync)
                        slave->mtd.sync = part_sync;
                if (!i && master->suspend && master->resume) {
index f7801eb730cede7b0c844fc892f9cc30fe51a13d..36d34e5e5a5ac21530593130d499aa5d0d0ec153 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/nand/Kconfig
-# $Id: Kconfig,v 1.26 2005/01/05 12:42:24 dwmw2 Exp $
+# $Id: Kconfig,v 1.31 2005/06/20 12:03:21 bjd Exp $
 
 menu "NAND Flash Device Drivers"
        depends on MTD!=n
@@ -58,20 +58,6 @@ config MTD_NAND_TOTO
 config MTD_NAND_IDS
        tristate
 
-config MTD_NAND_TX4925NDFMC
-       tristate "SmartMedia Card on Toshiba RBTX4925 reference board"
-       depends on TOSHIBA_RBTX4925 && MTD_NAND && TOSHIBA_RBTX4925_MPLEX_NAND
-       help
-         This enables the driver for the NAND flash device found on the
-         Toshiba RBTX4925 reference board, which is a SmartMediaCard.
-
-config MTD_NAND_TX4938NDFMC
-       tristate "NAND Flash device on Toshiba RBTX4938 reference board"
-       depends on TOSHIBA_RBTX4938 && MTD_NAND && TOSHIBA_RBTX4938_MPLEX_NAND 
-       help
-         This enables the driver for the NAND flash device found on the
-         Toshiba RBTX4938 reference board.
-
 config MTD_NAND_AU1550
        tristate "Au1550 NAND support"
        depends on SOC_AU1550 && MTD_NAND
@@ -95,10 +81,11 @@ config MTD_NAND_PPCHAMELEONEVB
          This enables the NAND flash driver on the PPChameleon EVB Board.
 
 config MTD_NAND_S3C2410
-       tristate "NAND Flash support for S3C2410 SoC"
+       tristate "NAND Flash support for S3C2410/S3C2440 SoC"
        depends on ARCH_S3C2410 && MTD_NAND
        help
-         This enables the NAND flash controller on the S3C2410.
+         This enables the NAND flash controller on the S3C2410 and S3C2440
+         SoCs
 
          No board specfic support is done by this driver, each board
          must advertise a platform_device for the driver to attach. 
index d9dc8cc2da8c77e365ac4313468ca46e4399caaa..41742026a52e7e45033f8a37ef57d7b0222c55df 100644 (file)
@@ -10,8 +10,6 @@ obj-$(CONFIG_MTD_NAND_SPIA)           += spia.o
 obj-$(CONFIG_MTD_NAND_TOTO)            += toto.o
 obj-$(CONFIG_MTD_NAND_AUTCPU12)                += autcpu12.o
 obj-$(CONFIG_MTD_NAND_EDB7312)         += edb7312.o
-obj-$(CONFIG_MTD_NAND_TX4925NDFMC)     += tx4925ndfmc.o
-obj-$(CONFIG_MTD_NAND_TX4938NDFMC)     += tx4938ndfmc.o
 obj-$(CONFIG_MTD_NAND_AU1550)          += au1550nd.o
 obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)  += ppchameleonevb.o
 obj-$(CONFIG_MTD_NAND_S3C2410)         += s3c2410.o
index 02135c3ac29a0372f19a05784cb7da8e90f38245..fdb5d4ad3d526d0953629e26b5c433b07e5231ac 100644 (file)
@@ -16,7 +16,7 @@
  *  
  * Interface to generic NAND code for M-Systems DiskOnChip devices
  *
- * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $
+ * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $
  */
 
 #include <linux/kernel.h>
 #include <linux/mtd/inftl.h>
 
 /* Where to look for the devices? */
-#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS
-#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0
+#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
 #endif
 
 static unsigned long __initdata doc_locations[] = {
 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
-#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH
+#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
        0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 
        0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
        0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, 
@@ -81,11 +81,6 @@ struct doc_priv {
        struct mtd_info *nextdoc;
 };
 
-/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL
-   MediaHeader.  The spec says to just keep going, I think, but that's just
-   silly. */
-#define MAX_MEDIAHEADER_SCAN 8
-
 /* This is the syndrome computed by the HW ecc generator upon reading an empty
    page, one with all 0xff for data and stored ecc code. */
 static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
@@ -111,10 +106,11 @@ module_param(try_dword, int, 0);
 static int no_ecc_failures=0;
 module_param(no_ecc_failures, int, 0);
 
-#ifdef CONFIG_MTD_PARTITIONS
 static int no_autopart=0;
 module_param(no_autopart, int, 0);
-#endif
+
+static int show_firmware_partition=0;
+module_param(show_firmware_partition, int, 0);
 
 #ifdef MTD_NAND_DISKONCHIP_BBTWRITE
 static int inftl_bbt_write=1;
@@ -123,7 +119,7 @@ static int inftl_bbt_write=0;
 #endif
 module_param(inftl_bbt_write, int, 0);
 
-static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
+static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
 module_param(doc_config_location, ulong, 0);
 MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
 
@@ -410,7 +406,12 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
        doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
        this->write_byte(mtd, 0);
        doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
-
+       
+       /* We cant' use dev_ready here, but at least we wait for the
+        * command to complete 
+        */
+       udelay(50);
+       
        ret = this->read_byte(mtd) << 8;
        ret |= this->read_byte(mtd);
 
@@ -429,6 +430,8 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
                doc2000_write_byte(mtd, 0);
                doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
 
+               udelay(50);
+
                ident.dword = readl(docptr + DoC_2k_CDSN_IO);
                if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
                        printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
@@ -1046,11 +1049,21 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
                
 //u_char mydatabuf[528];
 
+/* The strange out-of-order .oobfree list below is a (possibly unneeded)
+ * attempt to retain compatibility.  It used to read:
+ *     .oobfree = { {8, 8} }
+ * Since that leaves two bytes unusable, it was changed.  But the following
+ * scheme might affect existing jffs2 installs by moving the cleanmarker:
+ *     .oobfree = { {6, 10} }
+ * jffs2 seems to handle the above gracefully, but the current scheme seems
+ * safer.  The only problem with it is that any code that parses oobfree must
+ * be able to handle out-of-order segments.
+ */
 static struct nand_oobinfo doc200x_oobinfo = {
         .useecc = MTD_NANDECC_AUTOPLACE,
         .eccbytes = 6,
         .eccpos = {0, 1, 2, 3, 4, 5},
-        .oobfree = { {8, 8} }
+        .oobfree = { {8, 8}, {6, 2} }
 };
  
 /* Find the (I)NFTL Media Header, and optionally also the mirror media header.
@@ -1064,12 +1077,11 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = this->priv;
-       unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
+       unsigned offs;
        int ret;
        size_t retlen;
 
-       end = min(end, mtd->size); // paranoia
-       for (offs = 0; offs < end; offs += mtd->erasesize) {
+       for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
                ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
                if (retlen != mtd->oobblock) continue;
                if (ret) {
@@ -1111,6 +1123,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
        u_char *buf;
        struct NFTLMediaHeader *mh;
        const unsigned psize = 1 << this->page_shift;
+       int numparts = 0;
        unsigned blocks, maxblocks;
        int offs, numheaders;
 
@@ -1122,8 +1135,10 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
        if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
        mh = (struct NFTLMediaHeader *) buf;
 
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-//     if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+       mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits);
+       mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN);
+       mh->FormattedSize = le32_to_cpu(mh->FormattedSize);
+
        printk(KERN_INFO "    DataOrgID        = %s\n"
                         "    NumEraseUnits    = %d\n"
                         "    FirstPhysicalEUN = %d\n"
@@ -1132,7 +1147,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
                mh->DataOrgID, mh->NumEraseUnits,
                mh->FirstPhysicalEUN, mh->FormattedSize,
                mh->UnitSizeFactor);
-//#endif
 
        blocks = mtd->size >> this->phys_erase_shift;
        maxblocks = min(32768U, mtd->erasesize - psize);
@@ -1175,23 +1189,28 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
        offs <<= this->page_shift;
        offs += mtd->erasesize;
 
-       //parts[0].name = " DiskOnChip Boot / Media Header partition";
-       //parts[0].offset = 0;
-       //parts[0].size = offs;
+       if (show_firmware_partition == 1) {
+               parts[0].name = " DiskOnChip Firmware / Media Header partition";
+               parts[0].offset = 0;
+               parts[0].size = offs;
+               numparts = 1;
+       }
 
-       parts[0].name = " DiskOnChip BDTL partition";
-       parts[0].offset = offs;
-       parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+       parts[numparts].name = " DiskOnChip BDTL partition";
+       parts[numparts].offset = offs;
+       parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+
+       offs += parts[numparts].size;
+       numparts++;
 
-       offs += parts[0].size;
        if (offs < mtd->size) {
-               parts[1].name = " DiskOnChip Remainder partition";
-               parts[1].offset = offs;
-               parts[1].size = mtd->size - offs;
-               ret = 2;
-               goto out;
+               parts[numparts].name = " DiskOnChip Remainder partition";
+               parts[numparts].offset = offs;
+               parts[numparts].size = mtd->size - offs;
+               numparts++;
        }
-       ret = 1;
+
+       ret = numparts;
 out:
        kfree(buf);
        return ret;
@@ -1233,8 +1252,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
        mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
        mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
  
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-//     if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
        printk(KERN_INFO "    bootRecordID          = %s\n"
                         "    NoOfBootImageBlocks   = %d\n"
                         "    NoOfBinaryPartitions  = %d\n"
@@ -1252,7 +1269,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
                ((unsigned char *) &mh->OsakVersion)[2] & 0xf,
                ((unsigned char *) &mh->OsakVersion)[3] & 0xf,
                mh->PercentUsed);
-//#endif
 
        vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
 
@@ -1278,8 +1294,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
                ip->spareUnits = le32_to_cpu(ip->spareUnits);
                ip->Reserved0 = le32_to_cpu(ip->Reserved0);
 
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-//             if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
                printk(KERN_INFO        "    PARTITION[%d] ->\n"
                        "        virtualUnits    = %d\n"
                        "        firstUnit       = %d\n"
@@ -1289,16 +1303,14 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
                        i, ip->virtualUnits, ip->firstUnit,
                        ip->lastUnit, ip->flags,
                        ip->spareUnits);
-//#endif
 
-/*
-               if ((i == 0) && (ip->firstUnit > 0)) {
+               if ((show_firmware_partition == 1) &&
+                   (i == 0) && (ip->firstUnit > 0)) {
                        parts[0].name = " DiskOnChip IPL / Media Header partition";
                        parts[0].offset = 0;
                        parts[0].size = mtd->erasesize * ip->firstUnit;
                        numparts = 1;
                }
-*/
 
                if (ip->flags & INFTL_BINARY)
                        parts[numparts].name = " DiskOnChip BDK partition";
index 44d5b128911f665a6071565216c3a786ade11acf..1bd71a598c798f845a1331ec8655a796903972bc 100644 (file)
  *             among multiple independend devices. Suggestions and initial patch
  *             from Ben Dooks <ben-mtd@fluff.org>
  *
+ *  12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
+ *             Basically, any block not rewritten may lose data when surrounding blocks
+ *             are rewritten many times.  JFFS2 ensures this doesn't happen for blocks 
+ *             it uses, but the Bad Block Table(s) may not be rewritten.  To ensure they
+ *             do not lose data, force them to be rewritten when some of the surrounding
+ *             blocks are erased.  Rather than tracking a specific nearby block (which 
+ *             could itself go bad), use a page address 'mask' to select several blocks 
+ *             in the same area, and rewrite the BBT when any of them are erased.
+ *
+ *  01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas 
+ *             AG-AND chips.  If there was a sudden loss of power during an erase operation,
+ *             a "device recovery" operation must be performed when power is restored
+ *             to ensure correct operation.
+ *
+ *  01-20-2005 dmarlin: added support for optional hardware specific callback routine to 
+ *             perform extra error status checks on erase and write failures.  This required
+ *             adding a wrapper function for nand_read_ecc.
+ *
  * Credits:
  *     David Woodhouse for adding multichip support  
  *     
@@ -41,7 +59,7 @@
  *     The AG-AND chips have nice features for speed improvement,
  *     which are not supported yet. Read / program 4 pages in one go.
  *
- * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen Exp $
+ * $Id: nand_base.c,v 1.146 2005/06/17 15:02:06 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -149,17 +167,21 @@ static void nand_release_device (struct mtd_info *mtd)
 
        /* De-select the NAND device */
        this->select_chip(mtd, -1);
-       /* Do we have a hardware controller ? */
+
        if (this->controller) {
+               /* Release the controller and the chip */
                spin_lock(&this->controller->lock);
                this->controller->active = NULL;
+               this->state = FL_READY;
+               wake_up(&this->controller->wq);
                spin_unlock(&this->controller->lock);
+       } else {
+               /* Release the chip */
+               spin_lock(&this->chip_lock);
+               this->state = FL_READY;
+               wake_up(&this->wq);
+               spin_unlock(&this->chip_lock);
        }
-       /* Release the chip */
-       spin_lock (&this->chip_lock);
-       this->state = FL_READY;
-       wake_up (&this->wq);
-       spin_unlock (&this->chip_lock);
 }
 
 /**
@@ -443,7 +465,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
        
        /* Get block number */
        block = ((int) ofs) >> this->bbt_erase_shift;
-       this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+       if (this->bbt)
+               this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
 
        /* Do we have a flash based bad block table ? */
        if (this->options & NAND_USE_FLASH_BBT)
@@ -466,7 +489,7 @@ static int nand_check_wp (struct mtd_info *mtd)
        struct nand_chip *this = mtd->priv;
        /* Check the WP bit */
        this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-       return (this->read_byte(mtd) & 0x80) ? 0 : 1; 
+       return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; 
 }
 
 /**
@@ -490,6 +513,22 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i
        return nand_isbad_bbt (mtd, ofs, allowbbt);
 }
 
+/* 
+ * Wait for the ready pin, after a command
+ * The timeout is catched later.
+ */
+static void nand_wait_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       unsigned long   timeo = jiffies + 2;
+
+       /* wait until command is processed or timeout occures */
+       do {
+               if (this->dev_ready(mtd))
+                       return;
+       } while (time_before(jiffies, timeo));  
+}
+
 /**
  * nand_command - [DEFAULT] Send command to NAND device
  * @mtd:       MTD device structure
@@ -571,7 +610,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
                this->hwcontrol(mtd, NAND_CTL_SETCLE);
                this->write_byte(mtd, NAND_CMD_STATUS);
                this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-               while ( !(this->read_byte(mtd) & 0x40));
+               while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
                return;
 
        /* This applies to read commands */     
@@ -585,12 +624,11 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
                        return;
                }       
        }
-       
        /* Apply this short delay always to ensure that we do wait tWB in
         * any case on any machine. */
        ndelay (100);
-       /* wait until command is processed */
-       while (!this->dev_ready(mtd));
+
+       nand_wait_ready(mtd);
 }
 
 /**
@@ -619,7 +657,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
        /* Begin command latch cycle */
        this->hwcontrol(mtd, NAND_CTL_SETCLE);
        /* Write out the command to the device. */
-       this->write_byte(mtd, command);
+       this->write_byte(mtd, (command & 0xff));
        /* End command latch cycle */
        this->hwcontrol(mtd, NAND_CTL_CLRCLE);
 
@@ -647,8 +685,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
        
        /* 
         * program and erase have their own busy handlers 
-        * status and sequential in needs no delay
-       */
+        * status, sequential in, and deplete1 need no delay
+        */
        switch (command) {
                        
        case NAND_CMD_CACHEDPROG:
@@ -657,8 +695,19 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
        case NAND_CMD_ERASE2:
        case NAND_CMD_SEQIN:
        case NAND_CMD_STATUS:
+       case NAND_CMD_DEPLETE1:
                return;
 
+       /* 
+        * read error status commands require only a short delay
+        */
+       case NAND_CMD_STATUS_ERROR:
+       case NAND_CMD_STATUS_ERROR0:
+       case NAND_CMD_STATUS_ERROR1:
+       case NAND_CMD_STATUS_ERROR2:
+       case NAND_CMD_STATUS_ERROR3:
+               udelay(this->chip_delay);
+               return;
 
        case NAND_CMD_RESET:
                if (this->dev_ready)    
@@ -667,7 +716,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
                this->hwcontrol(mtd, NAND_CTL_SETCLE);
                this->write_byte(mtd, NAND_CMD_STATUS);
                this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-               while ( !(this->read_byte(mtd) & 0x40));
+               while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
                return;
 
        case NAND_CMD_READ0:
@@ -690,12 +739,12 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
                        return;
                }       
        }
-       
+
        /* Apply this short delay always to ensure that we do wait tWB in
         * any case on any machine. */
        ndelay (100);
-       /* wait until command is processed */
-       while (!this->dev_ready(mtd));
+
+       nand_wait_ready(mtd);
 }
 
 /**
@@ -708,37 +757,34 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
  */
 static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
 {
-       struct nand_chip *active = this;
-
+       struct nand_chip *active;
+       spinlock_t *lock;
+       wait_queue_head_t *wq;
        DECLARE_WAITQUEUE (wait, current);
 
-       /* 
-        * Grab the lock and see if the device is available 
-       */
+       lock = (this->controller) ? &this->controller->lock : &this->chip_lock;
+       wq = (this->controller) ? &this->controller->wq : &this->wq;
 retry:
+       active = this;
+       spin_lock(lock);
+
        /* Hardware controller shared among independend devices */
        if (this->controller) {
-               spin_lock (&this->controller->lock);
                if (this->controller->active)
                        active = this->controller->active;
                else
                        this->controller->active = this;
-               spin_unlock (&this->controller->lock);
        }
-       
-       if (active == this) {
-               spin_lock (&this->chip_lock);
-               if (this->state == FL_READY) {
-                       this->state = new_state;
-                       spin_unlock (&this->chip_lock);
-                       return;
-               }
-       }       
-       set_current_state (TASK_UNINTERRUPTIBLE);
-       add_wait_queue (&active->wq, &wait);
-       spin_unlock (&active->chip_lock);
-       schedule ();
-       remove_wait_queue (&active->wq, &wait);
+       if (active == this && this->state == FL_READY) {
+               this->state = new_state;
+               spin_unlock(lock);
+               return;
+       }
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       add_wait_queue(wq, &wait);
+       spin_unlock(lock);
+       schedule();
+       remove_wait_queue(wq, &wait);
        goto retry;
 }
 
@@ -785,7 +831,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
                        if (this->read_byte(mtd) & NAND_STATUS_READY)
                                break;
                }
-               yield ();
+               cond_resched();
        }
        status = (int) this->read_byte(mtd);
        return status;
@@ -871,8 +917,14 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
        if (!cached) {
                /* call wait ready function */
                status = this->waitfunc (mtd, this, FL_WRITING);
+
+               /* See if operation failed and additional status checks are available */
+               if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+                       status = this->errstat(mtd, this, FL_WRITING, status, page);
+               }
+
                /* See if device thinks it succeeded */
-               if (status & 0x01) {
+               if (status & NAND_STATUS_FAIL) {
                        DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
                        return -EIO;
                }
@@ -975,7 +1027,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
 
                /* All done, return happy */
                if (!numpages)
@@ -997,23 +1049,24 @@ out:
 #endif
 
 /**
- * nand_read - [MTD Interface] MTD compability function for nand_read_ecc
+ * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
  * @mtd:       MTD device structure
  * @from:      offset to read from
  * @len:       number of bytes to read
  * @retlen:    pointer to variable to store the number of read bytes
  * @buf:       the databuffer to put data
  *
- * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL
-*/
+ * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
+ * and flags = 0xff
+ */
 static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
 {
-       return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
-}                         
+       return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
+}
 
 
 /**
- * nand_read_ecc - [MTD Interface] Read data with ECC
+ * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
  * @mtd:       MTD device structure
  * @from:      offset to read from
  * @len:       number of bytes to read
@@ -1022,11 +1075,39 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re
  * @oob_buf:   filesystem supplied oob data buffer
  * @oobsel:    oob selection structure
  *
- * NAND read with ECC
+ * This function simply calls nand_do_read_ecc with flags = 0xff
  */
 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                          size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
 {
+       /* use userspace supplied oobinfo, if zero */
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
+       return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
+}
+
+
+/**
+ * nand_do_read_ecc - [MTD Interface] Read data with ECC
+ * @mtd:       MTD device structure
+ * @from:      offset to read from
+ * @len:       number of bytes to read
+ * @retlen:    pointer to variable to store the number of read bytes
+ * @buf:       the databuffer to put data
+ * @oob_buf:   filesystem supplied oob data buffer (can be NULL)
+ * @oobsel:    oob selection structure
+ * @flags:     flag to indicate if nand_get_device/nand_release_device should be preformed
+ *             and how many corrected error bits are acceptable:
+ *               bits 0..7 - number of tolerable errors
+ *               bit  8    - 0 == do not get/release chip, 1 == get/release chip
+ *
+ * NAND read with ECC
+ */
+int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+                            size_t * retlen, u_char * buf, u_char * oob_buf, 
+                            struct nand_oobinfo *oobsel, int flags)
+{
+
        int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
        int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
        struct nand_chip *this = mtd->priv;
@@ -1051,12 +1132,9 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        }
 
        /* Grab the lock and see if the device is available */
-       nand_get_device (this, mtd ,FL_READING);
+       if (flags & NAND_GET_DEVICE)
+               nand_get_device (this, mtd, FL_READING);
 
-       /* use userspace supplied oobinfo, if zero */
-       if (oobsel == NULL)
-               oobsel = &mtd->oobinfo;
-       
        /* Autoplace of oob data ? Use the default placement scheme */
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
                oobsel = this->autooob;
@@ -1118,7 +1196,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                }       
 
                /* get oob area, if we have no oob buffer from fs-driver */
-               if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE)
+               if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
+                       oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
                        oob_data = &this->data_buf[end];
 
                eccsteps = this->eccsteps;
@@ -1155,7 +1234,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                                        /* We calc error correction directly, it checks the hw
                                         * generator for an error, reads back the syndrome and
                                         * does the error correction on the fly */
-                                       if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) {
+                                       ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
+                                       if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
                                                DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " 
                                                        "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
                                                ecc_failed++;
@@ -1194,7 +1274,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                                p[i] = ecc_status;
                        }
                        
-                       if (ecc_status == -1) { 
+                       if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {     
                                DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
                                ecc_failed++;
                        }
@@ -1206,14 +1286,14 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                        /* without autoplace. Legacy mode used by YAFFS1 */
                        switch(oobsel->useecc) {
                        case MTD_NANDECC_AUTOPLACE:
+                       case MTD_NANDECC_AUTOPL_USR:
                                /* Walk through the autoplace chunks */
-                               for (i = 0, j = 0; j < mtd->oobavail; i++) {
+                               for (i = 0; oobsel->oobfree[i][1]; i++) {
                                        int from = oobsel->oobfree[i][0];
                                        int num = oobsel->oobfree[i][1];
                                        memcpy(&oob_buf[oob], &oob_data[from], num);
-                                       j+= num;
+                                       oob += num;
                                }
-                               oob += mtd->oobavail;
                                break;
                        case MTD_NANDECC_PLACE:
                                /* YAFFS1 legacy mode */
@@ -1239,7 +1319,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
                        
                if (read == len)
                        break;  
@@ -1264,7 +1344,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        }
 
        /* Deselect and wake up anyone waiting on the device */
-       nand_release_device(mtd);
+       if (flags & NAND_GET_DEVICE)
+               nand_release_device(mtd);
 
        /*
         * Return success, if no ECC failures, else -EBADMSG
@@ -1337,7 +1418,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
 
                /* Read more ? */
                if (i < len) {
@@ -1417,7 +1498,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
                        
                /* Check, if the chip supports auto page increment */ 
                if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
@@ -1567,6 +1648,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                oobsel = this->autooob;
                autoplace = 1;
        }       
+       if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
+               autoplace = 1;
 
        /* Setup variables and oob buffer */
        totalpages = len >> this->page_shift;
@@ -1733,7 +1816,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t *
        status = this->waitfunc (mtd, this, FL_WRITING);
 
        /* See if device thinks it succeeded */
-       if (status & 0x01) {
+       if (status & NAND_STATUS_FAIL) {
                DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
                ret = -EIO;
                goto out;
@@ -1841,6 +1924,8 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
                oobsel = this->autooob;
                autoplace = 1;
        }       
+       if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
+               autoplace = 1;
 
        /* Setup start page */
        page = (int) (to >> this->page_shift);
@@ -1987,6 +2072,7 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
        return nand_erase_nand (mtd, instr, 0);
 }
  
+#define BBT_PAGE_MASK  0xffffff3f
 /**
  * nand_erase_intern - [NAND Interface] erase block(s)
  * @mtd:       MTD device structure
@@ -1999,6 +2085,10 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
 {
        int page, len, status, pages_per_block, ret, chipnr;
        struct nand_chip *this = mtd->priv;
+       int rewrite_bbt[NAND_MAX_CHIPS]={0};    /* flags to indicate the page, if bbt needs to be rewritten. */
+       unsigned int bbt_masked_page;           /* bbt mask to compare to page being erased. */
+                                               /* It is used to see if the current page is in the same */
+                                               /*   256 block group and the same bank as the bbt. */
 
        DEBUG (MTD_DEBUG_LEVEL3,
               "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
@@ -2044,6 +2134,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
                goto erase_exit;
        }
 
+       /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
+       if (this->options & BBT_AUTO_REFRESH) {
+               bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+       } else {
+               bbt_masked_page = 0xffffffff;   /* should not match anything */
+       }
+
        /* Loop through the pages */
        len = instr->len;
 
@@ -2066,13 +2163,26 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
                
                status = this->waitfunc (mtd, this, FL_ERASING);
 
+               /* See if operation failed and additional status checks are available */
+               if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+                       status = this->errstat(mtd, this, FL_ERASING, status, page);
+               }
+
                /* See if block erase succeeded */
-               if (status & 0x01) {
+               if (status & NAND_STATUS_FAIL) {
                        DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
                        instr->state = MTD_ERASE_FAILED;
                        instr->fail_addr = (page << this->page_shift);
                        goto erase_exit;
                }
+
+               /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
+               if (this->options & BBT_AUTO_REFRESH) {
+                       if (((page & BBT_PAGE_MASK) == bbt_masked_page) && 
+                            (page != this->bbt_td->pages[chipnr])) {
+                               rewrite_bbt[chipnr] = (page << this->page_shift);
+                       }
+               }
                
                /* Increment page address and decrement length */
                len -= (1 << this->phys_erase_shift);
@@ -2083,6 +2193,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
                        chipnr++;
                        this->select_chip(mtd, -1);
                        this->select_chip(mtd, chipnr);
+
+                       /* if BBT requires refresh and BBT-PERCHIP, 
+                        *   set the BBT page mask to see if this BBT should be rewritten */
+                       if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
+                               bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+                       }
+
                }
        }
        instr->state = MTD_ERASE_DONE;
@@ -2097,6 +2214,18 @@ erase_exit:
        /* Deselect and wake up anyone waiting on the device */
        nand_release_device(mtd);
 
+       /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
+       if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
+               for (chipnr = 0; chipnr < this->numchips; chipnr++) {
+                       if (rewrite_bbt[chipnr]) {
+                               /* update the BBT for chip */
+                               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", 
+                                       chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
+                               nand_update_bbt (mtd, rewrite_bbt[chipnr]);
+                       }
+               }
+       }
+
        /* Return more or less happy */
        return ret;
 }
@@ -2168,7 +2297,7 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
  */
 int nand_scan (struct mtd_info *mtd, int maxchips)
 {
-       int i, j, nand_maf_id, nand_dev_id, busw;
+       int i, nand_maf_id, nand_dev_id, busw, maf_id;
        struct nand_chip *this = mtd->priv;
 
        /* Get buswidth to select the correct functions*/
@@ -2256,12 +2385,18 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                        busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
                }
 
+               /* Try to identify manufacturer */
+               for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
+                       if (nand_manuf_ids[maf_id].id == nand_maf_id)
+                               break;
+               }
+
                /* Check, if buswidth is correct. Hardware drivers should set
                 * this correct ! */
                if (busw != (this->options & NAND_BUSWIDTH_16)) {
                        printk (KERN_INFO "NAND device: Manufacturer ID:"
                                " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
-                               nand_manuf_ids[i].name , mtd->name);
+                               nand_manuf_ids[maf_id].name , mtd->name);
                        printk (KERN_WARNING 
                                "NAND bus width %d instead %d bit\n", 
                                        (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
@@ -2300,14 +2435,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
                        this->cmdfunc = nand_command_lp;
                                
-               /* Try to identify manufacturer */
-               for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
-                       if (nand_manuf_ids[j].id == nand_maf_id)
-                               break;
-               }
                printk (KERN_INFO "NAND device: Manufacturer ID:"
                        " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
-                       nand_manuf_ids[j].name , nand_flash_ids[i].name);
+                       nand_manuf_ids[maf_id].name , nand_flash_ids[i].name);
                break;
        }
 
@@ -2388,12 +2518,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
        
        /* The number of bytes available for the filesystem to place fs dependend
         * oob data */
-       if (this->options & NAND_BUSWIDTH_16) {
-               mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);
-               if (this->autooob->eccbytes & 0x01)
-                       mtd->oobavail--;
-       } else
-               mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);
+       mtd->oobavail = 0;
+       for (i = 0; this->autooob->oobfree[i][1]; i++)
+               mtd->oobavail += this->autooob->oobfree[i][1];
 
        /* 
         * check ECC mode, default to software
@@ -2524,6 +2651,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
        memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
 
        mtd->owner = THIS_MODULE;
+       
+       /* Check, if we should skip the bad block table scan */
+       if (this->options & NAND_SKIP_BBTSCAN)
+               return 0;
 
        /* Build bad block table */
        return this->scan_bbt (mtd);
@@ -2555,8 +2686,8 @@ void nand_release (struct mtd_info *mtd)
                kfree (this->data_buf);
 }
 
-EXPORT_SYMBOL (nand_scan);
-EXPORT_SYMBOL (nand_release);
+EXPORT_SYMBOL_GPL (nand_scan);
+EXPORT_SYMBOL_GPL (nand_release);
 
 MODULE_LICENSE ("GPL");
 MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
index 9a1949751c1f6c994f3f7f8bb242f820cf6c3e81..5ac2d2962220d271ecefb19f83befabf1f22022a 100644 (file)
@@ -6,7 +6,7 @@
  *   
  *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
  *
- * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $
+ * $Id: nand_bbt.c,v 1.33 2005/06/14 15:47:56 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -77,7 +77,7 @@
 */
 static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
 {
-       int i, end;
+       int i, end = 0;
        uint8_t *p = buf;
 
        end = paglen + td->offs;
@@ -95,9 +95,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
                        return -1;
        }
 
-       p += td->len;
-       end += td->len;
        if (td->options & NAND_BBT_SCANEMPTY) {
+               p += td->len;
+               end += td->len;
                for (i = end; i < len; i++) {
                        if (*p++ != 0xff)
                                return -1;
@@ -106,6 +106,32 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
        return 0;
 }
 
+/** 
+ * check_short_pattern - [GENERIC] check if a pattern is in the buffer
+ * @buf:       the buffer to search
+ * @len:       the length of buffer to search
+ * @paglen:    the pagelength
+ * @td:                search pattern descriptor
+ *
+ * Check for a pattern at the given place. Used to search bad block
+ * tables and good / bad block identifiers. Same as check_pattern, but 
+ * no optional empty check and the pattern is expected to start
+ * at offset 0.
+ *
+*/
+static int check_short_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
+{
+       int i;
+       uint8_t *p = buf;
+
+       /* Compare the pattern */
+       for (i = 0; i < td->len; i++) {
+               if (p[i] != td->pattern[i])
+                       return -1;
+       }
+       return 0;
+}
+
 /**
  * read_bbt - [GENERIC] Read the bad block table starting from page
  * @mtd:       MTD device structure
@@ -252,7 +278,7 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de
  * Create a bad block table by scanning the device
  * for the given good/bad block identify pattern
  */
-static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
+static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
 {
        struct nand_chip *this = mtd->priv;
        int i, j, numblocks, len, scanlen;
@@ -270,9 +296,17 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                else    
                        len = 1;
        }
-       scanlen = mtd->oobblock + mtd->oobsize;
-       readlen = len * mtd->oobblock;
-       ooblen = len * mtd->oobsize;
+
+       if (!(bd->options & NAND_BBT_SCANEMPTY)) {
+               /* We need only read few bytes from the OOB area */
+               scanlen = ooblen = 0;
+               readlen = bd->len;
+       } else {
+               /* Full page content should be read */
+               scanlen = mtd->oobblock + mtd->oobsize;
+               readlen = len * mtd->oobblock;
+               ooblen = len * mtd->oobsize;
+       }
 
        if (chip == -1) {
                /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
@@ -284,7 +318,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                if (chip >= this->numchips) {
                        printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
                                chip + 1, this->numchips);
-                       return
+                       return -EINVAL;
                }
                numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
                startblock = chip * numblocks;
@@ -293,18 +327,41 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
        }
        
        for (i = startblock; i < numblocks;) {
-               nand_read_raw (mtd, buf, from, readlen, ooblen);
+               int ret;
+               
+               if (bd->options & NAND_BBT_SCANEMPTY)
+                       if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
+                               return ret;
+
                for (j = 0; j < len; j++) {
-                       if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
-                               this->bbt[i >> 3] |= 0x03 << (i & 0x6);
-                               printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 
-                                       i >> 1, (unsigned int) from);
-                               break;
+                       if (!(bd->options & NAND_BBT_SCANEMPTY)) {
+                               size_t retlen;
+                               
+                               /* No need to read pages fully, just read required OOB bytes */
+                               ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs,
+                                                       readlen, &retlen, &buf[0]);
+                               if (ret)
+                                       return ret;
+
+                               if (check_short_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
+                                       this->bbt[i >> 3] |= 0x03 << (i & 0x6);
+                                       printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 
+                                               i >> 1, (unsigned int) from);
+                                       break;
+                               }
+                       } else {
+                               if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
+                                       this->bbt[i >> 3] |= 0x03 << (i & 0x6);
+                                       printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 
+                                               i >> 1, (unsigned int) from);
+                                       break;
+                               }
                        }
                }
                i += 2;
                from += (1 << this->bbt_erase_shift);
        }
+       return 0;
 }
 
 /**
@@ -589,14 +646,12 @@ write:
  * The function creates a memory based bbt by scanning the device 
  * for manufacturer / software marked good / bad blocks
 */
-static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
 {
        struct nand_chip *this = mtd->priv;
 
-       /* Ensure that we only scan for the pattern and nothing else */
-       bd->options = 0;
-       create_bbt (mtd, this->data_buf, bd, -1);
-       return 0;
+       bd->options &= ~NAND_BBT_SCANEMPTY;
+       return create_bbt (mtd, this->data_buf, bd, -1);
 }
 
 /**
@@ -808,8 +863,14 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
        /* If no primary table decriptor is given, scan the device
         * to build a memory based bad block table
         */
-       if (!td)
-               return nand_memory_bbt(mtd, bd);
+       if (!td) {
+               if ((res = nand_memory_bbt(mtd, bd))) {
+                       printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
+                       kfree (this->bbt);
+                       this->bbt = NULL;
+               }
+               return res;
+       }
 
        /* Allocate a temporary buffer for one eraseblock incl. oob */
        len = (1 << this->bbt_erase_shift);
@@ -904,14 +965,11 @@ out:
 }
 
 /* Define some generic bad / good block scan pattern which are used 
- * while scanning a device for factory marked good / bad blocks
- * 
- * The memory based patterns just 
- */
+ * while scanning a device for factory marked good / bad blocks. */
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
 
 static struct nand_bbt_descr smallpage_memorybased = {
-       .options = 0,
+       .options = NAND_BBT_SCAN2NDPAGE,
        .offs = 5,
        .len = 1,
        .pattern = scan_ff_pattern
@@ -1042,7 +1100,7 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
        res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
 
        DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", 
-               (unsigned int)offs, res, block >> 1);
+               (unsigned int)offs, block >> 1, res);
 
        switch ((int)res) {
        case 0x00:      return 0;
index 2d8c4321275bbc60308fd333a7cb0c32a8ff253c..efe246961b69fe1d1ee7b490a0108cdd24e95e1c 100644 (file)
@@ -2,8 +2,8 @@
  *  drivers/mtd/nandids.c
  *
  *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
 *
- * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $
+ *
+ * $Id: nand_ids.c,v 1.14 2005/06/23 09:38:50 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -56,17 +56,24 @@ struct nand_flash_dev nand_flash_ids[] = {
        {"NAND 64MiB 3,3V 16-bit",      0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
        
        {"NAND 128MiB 1,8V 8-bit",      0x78, 512, 128, 0x4000, 0},
+       {"NAND 128MiB 1,8V 8-bit",      0x39, 512, 128, 0x4000, 0},
        {"NAND 128MiB 3,3V 8-bit",      0x79, 512, 128, 0x4000, 0},
        {"NAND 128MiB 1,8V 16-bit",     0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 128MiB 1,8V 16-bit",     0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 128MiB 3,3V 16-bit",     0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 128MiB 3,3V 16-bit",     0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
        
        {"NAND 256MiB 3,3V 8-bit",      0x71, 512, 256, 0x4000, 0},
 
-       {"NAND 512MiB 3,3V 8-bit",      0xDC, 512, 512, 0x4000, 0},
-       
        /* These are the new chips with large page size. The pagesize
        * and the erasesize is determined from the extended id bytes
        */
+       /*512 Megabit */
+       {"NAND 64MiB 1,8V 8-bit",       0xA2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 64MiB 3,3V 8-bit",       0xF2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 64MiB 1,8V 16-bit",      0xB2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+       {"NAND 64MiB 3,3V 16-bit",      0xC2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+       
        /* 1 Gigabit */
        {"NAND 128MiB 1,8V 8-bit",      0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
        {"NAND 128MiB 3,3V 8-bit",      0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
@@ -103,7 +110,7 @@ struct nand_flash_dev nand_flash_ids[] = {
         * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
         * There are more speed improvements for reads and writes possible, but not implemented now 
         */
-       {"AND 128MiB 3,3V 8-bit",       0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY},
+       {"AND 128MiB 3,3V 8-bit",       0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
 
        {NULL,}
 };
@@ -118,6 +125,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
        {NAND_MFR_NATIONAL, "National"},
        {NAND_MFR_RENESAS, "Renesas"},
        {NAND_MFR_STMICRO, "ST Micro"},
+        {NAND_MFR_HYNIX, "Hynix"},
        {0x0, "Unknown"}
 };
 
index 13feefd7d8caf2bc12aa7a9a1637d65c68d7ad2a..754b6ed7ce140b5470f5c8533ac45b0aedf4030a 100644 (file)
@@ -22,7 +22,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  *
- * $Id: nandsim.c,v 1.7 2004/12/06 11:53:06 dedekind Exp $
+ * $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $
  */
 
 #include <linux/config.h>
@@ -1483,33 +1483,6 @@ ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
        }
 }
 
-/*
- * Having only NAND chip IDs we call nand_scan which detects NAND flash
- * parameters and then calls scan_bbt in order to scan/find/build the
- * NAND flash bad block table. But since at that moment the NAND flash
- * image isn't allocated in the simulator, errors arise. To avoid this
- * we redefine the scan_bbt callback and initialize the nandsim structure
- * before the flash media scanning.
- */
-int ns_scan_bbt(struct mtd_info *mtd)
-{ 
-       struct nand_chip *chip = (struct nand_chip *)mtd->priv;
-       struct nandsim   *ns   = (struct nandsim *)(chip->priv);
-       int retval;
-
-&nb