]> err.no Git - linux-2.6/blobdiff - drivers/mtd/chips/cfi_cmdset_0001.c
libata-sff: improve HSM violation reporting
[linux-2.6] / drivers / mtd / chips / cfi_cmdset_0001.c
index 1707f98c322c589c144b59d19cd9a52cbb22377a..fcd1aeccdf9393d0780da7ff83c94d8f32e1af62 100644 (file)
@@ -50,6 +50,7 @@
 #define I82802AC       0x00ac
 #define MANUFACTURER_ST         0x0020
 #define M50LPW080       0x002F
+#define AT49BV640D     0x02de
 
 static int cfi_intelext_read (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 *);
@@ -81,9 +82,8 @@ static struct mtd_info *cfi_intelext_setup (struct mtd_info *);
 static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
 
 static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
-                    size_t *retlen, u_char **mtdbuf);
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
-                       size_t len);
+                    size_t *retlen, void **virt, resource_size_t *phys);
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
 
 static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
@@ -157,6 +157,47 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
 }
 #endif
 
+/* Atmel chips don't use the same PRI format as Intel chips */
+static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+       struct cfi_pri_atmel atmel_pri;
+       uint32_t features = 0;
+
+       /* Reverse byteswapping */
+       extp->FeatureSupport = cpu_to_le32(extp->FeatureSupport);
+       extp->BlkStatusRegMask = cpu_to_le16(extp->BlkStatusRegMask);
+       extp->ProtRegAddr = cpu_to_le16(extp->ProtRegAddr);
+
+       memcpy(&atmel_pri, extp, sizeof(atmel_pri));
+       memset((char *)extp + 5, 0, sizeof(*extp) - 5);
+
+       printk(KERN_ERR "atmel Features: %02x\n", atmel_pri.Features);
+
+       if (atmel_pri.Features & 0x01) /* chip erase supported */
+               features |= (1<<0);
+       if (atmel_pri.Features & 0x02) /* erase suspend supported */
+               features |= (1<<1);
+       if (atmel_pri.Features & 0x04) /* program suspend supported */
+               features |= (1<<2);
+       if (atmel_pri.Features & 0x08) /* simultaneous operations supported */
+               features |= (1<<9);
+       if (atmel_pri.Features & 0x20) /* page mode read supported */
+               features |= (1<<7);
+       if (atmel_pri.Features & 0x40) /* queued erase supported */
+               features |= (1<<4);
+       if (atmel_pri.Features & 0x80) /* Protection bits supported */
+               features |= (1<<6);
+
+       extp->FeatureSupport = features;
+
+       /* burst write mode not supported */
+       cfi->cfiq->BufWriteTimeoutTyp = 0;
+       cfi->cfiq->BufWriteTimeoutMax = 0;
+}
+
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
 /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
 static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
@@ -227,13 +268,20 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
 /*
  * Some chips power-up with all sectors locked by default.
  */
-static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
+static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
 {
-       printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
-       mtd->flags |= MTD_STUPID_LOCK;
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+
+       if (cfip->FeatureSupport&32) {
+               printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
+               mtd->flags |= MTD_POWERUP_LOCK;
+       }
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
+       { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
        { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
 #endif
@@ -245,7 +293,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
 #endif
        { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
        { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
-       { MANUFACTURER_INTEL, 0x891c,         fixup_use_powerup_lock, NULL, },
+       { MANUFACTURER_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, },
        { 0, 0, NULL, NULL }
 };
 
@@ -277,7 +325,7 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                return NULL;
 
        if (extp->MajorVersion != '1' ||
-           (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
+           (extp->MinorVersion < '0' || extp->MinorVersion > '5')) {
                printk(KERN_ERR "  Unknown Intel/Sharp Extended Query "
                       "version %c.%c.\n",  extp->MajorVersion,
                       extp->MinorVersion);
@@ -335,7 +383,7 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                        if (extp_size > 4096) {
                                printk(KERN_ERR
                                        "%s: cfi_pri_intelext is too fat\n",
-                                       __FUNCTION__);
+                                       __func__);
                                return NULL;
                        }
                        goto again;
@@ -570,6 +618,9 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
                                  sizeof(struct cfi_intelext_blockinfo);
                }
 
+               if (!numparts)
+                       numparts = 1;
+
                /* Programming Region info */
                if (extp->MinorVersion >= '4') {
                        struct cfi_intelext_programming_regioninfo *prinfo;
@@ -592,7 +643,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
                if ((1 << partshift) < mtd->erasesize) {
                        printk( KERN_ERR
                                "%s: bad number of hw partitions (%d)\n",
-                               __FUNCTION__, numparts);
+                               __func__, numparts);
                        return -EINVAL;
                }
 
@@ -669,7 +720,7 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
                        /* Someone else might have been playing with it. */
                        return -EAGAIN;
                }
-
+               /* Fall through */
        case FL_READY:
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
@@ -729,14 +780,14 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
                chip->state = FL_READY;
                return 0;
 
+       case FL_SHUTDOWN:
+               /* The machine is rebooting now,so no one can get chip anymore */
+               return -EIO;
        case FL_POINT:
                /* Only if there's no operation suspended... */
                if (mode == FL_READY && chip->oldstate == FL_READY)
                        return 0;
-
-       case FL_SHUTDOWN:
-               /* The machine is rebooting now,so no one can get chip anymore */
-               return -EIO;
+               /* Fall through */
        default:
        sleep:
                set_current_state(TASK_UNINTERRUPTIBLE);
@@ -752,6 +803,7 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
 {
        int ret;
+       DECLARE_WAITQUEUE(wait, current);
 
  retry:
        if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
@@ -808,6 +860,20 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                        spin_unlock(contender->mutex);
                }
 
+               /* Check if we already have suspended erase
+                * on this chip. Sleep. */
+               if (mode == FL_ERASING && shared->erasing
+                   && shared->erasing->oldstate == FL_ERASING) {
+                       spin_unlock(&shared->lock);
+                       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);
+                       goto retry;
+               }
+
                /* We now own it */
                shared->writing = chip;
                if (mode == FL_ERASING)
@@ -1007,10 +1073,10 @@ static int __xipram xip_wait_for_operation(
                        chip->state = newstate;
                        map_write(map, CMD(0xff), adr);
                        (void) map_read(map, adr);
-                       asm volatile (".rep 8; nop; .endr");
+                       xip_iprefetch();
                        local_irq_enable();
                        spin_unlock(chip->mutex);
-                       asm volatile (".rep 8; nop; .endr");
+                       xip_iprefetch();
                        cond_resched();
 
                        /*
@@ -1173,7 +1239,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
        return ret;
 }
 
-static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, void **virt, resource_size_t *phys)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
@@ -1190,8 +1257,10 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
        chipnum = (from >> cfi->chipshift);
        ofs = from - (chipnum << cfi->chipshift);
 
-       *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
+       *virt = map->virt + cfi->chips[chipnum].start + ofs;
        *retlen = 0;
+       if (phys)
+               *phys = map->phys + cfi->chips[chipnum].start + ofs;
 
        while (len) {
                unsigned long thislen;
@@ -1224,7 +1293,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
        return 0;
 }
 
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
@@ -1949,7 +2018,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
-              __FUNCTION__, ofs, len);
+              __func__, ofs, len);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
                ofs, len, NULL);
 #endif
@@ -1959,7 +2028,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
-              __FUNCTION__, ret);
+              __func__, ret);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
                ofs, len, NULL);
 #endif
@@ -1973,7 +2042,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
 
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
-              __FUNCTION__, ofs, len);
+              __func__, ofs, len);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
                ofs, len, NULL);
 #endif
@@ -1983,7 +2052,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
 
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
-              __FUNCTION__, ret);
+              __func__, ret);
        cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
                ofs, len, NULL);
 #endif
@@ -2294,7 +2363,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
        struct flchip *chip;
        int ret = 0;
 
-       if ((mtd->flags & MTD_STUPID_LOCK)
+       if ((mtd->flags & MTD_POWERUP_LOCK)
            && extp && (extp->FeatureSupport & (1 << 5)))
                cfi_intelext_save_locks(mtd);
 
@@ -2405,7 +2474,7 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
                spin_unlock(chip->mutex);
        }
 
-       if ((mtd->flags & MTD_STUPID_LOCK)
+       if ((mtd->flags & MTD_POWERUP_LOCK)
            && extp && (extp->FeatureSupport & (1 << 5)))
                cfi_intelext_restore_locks(mtd);
 }