Merge git://git.infradead.org/mtd-2.6
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 9 May 2007 20:10:11 +0000 (13:10 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Wed, 9 May 2007 20:10:11 +0000 (13:10 -0700)
* git://git.infradead.org/mtd-2.6: (21 commits)
  [MTD] [CHIPS] Remove MTD_OBSOLETE_CHIPS (jedec, amd_flash, sharp)
  [MTD] Delete allegedly obsolete "bank_size" field of mtd_info.
  [MTD] Remove unnecessary user space check from mtd.h.
  [MTD] [MAPS] Remove flash maps for no longer supported 405LP boards
  [MTD] [MAPS] Fix missing printk() parameter in physmap_of.c MTD driver
  [MTD] [NAND] platform NAND driver: add driver
  [MTD] [NAND] platform NAND driver: update header
  [JFFS2] Simplify and clean up jffs2_add_tn_to_tree() some more.
  [JFFS2] Remove another bogus optimisation in jffs2_add_tn_to_tree()
  [JFFS2] Remove broken insert_point optimisation in jffs2_add_tn_to_tree()
  [JFFS2] Remember to calculate overlap on nodes which replace older nodes
  [JFFS2] Don't advance c->wbuf_ofs to next eraseblock after wbuf flush
  [MTD] [NAND] at91_nand.c: CMDLINE_PARTS support
  [MTD] [NAND] Tidy up handling of page number in nand_block_bad()
  [MTD] block2mtd_paramline[] mustn't be __initdata
  [MTD] [NAND] Support multiple chips in CAFÉ driver
  [MTD] [NAND] Rename cafe.c to cafe_nand.c and remove the multi-obj magic
  [MTD] [NAND] Use rslib for CAFÉ ECC
  [RSLIB] Support non-canonical GF representations
  [JFFS2] Remove dead file histo_mips.h
  ...

28 files changed:
MAINTAINERS
drivers/mtd/chips/Kconfig
drivers/mtd/chips/Makefile
drivers/mtd/chips/amd_flash.c [deleted file]
drivers/mtd/chips/jedec.c [deleted file]
drivers/mtd/chips/sharp.c [deleted file]
drivers/mtd/devices/block2mtd.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/arctic-mtd.c [deleted file]
drivers/mtd/maps/beech-mtd.c [deleted file]
drivers/mtd/maps/physmap_of.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/at91_nand.c
drivers/mtd/nand/cafe.c [deleted file]
drivers/mtd/nand/cafe_ecc.c [deleted file]
drivers/mtd/nand/cafe_nand.c [new file with mode: 0644]
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/plat_nand.c [new file with mode: 0644]
fs/jffs2/histo_mips.h [deleted file]
fs/jffs2/readinode.c
fs/jffs2/wbuf.c
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/rslib.h
lib/reed_solomon/reed_solomon.c

index 3b46f43c338bb5da005ef44de2551dd6c2a995c7..cfd26ddccd7a0997c10ed46e4c15a7dc021c1761 100644 (file)
@@ -2648,6 +2648,12 @@ M:       corbet@lwn.net
 L:     video4linux-list@redhat.com
 S:     Maintained
 
+ONENAND FLASH DRIVER
+P:     Kyungmin Park
+M:     kyungmin.park@samsung.com
+L:     linux-mtd@lists.infradead.org
+S:     Maintained
+
 ONSTREAM SCSI TAPE DRIVER
 P:     Willem Riede
 M:     osst@riede.org
index d28e0fc85e12c2e0bad8810551b1a3a8a4cffd42..479d32b57a1eb54b20b731855274bd9d343a62ae 100644 (file)
@@ -1,5 +1,4 @@
 # drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.18 2005/11/07 11:14:22 gleixner Exp $
 
 menu "RAM/ROM/Flash chip drivers"
        depends on MTD!=n
@@ -231,45 +230,6 @@ config MTD_ABSENT
          the system regardless of media presence.  Device nodes created
          with this driver will return -ENODEV upon access.
 
-config MTD_OBSOLETE_CHIPS
-       bool "Older (theoretically obsoleted now) drivers for non-CFI chips"
-       help
-         This option does not enable any code directly, but will allow you to
-         select some other chip drivers which are now considered obsolete,
-         because the generic CONFIG_JEDECPROBE code above should now detect
-         the chips which are supported by these drivers, and allow the generic
-         CFI-compatible drivers to drive the chips. Say 'N' here unless you have
-         already tried the CONFIG_JEDECPROBE method and reported its failure
-         to the MTD mailing list at <linux-mtd@lists.infradead.org>
-
-config MTD_AMDSTD
-       tristate "AMD compatible flash chip support (non-CFI)"
-       depends on MTD_OBSOLETE_CHIPS && BROKEN
-       help
-         This option enables support for flash chips using AMD-compatible
-         commands, including some which are not CFI-compatible and hence
-         cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
-
-         It also works on AMD compatible chips that do conform to CFI.
-
-config MTD_SHARP
-       tristate "pre-CFI Sharp chip support"
-       depends on MTD_OBSOLETE_CHIPS
-       help
-         This option enables support for flash chips using Sharp-compatible
-         commands, including some which are not CFI-compatible and hence
-         cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
-
-config MTD_JEDEC
-       tristate "JEDEC device support"
-       depends on MTD_OBSOLETE_CHIPS && BROKEN
-       help
-         Enable older JEDEC flash interface devices for self
-         programming flash.  It is commonly used in older AMD chips.  It is
-         only called JEDEC because the JEDEC association
-         <http://www.jedec.org/> distributes the identification codes for the
-         chips.
-
 config MTD_XIP
        bool "XIP aware MTD support"
        depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL && ARCH_MTD_XIP
index 75bc1c2a0f431b9954447921f03b7246ed2fb395..36582412ccdaeb2c2aea2c0752f8b62e51554154 100644 (file)
@@ -1,19 +1,15 @@
 #
 # linux/drivers/chips/Makefile
 #
-# $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $
 
 obj-$(CONFIG_MTD)              += chipreg.o
-obj-$(CONFIG_MTD_AMDSTD)       += amd_flash.o
 obj-$(CONFIG_MTD_CFI)          += cfi_probe.o
 obj-$(CONFIG_MTD_CFI_UTIL)     += cfi_util.o
 obj-$(CONFIG_MTD_CFI_STAA)     += cfi_cmdset_0020.o
 obj-$(CONFIG_MTD_CFI_AMDSTD)   += cfi_cmdset_0002.o
 obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
 obj-$(CONFIG_MTD_GEN_PROBE)    += gen_probe.o
-obj-$(CONFIG_MTD_JEDEC)                += jedec.o
 obj-$(CONFIG_MTD_JEDECPROBE)   += jedec_probe.o
 obj-$(CONFIG_MTD_RAM)          += map_ram.o
 obj-$(CONFIG_MTD_ROM)          += map_rom.o
-obj-$(CONFIG_MTD_SHARP)                += sharp.o
 obj-$(CONFIG_MTD_ABSENT)       += map_absent.o
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
deleted file mode 100644 (file)
index e7999f1..0000000
+++ /dev/null
@@ -1,1396 +0,0 @@
-/*
- * MTD map driver for AMD compatible flash chips (non-CFI)
- *
- * Author: Jonas Holmberg <jonas.holmberg@axis.com>
- *
- * $Id: amd_flash.c,v 1.28 2005/11/07 11:14:22 gleixner Exp $
- *
- * Copyright (c) 2001 Axis Communications AB
- *
- * This file is under GPL.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/flashchip.h>
-
-/* There's no limit. It exists only to avoid realloc. */
-#define MAX_AMD_CHIPS 8
-
-#define DEVICE_TYPE_X8 (8 / 8)
-#define DEVICE_TYPE_X16        (16 / 8)
-#define DEVICE_TYPE_X32        (32 / 8)
-
-/* Addresses */
-#define ADDR_MANUFACTURER              0x0000
-#define ADDR_DEVICE_ID                 0x0001
-#define ADDR_SECTOR_LOCK               0x0002
-#define ADDR_HANDSHAKE                 0x0003
-#define ADDR_UNLOCK_1                  0x0555
-#define ADDR_UNLOCK_2                  0x02AA
-
-/* Commands */
-#define CMD_UNLOCK_DATA_1              0x00AA
-#define CMD_UNLOCK_DATA_2              0x0055
-#define CMD_MANUFACTURER_UNLOCK_DATA   0x0090
-#define CMD_UNLOCK_BYPASS_MODE         0x0020
-#define CMD_PROGRAM_UNLOCK_DATA                0x00A0
-#define CMD_RESET_DATA                 0x00F0
-#define CMD_SECTOR_ERASE_UNLOCK_DATA   0x0080
-#define CMD_SECTOR_ERASE_UNLOCK_DATA_2 0x0030
-
-#define CMD_UNLOCK_SECTOR              0x0060
-
-/* Manufacturers */
-#define MANUFACTURER_AMD       0x0001
-#define MANUFACTURER_ATMEL     0x001F
-#define MANUFACTURER_FUJITSU   0x0004
-#define MANUFACTURER_ST                0x0020
-#define MANUFACTURER_SST       0x00BF
-#define MANUFACTURER_TOSHIBA   0x0098
-
-/* AMD */
-#define AM29F800BB     0x2258
-#define AM29F800BT     0x22D6
-#define AM29LV800BB    0x225B
-#define AM29LV800BT    0x22DA
-#define AM29LV160DT    0x22C4
-#define AM29LV160DB    0x2249
-#define AM29BDS323D     0x22D1
-
-/* Atmel */
-#define AT49xV16x      0x00C0
-#define AT49xV16xT     0x00C2
-
-/* Fujitsu */
-#define MBM29LV160TE   0x22C4
-#define MBM29LV160BE   0x2249
-#define MBM29LV800BB   0x225B
-
-/* ST - www.st.com */
-#define M29W800T       0x00D7
-#define M29W160DT      0x22C4
-#define M29W160DB      0x2249
-
-/* SST */
-#define SST39LF800     0x2781
-#define SST39LF160     0x2782
-
-/* Toshiba */
-#define TC58FVT160     0x00C2
-#define TC58FVB160     0x0043
-
-#define D6_MASK        0x40
-
-struct amd_flash_private {
-       int device_type;
-       int interleave;
-       int numchips;
-       unsigned long chipshift;
-       struct flchip chips[0];
-};
-
-struct amd_flash_info {
-       const __u16 mfr_id;
-       const __u16 dev_id;
-       const char *name;
-       const u_long size;
-       const int numeraseregions;
-       const struct mtd_erase_region_info regions[4];
-};
-
-
-
-static int amd_flash_read(struct mtd_info *, loff_t, size_t, size_t *,
-                         u_char *);
-static int amd_flash_write(struct mtd_info *, loff_t, size_t, size_t *,
-                          const u_char *);
-static int amd_flash_erase(struct mtd_info *, struct erase_info *);
-static void amd_flash_sync(struct mtd_info *);
-static int amd_flash_suspend(struct mtd_info *);
-static void amd_flash_resume(struct mtd_info *);
-static void amd_flash_destroy(struct mtd_info *);
-static struct mtd_info *amd_flash_probe(struct map_info *map);
-
-
-static struct mtd_chip_driver amd_flash_chipdrv = {
-       .probe = amd_flash_probe,
-       .destroy = amd_flash_destroy,
-       .name = "amd_flash",
-       .module = THIS_MODULE
-};
-
-static inline __u32 wide_read(struct map_info *map, __u32 addr)
-{
-       if (map->buswidth == 1) {
-               return map_read8(map, addr);
-       } else if (map->buswidth == 2) {
-               return map_read16(map, addr);
-       } else if (map->buswidth == 4) {
-               return map_read32(map, addr);
-        }
-
-       return 0;
-}
-
-static inline void wide_write(struct map_info *map, __u32 val, __u32 addr)
-{
-       if (map->buswidth == 1) {
-               map_write8(map, val, addr);
-       } else if (map->buswidth == 2) {
-               map_write16(map, val, addr);
-       } else if (map->buswidth == 4) {
-               map_write32(map, val, addr);
-       }
-}
-
-static inline __u32 make_cmd(struct map_info *map, __u32 cmd)
-{
-       const struct amd_flash_private *private = map->fldrv_priv;
-       if ((private->interleave == 2) &&
-           (private->device_type == DEVICE_TYPE_X16)) {
-               cmd |= (cmd << 16);
-       }
-
-       return cmd;
-}
-
-static inline void send_unlock(struct map_info *map, unsigned long base)
-{
-       wide_write(map, (CMD_UNLOCK_DATA_1 << 16) | CMD_UNLOCK_DATA_1,
-                  base + (map->buswidth * ADDR_UNLOCK_1));
-       wide_write(map, (CMD_UNLOCK_DATA_2 << 16) | CMD_UNLOCK_DATA_2,
-                  base + (map->buswidth * ADDR_UNLOCK_2));
-}
-
-static inline void send_cmd(struct map_info *map, unsigned long base, __u32 cmd)
-{
-       send_unlock(map, base);
-       wide_write(map, make_cmd(map, cmd),
-                  base + (map->buswidth * ADDR_UNLOCK_1));
-}
-
-static inline void send_cmd_to_addr(struct map_info *map, unsigned long base,
-                                   __u32 cmd, unsigned long addr)
-{
-       send_unlock(map, base);
-       wide_write(map, make_cmd(map, cmd), addr);
-}
-
-static inline int flash_is_busy(struct map_info *map, unsigned long addr,
-                               int interleave)
-{
-
-       if ((interleave == 2) && (map->buswidth == 4)) {
-               __u32 read1, read2;
-
-               read1 = wide_read(map, addr);
-               read2 = wide_read(map, addr);
-
-               return (((read1 >> 16) & D6_MASK) !=
-                       ((read2 >> 16) & D6_MASK)) ||
-                      (((read1 & 0xffff) & D6_MASK) !=
-                       ((read2 & 0xffff) & D6_MASK));
-       }
-
-       return ((wide_read(map, addr) & D6_MASK) !=
-               (wide_read(map, addr) & D6_MASK));
-}
-
-static inline void unlock_sector(struct map_info *map, unsigned long sect_addr,
-                                int unlock)
-{
-       /* Sector lock address. A6 = 1 for unlock, A6 = 0 for lock */
-       int SLA = unlock ?
-               (sect_addr |  (0x40 * map->buswidth)) :
-               (sect_addr & ~(0x40 * map->buswidth)) ;
-
-       __u32 cmd = make_cmd(map, CMD_UNLOCK_SECTOR);
-
-       wide_write(map, make_cmd(map, CMD_RESET_DATA), 0);
-       wide_write(map, cmd, SLA); /* 1st cycle: write cmd to any address */
-       wide_write(map, cmd, SLA); /* 2nd cycle: write cmd to any address */
-       wide_write(map, cmd, SLA); /* 3rd cycle: write cmd to SLA */
-}
-
-static inline int is_sector_locked(struct map_info *map,
-                                  unsigned long sect_addr)
-{
-       int status;
-
-       wide_write(map, CMD_RESET_DATA, 0);
-       send_cmd(map, sect_addr, CMD_MANUFACTURER_UNLOCK_DATA);
-
-       /* status is 0x0000 for unlocked and 0x0001 for locked */
-       status = wide_read(map, sect_addr + (map->buswidth * ADDR_SECTOR_LOCK));
-       wide_write(map, CMD_RESET_DATA, 0);
-       return status;
-}
-
-static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len,
-                              int is_unlock)
-{
-       struct map_info *map;
-       struct mtd_erase_region_info *merip;
-       int eraseoffset, erasesize, eraseblocks;
-       int i;
-       int retval = 0;
-       int lock_status;
-
-       map = mtd->priv;
-
-       /* Pass the whole chip through sector by sector and check for each
-          sector if the sector and the given interval overlap */
-       for(i = 0; i < mtd->numeraseregions; i++) {
-               merip = &mtd->eraseregions[i];
-
-               eraseoffset = merip->offset;
-               erasesize = merip->erasesize;
-               eraseblocks = merip->numblocks;
-
-               if (ofs > eraseoffset + erasesize)
-                       continue;
-
-               while (eraseblocks > 0) {
-                       if (ofs < eraseoffset + erasesize && ofs + len > eraseoffset) {
-                               unlock_sector(map, eraseoffset, is_unlock);
-
-                               lock_status = is_sector_locked(map, eraseoffset);
-
-                               if (is_unlock && lock_status) {
-                                       printk("Cannot unlock sector at address %x length %xx\n",
-                                              eraseoffset, merip->erasesize);
-                                       retval = -1;
-                               } else if (!is_unlock && !lock_status) {
-                                       printk("Cannot lock sector at address %x length %x\n",
-                                              eraseoffset, merip->erasesize);
-                                       retval = -1;
-                               }
-                       }
-                       eraseoffset += erasesize;
-                       eraseblocks --;
-               }
-       }
-       return retval;
-}
-
-static int amd_flash_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-       return amd_flash_do_unlock(mtd, ofs, len, 1);
-}
-
-static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
-{
-       return amd_flash_do_unlock(mtd, ofs, len, 0);
-}
-
-
-/*
- * Reads JEDEC manufacturer ID and device ID and returns the index of the first
- * matching table entry (-1 if not found or alias for already found chip).
- */
-static int probe_new_chip(struct mtd_info *mtd, __u32 base,
-                         struct flchip *chips,
-                         struct amd_flash_private *private,
-                         const struct amd_flash_info *table, int table_size)
-{
-       __u32 mfr_id;
-       __u32 dev_id;
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private temp;
-       int i;
-
-       temp.device_type = DEVICE_TYPE_X16;     // Assume X16 (FIXME)
-       temp.interleave = 2;
-       map->fldrv_priv = &temp;
-
-       /* Enter autoselect mode. */
-       send_cmd(map, base, CMD_RESET_DATA);
-       send_cmd(map, base, CMD_MANUFACTURER_UNLOCK_DATA);
-
-       mfr_id = wide_read(map, base + (map->buswidth * ADDR_MANUFACTURER));
-       dev_id = wide_read(map, base + (map->buswidth * ADDR_DEVICE_ID));
-
-       if ((map->buswidth == 4) && ((mfr_id >> 16) == (mfr_id & 0xffff)) &&
-           ((dev_id >> 16) == (dev_id & 0xffff))) {
-               mfr_id &= 0xffff;
-               dev_id &= 0xffff;
-       } else {
-               temp.interleave = 1;
-       }
-
-       for (i = 0; i < table_size; i++) {
-               if ((mfr_id == table[i].mfr_id) &&
-                   (dev_id == table[i].dev_id)) {
-                       if (chips) {
-                               int j;
-
-                               /* Is this an alias for an already found chip?
-                                * In that case that chip should be in
-                                * autoselect mode now.
-                                */
-                               for (j = 0; j < private->numchips; j++) {
-                                       __u32 mfr_id_other;
-                                       __u32 dev_id_other;
-
-                                       mfr_id_other =
-                                               wide_read(map, chips[j].start +
-                                                              (map->buswidth *
-                                                               ADDR_MANUFACTURER
-                                                              ));
-                                       dev_id_other =
-                                               wide_read(map, chips[j].start +
-                                                              (map->buswidth *
-                                                               ADDR_DEVICE_ID));
-                                       if (temp.interleave == 2) {
-                                               mfr_id_other &= 0xffff;
-                                               dev_id_other &= 0xffff;
-                                       }
-                                       if ((mfr_id_other == mfr_id) &&
-                                           (dev_id_other == dev_id)) {
-
-                                               /* Exit autoselect mode. */
-                                               send_cmd(map, base,
-                                                        CMD_RESET_DATA);
-
-                                               return -1;
-                                       }
-                               }
-
-                               if (private->numchips == MAX_AMD_CHIPS) {
-                                       printk(KERN_WARNING
-                                              "%s: Too many flash chips "
-                                              "detected. Increase "
-                                              "MAX_AMD_CHIPS from %d.\n",
-                                              map->name, MAX_AMD_CHIPS);
-
-                                       return -1;
-                               }
-
-                               chips[private->numchips].start = base;
-                               chips[private->numchips].state = FL_READY;
-                               chips[private->numchips].mutex =
-                                       &chips[private->numchips]._spinlock;
-                               private->numchips++;
-                       }
-
-                       printk("%s: Found %d x %ldMiB %s at 0x%x\n", map->name,
-                              temp.interleave, (table[i].size)/(1024*1024),
-                              table[i].name, base);
-
-                       mtd->size += table[i].size * temp.interleave;
-                       mtd->numeraseregions += table[i].numeraseregions;
-
-                       break;
-               }
-       }
-
-       /* Exit autoselect mode. */
-       send_cmd(map, base, CMD_RESET_DATA);
-
-       if (i == table_size) {
-               printk(KERN_DEBUG "%s: unknown flash device at 0x%x, "
-                      "mfr id 0x%x, dev id 0x%x\n", map->name,
-                      base, mfr_id, dev_id);
-               map->fldrv_priv = NULL;
-
-               return -1;
-       }
-
-       private->device_type = temp.device_type;
-       private->interleave = temp.interleave;
-
-       return i;
-}
-
-
-
-static struct mtd_info *amd_flash_probe(struct map_info *map)
-{
-       static const struct amd_flash_info table[] = {
-       {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29LV160DT,
-               .name = "AMD AM29LV160DT",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29LV160DB,
-               .name = "AMD AM29LV160DB",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_TOSHIBA,
-               .dev_id = TC58FVT160,
-               .name = "Toshiba TC58FVT160",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_FUJITSU,
-               .dev_id = MBM29LV160TE,
-               .name = "Fujitsu MBM29LV160TE",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_TOSHIBA,
-               .dev_id = TC58FVB160,
-               .name = "Toshiba TC58FVB160",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_FUJITSU,
-               .dev_id = MBM29LV160BE,
-               .name = "Fujitsu MBM29LV160BE",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29LV800BB,
-               .name = "AMD AM29LV800BB",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29F800BB,
-               .name = "AMD AM29F800BB",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29LV800BT,
-               .name = "AMD AM29LV800BT",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-                       { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29F800BT,
-               .name = "AMD AM29F800BT",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-                       { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29LV800BB,
-               .name = "AMD AM29LV800BB",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-                       { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_FUJITSU,
-               .dev_id = MBM29LV800BB,
-               .name = "Fujitsu MBM29LV800BB",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_ST,
-               .dev_id = M29W800T,
-               .name = "ST M29W800T",
-               .size = 0x00100000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
-                       { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_ST,
-               .dev_id = M29W160DT,
-               .name = "ST M29W160DT",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_ST,
-               .dev_id = M29W160DB,
-               .name = "ST M29W160DB",
-               .size = 0x00200000,
-               .numeraseregions = 4,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
-                       { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
-                       { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29BDS323D,
-               .name = "AMD AM29BDS323D",
-               .size = 0x00400000,
-               .numeraseregions = 3,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 },
-                       { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
-                       { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks =  8 },
-               }
-       }, {
-               .mfr_id = MANUFACTURER_ATMEL,
-               .dev_id = AT49xV16x,
-               .name = "Atmel AT49xV16x",
-               .size = 0x00200000,
-               .numeraseregions = 2,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x02000, .numblocks =  8 },
-                       { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
-               }
-       }, {
-               .mfr_id = MANUFACTURER_ATMEL,
-               .dev_id = AT49xV16xT,
-               .name = "Atmel AT49xV16xT",
-               .size = 0x00200000,
-               .numeraseregions = 2,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks =  8 }
-               }
-       }
-       };
-
-       struct mtd_info *mtd;
-       struct flchip chips[MAX_AMD_CHIPS];
-       int table_pos[MAX_AMD_CHIPS];
-       struct amd_flash_private temp;
-       struct amd_flash_private *private;
-       u_long size;
-       unsigned long base;
-       int i;
-       int reg_idx;
-       int offset;
-
-       mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-       if (!mtd) {
-               printk(KERN_WARNING
-                      "%s: kmalloc failed for info structure\n", map->name);
-               return NULL;
-       }
-       mtd->priv = map;
-
-       memset(&temp, 0, sizeof(temp));
-
-       printk("%s: Probing for AMD compatible flash...\n", map->name);
-
-       if ((table_pos[0] = probe_new_chip(mtd, 0, NULL, &temp, table,
-                                          ARRAY_SIZE(table)))
-           == -1) {
-               printk(KERN_WARNING
-                      "%s: Found no AMD compatible device at location zero\n",
-                      map->name);
-               kfree(mtd);
-
-               return NULL;
-       }
-
-       chips[0].start = 0;
-       chips[0].state = FL_READY;
-       chips[0].mutex = &chips[0]._spinlock;
-       temp.numchips = 1;
-       for (size = mtd->size; size > 1; size >>= 1) {
-               temp.chipshift++;
-       }
-       switch (temp.interleave) {
-               case 2:
-                       temp.chipshift += 1;
-                       break;
-               case 4:
-                       temp.chipshift += 2;
-                       break;
-       }
-
-       /* Find out if there are any more chips in the map. */
-       for (base = (1 << temp.chipshift);
-            base < map->size;
-            base += (1 << temp.chipshift)) {
-               int numchips = temp.numchips;
-               table_pos[numchips] = probe_new_chip(mtd, base, chips,
-                       &temp, table, ARRAY_SIZE(table));
-       }
-
-       mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) *
-                                   mtd->numeraseregions, GFP_KERNEL);
-       if (!mtd->eraseregions) {
-               printk(KERN_WARNING "%s: Failed to allocate "
-                      "memory for MTD erase region info\n", map->name);
-               kfree(mtd);
-               map->fldrv_priv = NULL;
-               return NULL;
-       }
-
-       reg_idx = 0;
-       offset = 0;
-       for (i = 0; i < temp.numchips; i++) {
-               int dev_size;
-               int j;
-
-               dev_size = 0;
-               for (j = 0; j < table[table_pos[i]].numeraseregions; j++) {
-                       mtd->eraseregions[reg_idx].offset = offset +
-                               (table[table_pos[i]].regions[j].offset *
-                                temp.interleave);
-                       mtd->eraseregions[reg_idx].erasesize =
-                               table[table_pos[i]].regions[j].erasesize *
-                               temp.interleave;
-                       mtd->eraseregions[reg_idx].numblocks =
-                               table[table_pos[i]].regions[j].numblocks;
-                       if (mtd->erasesize <
-                           mtd->eraseregions[reg_idx].erasesize) {
-                               mtd->erasesize =
-                                       mtd->eraseregions[reg_idx].erasesize;
-                       }
-                       dev_size += mtd->eraseregions[reg_idx].erasesize *
-                                   mtd->eraseregions[reg_idx].numblocks;
-                       reg_idx++;
-               }
-               offset += dev_size;
-       }
-       mtd->type = MTD_NORFLASH;
-       mtd->writesize = 1;
-       mtd->flags = MTD_CAP_NORFLASH;
-       mtd->name = map->name;
-       mtd->erase = amd_flash_erase;
-       mtd->read = amd_flash_read;
-       mtd->write = amd_flash_write;
-       mtd->sync = amd_flash_sync;
-       mtd->suspend = amd_flash_suspend;
-       mtd->resume = amd_flash_resume;
-       mtd->lock = amd_flash_lock;
-       mtd->unlock = amd_flash_unlock;
-
-       private = kmalloc(sizeof(*private) + (sizeof(struct flchip) *
-                                             temp.numchips), GFP_KERNEL);
-       if (!private) {
-               printk(KERN_WARNING
-                      "%s: kmalloc failed for private structure\n", map->name);
-               kfree(mtd);
-               map->fldrv_priv = NULL;
-               return NULL;
-       }
-       memcpy(private, &temp, sizeof(temp));
-       memcpy(private->chips, chips,
-              sizeof(struct flchip) * private->numchips);
-       for (i = 0; i < private->numchips; i++) {
-               init_waitqueue_head(&private->chips[i].wq);
-               spin_lock_init(&private->chips[i]._spinlock);
-       }
-
-       map->fldrv_priv = private;
-
-       map->fldrv = &amd_flash_chipdrv;
-
-       __module_get(THIS_MODULE);
-       return mtd;
-}
-
-
-
-static inline int read_one_chip(struct map_info *map, struct flchip *chip,
-                              loff_t adr, size_t len, u_char *buf)
-{
-       DECLARE_WAITQUEUE(wait, current);
-       unsigned long timeo = jiffies + HZ;
-
-retry:
-       spin_lock_bh(chip->mutex);
-
-       if (chip->state != FL_READY){
-               printk(KERN_INFO "%s: waiting for chip to read, state = %d\n",
-                      map->name, chip->state);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-
-               spin_unlock_bh(chip->mutex);
-
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-
-               if(signal_pending(current)) {
-                       return -EINTR;
-               }
-
-               timeo = jiffies + HZ;
-
-               goto retry;
-       }
-
-       adr += chip->start;
-
-       chip->state = FL_READY;
-
-       map_copy_from(map, buf, adr, len);
-
-       wake_up(&chip->wq);
-       spin_unlock_bh(chip->mutex);
-
-       return 0;
-}
-
-
-
-static int amd_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
-                         size_t *retlen, u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private *private = map->fldrv_priv;
-       unsigned long ofs;
-       int chipnum;
-       int ret = 0;
-
-       if ((from + len) > mtd->size) {
-               printk(KERN_WARNING "%s: read request past end of device "
-                      "(0x%lx)\n", map->name, (unsigned long)from + len);
-
-               return -EINVAL;
-       }
-
-       /* Offset within the first chip that the first read should start. */
-       chipnum = (from >> private->chipshift);
-       ofs = from - (chipnum <<  private->chipshift);
-
-       *retlen = 0;
-
-       while (len) {
-               unsigned long this_len;
-
-               if (chipnum >= private->numchips) {
-                       break;
-               }
-
-               if ((len + ofs - 1) >> private->chipshift) {
-                       this_len = (1 << private->chipshift) - ofs;
-               } else {
-                       this_len = len;
-               }
-
-               ret = read_one_chip(map, &private->chips[chipnum], ofs,
-                                   this_len, buf);
-               if (ret) {
-                       break;
-               }
-
-               *retlen += this_len;
-               len -= this_len;
-               buf += this_len;
-
-               ofs = 0;
-               chipnum++;
-       }
-
-       return ret;
-}
-
-
-
-static int write_one_word(struct map_info *map, struct flchip *chip,
-                         unsigned long adr, __u32 datum)
-{
-       unsigned long timeo = jiffies + HZ;
-       struct amd_flash_private *private = map->fldrv_priv;
-       DECLARE_WAITQUEUE(wait, current);
-       int ret = 0;
-       int times_left;
-
-retry:
-       spin_lock_bh(chip->mutex);
-
-       if (chip->state != FL_READY){
-               printk("%s: waiting for chip to write, state = %d\n",
-                      map->name, chip->state);
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-
-               spin_unlock_bh(chip->mutex);
-
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-               printk(KERN_INFO "%s: woke up to write\n", map->name);
-               if(signal_pending(current))
-                       return -EINTR;
-
-               timeo = jiffies + HZ;
-
-               goto retry;
-       }
-
-       chip->state = FL_WRITING;
-
-       adr += chip->start;
-       ENABLE_VPP(map);
-       send_cmd(map, chip->start, CMD_PROGRAM_UNLOCK_DATA);
-       wide_write(map, datum, adr);
-
-       times_left = 500000;
-       while (times_left-- && flash_is_busy(map, adr, private->interleave)) {
-               if (need_resched()) {
-                       spin_unlock_bh(chip->mutex);
-                       schedule();
-                       spin_lock_bh(chip->mutex);
-               }
-       }
-
-       if (!times_left) {
-               printk(KERN_WARNING "%s: write to 0x%lx timed out!\n",
-                      map->name, adr);
-               ret = -EIO;
-       } else {
-               __u32 verify;
-               if ((verify = wide_read(map, adr)) != datum) {
-                       printk(KERN_WARNING "%s: write to 0x%lx failed. "
-                              "datum = %x, verify = %x\n",
-                              map->name, adr, datum, verify);
-                       ret = -EIO;
-               }
-       }
-
-       DISABLE_VPP(map);
-       chip->state = FL_READY;
-       wake_up(&chip->wq);
-       spin_unlock_bh(chip->mutex);
-
-       return ret;
-}
-
-
-
-static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len,
-                          size_t *retlen, const u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private *private = map->fldrv_priv;
-       int ret = 0;
-       int chipnum;
-       unsigned long ofs;
-       unsigned long chipstart;
-
-       *retlen = 0;
-       if (!len) {
-               return 0;
-       }
-
-       chipnum = to >> private->chipshift;
-       ofs = to  - (chipnum << private->chipshift);
-       chipstart = private->chips[chipnum].start;
-
-       /* If it's not bus-aligned, do the first byte write. */
-       if (ofs & (map->buswidth - 1)) {
-               unsigned long bus_ofs = ofs & ~(map->buswidth - 1);
-               int i = ofs - bus_ofs;
-               int n = 0;
-               u_char tmp_buf[4];
-               __u32 datum;
-
-               map_copy_from(map, tmp_buf,
-                              bus_ofs + private->chips[chipnum].start,
-                              map->buswidth);
-               while (len && i < map->buswidth)
-                       tmp_buf[i++] = buf[n++], len--;
-
-               if (map->buswidth == 2) {
-                       datum = *(__u16*)tmp_buf;
-               } else if (map->buswidth == 4) {
-                       datum = *(__u32*)tmp_buf;
-               } else {
-                       return -EINVAL;  /* should never happen, but be safe */
-               }
-
-               ret = write_one_word(map, &private->chips[chipnum], bus_ofs,
-                                    datum);
-               if (ret) {
-                       return ret;
-               }
-
-               ofs += n;
-               buf += n;
-               (*retlen) += n;
-
-               if (ofs >> private->chipshift) {
-                       chipnum++;
-                       ofs = 0;
-                       if (chipnum == private->numchips) {
-                               return 0;
-                       }
-               }
-       }
-
-       /* We are now aligned, write as much as possible. */
-       while(len >= map->buswidth) {
-               __u32 datum;
-
-               if (map->buswidth == 1) {
-                       datum = *(__u8*)buf;
-               } else if (map->buswidth == 2) {
-                       datum = *(__u16*)buf;
-               } else if (map->buswidth == 4) {
-                       datum = *(__u32*)buf;
-               } else {
-                       return -EINVAL;
-               }
-
-               ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
-
-               if (ret) {
-                       return ret;
-               }
-
-               ofs += map->buswidth;
-               buf += map->buswidth;
-               (*retlen) += map->buswidth;
-               len -= map->buswidth;
-
-               if (ofs >> private->chipshift) {
-                       chipnum++;
-                       ofs = 0;
-                       if (chipnum == private->numchips) {
-                               return 0;
-                       }
-                       chipstart = private->chips[chipnum].start;
-               }
-       }
-
-       if (len & (map->buswidth - 1)) {
-               int i = 0, n = 0;
-               u_char tmp_buf[2];
-               __u32 datum;
-
-               map_copy_from(map, tmp_buf,
-                              ofs + private->chips[chipnum].start,
-                              map->buswidth);
-               while (len--) {
-                       tmp_buf[i++] = buf[n++];
-               }
-
-               if (map->buswidth == 2) {
-                       datum = *(__u16*)tmp_buf;
-               } else if (map->buswidth == 4) {
-                       datum = *(__u32*)tmp_buf;
-               } else {
-                       return -EINVAL;  /* should never happen, but be safe */
-               }
-
-               ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
-
-               if (ret) {
-                       return ret;
-               }
-
-               (*retlen) += n;
-       }
-
-       return 0;
-}
-
-
-
-static inline int erase_one_block(struct map_info *map, struct flchip *chip,
-                                 unsigned long adr, u_long size)
-{
-       unsigned long timeo = jiffies + HZ;
-       struct amd_flash_private *private = map->fldrv_priv;
-       DECLARE_WAITQUEUE(wait, current);
-
-retry:
-       spin_lock_bh(chip->mutex);
-
-       if (chip->state != FL_READY){
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-
-               spin_unlock_bh(chip->mutex);
-
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-
-               if (signal_pending(current)) {
-                       return -EINTR;
-               }
-
-               timeo = jiffies + HZ;
-
-               goto retry;
-       }
-
-       chip->state = FL_ERASING;
-
-       adr += chip->start;
-       ENABLE_VPP(map);
-       send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA);
-       send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr);
-
-       timeo = jiffies + (HZ * 20);
-
-       spin_unlock_bh(chip->mutex);
-       msleep(1000);
-       spin_lock_bh(chip->mutex);
-
-       while (flash_is_busy(map, adr, private->interleave)) {
-
-               if (chip->state != FL_ERASING) {
-                       /* Someone's suspended the erase. Sleep */
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       add_wait_queue(&chip->wq, &wait);
-
-                       spin_unlock_bh(chip->mutex);
-                       printk(KERN_INFO "%s: erase suspended. Sleeping\n",
-                              map->name);
-                       schedule();
-                       remove_wait_queue(&chip->wq, &wait);
-
-                       if (signal_pending(current)) {
-                               return -EINTR;
-                       }
-
-                       timeo = jiffies + (HZ*2); /* FIXME */
-                       spin_lock_bh(chip->mutex);
-                       continue;
-               }
-
-               /* OK Still waiting */
-               if (time_after(jiffies, timeo)) {
-                       chip->state = FL_READY;
-                       spin_unlock_bh(chip->mutex);
-                       printk(KERN_WARNING "%s: waiting for erase to complete "
-                              "timed out.\n", map->name);
-                       DISABLE_VPP(map);
-
-                       return -EIO;
-               }
-
-               /* Latency issues. Drop the lock, wait a while and retry */
-               spin_unlock_bh(chip->mutex);
-
-               if (need_resched())
-                       schedule();
-               else
-                       udelay(1);
-
-               spin_lock_bh(chip->mutex);
-       }
-
-       /* Verify every single word */
-       {
-               int address;
-               int error = 0;
-               __u8 verify;
-
-               for (address = adr; address < (adr + size); address++) {
-                       if ((verify = map_read8(map, address)) != 0xFF) {
-                               error = 1;
-                               break;
-                       }
-               }
-               if (error) {
-                       chip->state = FL_READY;
-                       spin_unlock_bh(chip->mutex);
-                       printk(KERN_WARNING
-                              "%s: verify error at 0x%x, size %ld.\n",
-                              map->name, address, size);
-                       DISABLE_VPP(map);
-
-                       return -EIO;
-               }
-       }
-
-       DISABLE_VPP(map);
-       chip->state = FL_READY;
-       wake_up(&chip->wq);
-       spin_unlock_bh(chip->mutex);
-
-       return 0;
-}
-
-
-
-static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private *private = map->fldrv_priv;
-       unsigned long adr, len;
-       int chipnum;
-       int ret = 0;
-       int i;
-       int first;
-       struct mtd_erase_region_info *regions = mtd->eraseregions;
-
-       if (instr->addr > mtd->size) {
-               return -EINVAL;
-       }
-
-       if ((instr->len + instr->addr) > mtd->size) {
-               return -EINVAL;
-       }
-
-       /* Check that both start and end of the requested erase are
-        * aligned with the erasesize at the appropriate addresses.
-        */
-
-       i = 0;
-
-        /* Skip all erase regions which are ended before the start of
-           the requested erase. Actually, to save on the calculations,
-           we skip to the first erase region which starts after the
-           start of the requested erase, and then go back one.
-        */
-
-        while ((i < mtd->numeraseregions) &&
-              (instr->addr >= regions[i].offset)) {
-               i++;
-       }
-        i--;
-
-       /* OK, now i is pointing at the erase region in which this
-        * erase request starts. Check the start of the requested
-        * erase range is aligned with the erase size which is in
-        * effect here.
-        */
-
-       if (instr->addr & (regions[i].erasesize-1)) {
-               return -EINVAL;
-       }
-
-       /* Remember the erase region we start on. */
-
-       first = i;
-
-       /* Next, check that the end of the requested erase is aligned
-        * with the erase region at that address.
-        */
-
-       while ((i < mtd->numeraseregions) &&
-              ((instr->addr + instr->len) >= regions[i].offset)) {
-                i++;
-       }
-
-       /* As before, drop back one to point at the region in which
-        * the address actually falls.
-        */
-
-       i--;
-
-       if ((instr->addr + instr->len) & (regions[i].erasesize-1)) {
-                return -EINVAL;
-       }
-
-       chipnum = instr->addr >> private->chipshift;
-       adr = instr->addr - (chipnum << private->chipshift);
-       len = instr->len;
-
-       i = first;
-
-       while (len) {
-               ret = erase_one_block(map, &private->chips[chipnum], adr,
-                                     regions[i].erasesize);
-
-               if (ret) {
-                       return ret;
-               }
-
-               adr += regions[i].erasesize;
-               len -= regions[i].erasesize;
-
-               if ((adr % (1 << private->chipshift)) ==
-                   ((regions[i].offset + (regions[i].erasesize *
-                                          regions[i].numblocks))
-                    % (1 << private->chipshift))) {
-                       i++;
-               }
-
-               if (adr >> private->chipshift) {
-                       adr = 0;
-                       chipnum++;
-                       if (chipnum >= private->numchips) {
-                               break;
-                       }
-               }
-       }
-
-       instr->state = MTD_ERASE_DONE;
-       mtd_erase_callback(instr);
-
-       return 0;
-}
-
-
-
-static void amd_flash_sync(struct mtd_info *mtd)
-{
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private *private = map->fldrv_priv;
-       int i;
-       struct flchip *chip;
-       int ret = 0;
-       DECLARE_WAITQUEUE(wait, current);
-
-       for (i = 0; !ret && (i < private->numchips); i++) {
-               chip = &private->chips[i];
-
-       retry:
-               spin_lock_bh(chip->mutex);
-
-               switch(chip->state) {
-               case FL_READY:
-               case FL_STATUS:
-               case FL_CFI_QUERY:
-               case FL_JEDEC_QUERY:
-                       chip->oldstate = chip->state;
-                       chip->state = FL_SYNCING;
-                       /* No need to wake_up() on this state change -
-                        * as the whole point is that nobody can do anything
-                        * with the chip now anyway.
-                        */
-               case FL_SYNCING:
-                       spin_unlock_bh(chip->mutex);
-                       break;
-
-               default:
-                       /* Not an idle state */
-                       add_wait_queue(&chip->wq, &wait);
-
-                       spin_unlock_bh(chip->mutex);
-
-                       schedule();
-
-                       remove_wait_queue(&chip->wq, &wait);
-
-                       goto retry;
-               }
-       }
-
-       /* Unlock the chips again */
-       for (i--; i >= 0; i--) {
-               chip = &private->chips[i];
-
-               spin_lock_bh(chip->mutex);
-
-               if (chip->state == FL_SYNCING) {
-                       chip->state = chip->oldstate;
-                       wake_up(&chip->wq);
-               }
-               spin_unlock_bh(chip->mutex);
-       }
-}
-
-
-
-static int amd_flash_suspend(struct mtd_info *mtd)
-{
-printk("amd_flash_suspend(): not implemented!\n");
-       return -EINVAL;
-}
-
-
-
-static void amd_flash_resume(struct mtd_info *mtd)
-{
-printk("amd_flash_resume(): not implemented!\n");
-}
-
-
-
-static void amd_flash_destroy(struct mtd_info *mtd)
-{
-       struct map_info *map = mtd->priv;
-       struct amd_flash_private *private = map->fldrv_priv;
-       kfree(private);
-}
-
-int __init amd_flash_init(void)
-{
-       register_mtd_chip_driver(&amd_flash_chipdrv);
-       return 0;
-}
-
-void __exit amd_flash_exit(void)
-{
-       unregister_mtd_chip_driver(&amd_flash_chipdrv);
-}
-
-module_init(amd_flash_init);
-module_exit(amd_flash_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jonas Holmberg <jonas.holmberg@axis.com>");
-MODULE_DESCRIPTION("Old MTD chip driver for AMD flash chips");
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c
deleted file mode 100644 (file)
index 14e57b2..0000000
+++ /dev/null
@@ -1,935 +0,0 @@
-
-/* JEDEC Flash Interface.
- * This is an older type of interface for self programming flash. It is
- * commonly use in older AMD chips and is obsolete compared with CFI.
- * It is called JEDEC because the JEDEC association distributes the ID codes
- * for the chips.
- *
- * See the AMD flash databook for information on how to operate the interface.
- *
- * This code does not support anything wider than 8 bit flash chips, I am
- * not going to guess how to send commands to them, plus I expect they will
- * all speak CFI..
- *
- * $Id: jedec.c,v 1.22 2005/01/05 18:05:11 dwmw2 Exp $
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mtd/jedec.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/compatmac.h>
-
-static struct mtd_info *jedec_probe(struct map_info *);
-static int jedec_probe8(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv);
-static int jedec_probe16(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv);
-static int jedec_probe32(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv);
-static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
-                           unsigned long len);
-static int flash_erase(struct mtd_info *mtd, struct erase_info *instr);
-static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
-                      size_t *retlen, const u_char *buf);
-
-static unsigned long my_bank_size;
-
-/* Listing of parts and sizes. We need this table to learn the sector
-   size of the chip and the total length */
-static const struct JEDECTable JEDEC_table[] = {
-       {
-               .jedec          = 0x013D,
-               .name           = "AMD Am29F017D",
-               .size           = 2*1024*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       {
-               .jedec          = 0x01AD,
-               .name           = "AMD Am29F016",
-               .size           = 2*1024*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       {
-               .jedec          = 0x01D5,
-               .name           = "AMD Am29F080",
-               .size           = 1*1024*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       {
-               .jedec          = 0x01A4,
-               .name           = "AMD Am29F040",
-               .size           = 512*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       {
-               .jedec          = 0x20E3,
-               .name           = "AMD Am29W040B",
-               .size           = 512*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       {
-               .jedec          = 0xC2AD,
-               .name           = "Macronix MX29F016",
-               .size           = 2*1024*1024,
-               .sectorsize     = 64*1024,
-               .capabilities   = MTD_CAP_NORFLASH
-       },
-       { .jedec = 0x0 }
-};
-
-static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id);
-static void jedec_sync(struct mtd_info *mtd) {};
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
-                     size_t *retlen, u_char *buf);
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
-                            size_t *retlen, u_char *buf);
-
-static struct mtd_info *jedec_probe(struct map_info *map);
-
-
-
-static struct mtd_chip_driver jedec_chipdrv = {
-       .probe  = jedec_probe,
-       .name   = "jedec",
-       .module = THIS_MODULE
-};
-
-/* Probe entry point */
-
-static struct mtd_info *jedec_probe(struct map_info *map)
-{
-   struct mtd_info *MTD;
-   struct jedec_private *priv;
-   unsigned long Base;
-   unsigned long SectorSize;
-   unsigned count;
-   unsigned I,Uniq;
-   char Part[200];
-   memset(&priv,0,sizeof(priv));
-
-   MTD = kzalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
-   if (!MTD)
-          return NULL;
-
-   priv = (struct jedec_private *)&MTD[1];
-
-   my_bank_size = map->size;
-
-   if (map->size/my_bank_size > MAX_JEDEC_CHIPS)
-   {
-      printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
-      kfree(MTD);
-      return NULL;
-   }
-
-   for (Base = 0; Base < map->size; Base += my_bank_size)
-   {
-      // Perhaps zero could designate all tests?
-      if (map->buswidth == 0)
-        map->buswidth = 1;
-
-      if (map->buswidth == 1){
-        if (jedec_probe8(map,Base,priv) == 0) {
-                printk("did recognize jedec chip\n");
-                kfree(MTD);
-                return NULL;
-        }
-      }
-      if (map->buswidth == 2)
-        jedec_probe16(map,Base,priv);
-      if (map->buswidth == 4)
-        jedec_probe32(map,Base,priv);
-   }
-
-   // Get the biggest sector size
-   SectorSize = 0;
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-          //      printk("priv->chips[%d].jedec is %x\n",I,priv->chips[I].jedec);
-          //      printk("priv->chips[%d].sectorsize is %lx\n",I,priv->chips[I].sectorsize);
-      if (priv->chips[I].sectorsize > SectorSize)
-        SectorSize = priv->chips[I].sectorsize;
-   }
-
-   // Quickly ensure that the other sector sizes are factors of the largest
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      if ((SectorSize/priv->chips[I].sectorsize)*priv->chips[I].sectorsize != SectorSize)
-      {
-        printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
-        kfree(MTD);
-        return NULL;
-      }
-   }
-
-   /* Generate a part name that includes the number of different chips and
-      other configuration information */
-   count = 1;
-   strlcpy(Part,map->name,sizeof(Part)-10);
-   strcat(Part," ");
-   Uniq = 0;
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      const struct JEDECTable *JEDEC;
-
-      if (priv->chips[I+1].jedec == priv->chips[I].jedec)
-      {
-        count++;
-        continue;
-      }
-
-      // Locate the chip in the jedec table
-      JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec);
-      if (JEDEC == 0)
-      {
-        printk("mtd: Internal Error, JEDEC not set\n");
-        kfree(MTD);
-        return NULL;
-      }
-
-      if (Uniq != 0)
-        strcat(Part,",");
-      Uniq++;
-
-      if (count != 1)
-        sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name);
-      else
-        sprintf(Part+strlen(Part),"%s",JEDEC->name);
-      if (strlen(Part) > sizeof(Part)*2/3)
-        break;
-      count = 1;
-   }
-
-   /* Determine if the chips are organized in a linear fashion, or if there
-      are empty banks. Note, the last bank does not count here, only the
-      first banks are important. Holes on non-bank boundaries can not exist
-      due to the way the detection algorithm works. */
-   if (priv->size < my_bank_size)
-      my_bank_size = priv->size;
-   priv->is_banked = 0;
-   //printk("priv->size is %x, my_bank_size is %x\n",priv->size,my_bank_size);
-   //printk("priv->bank_fill[0] is %x\n",priv->bank_fill[0]);
-   if (!priv->size) {
-          printk("priv->size is zero\n");
-          kfree(MTD);
-          return NULL;
-   }
-   if (priv->size/my_bank_size) {
-          if (priv->size/my_bank_size == 1) {
-                  priv->size = my_bank_size;
-          }
-          else {
-                  for (I = 0; I != priv->size/my_bank_size - 1; I++)
-                  {
-                     if (priv->bank_fill[I] != my_bank_size)
-                        priv->is_banked = 1;
-
-                     /* This even could be eliminated, but new de-optimized read/write
-                        functions have to be written */
-                     printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]);
-                     if (priv->bank_fill[I] != priv->bank_fill[0])
-                     {
-                        printk("mtd: Failed. Cannot handle unsymmetric banking\n");
-                        kfree(MTD);
-                        return NULL;
-                     }
-                  }
-          }
-   }
-   if (priv->is_banked == 1)
-      strcat(Part,", banked");
-
-   //   printk("Part: '%s'\n",Part);
-
-   memset(MTD,0,sizeof(*MTD));
-  // strlcpy(MTD->name,Part,sizeof(MTD->name));
-   MTD->name = map->name;
-   MTD->type = MTD_NORFLASH;
-   MTD->flags = MTD_CAP_NORFLASH;
-   MTD->writesize = 1;
-   MTD->erasesize = SectorSize*(map->buswidth);
-   //   printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
-   MTD->size = priv->size;
-   //   printk("MTD->size is %x\n",(unsigned int)MTD->size);
-   //MTD->module = THIS_MODULE; // ? Maybe this should be the low level module?
-   MTD->erase = flash_erase;
-   if (priv->is_banked == 1)
-      MTD->read = jedec_read_banked;
-   else
-      MTD->read = jedec_read;
-   MTD->write = flash_write;
-   MTD->sync = jedec_sync;
-   MTD->priv = map;
-   map->fldrv_priv = priv;
-   map->fldrv = &jedec_chipdrv;
-   __module_get(THIS_MODULE);
-   return MTD;
-}
-
-/* Helper for the JEDEC function, JEDEC numbers all have odd parity */
-static int checkparity(u_char C)
-{
-   u_char parity = 0;
-   while (C != 0)
-   {
-      parity ^= C & 1;
-      C >>= 1;
-   }
-
-   return parity == 1;
-}
-
-
-/* Take an array of JEDEC numbers that represent interleved flash chips
-   and process them. Check to make sure they are good JEDEC numbers, look
-   them up and then add them to the chip list */
-static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
-                 unsigned long base,struct jedec_private *priv)
-{
-   unsigned I,J;
-   unsigned long Size;
-   unsigned long SectorSize;
-   const struct JEDECTable *JEDEC;
-
-   // Test #2 JEDEC numbers exhibit odd parity
-   for (I = 0; I != Count; I++)
-   {
-      if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0)
-        return 0;
-   }
-
-   // Finally, just make sure all the chip sizes are the same
-   JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
-
-   if (JEDEC == 0)
-   {
-      printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
-      return 0;
-   }
-
-   Size = JEDEC->size;
-   SectorSize = JEDEC->sectorsize;
-   for (I = 0; I != Count; I++)
-   {
-      JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
-      if (JEDEC == 0)
-      {
-        printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
-        return 0;
-      }
-
-      if (Size != JEDEC->size || SectorSize != JEDEC->sectorsize)
-      {
-        printk("mtd: Failed. Interleved flash does not have matching characteristics\n");
-        return 0;
-      }
-   }
-
-   // Load the Chips
-   for (I = 0; I != MAX_JEDEC_CHIPS; I++)
-   {
-      if (priv->chips[I].jedec == 0)
-        break;
-   }
-
-   if (I + Count > MAX_JEDEC_CHIPS)
-   {
-      printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n");
-      return 0;
-   }
-
-   // Add them to the table
-   for (J = 0; J != Count; J++)
-   {
-      unsigned long Bank;
-
-      JEDEC = jedec_idtoinf(Mfg[J],Id[J]);
-      priv->chips[I].jedec = (Mfg[J] << 8) | Id[J];
-      priv->chips[I].size = JEDEC->size;
-      priv->chips[I].sectorsize = JEDEC->sectorsize;
-      priv->chips[I].base = base + J;
-      priv->chips[I].datashift = J*8;
-      priv->chips[I].capabilities = JEDEC->capabilities;
-      priv->chips[I].offset = priv->size + J;
-
-      // log2 n :|
-      priv->chips[I].addrshift = 0;
-      for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++);
-
-      // Determine how filled this bank is.
-      Bank = base & (~(my_bank_size-1));
-      if (priv->bank_fill[Bank/my_bank_size] < base +
-         (JEDEC->size << priv->chips[I].addrshift) - Bank)
-        priv->bank_fill[Bank/my_bank_size] =  base + (JEDEC->size << priv->chips[I].addrshift) - Bank;
-      I++;
-   }
-
-   priv->size += priv->chips[I-1].size*Count;
-
-   return priv->chips[I-1].size;
-}
-
-/* Lookup the chip information from the JEDEC ID table. */
-static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
-{
-   __u16 Id = (mfr << 8) | id;
-   unsigned long I = 0;
-   for (I = 0; JEDEC_table[I].jedec != 0; I++)
-      if (JEDEC_table[I].jedec == Id)
-        return JEDEC_table + I;
-   return NULL;
-}
-
-// Look for flash using an 8 bit bus interface
-static int jedec_probe8(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv)
-{
-   #define flread(x) map_read8(map,base+x)
-   #define flwrite(v,x) map_write8(map,v,base+x)
-
-   const unsigned long AutoSel1 = 0xAA;
-   const unsigned long AutoSel2 = 0x55;
-   const unsigned long AutoSel3 = 0x90;
-   const unsigned long Reset = 0xF0;
-   __u32 OldVal;
-   __u8 Mfg[1];
-   __u8 Id[1];
-   unsigned I;
-   unsigned long Size;
-
-   // Wait for any write/erase operation to settle
-   OldVal = flread(base);
-   for (I = 0; OldVal != flread(base) && I < 10000; I++)
-      OldVal = flread(base);
-
-   // Reset the chip
-   flwrite(Reset,0x555);
-
-   // Send the sequence
-   flwrite(AutoSel1,0x555);
-   flwrite(AutoSel2,0x2AA);
-   flwrite(AutoSel3,0x555);
-
-   //  Get the JEDEC numbers
-   Mfg[0] = flread(0);
-   Id[0] = flread(1);
-   //   printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]);
-
-   Size = handle_jedecs(map,Mfg,Id,1,base,priv);
-   //   printk("handle_jedecs Size is %x\n",(unsigned int)Size);
-   if (Size == 0)
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-
-
-   // Reset.
-   flwrite(Reset,0x555);
-
-   return 1;
-
-   #undef flread
-   #undef flwrite
-}
-
-// Look for flash using a 16 bit bus interface (ie 2 8-bit chips)
-static int jedec_probe16(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv)
-{
-   return 0;
-}
-
-// Look for flash using a 32 bit bus interface (ie 4 8-bit chips)
-static int jedec_probe32(struct map_info *map,unsigned long base,
-                 struct jedec_private *priv)
-{
-   #define flread(x) map_read32(map,base+((x)<<2))
-   #define flwrite(v,x) map_write32(map,v,base+((x)<<2))
-
-   const unsigned long AutoSel1 = 0xAAAAAAAA;
-   const unsigned long AutoSel2 = 0x55555555;
-   const unsigned long AutoSel3 = 0x90909090;
-   const unsigned long Reset = 0xF0F0F0F0;
-   __u32 OldVal;
-   __u8 Mfg[4];
-   __u8 Id[4];
-   unsigned I;
-   unsigned long Size;
-
-   // Wait for any write/erase operation to settle
-   OldVal = flread(base);
-   for (I = 0; OldVal != flread(base) && I < 10000; I++)
-      OldVal = flread(base);
-
-   // Reset the chip
-   flwrite(Reset,0x555);
-
-   // Send the sequence
-   flwrite(AutoSel1,0x555);
-   flwrite(AutoSel2,0x2AA);
-   flwrite(AutoSel3,0x555);
-
-   // Test #1, JEDEC numbers are readable from 0x??00/0x??01
-   if (flread(0) != flread(0x100) ||
-       flread(1) != flread(0x101))
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-
-   // Split up the JEDEC numbers
-   OldVal = flread(0);
-   for (I = 0; I != 4; I++)
-      Mfg[I] = (OldVal >> (I*8));
-   OldVal = flread(1);
-   for (I = 0; I != 4; I++)
-      Id[I] = (OldVal >> (I*8));
-
-   Size = handle_jedecs(map,Mfg,Id,4,base,priv);
-   if (Size == 0)
-   {
-      flwrite(Reset,0x555);
-      return 0;
-   }
-
-   /* Check if there is address wrap around within a single bank, if this
-      returns JEDEC numbers then we assume that it is wrap around. Notice
-      we call this routine with the JEDEC return still enabled, if two or
-      more flashes have a truncated address space the probe test will still
-      work */
-   if (base + (Size<<2)+0x555 < map->size &&
-       base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size)
-   {
-      if (flread(base+Size) != flread(base+Size + 0x100) ||
-         flread(base+Size + 1) != flread(base+Size + 0x101))
-      {
-        jedec_probe32(map,base+Size,priv);
-      }
-   }
-
-   // Reset.
-   flwrite(0xF0F0F0F0,0x555);
-
-   return 1;
-
-   #undef flread
-   #undef flwrite
-}
-
-/* Linear read. */
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
-                     size_t *retlen, u_char *buf)
-{
-   struct map_info *map = mtd->priv;
-
-   map_copy_from(map, buf, from, len);
-   *retlen = len;
-   return 0;
-}
-
-/* Banked read. Take special care to jump past the holes in the bank
-   mapping. This version assumes symetry in the holes.. */
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
-                            size_t *retlen, u_char *buf)
-{
-   struct map_info *map = mtd->priv;
-   struct jedec_private *priv = map->fldrv_priv;
-
-   *retlen = 0;
-   while (len > 0)
-   {
-      // Determine what bank and offset into that bank the first byte is
-      unsigned long bank = from & (~(priv->bank_fill[0]-1));
-      unsigned long offset = from & (priv->bank_fill[0]-1);
-      unsigned long get = len;
-      if (priv->bank_fill[0] - offset < len)
-        get = priv->bank_fill[0] - offset;
-
-      bank /= priv->bank_fill[0];
-      map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
-
-      len -= get;
-      *retlen += get;
-      from += get;
-   }
-   return 0;
-}
-
-/* Pass the flags value that the flash return before it re-entered read
-   mode. */
-static void jedec_flash_failed(unsigned char code)
-{
-   /* Bit 5 being high indicates that there was an internal device
-      failure, erasure time limits exceeded or something */
-   if ((code & (1 << 5)) != 0)
-   {
-      printk("mtd: Internal Flash failure\n");
-      return;
-   }
-   printk("mtd: Programming didn't take\n");
-}
-
-/* This uses the erasure function described in the AMD Flash Handbook,
-   it will work for flashes with a fixed sector size only. Flashes with
-   a selection of sector sizes (ie the AMD Am29F800B) will need a different
-   routine. This routine tries to parallize erasing multiple chips/sectors
-   where possible */
-static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-   // Does IO to the currently selected chip
-   #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift))
-   #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift))
-
-   unsigned long Time = 0;
-   unsigned long NoTime = 0;
-   unsigned long start = instr->addr, len = instr->len;
-   unsigned int I;
-   struct map_info *map = mtd->priv;
-   struct jedec_private *priv = map->fldrv_priv;
-
-   // Verify the arguments..
-   if (start + len > mtd->size ||
-       (start % mtd->erasesize) != 0 ||
-       (len % mtd->erasesize) != 0 ||
-       (len/mtd->erasesize) == 0)
-      return -EINVAL;
-
-   jedec_flash_chip_scan(priv,start,len);
-
-   // Start the erase sequence on each chip
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      unsigned long off;
-      struct jedec_flash_chip *chip = priv->chips + I;
-
-      if (chip->length == 0)
-        continue;
-
-      if (chip->start + chip->length > chip->size)
-      {
-        printk("DIE\n");
-        return -EIO;
-      }
-
-      flwrite(0xF0,chip->start + 0x555);
-      flwrite(0xAA,chip->start + 0x555);
-      flwrite(0x55,chip->start + 0x2AA);
-      flwrite(0x80,chip->start + 0x555);
-      flwrite(0xAA,chip->start + 0x555);
-      flwrite(0x55,chip->start + 0x2AA);
-
-      /* Once we start selecting the erase sectors the delay between each
-         command must not exceed 50us or it will immediately start erasing
-         and ignore the other sectors */
-      for (off = 0; off < len; off += chip->sectorsize)
-      {
-        // Check to make sure we didn't timeout
-        flwrite(0x30,chip->start + off);
-        if (off == 0)
-           continue;
-        if ((flread(chip->start + off) & (1 << 3)) != 0)
-        {
-           printk("mtd: Ack! We timed out the erase timer!\n");
-           return -EIO;
-        }
-      }
-   }
-
-   /* We could split this into a timer routine and return early, performing
-      background erasure.. Maybe later if the need warrents */
-
-   /* Poll the flash for erasure completion, specs say this can take as long
-      as 480 seconds to do all the sectors (for a 2 meg flash).
-      Erasure time is dependent on chip age, temp and wear.. */
-
-   /* This being a generic routine assumes a 32 bit bus. It does read32s
-      and bundles interleved chips into the same grouping. This will work
-      for all bus widths */
-   Time = 0;
-   NoTime = 0;
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      struct jedec_flash_chip *chip = priv->chips + I;
-      unsigned long off = 0;
-      unsigned todo[4] = {0,0,0,0};
-      unsigned todo_left = 0;
-      unsigned J;
-
-      if (chip->length == 0)
-        continue;
-
-      /* Find all chips in this data line, realistically this is all
-         or nothing up to the interleve count */
-      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
-      {
-        if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
-            (chip->base & (~((1<<chip->addrshift)-1))))
-        {
-           todo_left++;
-           todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;
-        }
-      }
-
-      /*      printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],
-             (short)todo[2],(short)todo[3]);
-      */
-      while (1)
-      {
-        __u32 Last[4];
-        unsigned long Count = 0;
-
-        /* During erase bit 7 is held low and bit 6 toggles, we watch this,
-           should it stop toggling or go high then the erase is completed,
-           or this is not really flash ;> */
-        switch (map->buswidth) {
-        case 1:
-           Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-           break;
-        case 2:
-           Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-           break;
-        case 3:
-           Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-           Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-           break;
-        }
-        Count = 3;
-        while (todo_left != 0)
-        {
-           for (J = 0; J != 4; J++)
-           {
-              __u8 Byte1 = (Last[(Count-1)%4] >> (J*8)) & 0xFF;
-              __u8 Byte2 = (Last[(Count-2)%4] >> (J*8)) & 0xFF;
-              __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;
-              if (todo[J] == 0)
-                 continue;
-
-              if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)
-              {
-//               printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);
-                 continue;
-              }
-
-              if (Byte1 == Byte2)
-              {
-                 jedec_flash_failed(Byte3);
-                 return -EIO;
-              }
-
-              todo[J] = 0;
-              todo_left--;
-           }
-
-/*         if (NoTime == 0)
-              Time += HZ/10 - schedule_timeout(HZ/10);*/
-           NoTime = 0;
-
-           switch (map->buswidth) {
-           case 1:
-              Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off);
-             break;
-           case 2:
-              Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off);
-             break;
-           case 4:
-              Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off);
-             break;
-           }
-           Count++;
-
-/*         // Count time, max of 15s per sector (according to AMD)
-           if (Time > 15*len/mtd->erasesize*HZ)
-           {
-              printk("mtd: Flash Erase Timed out\n");
-              return -EIO;
-           }       */
-        }
-
-        // Skip to the next chip if we used chip erase
-        if (chip->length == chip->size)
-           off = chip->size;
-        else
-           off += chip->sectorsize;
-
-        if (off >= chip->length)
-           break;
-        NoTime = 1;
-      }
-
-      for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
-      {
-        if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
-            (chip->base & (~((1<<chip->addrshift)-1))))
-           priv->chips[J].length = 0;
-      }
-   }
-
-   //printk("done\n");
-   instr->state = MTD_ERASE_DONE;
-   mtd_erase_callback(instr);
-   return 0;
-
-   #undef flread
-   #undef flwrite
-}
-
-/* This is the simple flash writing function. It writes to every byte, in
-   sequence. It takes care of how to properly address the flash if
-   the flash is interleved. It can only be used if all the chips in the
-   array are identical!*/
-static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
-                      size_t *retlen, const u_char *buf)
-{
-   /* Does IO to the currently selected chip. It takes the bank addressing
-      base (which is divisible by the chip size) adds the necessary lower bits
-      of addrshift (interleave index) and then adds the control register index. */
-   #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-   #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-
-   struct map_info *map = mtd->priv;
-   struct jedec_private *priv = map->fldrv_priv;
-   unsigned long base;
-   unsigned long off;
-   size_t save_len = len;
-
-   if (start + len > mtd->size)
-      return -EIO;
-
-   //printk("Here");
-
-   //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len);
-   while (len != 0)
-   {
-      struct jedec_flash_chip *chip = priv->chips;
-      unsigned long bank;
-      unsigned long boffset;
-
-      // Compute the base of the flash.
-      off = ((unsigned long)start) % (chip->size << chip->addrshift);
-      base = start - off;
-
-      // Perform banked addressing translation.
-      bank = base & (~(priv->bank_fill[0]-1));
-      boffset = base & (priv->bank_fill[0]-1);
-      bank = (bank/priv->bank_fill[0])*my_bank_size;
-      base = bank + boffset;
-
-    //  printk("Flasing %X %X %X\n",base,chip->size,len);
-     // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift);
-
-      // Loop over this page
-      for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
-      {
-        unsigned char oldbyte = map_read8(map,base+off);
-        unsigned char Last[4];
-        unsigned long Count = 0;
-
-        if (oldbyte == *buf) {
-       //       printk("oldbyte and *buf is %x,len is %x\n",oldbyte,len);
-           continue;
-        }
-        if (((~oldbyte) & *buf) != 0)
-           printk("mtd: warn: Trying to set a 0 to a 1\n");
-
-        // Write
-        flwrite(0xAA,0x555);
-        flwrite(0x55,0x2AA);
-        flwrite(0xA0,0x555);
-        map_write8(map,*buf,base + off);
-        Last[0] = map_read8(map,base + off);
-        Last[1] = map_read8(map,base + off);
-        Last[2] = map_read8(map,base + off);
-
-        /* Wait for the flash to finish the operation. We store the last 4
-           status bytes that have been retrieved so we can determine why
-           it failed. The toggle bits keep toggling when there is a
-           failure */
-        for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
-             Count < 10000; Count++)
-           Last[Count % 4] = map_read8(map,base + off);
-        if (Last[(Count - 1) % 4] != *buf)
-        {
-           jedec_flash_failed(Last[(Count - 3) % 4]);
-           return -EIO;
-        }
-      }
-   }
-   *retlen = save_len;
-   return 0;
-}
-
-/* This is used to enhance the speed of the erase routine,
-   when things are being done to multiple chips it is possible to
-   parallize the operations, particularly full memory erases of multi
-   chip memories benifit */
-static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start,
-                    unsigned long len)
-{
-   unsigned int I;
-
-   // Zero the records
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-      priv->chips[I].start = priv->chips[I].length = 0;
-
-   // Intersect the region with each chip
-   for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
-   {
-      struct jedec_flash_chip *chip = priv->chips + I;
-      unsigned long ByteStart;
-      unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);
-
-      // End is before this chip or the start is after it
-      if (start+len < chip->offset ||
-         ChipEndByte - (1 << chip->addrshift) < start)
-        continue;
-
-      if (start < chip->offset)
-      {
-        ByteStart = chip->offset;
-        chip->start = 0;
-      }
-      else
-      {
-        chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;
-        ByteStart = start;
-      }
-
-      if (start + len >= ChipEndByte)
-        chip->length = (ChipEndByte - ByteStart) >> chip->addrshift;
-      else
-        chip->length = (start + len - ByteStart + (1 << chip->addrshift)-1) >> chip->addrshift;
-   }
-}
-
-int __init jedec_init(void)
-{
-       register_mtd_chip_driver(&jedec_chipdrv);
-       return 0;
-}
-
-static void __exit jedec_exit(void)
-{
-       unregister_mtd_chip_driver(&jedec_chipdrv);
-}
-
-module_init(jedec_init);
-module_exit(jedec_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com> et al.");
-MODULE_DESCRIPTION("Old MTD chip driver for JEDEC-compliant flash chips");
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
deleted file mode 100644 (file)
index c9cd3d2..0000000
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * MTD chip driver for pre-CFI Sharp flash chips
- *
- * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
- *           2000,2001 Lineo, Inc.
- *
- * $Id: sharp.c,v 1.17 2005/11/29 14:28:28 gleixner Exp $
- *
- * Devices supported:
- *   LH28F016SCT Symmetrical block flash memory, 2Mx8
- *   LH28F008SCT Symmetrical block flash memory, 1Mx8
- *
- * Documentation:
- *   http://www.sharpmeg.com/datasheets/memic/flashcmp/
- *   http://www.sharpmeg.com/datasheets/memic/flashcmp/01symf/16m/016sctl9.pdf
- *   016sctl9.pdf
- *
- * Limitations:
- *   This driver only supports 4x1 arrangement of chips.
- *   Not tested on anything but PowerPC.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/cfi.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-
-#define CMD_RESET              0xffffffff
-#define CMD_READ_ID            0x90909090
-#define CMD_READ_STATUS                0x70707070
-#define CMD_CLEAR_STATUS       0x50505050
-#define CMD_BLOCK_ERASE_1      0x20202020
-#define CMD_BLOCK_ERASE_2      0xd0d0d0d0
-#define CMD_BYTE_WRITE         0x40404040
-#define CMD_SUSPEND            0xb0b0b0b0
-#define CMD_RESUME             0xd0d0d0d0
-#define CMD_SET_BLOCK_LOCK_1   0x60606060
-#define CMD_SET_BLOCK_LOCK_2   0x01010101
-#define CMD_SET_MASTER_LOCK_1  0x60606060
-#define CMD_SET_MASTER_LOCK_2  0xf1f1f1f1
-#define CMD_CLEAR_BLOCK_LOCKS_1        0x60606060
-#define CMD_CLEAR_BLOCK_LOCKS_2        0xd0d0d0d0
-
-#define SR_READY               0x80808080 // 1 = ready
-#define SR_ERASE_SUSPEND       0x40404040 // 1 = block erase suspended
-#define SR_ERROR_ERASE         0x20202020 // 1 = error in block erase or clear lock bits
-#define SR_ERROR_WRITE         0x10101010 // 1 = error in byte write or set lock bit
-#define        SR_VPP                  0x08080808 // 1 = Vpp is low
-#define SR_WRITE_SUSPEND       0x04040404 // 1 = byte write suspended
-#define SR_PROTECT             0x02020202 // 1 = lock bit set
-#define SR_RESERVED            0x01010101
-
-#define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT)
-
-/* Configuration options */
-
-#undef AUTOUNLOCK  /* automatically unlocks blocks before erasing */
-
-static struct mtd_info *sharp_probe(struct map_info *);
-
-static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd);
-
-static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
-       size_t *retlen, u_char *buf);
-static int sharp_write(struct mtd_info *mtd, loff_t from, size_t len,
-       size_t *retlen, const u_char *buf);
-static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr);
-static void sharp_sync(struct mtd_info *mtd);
-static int sharp_suspend(struct mtd_info *mtd);
-static void sharp_resume(struct mtd_info *mtd);
-static void sharp_destroy(struct mtd_info *mtd);
-
-static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
-       unsigned long adr, __u32 datum);
-static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
-       unsigned long adr);
-#ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
-       unsigned long adr);
-#endif
-
-
-struct sharp_info{
-       struct flchip *chip;
-       int bogus;
-       int chipshift;
-       int numchips;
-       struct flchip chips[1];
-};
-
-static void sharp_destroy(struct mtd_info *mtd);
-
-static struct mtd_chip_driver sharp_chipdrv = {
-       .probe          = sharp_probe,
-       .destroy        = sharp_destroy,
-       .name           = "sharp",
-       .module         = THIS_MODULE
-};
-
-
-static struct mtd_info *sharp_probe(struct map_info *map)
-{
-       struct mtd_info *mtd = NULL;
-       struct sharp_info *sharp = NULL;
-       int width;
-
-       mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-       if(!mtd)
-               return NULL;
-
-       sharp = kzalloc(sizeof(*sharp), GFP_KERNEL);
-       if(!sharp) {
-               kfree(mtd);
-               return NULL;
-       }
-
-       width = sharp_probe_map(map,mtd);
-       if(!width){
-               kfree(mtd);
-               kfree(sharp);
-               return NULL;
-       }
-
-       mtd->priv = map;
-       mtd->type = MTD_NORFLASH;
-       mtd->erase = sharp_erase;
-       mtd->read = sharp_read;
-       mtd->write = sharp_write;
-       mtd->sync = sharp_sync;
-       mtd->suspend = sharp_suspend;
-       mtd->resume = sharp_resume;
-       mtd->flags = MTD_CAP_NORFLASH;
-       mtd->writesize = 1;
-       mtd->name = map->name;
-
-       sharp->chipshift = 23;
-       sharp->numchips = 1;
-       sharp->chips[0].start = 0;
-       sharp->chips[0].state = FL_READY;
-       sharp->chips[0].mutex = &sharp->chips[0]._spinlock;
-       sharp->chips[0].word_write_time = 0;
-       init_waitqueue_head(&sharp->chips[0].wq);
-       spin_lock_init(&sharp->chips[0]._spinlock);
-
-       map->fldrv = &sharp_chipdrv;
-       map->fldrv_priv = sharp;
-
-       __module_get(THIS_MODULE);
-       return mtd;
-}
-
-static inline void sharp_send_cmd(struct map_info *map, unsigned long cmd, unsigned long adr)
-{
-       map_word map_cmd;
-       map_cmd.x[0] = cmd;
-       map_write(map, map_cmd, adr);
-}
-
-static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd)
-{
-       map_word tmp, read0, read4;
-       unsigned long base = 0;
-       int width = 4;
-
-       tmp = map_read(map, base+0);
-
-       sharp_send_cmd(map, CMD_READ_ID, base+0);
-
-       read0 = map_read(map, base+0);
-       read4 = map_read(map, base+4);
-       if(read0.x[0] == 0x89898989){
-               printk("Looks like sharp flash\n");
-               switch(read4.x[0]){
-               case 0xaaaaaaaa:
-               case 0xa0a0a0a0:
-                       /* aa - LH28F016SCT-L95 2Mx8, 32 64k blocks*/
-                       /* a0 - LH28F016SCT-Z4  2Mx8, 32 64k blocks*/
-                       mtd->erasesize = 0x10000 * width;
-                       mtd->size = 0x200000 * width;
-                       return width;
-               case 0xa6a6a6a6:
-                       /* a6 - LH28F008SCT-L12 1Mx8, 16 64k blocks*/
-                       /* a6 - LH28F008SCR-L85 1Mx8, 16 64k blocks*/
-                       mtd->erasesize = 0x10000 * width;
-                       mtd->size = 0x100000 * width;
-                       return width;
-#if 0
-               case 0x00000000: /* unknown */
-                       /* XX - LH28F004SCT 512kx8, 8 64k blocks*/
-                       mtd->erasesize = 0x10000 * width;
-                       mtd->size = 0x80000 * width;
-                       return width;
-#endif
-               default:
-                       printk("Sort-of looks like sharp flash, 0x%08lx 0x%08lx\n",
-                               read0.x[0], read4.x[0]);
-               }
-       }else if((map_read(map, base+0).x[0] == CMD_READ_ID)){
-               /* RAM, probably */
-               printk("Looks like RAM\n");
-               map_write(map, tmp, base+0);
-       }else{
-               printk("Doesn't look like sharp flash, 0x%08lx 0x%08lx\n",
-                       read0.x[0], read4.x[0]);
-       }
-
-       return 0;
-}
-
-/* This function returns with the chip->mutex lock held. */
-static int sharp_wait(struct map_info *map, struct flchip *chip)
-{
-       int i;
-       map_word status;
-       unsigned long timeo = jiffies + HZ;
-       DECLARE_WAITQUEUE(wait, current);
-       int adr = 0;
-
-retry:
-       spin_lock_bh(chip->mutex);
-
-       switch(chip->state){
-       case FL_READY:
-               sharp_send_cmd(map, CMD_READ_STATUS, adr);
-               chip->state = FL_STATUS;
-       case FL_STATUS:
-               for(i=0;i<100;i++){
-                       status = map_read(map, adr);
-                       if((status.x[0] & SR_READY)==SR_READY)
-                               break;
-                       udelay(1);
-               }
-               break;
-       default:
-               printk("Waiting for chip\n");
-
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-
-               spin_unlock_bh(chip->mutex);
-
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-
-               if(signal_pending(current))
-                       return -EINTR;
-
-               timeo = jiffies + HZ;
-
-               goto retry;
-       }
-
-       sharp_send_cmd(map, CMD_RESET, adr);
-
-       chip->state = FL_READY;
-
-       return 0;
-}
-
-static void sharp_release(struct flchip *chip)
-{
-       wake_up(&chip->wq);
-       spin_unlock_bh(chip->mutex);
-}
-
-static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
-       size_t *retlen, u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct sharp_info *sharp = map->fldrv_priv;
-       int chipnum;
-       int ret = 0;
-       int ofs = 0;
-
-       chipnum = (from >> sharp->chipshift);
-       ofs = from & ((1 << sharp->chipshift)-1);
-
-       *retlen = 0;
-
-       while(len){
-               unsigned long thislen;
-
-               if(chipnum>=sharp->numchips)
-                       break;
-
-               thislen = len;
-               if(ofs+thislen >= (1<<sharp->chipshift))
-                       thislen = (1<<sharp->chipshift) - ofs;
-
-               ret = sharp_wait(map,&sharp->chips[chipnum]);
-               if(ret<0)
-                       break;
-
-               map_copy_from(map,buf,ofs,thislen);
-
-               sharp_release(&sharp->chips[chipnum]);
-
-               *retlen += thislen;
-               len -= thislen;
-               buf += thislen;
-
-               ofs = 0;
-               chipnum++;
-       }
-       return ret;
-}
-
-static int sharp_write(struct mtd_info *mtd, loff_t to, size_t len,
-       size_t *retlen, const u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct sharp_info *sharp = map->fldrv_priv;
-       int ret = 0;
-       int i,j;
-       int chipnum;
-       unsigned long ofs;
-       union { u32 l; unsigned char uc[4]; } tbuf;
-
-       *retlen = 0;
-
-       while(len){
-               tbuf.l = 0xffffffff;
-               chipnum = to >> sharp->chipshift;
-               ofs = to & ((1<<sharp->chipshift)-1);
-
-               j=0;
-               for(i=ofs&3;i<4 && len;i++){
-                       tbuf.uc[i] = *buf;
-                       buf++;
-                       to++;
-                       len--;
-                       j++;
-               }
-               sharp_write_oneword(map, &sharp->chips[chipnum], ofs&~3, tbuf.l);
-               if(ret<0)
-                       return ret;
-               (*retlen)+=j;
-       }
-
-       return 0;
-}
-
-static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
-       unsigned long adr, __u32 datum)
-{
-       int ret;
-       int timeo;
-       int try;
-       int i;
-       map_word data, status;
-
-       status.x[0] = 0;
-       ret = sharp_wait(map,chip);
-
-       for(try=0;try<10;try++){
-               sharp_send_cmd(map, CMD_BYTE_WRITE, adr);
-               /* cpu_to_le32 -> hack to fix the writel be->le conversion */
-               data.x[0] = cpu_to_le32(datum);
-               map_write(map, data, adr);
-
-               chip->state = FL_WRITING;
-
-               timeo = jiffies + (HZ/2);
-
-               sharp_send_cmd(map, CMD_READ_STATUS, adr);
-               for(i=0;i<100;i++){
-                       status = map_read(map, adr);
-                       if((status.x[0] & SR_READY) == SR_READY)
-                               break;
-               }
-               if(i==100){
-                       printk("sharp: timed out writing\n");
-               }
-
-               if(!(status.x[0] & SR_ERRORS))
-                       break;
-
-               printk("sharp: error writing byte at addr=%08lx status=%08lx\n", adr, status.x[0]);
-
-               sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-       }
-       sharp_send_cmd(map, CMD_RESET, adr);
-       chip->state = FL_READY;
-
-       wake_up(&chip->wq);
-       spin_unlock_bh(chip->mutex);
-
-       return 0;
-}
-
-static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-       struct map_info *map = mtd->priv;
-       struct sharp_info *sharp = map->fldrv_priv;
-       unsigned long adr,len;
-       int chipnum, ret=0;
-
-//printk("sharp_erase()\n");
-       if(instr->addr & (mtd->erasesize - 1))
-               return -EINVAL;
-       if(instr->len & (mtd->erasesize - 1))
-               return -EINVAL;
-       if(instr->len + instr->addr > mtd->size)
-               return -EINVAL;
-
-       chipnum = instr->addr >> sharp->chipshift;
-       adr = instr->addr & ((1<<sharp->chipshift)-1);
-       len = instr->len;
-
-       while(len){
-               ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr);
-               if(ret)return ret;
-
-               adr += mtd->erasesize;
-               len -= mtd->erasesize;
-               if(adr >> sharp->chipshift){
-                       adr = 0;
-                       chipnum++;
-                       if(chipnum>=sharp->numchips)
-                               break;
-               }
-       }
-
-       instr->state = MTD_ERASE_DONE;
-       mtd_erase_callback(instr);
-
-       return 0;
-}
-
-static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
-       unsigned long adr)
-{
-       int ret;
-       unsigned long timeo;
-       map_word status;
-       DECLARE_WAITQUEUE(wait, current);
-
-       sharp_send_cmd(map, CMD_READ_STATUS, adr);
-       status = map_read(map, adr);
-
-       timeo = jiffies + HZ;
-
-       while(time_before(jiffies, timeo)){
-               sharp_send_cmd(map, CMD_READ_STATUS, adr);
-               status = map_read(map, adr);
-               if((status.x[0] & SR_READY)==SR_READY){
-                       ret = 0;
-                       goto out;
-               }
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-
-               //spin_unlock_bh(chip->mutex);
-
-               schedule_timeout(1);
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-
-               //spin_lock_bh(chip->mutex);
-
-               if (signal_pending(current)){
-                       ret = -EINTR;
-                       goto out;
-               }
-
-       }
-       ret = -ETIME;
-out:
-       return ret;
-}
-
-static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
-       unsigned long adr)
-{
-       int ret;
-       //int timeo;
-       map_word status;
-       //int i;
-
-//printk("sharp_erase_oneblock()\n");
-
-#ifdef AUTOUNLOCK
-       /* This seems like a good place to do an unlock */
-       sharp_unlock_oneblock(map,chip,adr);
-#endif
-
-       sharp_send_cmd(map, CMD_BLOCK_ERASE_1, adr);
-       sharp_send_cmd(map, CMD_BLOCK_ERASE_2, adr);
-
-       chip->state = FL_ERASING;
-
-       ret = sharp_do_wait_for_ready(map,chip,adr);
-       if(ret<0)return ret;
-
-       sharp_send_cmd(map, CMD_READ_STATUS, adr);
-       status = map_read(map, adr);
-
-       if(!(status.x[0] & SR_ERRORS)){
-               sharp_send_cmd(map, CMD_RESET, adr);
-               chip->state = FL_READY;
-               //spin_unlock_bh(chip->mutex);
-               return 0;
-       }
-
-       printk("sharp: error erasing block at addr=%08lx status=%08lx\n", adr, status.x[0]);
-       sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-
-       //spin_unlock_bh(chip->mutex);
-
-       return -EIO;
-}
-
-#ifdef AUTOUNLOCK
-static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
-       unsigned long adr)
-{
-       int i;
-       map_word status;
-
-       sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_1, adr);
-       sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_2, adr);
-
-       udelay(100);
-
-       status = map_read(map, adr);
-       printk("status=%08lx\n", status.x[0]);
-
-       for(i=0;i<1000;i++){
-               //sharp_send_cmd(map, CMD_READ_STATUS, adr);
-               status = map_read(map, adr);
-               if((status.x[0] & SR_READY) == SR_READY)
-                       break;
-               udelay(100);
-       }
-       if(i==1000){
-               printk("sharp: timed out unlocking block\n");
-       }
-
-       if(!(status.x[0] & SR_ERRORS)){
-               sharp_send_cmd(map, CMD_RESET, adr);
-               chip->state = FL_READY;
-               return;
-       }
-
-       printk("sharp: error unlocking block at addr=%08lx status=%08lx\n", adr, status.x[0]);
-       sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
-}
-#endif
-
-static void sharp_sync(struct mtd_info *mtd)
-{
-       //printk("sharp_sync()\n");
-}
-
-static int sharp_suspend(struct mtd_info *mtd)
-{
-       printk("sharp_suspend()\n");
-       return -EINVAL;
-}
-
-static void sharp_resume(struct mtd_info *mtd)
-{
-       printk("sharp_resume()\n");
-
-}
-
-static void sharp_destroy(struct mtd_info *mtd)
-{
-       printk("sharp_destroy()\n");
-
-}
-
-static int __init sharp_probe_init(void)
-{
-       printk("MTD Sharp chip driver <ds@lineo.com>\n");
-
-       register_mtd_chip_driver(&sharp_chipdrv);
-
-       return 0;
-}
-
-static void __exit sharp_probe_exit(void)
-{
-       unregister_mtd_chip_driver(&sharp_chipdrv);
-}
-
-module_init(sharp_probe_init);
-module_exit(sharp_probe_exit);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Schleef <ds@schleef.org>");
-MODULE_DESCRIPTION("Old MTD chip driver for pre-CFI Sharp flash chips");
index fc4cc8ba9e29b98a5df19e0d5119dfefd5455882..be4b9948c762e33b577cbd192dd836ff50c75e46 100644 (file)
@@ -373,7 +373,7 @@ static inline void kill_final_newline(char *str)
 
 #ifndef MODULE
 static int block2mtd_init_called = 0;
-static __initdata char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
+static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
 #endif
 
 
index 5fcd8b3631ba83760f107ef5edceb3c414a136d2..b665e4ac2208458bc70d1f8dfe9cd00a3a6a58fd 100644 (file)
@@ -358,22 +358,6 @@ config MTD_CFI_FLAGADM
          Mapping for the Flaga digital module. If you don't have one, ignore
          this setting.
 
-config MTD_BEECH
-       tristate "CFI Flash device mapped on IBM 405LP Beech"
-       depends on MTD_CFI && BEECH
-       help
-         This enables access routines for the flash chips on the IBM
-         405LP Beech board. If you have one of these boards and would like
-         to use the flash chips on it, say 'Y'.
-
-config MTD_ARCTIC
-       tristate "CFI Flash device mapped on IBM 405LP Arctic"
-       depends on MTD_CFI && ARCTIC2
-       help
-         This enables access routines for the flash chips on the IBM 405LP
-         Arctic board. If you have one of these boards and would like to
-         use the flash chips on it, say 'Y'.
-
 config MTD_WALNUT
        tristate "Flash device mapped on IBM 405GP Walnut"
        depends on MTD_JEDECPROBE && WALNUT
index de036c5e61394375721a4fe789a824da6cbcf23e..3acbb5d01ca4edc159238390e1f827ebee431524 100644 (file)
@@ -58,8 +58,6 @@ obj-$(CONFIG_MTD_NETtel)      += nettel.o
 obj-$(CONFIG_MTD_SCB2_FLASH)   += scb2_flash.o
 obj-$(CONFIG_MTD_EBONY)                += ebony.o
 obj-$(CONFIG_MTD_OCOTEA)       += ocotea.o
-obj-$(CONFIG_MTD_BEECH)                += beech-mtd.o
-obj-$(CONFIG_MTD_ARCTIC)       += arctic-mtd.o
 obj-$(CONFIG_MTD_WALNUT)        += walnut.o
 obj-$(CONFIG_MTD_H720X)                += h720x-flash.o
 obj-$(CONFIG_MTD_SBC8240)      += sbc8240.o
diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c
deleted file mode 100644 (file)
index 2cc9024..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * $Id: arctic-mtd.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $
- *
- * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for
- *                              IBM 405LP Arctic boards.
- *
- * 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
- *
- * Copyright (C) 2002, International Business Machines Corporation
- * All Rights Reserved.
- *
- * Bishop Brock
- * IBM Research, Austin Center for Low-Power Computing
- * bcbrock@us.ibm.com
- * March 2002
- *
- * modified for Arctic by,
- * David Gibson
- * IBM OzLabs, Canberra, Australia
- * <arctic@gibson.dropbear.id.au>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/ibm4xx.h>
-
-/*
- * 0 : 0xFE00 0000 - 0xFEFF FFFF : Filesystem 1 (16MiB)
- * 1 : 0xFF00 0000 - 0xFF4F FFFF : kernel (5.12MiB)
- * 2 : 0xFF50 0000 - 0xFFF5 FFFF : Filesystem 2 (10.624MiB) (if non-XIP)
- * 3 : 0xFFF6 0000 - 0xFFFF FFFF : PIBS Firmware (640KiB)
- */
-
-#define FFS1_SIZE      0x01000000 /* 16MiB */
-#define KERNEL_SIZE    0x00500000 /* 5.12MiB */
-#define FFS2_SIZE      0x00a60000 /* 10.624MiB */
-#define FIRMWARE_SIZE  0x000a0000 /* 640KiB */
-
-
-#define NAME           "Arctic Linux Flash"
-#define PADDR          SUBZERO_BOOTFLASH_PADDR
-#define BUSWIDTH       2
-#define SIZE           SUBZERO_BOOTFLASH_SIZE
-#define PARTITIONS     4
-
-/* Flash memories on these boards are memory resources, accessed big-endian. */
-
-{
-  /* do nothing for now */
-}
-
-static struct map_info arctic_mtd_map = {
-       .name           = NAME,
-       .size           = SIZE,
-       .bankwidth      = BUSWIDTH,
-       .phys           = PADDR,
-};
-
-static struct mtd_info *arctic_mtd;
-
-static struct mtd_partition arctic_partitions[PARTITIONS] = {
-       { .name         = "Filesystem",
-         .size         = FFS1_SIZE,
-         .offset       = 0,},
-        { .name                = "Kernel",
-         .size         = KERNEL_SIZE,
-         .offset       = FFS1_SIZE,},
-       { .name         = "Filesystem",
-         .size         = FFS2_SIZE,
-         .offset       = FFS1_SIZE + KERNEL_SIZE,},
-       { .name         = "Firmware",
-         .size         = FIRMWARE_SIZE,
-         .offset       = SUBZERO_BOOTFLASH_SIZE - FIRMWARE_SIZE,},
-};
-
-static int __init
-init_arctic_mtd(void)
-{
-       int err;
-
-       printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-
-       arctic_mtd_map.virt = ioremap(PADDR, SIZE);
-
-       if (!arctic_mtd_map.virt) {
-               printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-               return -EIO;
-       }
-       simple_map_init(&arctic_mtd_map);
-
-       printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
-       arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
-
-       if (!arctic_mtd) {
-               iounmap(arctic_mtd_map.virt);
-               return -ENXIO;
-       }
-
-       arctic_mtd->owner = THIS_MODULE;
-
-       err = add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
-       if (err) {
-               printk("%s: add_mtd_partitions failed\n", NAME);
-               iounmap(arctic_mtd_map.virt);
-       }
-
-       return err;
-}
-
-static void __exit
-cleanup_arctic_mtd(void)
-{
-       if (arctic_mtd) {
-               del_mtd_partitions(arctic_mtd);
-               map_destroy(arctic_mtd);
-               iounmap((void *) arctic_mtd_map.virt);
-       }
-}
-
-module_init(init_arctic_mtd);
-module_exit(cleanup_arctic_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Gibson <arctic@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Arctic boards");
diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c
deleted file mode 100644 (file)
index d76d598..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * $Id: beech-mtd.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $
- *
- * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for
- *                              IBM 405LP Beech boards.
- *
- * 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
- *
- * Copyright (C) 2002, International Business Machines Corporation
- * All Rights Reserved.
- *
- * Bishop Brock
- * IBM Research, Austin Center for Low-Power Computing
- * bcbrock@us.ibm.com
- * March 2002
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/ibm4xx.h>
-
-#define NAME     "Beech Linux Flash"
-#define PADDR    BEECH_BIGFLASH_PADDR
-#define SIZE     BEECH_BIGFLASH_SIZE
-#define BUSWIDTH 1
-
-/* Flash memories on these boards are memory resources, accessed big-endian. */
-
-
-static struct map_info beech_mtd_map = {
-       .name =         NAME,
-       .size =         SIZE,
-       .bankwidth =    BUSWIDTH,
-       .phys =         PADDR
-};
-
-static struct mtd_info *beech_mtd;
-
-static struct mtd_partition beech_partitions[2] = {
-       {
-             .name = "Linux Kernel",
-             .size = BEECH_KERNEL_SIZE,
-             .offset = BEECH_KERNEL_OFFSET
-       }, {
-             .name = "Free Area",
-             .size = BEECH_FREE_AREA_SIZE,
-             .offset = BEECH_FREE_AREA_OFFSET
-       }
-};
-
-static int __init
-init_beech_mtd(void)
-{
-       int err;
-
-       printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
-
-       beech_mtd_map.virt = ioremap(PADDR, SIZE);
-
-       if (!beech_mtd_map.virt) {
-               printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-               return -EIO;
-       }
-
-       simple_map_init(&beech_mtd_map);
-
-       printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
-       beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
-
-       if (!beech_mtd) {
-               iounmap(beech_mtd_map.virt);
-               return -ENXIO;
-       }
-
-       beech_mtd->owner = THIS_MODULE;
-
-       err = add_mtd_partitions(beech_mtd, beech_partitions, 2);
-       if (err) {
-               printk("%s: add_mtd_partitions failed\n", NAME);
-               iounmap(beech_mtd_map.virt);
-       }
-
-       return err;
-}
-
-static void __exit
-cleanup_beech_mtd(void)
-{
-       if (beech_mtd) {
-               del_mtd_partitions(beech_mtd);
-               map_destroy(beech_mtd);
-               iounmap((void *) beech_mtd_map.virt);
-       }
-}
-
-module_init(init_beech_mtd);
-module_exit(cleanup_beech_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bishop Brock <bcbrock@us.ibm.com>");
-MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Beech boards");
index 72107dc06d6745df15a528febb2cabbe9255a58b..bbb42c35b69b9df05a108f21b0d837f80ca3d7e6 100644 (file)
@@ -186,7 +186,7 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev
        else {
                if (strcmp(of_probe, "ROM"))
                        dev_dbg(&dev->dev, "map_probe: don't know probe type "
-                       "'%s', mapping as rom\n");
+                       "'%s', mapping as rom\n", of_probe);
                info->mtd = do_map_probe("mtd_rom", &info->map);
        }
        if (info->mtd == NULL) {
index 1af989023c6644ca89c8e4107c21fcde8137904d..9c6236852942ec7e98441c5a333c1786a0e83a0c 100644 (file)
@@ -347,7 +347,6 @@ int add_mtd_partitions(struct mtd_info *master,
                slave->mtd.subpage_sft = master->subpage_sft;
 
                slave->mtd.name = parts[i].name;
-               slave->mtd.bank_size = master->bank_size;
                slave->mtd.owner = master->owner;
 
                slave->mtd.read = part_read;
index d05873b8c155a8f8c478fc86cd522ca792441451..f1d60b6f048e6f08aa855e19fed1337a292cfe79 100644 (file)
@@ -232,11 +232,13 @@ config MTD_NAND_BASLER_EXCITE
           will be named "excite_nandflash.ko".
 
 config MTD_NAND_CAFE
-       tristate "NAND support for OLPC CAFÉ chip"
-       depends on PCI
-       help
-        Use NAND flash attached to the CAFÉ chip designed for the $100
-        laptop.
+       tristate "NAND support for OLPC CAFÉ chip"
+       depends on PCI
+       select REED_SOLOMON
+       select REED_SOLOMON_DEC16
+       help
+         Use NAND flash attached to the CAFÉ chip designed for the $100
+         laptop.
 
 config MTD_NAND_CS553X
        tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
@@ -270,4 +272,13 @@ config MTD_NAND_NANDSIM
          The simulator may simulate various NAND flash chips for the
          MTD nand layer.
 
+config MTD_NAND_PLATFORM
+       tristate "Support for generic platform NAND driver"
+       depends on MTD_NAND
+       help
+         This implements a generic NAND driver for on-SOC platform
+         devices. You will need to provide platform-specific functions
+         via platform_data.
+
+
 endif # MTD_NAND
index 6872031a3fb25ff45d4e263691133d4698d94c8f..edba1db14bfad6581260b822b60a260063fc542c 100644 (file)
@@ -26,6 +26,6 @@ obj-$(CONFIG_MTD_NAND_NDFC)           += ndfc.o
 obj-$(CONFIG_MTD_NAND_AT91)            += at91_nand.o
 obj-$(CONFIG_MTD_NAND_CM_X270)         += cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)   += excite_nandflash.o
+obj-$(CONFIG_MTD_NAND_PLATFORM)                += plat_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
-cafe_nand-objs := cafe.o cafe_ecc.o
index 14b80cc90a7b789d7af4efe96b549bb105f87e22..512e999177f70cb39c745ac6d454d22e6a4c3bae 100644 (file)
@@ -82,6 +82,10 @@ static void at91_nand_disable(struct at91_nand_host *host)
                at91_set_gpio_value(host->board->enable_pin, 1);
 }
 
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
 /*
  * Probe for the NAND device.
  */
@@ -151,6 +155,12 @@ static int __init at91_nand_probe(struct platform_device *pdev)
 #ifdef CONFIG_MTD_PARTITIONS
        if (host->board->partition_info)
                partitions = host->board->partition_info(mtd->size, &num_partitions);
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+       else {
+               mtd->name = "at91_nand";
+               num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
+       }
+#endif
 
        if ((!partitions) || (num_partitions == 0)) {
                printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n");
diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c
deleted file mode 100644 (file)
index c328a75..0000000
+++ /dev/null
@@ -1,752 +0,0 @@
-/*
- * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
- *
- * Copyright © 2006 Red Hat, Inc.
- * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
- */
-
-#define DEBUG
-
-#include <linux/device.h>
-#undef DEBUG
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <asm/io.h>
-
-#define CAFE_NAND_CTRL1                0x00
-#define CAFE_NAND_CTRL2                0x04
-#define CAFE_NAND_CTRL3                0x08
-#define CAFE_NAND_STATUS       0x0c
-#define CAFE_NAND_IRQ          0x10
-#define CAFE_NAND_IRQ_MASK     0x14
-#define CAFE_NAND_DATA_LEN     0x18
-#define CAFE_NAND_ADDR1                0x1c
-#define CAFE_NAND_ADDR2                0x20
-#define CAFE_NAND_TIMING1      0x24
-#define CAFE_NAND_TIMING2      0x28
-#define CAFE_NAND_TIMING3      0x2c
-#define CAFE_NAND_NONMEM       0x30
-#define CAFE_NAND_ECC_RESULT   0x3C
-#define CAFE_NAND_DMA_CTRL     0x40
-#define CAFE_NAND_DMA_ADDR0    0x44
-#define CAFE_NAND_DMA_ADDR1    0x48
-#define CAFE_NAND_ECC_SYN01    0x50
-#define CAFE_NAND_ECC_SYN23    0x54
-#define CAFE_NAND_ECC_SYN45    0x58
-#define CAFE_NAND_ECC_SYN67    0x5c
-#define CAFE_NAND_READ_DATA    0x1000
-#define CAFE_NAND_WRITE_DATA   0x2000
-
-#define CAFE_GLOBAL_CTRL       0x3004
-#define CAFE_GLOBAL_IRQ                0x3008
-#define CAFE_GLOBAL_IRQ_MASK   0x300c
-#define CAFE_NAND_RESET                0x3034
-
-int cafe_correct_ecc(unsigned char *buf,
-                    unsigned short *chk_syndrome_list);
-
-struct cafe_priv {
-       struct nand_chip nand;
-       struct pci_dev *pdev;
-       void __iomem *mmio;
-       uint32_t ctl1;
-       uint32_t ctl2;
-       int datalen;
-       int nr_data;
-       int data_pos;
-       int page_addr;
-       dma_addr_t dmaaddr;
-       unsigned char *dmabuf;
-};
-
-static int usedma = 1;
-module_param(usedma, int, 0644);
-
-static int skipbbt = 0;
-module_param(skipbbt, int, 0644);
-
-static int debug = 0;
-module_param(debug, int, 0644);
-
-static int regdebug = 0;
-module_param(regdebug, int, 0644);
-
-static int checkecc = 1;
-module_param(checkecc, int, 0644);
-
-static int numtimings;
-static int timing[3];
-module_param_array(timing, int, &numtimings, 0644);
-
-/* Hrm. Why isn't this already conditional on something in the struct device? */
-#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
-
-/* Make it easier to switch to PIO if we need to */
-#define cafe_readl(cafe, addr)                 readl((cafe)->mmio + CAFE_##addr)
-#define cafe_writel(cafe, datum, addr)         writel(datum, (cafe)->mmio + CAFE_##addr)
-
-static int cafe_device_ready(struct mtd_info *mtd)
-{
-       struct cafe_priv *cafe = mtd->priv;
-       int result = !!(cafe_readl(cafe, NAND_STATUS) | 0x40000000);
-       uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
-
-       cafe_writel(cafe, irqs, NAND_IRQ);
-
-       cafe_dev_dbg(&cafe->pdev->dev, "NAND device is%s ready, IRQ %x (%x) (%x,%x)\n",
-               result?"":" not", irqs, cafe_readl(cafe, NAND_IRQ),
-               cafe_readl(cafe, GLOBAL_IRQ), cafe_readl(cafe, GLOBAL_IRQ_MASK));
-
-       return result;
-}
-
-
-static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-       struct cafe_priv *cafe = mtd->priv;
-
-       if (usedma)
-               memcpy(cafe->dmabuf + cafe->datalen, buf, len);
-       else
-               memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len);
-
-       cafe->datalen += len;
-
-       cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes to write buffer. datalen 0x%x\n",
-               len, cafe->datalen);
-}
-
-static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-       struct cafe_priv *cafe = mtd->priv;
-
-       if (usedma)
-               memcpy(buf, cafe->dmabuf + cafe->datalen, len);
-       else
-               memcpy_fromio(buf, cafe->mmio + CAFE_NAND_READ_DATA + cafe->datalen, len);
-
-       cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes from position 0x%x in read buffer.\n",
-                 len, cafe->datalen);
-       cafe->datalen += len;
-}
-
-static uint8_t cafe_read_byte(struct mtd_info *mtd)
-{
-       struct cafe_priv *cafe = mtd->priv;
-       uint8_t d;
-
-       cafe_read_buf(mtd, &d, 1);
-       cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
-
-       return d;
-}
-
-static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
-                             int column, int page_addr)
-{
-       struct cafe_priv *cafe = mtd->priv;
-       int adrbytes = 0;
-       uint32_t ctl1;
-       uint32_t doneint = 0x80000000;
-
-       cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n",
-               command, column, page_addr);
-
-       if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) {
-               /* Second half of a command we already calculated */
-               cafe_writel(cafe, cafe->ctl2 | 0x100 | command, NAND_CTRL2);
-               ctl1 = cafe->ctl1;
-               cafe->ctl2 &= ~(1<<30);
-               cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n",
-                         cafe->ctl1, cafe->nr_data);
-               goto do_command;
-       }
-       /* Reset ECC engine */
-       cafe_writel(cafe, 0, NAND_CTRL2);
-
-       /* Emulate NAND_CMD_READOOB on large-page chips */
-       if (mtd->writesize > 512 &&
-           command == NAND_CMD_READOOB) {
-               column += mtd->writesize;
-               command = NAND_CMD_READ0;
-       }
-
-       /* FIXME: Do we need to send read command before sending data
-          for small-page chips, to position the buffer correctly? */
-
-       if (column != -1) {
-               cafe_writel(cafe, column, NAND_ADDR1);
-               adrbytes = 2;
-               if (page_addr != -1)
-                       goto write_adr2;
-       } else if (page_addr != -1) {
-               cafe_writel(cafe, page_addr & 0xffff, NAND_ADDR1);
-               page_addr >>= 16;
-       write_adr2:
-               cafe_writel(cafe, page_addr, NAND_ADDR2);
-               adrbytes += 2;
-               if (mtd->size > mtd->writesize << 16)
-                       adrbytes++;
-       }
-
-       cafe->data_pos = cafe->datalen = 0;
-
-       /* Set command valid bit */
-       ctl1 = 0x80000000 | command;
-
-       /* Set RD or WR bits as appropriate */
-       if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) {
-               ctl1 |= (1<<26); /* rd */
-               /* Always 5 bytes, for now */
-               cafe->datalen = 4;
-               /* And one address cycle -- even for STATUS, since the controller doesn't work without */
-               adrbytes = 1;
-       } else if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
-                  command == NAND_CMD_READOOB || command == NAND_CMD_RNDOUT) {
-               ctl1 |= 1<<26; /* rd */
-               /* For now, assume just read to end of page */
-               cafe->datalen = mtd->writesize + mtd->oobsize - column;
-       } else if (command == NAND_CMD_SEQIN)
-               ctl1 |= 1<<25; /* wr */
-
-       /* Set number of address bytes */
-       if (adrbytes)
-               ctl1 |= ((adrbytes-1)|8) << 27;
-
-       if (command == NAND_CMD_SEQIN || command == NAND_CMD_ERASE1) {
-               /* Ignore the first command of a pair; the hardware
-                  deals with them both at once, later */
-               cafe->ctl1 = ctl1;
-               cafe_dev_dbg(&cafe->pdev->dev, "Setup for delayed command, ctl1 %08x, dlen %x\n",
-                         cafe->ctl1, cafe->datalen);
-               return;
-       }
-       /* RNDOUT and READ0 commands need a following byte */
-       if (command == NAND_CMD_RNDOUT)
-               cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_RNDOUTSTART, NAND_CTRL2);
-       else if (command == NAND_CMD_READ0 && mtd->writesize > 512)
-               cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_READSTART, NAND_CTRL2);
-
- do_command:
-       cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n",
-               cafe->datalen, ctl1, cafe_readl(cafe, NAND_CTRL2));
-
-       /* NB: The datasheet lies -- we really should be subtracting 1 here */
-       cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN);
-       cafe_writel(cafe, 0x90000000, NAND_IRQ);
-       if (usedma && (ctl1 & (3<<25))) {
-               uint32_t dmactl = 0xc0000000 + cafe->datalen;
-               /* If WR or RD bits set, set up DMA */
-               if (ctl1 & (1<<26)) {
-                       /* It's a read */
-                       dmactl |= (1<<29);
-                       /* ... so it's done when the DMA is done, not just
-                          the command. */
-                       doneint = 0x10000000;
-               }
-               cafe_writel(cafe, dmactl, NAND_DMA_CTRL);
-       }
-       cafe->datalen = 0;
-
-       if (unlikely(regdebug)) {
-               int i;
-               printk("About to write command %08x to register 0\n", ctl1);
-               for (i=4; i< 0x5c; i+=4)
-                       printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
-       }
-
-       cafe_writel(cafe, ctl1, NAND_CTRL1);
-       /* Apply this short delay always to ensure that we do wait tWB in
-        * any case on any machine. */
-       ndelay(100);
-
-       if (1) {
-               int c;
-               uint32_t irqs;
-
-               for (c = 500000; c != 0; c--) {
-                       irqs = cafe_readl(cafe, NAND_IRQ);
-                       if (irqs & doneint)
-                               break;
-                       udelay(1);
-                       if (!(c % 100000))
-                               cafe_dev_dbg(&cafe->pdev->dev, "Wait for ready, IRQ %x\n", irqs);
-                       cpu_relax();
-               }
-               cafe_writel(cafe, doneint, NAND_IRQ);
-               cafe_dev_dbg(&cafe->pdev->dev, "Command %x completed after %d usec, irqs %x (%x)\n",
-                            command, 500000-c, irqs, cafe_readl(cafe, NAND_IRQ));
-       }
-
-       WARN_ON(cafe->ctl2 & (1<<30));
-
-       switch (command) {
-
-       case NAND_CMD_CACHEDPROG:
-       case NAND_CMD_PAGEPROG:
-       case NAND_CMD_ERASE1:
-       case NAND_CMD_ERASE2:
-       case NAND_CMD_SEQIN:
-       case NAND_CMD_RNDIN:
-       case NAND_CMD_STATUS:
-       case NAND_CMD_DEPLETE1:
-       case NAND_CMD_RNDOUT:
-       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:
-               cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
-               return;
-       }
-       nand_wait_ready(mtd);
-       cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
-}
-
-static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
-{
-       //struct cafe_priv *cafe = mtd->priv;
-       //      cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
-}
-
-static int cafe_nand_interrupt(int irq, void *id)
-{
-       struct mtd_info *mtd = id;
-       struct cafe_priv *cafe = mtd->priv;
-       uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
-       cafe_writel(cafe, irqs & ~0x90000000, NAND_IRQ);
-       if (!irqs)
-               return IRQ_NONE;
-
-       cafe_dev_dbg(&cafe->pdev->dev, "irq, bits %x (%x)\n", irqs, cafe_readl(cafe, NAND_IRQ));
-       return IRQ_HANDLED;
-}
-
-static void cafe_nand_bug(struct mtd_info *mtd)
-{
-       BUG();
-}
-
-static int cafe_nand_write_oob(struct mtd_info *mtd,
-                              struct nand_chip *chip, int page)
-{
-       int status = 0;
-
-       chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
-       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-       status = chip->waitfunc(mtd, chip);
-
-       return status & NAND_STATUS_FAIL ? -EIO : 0;
-}
-
-/* Don't use -- use nand_read_oob_std for now */
-static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-                             int page, int sndcmd)
-{
-       chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
-       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-       return 1;
-}
-/**
- * cafe_nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
- * @mtd:       mtd info structure
- * @chip:      nand chip info structure
- * @buf:       buffer to store read data
- *
- * The hw generator calculates the error syndrome automatically. Therefor
- * we need a special oob layout and handling.
- */
-static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-                              uint8_t *buf)
-{
-       struct cafe_priv *cafe = mtd->priv;
-
-       cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
-                    cafe_readl(cafe, NAND_ECC_RESULT),
-                    cafe_readl(cafe, NAND_ECC_SYN01));
-
-       chip->read_buf(mtd, buf, mtd->writesize);
-       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-       if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
-               unsigned short syn[8];
-               int i;
-
-               for (i=0; i<8; i+=2) {
-                       uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
-                       syn[i] = tmp & 0xfff;
-                       syn[i+1] = (tmp >> 16) & 0xfff;
-               }
-
-               if ((i = cafe_correct_ecc(buf, syn)) < 0) {
-                       dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
-                               cafe_readl(cafe, NAND_ADDR2) * 2048);
-                       for (i=0; i< 0x5c; i+=4)
-                               printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
-                       mtd->ecc_stats.failed++;
-               } else {
-                       dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", i);
-                       mtd->ecc_stats.corrected += i;
-               }
-       }
-
-
-       return 0;
-}
-
-static struct nand_ecclayout cafe_oobinfo_2048 = {
-       .eccbytes = 14,
-       .eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
-       .oobfree = {{14, 50}}
-};
-
-/* Ick. The BBT code really ought to be able to work this bit out
-   for itself from the above, at least for the 2KiB case */
-static uint8_t cafe_bbt_pattern_2048[] = { 'B', 'b', 't', '0' };
-static uint8_t cafe_mirror_pattern_2048[] = { '1', 't', 'b', 'B' };
-
-static uint8_t cafe_bbt_pattern_512[] = { 0xBB };
-static uint8_t cafe_mirror_pattern_512[] = { 0xBC };
-
-
-static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
-       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-       .offs = 14,
-       .len = 4,
-       .veroffs = 18,
-       .maxblocks = 4,
-       .pattern = cafe_bbt_pattern_2048
-};
-
-static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
-       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-       .offs = 14,
-       .len = 4,
-       .veroffs = 18,
-       .maxblocks = 4,
-       .pattern = cafe_mirror_pattern_2048
-};
-
-static struct nand_ecclayout cafe_oobinfo_512 = {
-       .eccbytes = 14,
-       .eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
-       .oobfree = {{14, 2}}
-};
-
-static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
-       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-       .offs = 14,
-       .len = 1,
-       .veroffs = 15,
-       .maxblocks = 4,
-       .pattern = cafe_bbt_pattern_512
-};
-
-static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
-       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-       .offs = 14,
-       .len = 1,
-       .veroffs = 15,
-       .maxblocks = 4,
-       .pattern = cafe_mirror_pattern_512
-};
-
-
-static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
-                                         struct nand_chip *chip, const uint8_t *buf)
-{
-       struct cafe_priv *cafe = mtd->priv;
-
-       chip->write_buf(mtd, buf, mtd->writesize);
-       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-       /* Set up ECC autogeneration */
-       cafe->ctl2 |= (1<<30);
-}
-
-static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                               const uint8_t *buf, int page, int cached, int raw)
-{
-       int status;
-
-       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-
-       if (unlikely(raw))
-               chip->ecc.write_page_raw(mtd, chip, buf);
-       else
-               chip->ecc.write_page(mtd, chip, buf);
-
-       /*
-        * Cached progamming disabled for now, Not sure if its worth the
-        * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
-        */
-       cached = 0;
-
-       if (!cached || !(chip->options & NAND_CACHEPRG)) {
-
-               chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-               status = chip->waitfunc(mtd, chip);
-               /*
-                * See if operation failed and additional status checks are
-                * available
-                */
-               if ((status & NAND_STATUS_FAIL) && (chip->errstat))
-                       status = chip->errstat(mtd, chip, FL_WRITING, status,
-                                              page);
-
-               if (status & NAND_STATUS_FAIL)
-                       return -EIO;
-       } else {
-               chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
-               status = chip->waitfunc(mtd, chip);
-       }
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-       /* Send command to read back the data */
-       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
-       if (chip->verify_buf(mtd, buf, mtd->writesize))
-               return -EIO;
-#endif
-       return 0;
-}
-
-static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
-{
-       return 0;
-}
-
-static int __devinit cafe_nand_probe(struct pci_dev *pdev,
-                                    const struct pci_device_id *ent)
-{
-       struct mtd_info *mtd;
-       struct cafe_priv *cafe;
-       uint32_t ctrl;
-       int err = 0;
-
-       err = pci_enable_device(pdev);
-       if (err)
-               return err;
-
-       pci_set_master(pdev);
-
-       mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL);
-       if (!mtd) {
-               dev_warn(&pdev->dev, "failed to alloc mtd_info\n");
-               return  -ENOMEM;
-       }
-       cafe = (void *)(&mtd[1]);
-
-       mtd->priv = cafe;
-       mtd->owner = THIS_MODULE;
-
-       cafe->pdev = pdev;
-       cafe->mmio = pci_iomap(pdev, 0, 0);
-       if (!cafe->mmio) {
-               dev_warn(&pdev->dev, "failed to iomap\n");
-               err = -ENOMEM;
-               goto out_free_mtd;
-       }
-       cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112 + sizeof(struct nand_buffers),
-                                         &cafe->dmaaddr, GFP_KERNEL);
-       if (!cafe->dmabuf) {
-               err = -ENOMEM;
-               goto out_ior;
-       }
-       cafe->nand.buffers = (void *)cafe->dmabuf + 2112;
-
-       cafe->nand.cmdfunc = cafe_nand_cmdfunc;
-       cafe->nand.dev_ready = cafe_device_ready;
-       cafe->nand.read_byte = cafe_read_byte;
-       cafe->nand.read_buf = cafe_read_buf;
-       cafe->nand.write_buf = cafe_write_buf;
-       cafe->nand.select_chip = cafe_select_chip;
-
-       cafe->nand.chip_delay = 0;
-
-       /* Enable the following for a flash based bad block table */
-       cafe->nand.options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR | NAND_OWN_BUFFERS;
-
-       if (skipbbt) {
-               cafe->nand.options |= NAND_SKIP_BBTSCAN;
-               cafe->nand.block_bad = cafe_nand_block_bad;
-       }
-
-       if (numtimings && numtimings != 3) {
-               dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings);
-       }
-
-       if (numtimings == 3) {
-               cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
-                            timing[0], timing[1], timing[2]);
-       } else {
-               timing[0] = cafe_readl(cafe, NAND_TIMING1);
-               timing[1] = cafe_readl(cafe, NAND_TIMING2);
-               timing[2] = cafe_readl(cafe, NAND_TIMING3);
-
-               if (timing[0] | timing[1] | timing[2]) {
-                       cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n",
-                                    timing[0], timing[1], timing[2]);
-               } else {
-                       dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
-                       timing[0] = timing[1] = timing[2] = 0xffffffff;
-               }
-       }
-
-       /* Start off by resetting the NAND controller completely */
-       cafe_writel(cafe, 1, NAND_RESET);
-       cafe_writel(cafe, 0, NAND_RESET);
-
-       cafe_writel(cafe, timing[0], NAND_TIMING1);
-       cafe_writel(cafe, timing[1], NAND_TIMING2);
-       cafe_writel(cafe, timing[2], NAND_TIMING3);
-
-       cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
-       err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
-                         "CAFE NAND", mtd);
-       if (err) {
-               dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
-               goto out_free_dma;
-       }
-
-       /* Disable master reset, enable NAND clock */
-       ctrl = cafe_readl(cafe, GLOBAL_CTRL);
-       ctrl &= 0xffffeff0;
-       ctrl |= 0x00007000;
-       cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
-       cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
-       cafe_writel(cafe, 0, NAND_DMA_CTRL);
-
-       cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
-       cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
-
-       /* Set up DMA address */
-       cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
-       if (sizeof(cafe->dmaaddr) > 4)
-               /* Shift in two parts to shut the compiler up */
-               cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
-       else
-               cafe_writel(cafe, 0, NAND_DMA_ADDR1);
-
-       cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
-               cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
-
-       /* Enable NAND IRQ in global IRQ mask register */
-       cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
-       cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
-               cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
-
-       /* Scan to find existence of the device */
-       if (nand_scan_ident(mtd, 1)) {
-               err = -ENXIO;
-               goto out_irq;
-       }
-
-       cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
-       if (mtd->writesize == 2048)
-               cafe->ctl2 |= 1<<29; /* 2KiB page size */
-
-       /* Set up ECC according to the type of chip we found */
-       if (mtd->writesize == 2048) {
-               cafe->nand.ecc.layout = &cafe_oobinfo_2048;
-               cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
-               cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
-       } else if (mtd->writesize == 512) {
-               cafe->nand.ecc.layout = &cafe_oobinfo_512;
-               cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
-               cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
-       } else {
-               printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
-                      mtd->writesize);
-               goto out_irq;
-       }
-       cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
-       cafe->nand.ecc.size = mtd->writesize;
-       cafe->nand.ecc.bytes = 14;
-       cafe->nand.ecc.hwctl  = (void *)cafe_nand_bug;
-       cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
-       cafe->nand.ecc.correct  = (void *)cafe_nand_bug;
-       cafe->nand.write_page = cafe_nand_write_page;
-       cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
-       cafe->nand.ecc.write_oob = cafe_nand_write_oob;
-       cafe->nand.ecc.read_page = cafe_nand_read_page;
-       cafe->nand.ecc.read_oob = cafe_nand_read_oob;
-
-       err = nand_scan_tail(mtd);
-       if (err)
-               goto out_irq;
-
-       pci_set_drvdata(pdev, mtd);
-       add_mtd_device(mtd);
-       goto out;
-
- out_irq:
-       /* Disable NAND IRQ in global IRQ mask register */
-       cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
-       free_irq(pdev->irq, mtd);
- out_free_dma:
-       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
- out_ior:
-       pci_iounmap(pdev, cafe->mmio);
- out_free_mtd:
-       kfree(mtd);
- out:
-       return err;
-}
-
-static void __devexit cafe_nand_remove(struct pci_dev *pdev)
-{
-       struct mtd_info *mtd = pci_get_drvdata(pdev);
-       struct cafe_priv *cafe = mtd->priv;
-
-       del_mtd_device(mtd);
-       /* Disable NAND IRQ in global IRQ mask register */
-       cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
-       free_irq(pdev->irq, mtd);
-       nand_release(mtd);
-       pci_iounmap(pdev, cafe->mmio);
-       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
-       kfree(mtd);
-}
-
-static struct pci_device_id cafe_nand_tbl[] = {
-       { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 }
-};
-
-MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
-
-static struct pci_driver cafe_nand_pci_driver = {
-       .name = "CAFÉ NAND",
-       .id_table = cafe_nand_tbl,
-       .probe = cafe_nand_probe,
-       .remove = __devexit_p(cafe_nand_remove),
-#ifdef CONFIG_PMx
-       .suspend = cafe_nand_suspend,
-       .resume = cafe_nand_resume,
-#endif
-};
-
-static int cafe_nand_init(void)
-{
-       return pci_register_driver(&cafe_nand_pci_driver);
-}
-
-static void cafe_nand_exit(void)
-{
-       pci_unregister_driver(&cafe_nand_pci_driver);
-}
-module_init(cafe_nand_init);
-module_exit(cafe_nand_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
diff --git a/drivers/mtd/nand/cafe_ecc.c b/drivers/mtd/nand/cafe_ecc.c
deleted file mode 100644 (file)
index ea5c849..0000000
+++ /dev/null
@@ -1,1381 +0,0 @@
-/* Error correction for CAFÉ NAND controller
- *
- * © 2006 Marvell, Inc.
- * Author: Tom Chiou
- *
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-
-static unsigned short gf4096_mul(unsigned short, unsigned short);
-static unsigned short gf64_mul(unsigned short, unsigned short);
-static unsigned short gf4096_inv(unsigned short);
-static unsigned short err_pos(unsigned short);
-static void find_4bit_err_coefs(unsigned short, unsigned short, unsigned short,
-                               unsigned short, unsigned short, unsigned short,
-                               unsigned short, unsigned short, unsigned short *);
-static void zero_4x5_col3(unsigned short[4][5]);
-static void zero_4x5_col2(unsigned short[4][5]);
-static void zero_4x5_col1(unsigned short[4][5]);
-static void swap_4x5_rows(unsigned short[4][5], int, int, int);
-static void swap_2x3_rows(unsigned short m[2][3]);
-static void solve_4x5(unsigned short m[4][5], unsigned short *, int *);
-static void sort_coefs(int *, unsigned short *, int);
-static void find_4bit_err_pats(unsigned short, unsigned short, unsigned short,
-                              unsigned short, unsigned short, unsigned short,
-                              unsigned short, unsigned short, unsigned short *);
-static void find_3bit_err_coefs(unsigned short, unsigned short, unsigned short,
-                               unsigned short, unsigned short, unsigned short,
-                               unsigned short *);
-static void zero_3x4_col2(unsigned short[3][4]);
-static void zero_3x4_col1(unsigned short[3][4]);
-static void swap_3x4_rows(unsigned short[3][4], int, int, int);
-static void solve_3x4(unsigned short[3][4], unsigned short *, int *);
-static void find_3bit_err_pats(unsigned short, unsigned short, unsigned short,
-                              unsigned short, unsigned short, unsigned short,
-                              unsigned short *);
-
-static void find_2bit_err_pats(unsigned short, unsigned short, unsigned short,
-                              unsigned short, unsigned short *);
-static void find_2x2_soln(unsigned short, unsigned short, unsigned short,
-                         unsigned short, unsigned short, unsigned short,
-                         unsigned short *);
-static void solve_2x3(unsigned short[2][3], unsigned short *);
-static int chk_no_err_only(unsigned short *, unsigned short *);
-static int chk_1_err_only(unsigned short *, unsigned short *);
-static int chk_2_err_only(unsigned short *, unsigned short *);
-static int chk_3_err_only(unsigned short *, unsigned short *);
-static int chk_4_err_only(unsigned short *, unsigned short *);
-
-static unsigned short gf64_mul(unsigned short a, unsigned short b)
-{
-       unsigned short tmp1, tmp2, tmp3, tmp4, tmp5;
-       unsigned short c_bit0, c_bit1, c_bit2, c_bit3, c_bit4, c_bit5, c;
-
-       tmp1 = ((a) ^ (a >> 5));
-       tmp2 = ((a >> 4) ^ (a >> 5));
-       tmp3 = ((a >> 3) ^ (a >> 4));
-       tmp4 = ((a >> 2) ^ (a >> 3));
-       tmp5 = ((a >> 1) ^ (a >> 2));
-
-       c_bit0 = ((a & b) ^ ((a >> 5) & (b >> 1)) ^ ((a >> 4) & (b >> 2)) ^
-                 ((a >> 3) & (b >> 3)) ^ ((a >> 2) & (b >> 4)) ^ ((a >> 1) & (b >> 5))) & 0x1;
-
-       c_bit1 = (((a >> 1) & b) ^ (tmp1 & (b >> 1)) ^ (tmp2 & (b >> 2)) ^
-                 (tmp3 & (b >> 3)) ^ (tmp4 & (b >> 4)) ^ (tmp5 & (b >> 5))) & 0x1;
-
-       c_bit2 = (((a >> 2) & b) ^ ((a >> 1) & (b >> 1)) ^ (tmp1 & (b >> 2)) ^
-                 (tmp2 & (b >> 3)) ^ (tmp3 & (b >> 4)) ^ (tmp4 & (b >> 5))) & 0x1;
-
-       c_bit3 = (((a >> 3) & b) ^ ((a >> 2) & (b >> 1)) ^ ((a >> 1) & (b >> 2)) ^
-                 (tmp1 & (b >> 3)) ^ (tmp2 & (b >> 4)) ^ (tmp3 & (b >> 5))) & 0x1;
-
-       c_bit4 = (((a >> 4) & b) ^ ((a >> 3) & (b >> 1)) ^ ((a >> 2) & (b >> 2)) ^
-                 ((a >> 1) & (b >> 3)) ^ (tmp1 & (b >> 4)) ^ (tmp2 & (b >> 5))) & 0x1;
-
-       c_bit5 = (((a >> 5) & b) ^ ((a >> 4) & (b >> 1)) ^ ((a >> 3) & (b >> 2)) ^
-                 ((a >> 2) & (b >> 3)) ^ ((a >> 1) & (b >> 4)) ^ (tmp1 & (b >> 5))) & 0x1;
-
-       c = c_bit0 | (c_bit1 << 1) | (c_bit2 << 2) | (c_bit3 << 3) | (c_bit4 << 4) | (c_bit5 << 5);
-
-       return c;
-}
-
-static unsigned short gf4096_mul(unsigned short a, unsigned short b)
-{
-       unsigned short ah, al, bh, bl, alxah, blxbh, ablh, albl, ahbh, ahbhB, c;
-
-       ah = (a >> 6) & 0x3f;
-       al = a & 0x3f;
-       bh = (b >> 6) & 0x3f;
-       bl = b & 0x3f;
-       alxah = al ^ ah;
-       blxbh = bl ^ bh;
-
-       ablh = gf64_mul(alxah, blxbh);
-       albl = gf64_mul(al, bl);
-       ahbh = gf64_mul(ah, bh);
-
-       ahbhB = ((ahbh & 0x1) << 5) |
-           ((ahbh & 0x20) >> 1) |
-           ((ahbh & 0x10) >> 1) | ((ahbh & 0x8) >> 1) | ((ahbh & 0x4) >> 1) | (((ahbh >> 1) ^ ahbh) & 0x1);
-
-       c = ((ablh ^ albl) << 6) | (ahbhB ^ albl);
-       return c;
-}
-
-static void find_2bit_err_pats(unsigned short s0, unsigned short s1, unsigned short r0, unsigned short r1, unsigned short *pats)
-{
-       find_2x2_soln(0x1, 0x1, r0, r1, s0, s1, pats);
-}
-
-static void find_3bit_err_coefs(unsigned short s0, unsigned short s1,
-                               unsigned short s2, unsigned short s3, unsigned short s4, unsigned short s5, unsigned short *coefs)
-{
-       unsigned short m[3][4];
-       int row_order[3];
-
-       row_order[0] = 0;
-       row_order[1] = 1;
-       row_order[2] = 2;
-       m[0][0] = s2;
-       m[0][1] = s1;
-       m[0][2] = s0;
-       m[0][3] = s3;
-       m[1][0] = s3;
-       m[1][1] = s2;
-       m[1][2] = s1;
-       m[1][3] = s4;
-       m[2][0] = s4;
-       m[2][1] = s3;
-       m[2][2] = s2;
-       m[2][3] = s5;
-
-       if (m[0][2] != 0x0) {
-               zero_3x4_col2(m);
-       } else if (m[1][2] != 0x0) {
-               swap_3x4_rows(m, 0, 1, 4);
-               zero_3x4_col2(m);
-       } else if (m[2][2] != 0x0) {
-               swap_3x4_rows(m, 0, 2, 4);
-               zero_3x4_col2(m);
-       } else {
-               printk(KERN_ERR "Error: find_3bit_err_coefs, s0,s1,s2 all zeros!\n");
-       }
-
-       if (m[1][1] != 0x0) {
-               zero_3x4_col1(m);
-       } else if (m[2][1] != 0x0) {
-               swap_3x4_rows(m, 1, 2, 4);
-               zero_3x4_col1(m);
-       } else {
-               printk(KERN_ERR "Error: find_3bit_err_coefs, cannot resolve col 1!\n");
-       }
-
-       /* solve coefs */
-       solve_3x4(m, coefs, row_order);
-}
-
-static void zero_3x4_col2(unsigned short m[3][4])
-{
-       unsigned short minv1, minv2;
-
-       minv1 = gf4096_mul(m[1][2], gf4096_inv(m[0][2]));
-       minv2 = gf4096_mul(m[2][2], gf4096_inv(m[0][2]));
-       m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1);
-       m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1);
-       m[1][3] = m[1][3] ^ gf4096_mul(m[0][3], minv1);
-       m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2);
-       m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2);
-       m[2][3] = m[2][3] ^ gf4096_mul(m[0][3], minv2);
-}
-
-static void zero_3x4_col1(unsigned short m[3][4])
-{
-       unsigned short minv;
-       minv = gf4096_mul(m[2][1], gf4096_inv(m[1][1]));
-       m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv);
-       m[2][3] = m[2][3] ^ gf4096_mul(m[1][3], minv);
-}
-
-static void swap_3x4_rows(unsigned short m[3][4], int i, int j, int col_width)
-{
-       unsigned short tmp0;
-       int cnt;
-       for (cnt = 0; cnt < col_width; cnt++) {
-               tmp0 = m[i][cnt];
-               m[i][cnt] = m[j][cnt];
-               m[j][cnt] = tmp0;
-       }
-}
-
-static void solve_3x4(unsigned short m[3][4], unsigned short *coefs, int *row_order)
-{
-       unsigned short tmp[3];
-       tmp[0] = gf4096_mul(m[2][3], gf4096_inv(m[2][0]));
-       tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ m[1][3]), gf4096_inv(m[1][1]));
-       tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^ gf4096_mul(tmp[1], m[0][1]) ^ m[0][3]), gf4096_inv(m[0][2]));
-       sort_coefs(row_order, tmp, 3);
-       coefs[0] = tmp[0];
-       coefs[1] = tmp[1];
-       coefs[2] = tmp[2];
-}
-
-static void find_3bit_err_pats(unsigned short s0, unsigned short s1,
-                              unsigned short s2, unsigned short r0,
-                              unsigned short r1, unsigned short r2,
-                              unsigned short *pats)
-{
-       find_2x2_soln(r0 ^ r2, r1 ^ r2,
-                     gf4096_mul(r0, r0 ^ r2), gf4096_mul(r1, r1 ^ r2),
-                     gf4096_mul(s0, r2) ^ s1, gf4096_mul(s1, r2) ^ s2, pats);
-       pats[2] = s0 ^ pats[0] ^ pats[1];
-}
-
-static void find_4bit_err_coefs(unsigned short s0, unsigned short s1,
-                               unsigned short s2, unsigned short s3,
-                               unsigned short s4, unsigned short s5,
-                               unsigned short s6, unsigned short s7,
-                               unsigned short *coefs)
-{
-       unsigned short m[4][5];
-       int row_order[4];
-
-       row_order[0] = 0;
-       row_order[1] = 1;
-       row_order[2] = 2;
-       row_order[3] = 3;
-
-       m[0][0] = s3;
-       m[0][1] = s2;
-       m[0][2] = s1;
-       m[0][3] = s0;
-       m[0][4] = s4;
-       m[1][0] = s4;
-       m[1][1] = s3;
-       m[1][2] = s2;
-       m[1][3] = s1;
-       m[1][4] = s5;
-       m[2][0] = s5;
-       m[2][1] = s4;
-       m[2][2] = s3;
-       m[2][3] = s2;
-       m[2][4] = s6;
-       m[3][0] = s6;
-       m[3][1] = s5;
-       m[3][2] = s4;
-       m[3][3] = s3;
-       m[3][4] = s7;
-
-       if (m[0][3] != 0x0) {
-               zero_4x5_col3(m);
-       } else if (m[1][3] != 0x0) {
-               swap_4x5_rows(m, 0, 1, 5);
-               zero_4x5_col3(m);
-       } else if (m[2][3] != 0x0) {
-               swap_4x5_rows(m, 0, 2, 5);
-               zero_4x5_col3(m);
-       } else if (m[3][3] != 0x0) {
-               swap_4x5_rows(m, 0, 3, 5);
-               zero_4x5_col3(m);
-       } else {
-               printk(KERN_ERR "Error: find_4bit_err_coefs, s0,s1,s2,s3 all zeros!\n");
-       }
-
-       if (m[1][2] != 0x0) {
-               zero_4x5_col2(m);
-       } else if (m[2][2] != 0x0) {
-               swap_4x5_rows(m, 1, 2, 5);
-               zero_4x5_col2(m);
-       } else if (m[3][2] != 0x0) {
-               swap_4x5_rows(m, 1, 3, 5);
-               zero_4x5_col2(m);
-       } else {
-               printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 2!\n");
-       }
-
-       if (m[2][1] != 0x0) {
-               zero_4x5_col1(m);
-       } else if (m[3][1] != 0x0) {
-               swap_4x5_rows(m, 2, 3, 5);
-               zero_4x5_col1(m);
-       } else {
-               printk(KERN_ERR "Error: find_4bit_err_coefs, cannot resolve col 1!\n");
-       }
-
-       solve_4x5(m, coefs, row_order);
-}
-
-static void zero_4x5_col3(unsigned short m[4][5])
-{
-       unsigned short minv1, minv2, minv3;
-
-       minv1 = gf4096_mul(m[1][3], gf4096_inv(m[0][3]));
-       minv2 = gf4096_mul(m[2][3], gf4096_inv(m[0][3]));
-       minv3 = gf4096_mul(m[3][3], gf4096_inv(m[0][3]));
-
-       m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv1);
-       m[1][1] = m[1][1] ^ gf4096_mul(m[0][1], minv1);
-       m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv1);
-       m[1][4] = m[1][4] ^ gf4096_mul(m[0][4], minv1);
-       m[2][0] = m[2][0] ^ gf4096_mul(m[0][0], minv2);
-       m[2][1] = m[2][1] ^ gf4096_mul(m[0][1], minv2);
-       m[2][2] = m[2][2] ^ gf4096_mul(m[0][2], minv2);
-       m[2][4] = m[2][4] ^ gf4096_mul(m[0][4], minv2);
-       m[3][0] = m[3][0] ^ gf4096_mul(m[0][0], minv3);
-       m[3][1] = m[3][1] ^ gf4096_mul(m[0][1], minv3);
-       m[3][2] = m[3][2] ^ gf4096_mul(m[0][2], minv3);
-       m[3][4] = m[3][4] ^ gf4096_mul(m[0][4], minv3);
-}
-
-static void zero_4x5_col2(unsigned short m[4][5])
-{
-       unsigned short minv2, minv3;
-
-       minv2 = gf4096_mul(m[2][2], gf4096_inv(m[1][2]));
-       minv3 = gf4096_mul(m[3][2], gf4096_inv(m[1][2]));
-
-       m[2][0] = m[2][0] ^ gf4096_mul(m[1][0], minv2);
-       m[2][1] = m[2][1] ^ gf4096_mul(m[1][1], minv2);
-       m[2][4] = m[2][4] ^ gf4096_mul(m[1][4], minv2);
-       m[3][0] = m[3][0] ^ gf4096_mul(m[1][0], minv3);
-       m[3][1] = m[3][1] ^ gf4096_mul(m[1][1], minv3);
-       m[3][4] = m[3][4] ^ gf4096_mul(m[1][4], minv3);
-}
-
-static void zero_4x5_col1(unsigned short m[4][5])
-{
-       unsigned short minv;
-
-       minv = gf4096_mul(m[3][1], gf4096_inv(m[2][1]));
-
-       m[3][0] = m[3][0] ^ gf4096_mul(m[2][0], minv);
-       m[3][4] = m[3][4] ^ gf4096_mul(m[2][4], minv);
-}
-
-static void swap_4x5_rows(unsigned short m[4][5], int i, int j, int col_width)
-{
-       unsigned short tmp0;
-       int cnt;
-
-       for (cnt = 0; cnt < col_width; cnt++) {
-               tmp0 = m[i][cnt];
-               m[i][cnt] = m[j][cnt];
-               m[j][cnt] = tmp0;
-       }
-}
-
-static void solve_4x5(unsigned short m[4][5], unsigned short *coefs, int *row_order)
-{
-       unsigned short tmp[4];
-
-       tmp[0] = gf4096_mul(m[3][4], gf4096_inv(m[3][0]));
-       tmp[1] = gf4096_mul((gf4096_mul(tmp[0], m[2][0]) ^ m[2][4]), gf4096_inv(m[2][1]));
-       tmp[2] = gf4096_mul((gf4096_mul(tmp[0], m[1][0]) ^ gf4096_mul(tmp[1], m[1][1]) ^ m[1][4]), gf4096_inv(m[1][2]));
-       tmp[3] = gf4096_mul((gf4096_mul(tmp[0], m[0][0]) ^
-                       gf4096_mul(tmp[1], m[0][1]) ^ gf4096_mul(tmp[2], m[0][2]) ^ m[0][4]), gf4096_inv(m[0][3]));
-       sort_coefs(row_order, tmp, 4);
-       coefs[0] = tmp[0];
-       coefs[1] = tmp[1];
-       coefs[2] = tmp[2];
-       coefs[3] = tmp[3];
-}
-
-static void sort_coefs(int *order, unsigned short *soln, int len)
-{
-       int cnt, start_cnt, least_ord, least_cnt;
-       unsigned short tmp0;
-       for (start_cnt = 0; start_cnt < len; start_cnt++) {
-               for (cnt = start_cnt; cnt < len; cnt++) {
-                       if (cnt == start_cnt) {
-                               least_ord = order[cnt];
-                               least_cnt = start_cnt;
-                       } else {
-                               if (least_ord > order[cnt]) {
-                                       least_ord = order[cnt];
-                                       least_cnt = cnt;
-                               }
-                       }
-               }
-               if (least_cnt != start_cnt) {
-                       tmp0 = order[least_cnt];
-                       order[least_cnt] = order[start_cnt];
-                       order[start_cnt] = tmp0;
-                       tmp0 = soln[least_cnt];
-                       soln[least_cnt] = soln[start_cnt];
-                       soln[start_cnt] = tmp0;
-               }
-       }
-}
-
-static void find_4bit_err_pats(unsigned short s0, unsigned short s1,
-                              unsigned short s2, unsigned short s3,
-                              unsigned short z1, unsigned short z2,
-                              unsigned short z3, unsigned short z4,
-                              unsigned short *pats)
-{
-       unsigned short z4_z1, z3z4_z3z3, z4_z2, s0z4_s1, z1z4_z1z1,
-               z4_z3, z2z4_z2z2, s1z4_s2, z3z3z4_z3z3z3, z1z1z4_z1z1z1, z2z2z4_z2z2z2, s2z4_s3;
-       unsigned short tmp0, tmp1, tmp2, tmp3;
-
-       z4_z1 = z4 ^ z1;
-       z3z4_z3z3 = gf4096_mul(z3, z4) ^ gf4096_mul(z3, z3);
-       z4_z2 = z4 ^ z2;
-       s0z4_s1 = gf4096_mul(s0, z4) ^ s1;
-       z1z4_z1z1 = gf4096_mul(z1, z4) ^ gf4096_mul(z1, z1);
-       z4_z3 = z4 ^ z3;
-       z2z4_z2z2 = gf4096_mul(z2, z4) ^ gf4096_mul(z2, z2);
-       s1z4_s2 = gf4096_mul(s1, z4) ^ s2;
-       z3z3z4_z3z3z3 = gf4096_mul(gf4096_mul(z3, z3), z4) ^ gf4096_mul(gf4096_mul(z3, z3), z3);
-       z1z1z4_z1z1z1 = gf4096_mul(gf4096_mul(z1, z1), z4) ^ gf4096_mul(gf4096_mul(z1, z1), z1);
-       z2z2z4_z2z2z2 = gf4096_mul(gf4096_mul(z2, z2), z4) ^ gf4096_mul(gf4096_mul(z2, z2), z2);
-       s2z4_s3 = gf4096_mul(s2, z4) ^ s3;
-
-       //find err pat 0,1
-       find_2x2_soln(gf4096_mul(z4_z1, z3z4_z3z3) ^
-                     gf4096_mul(z1z4_z1z1, z4_z3), gf4096_mul(z4_z2,
-                                                              z3z4_z3z3) ^
-                     gf4096_mul(z2z4_z2z2, z4_z3), gf4096_mul(z1z4_z1z1,
-                                                              z3z3z4_z3z3z3) ^
-                     gf4096_mul(z1z1z4_z1z1z1, z3z4_z3z3),
-                     gf4096_mul(z2z4_z2z2,
-                                z3z3z4_z3z3z3) ^ gf4096_mul(z2z2z4_z2z2z2,
-                                                            z3z4_z3z3),
-                     gf4096_mul(s0z4_s1, z3z4_z3z3) ^ gf4096_mul(s1z4_s2,
-                                                                 z4_z3),
-                     gf4096_mul(s1z4_s2, z3z3z4_z3z3z3) ^ gf4096_mul(s2z4_s3, z3z4_z3z3), pats);
-       tmp0 = pats[0];
-       tmp1 = pats[1];
-       tmp2 = pats[0] ^ pats[1] ^ s0;
-       tmp3 = gf4096_mul(pats[0], z1) ^ gf4096_mul(pats[1], z2) ^ s1;
-
-       //find err pat 2,3
-       find_2x2_soln(0x1, 0x1, z3, z4, tmp2, tmp3, pats);
-       pats[2] = pats[0];
-       pats[3] = pats[1];
-       pats[0] = tmp0;
-       pats[1] = tmp1;
-}
-
-static void find_2x2_soln(unsigned short c00, unsigned short c01,
-                         unsigned short c10, unsigned short c11,
-                         unsigned short lval0, unsigned short lval1,
-                         unsigned short *soln)
-{
-       unsigned short m[2][3];
-       m[0][0] = c00;
-       m[0][1] = c01;
-       m[0][2] = lval0;
-       m[1][0] = c10;
-       m[1][1] = c11;
-       m[1][2] = lval1;
-
-       if (m[0][1] != 0x0) {
-               /* */
-       } else if (m[1][1] != 0x0) {
-               swap_2x3_rows(m);
-       } else {
-               printk(KERN_ERR "Warning: find_2bit_err_coefs, s0,s1 all zeros!\n");
-       }
-
-       solve_2x3(m, soln);
-}
-
-static void swap_2x3_rows(unsigned short m[2][3])
-{
-       unsigned short tmp0;
-       int cnt;
-
-       for (cnt = 0; cnt < 3; cnt++) {
-               tmp0 = m[0][cnt];
-               m[0][cnt] = m[1][cnt];
-               m[1][cnt] = tmp0;
-       }
-}
-
-static void solve_2x3(unsigned short m[2][3], unsigned short *coefs)
-{
-       unsigned short minv;
-
-       minv = gf4096_mul(m[1][1], gf4096_inv(m[0][1]));
-       m[1][0] = m[1][0] ^ gf4096_mul(m[0][0], minv);
-       m[1][2] = m[1][2] ^ gf4096_mul(m[0][2], minv);
-       coefs[0] = gf4096_mul(m[1][2], gf4096_inv(m[1][0]));
-       coefs[1] = gf4096_mul((gf4096_mul(coefs[0], m[0][0]) ^ m[0][2]), gf4096_inv(m[0][1]));
-}
-
-static unsigned char gf64_inv[64] = {
-        0,  1, 33, 62, 49, 43, 31, 44, 57, 37, 52, 28, 46, 40, 22, 25,
-       61, 54, 51, 39, 26, 35, 14, 24, 23, 15, 20, 34, 11, 53, 45,  6,
-       63,  2, 27, 21, 56,  9, 50, 19, 13, 47, 48,  5,  7, 30, 12, 41,
-       42,  4, 38, 18, 10, 29, 17, 60, 36,  8, 59, 58, 55, 16,  3, 32
-};
-
-static unsigned short gf4096_inv(unsigned short din)
-{
-       unsigned short alahxal, ah2B, deno, inv, bl, bh;
-       unsigned short ah, al, ahxal;
-       unsigned short dout;
-
-       ah = (din >> 6) & 0x3f;
-       al = din & 0x3f;
-       ahxal = ah ^ al;
-       ah2B = (((ah ^ (ah >> 3)) & 0x1) << 5) |
-               ((ah >> 1) & 0x10) |
-               ((((ah >> 5) ^ (ah >> 2)) & 0x1) << 3) |
-               ((ah >> 2) & 0x4) | ((((ah >> 4) ^ (ah >> 1)) & 0x1) << 1) | (ah & 0x1);
-       alahxal = gf64_mul(ahxal, al);
-       deno = alahxal ^ ah2B;
-       inv = gf64_inv[deno];
-       bl = gf64_mul(inv, ahxal);
-       bh = gf64_mul(inv, ah);
-       dout = ((bh & 0x3f) << 6) | (bl & 0x3f);
-       return (((bh & 0x3f) << 6) | (bl & 0x3f));
-}
-
-static unsigned short err_pos_lut[4096] = {
-       0xfff, 0x000, 0x451, 0xfff, 0xfff, 0x3cf, 0xfff, 0x041,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x28a, 0xfff, 0x492, 0xfff,
-       0x145, 0xfff, 0xfff, 0x514, 0xfff, 0x082, 0xfff, 0xfff,
-       0xfff, 0x249, 0x38e, 0x410, 0xfff, 0x104, 0x208, 0x1c7,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x2cb, 0xfff, 0xfff, 0xfff,
-       0x0c3, 0x34d, 0x4d3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x186, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x30c, 0x555, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x166, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x385, 0x14e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e1,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x538, 0xfff, 0x16d, 0xfff,
-       0xfff, 0xfff, 0x45b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x29c, 0x2cc, 0x30b, 0x2b3, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0b3, 0xfff, 0x2f7,
-       0xfff, 0x32b, 0xfff, 0xfff, 0xfff, 0xfff, 0x0a7, 0xfff,
-       0xfff, 0x2da, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x07e, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x11c, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x22f, 0xfff, 0x1f4, 0xfff, 0xfff,
-       0x2b0, 0x504, 0xfff, 0x114, 0xfff, 0xfff, 0xfff, 0x21d,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x00d, 0x3c4, 0x340, 0x10f,
-       0xfff, 0xfff, 0x266, 0x02e, 0xfff, 0xfff, 0xfff, 0x4f8,
-       0x337, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x07b, 0x168, 0xfff, 0xfff, 0x0fe,
-       0xfff, 0xfff, 0x51a, 0xfff, 0x458, 0xfff, 0x36d, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x073, 0x37d, 0x415, 0x550, 0xfff,
-       0xfff, 0xfff, 0x23b, 0x4b4, 0xfff, 0xfff, 0xfff, 0x1a1,
-       0xfff, 0xfff, 0x3aa, 0xfff, 0x117, 0x04d, 0x341, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x518, 0x03e, 0x0f2, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x363, 0xfff, 0x0b9, 0xfff, 0xfff,
-       0x241, 0xfff, 0xfff, 0x049, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x15f, 0x52d, 0xfff, 0xfff, 0xfff, 0x29e, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x4cf, 0x0fc, 0xfff, 0x36f, 0x3d3, 0xfff,
-       0x228, 0xfff, 0xfff, 0x45e, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x238, 0xfff, 0xfff, 0xfff, 0xfff, 0x47f, 0xfff, 0xfff,
-       0x43a, 0x265, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e8,
-       0xfff, 0xfff, 0x01a, 0xfff, 0xfff, 0xfff, 0xfff, 0x21e,
-       0x1fc, 0x40b, 0xfff, 0xfff, 0xfff, 0x2d0, 0x159, 0xfff,
-       0xfff, 0x313, 0xfff, 0xfff, 0x05c, 0x4cc, 0xfff, 0xfff,
-       0x0f6, 0x3d5, 0xfff, 0xfff, 0xfff, 0x54f, 0xfff, 0xfff,
-       0xfff, 0x172, 0x1e4, 0x07c, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x53c, 0x1ad, 0x535,
-       0x19b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x092, 0xfff, 0x2be, 0xfff, 0xfff, 0x482,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0e6, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x476, 0xfff, 0x51d, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x342, 0x2b5, 0x22e, 0x09a, 0xfff, 0x08d,
-       0x44f, 0x3ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d1, 0xfff,
-       0xfff, 0x543, 0xfff, 0x48f, 0xfff, 0x3d2, 0xfff, 0x0d5,
-       0x113, 0x0ec, 0x427, 0xfff, 0xfff, 0xfff, 0x4c4, 0xfff,
-       0xfff, 0x50a, 0xfff, 0x144, 0xfff, 0x105, 0x39f, 0x294,
-       0x164, 0xfff, 0x31a, 0xfff, 0xfff, 0x49a, 0xfff, 0x130,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x1be, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x49e, 0x371, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x0e8, 0x49c, 0x0f4, 0xfff,
-       0x338, 0x1a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x36c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x1ae, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x31b, 0xfff, 0xfff, 0x2dd, 0x522, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f4,
-       0x3c6, 0x30d, 0xfff, 0xfff, 0xfff, 0xfff, 0x34c, 0x18f,
-       0x30a, 0xfff, 0x01f, 0x079, 0xfff, 0xfff, 0x54d, 0x46b,
-       0x28c, 0x37f, 0xfff, 0xfff, 0xfff, 0xfff, 0x355, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x14f, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x359, 0x3fe, 0x3c5, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x423, 0xfff, 0xfff, 0x34a, 0x22c, 0xfff,
-       0x25a, 0xfff, 0xfff, 0x4ad, 0xfff, 0x28d, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x547, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x2e2, 0xfff, 0xfff, 0x1d5, 0xfff, 0x2a8, 0xfff, 0xfff,
-       0x03f, 0xfff, 0xfff, 0xfff, 0xfff, 0x3eb, 0x0fa, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x55b, 0xfff,
-       0x08e, 0xfff, 0x3ae, 0xfff, 0x3a4, 0xfff, 0x282, 0x158,
-       0xfff, 0x382, 0xfff, 0xfff, 0x499, 0xfff, 0xfff, 0x08a,
-       0xfff, 0xfff, 0xfff, 0x456, 0x3be, 0xfff, 0x1e2, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x559, 0xfff, 0x1a0, 0xfff,
-       0xfff, 0x0b4, 0xfff, 0xfff, 0xfff, 0x2df, 0xfff, 0xfff,
-       0xfff, 0x07f, 0x4f5, 0xfff, 0xfff, 0x27c, 0x133, 0x017,
-       0xfff, 0x3fd, 0xfff, 0xfff, 0xfff, 0x44d, 0x4cd, 0x17a,
-       0x0d7, 0x537, 0xfff, 0xfff, 0x353, 0xfff, 0xfff, 0x351,
-       0x366, 0xfff, 0x44a, 0xfff, 0x1a6, 0xfff, 0xfff, 0xfff,
-       0x291, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1e3,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x389, 0xfff, 0x07a, 0xfff,
-       0x1b6, 0x2ed, 0xfff, 0xfff, 0xfff, 0xfff, 0x24e, 0x074,
-       0xfff, 0xfff, 0x3dc, 0xfff, 0x4e3, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x4eb, 0xfff, 0xfff, 0x3b8, 0x4de, 0xfff, 0x19c,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x262,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x076, 0x4e8, 0x3da,
-       0xfff, 0x531, 0xfff, 0xfff, 0x14a, 0xfff, 0x0a2, 0x433,
-       0x3df, 0x1e9, 0xfff, 0xfff, 0xfff, 0xfff, 0x3e7, 0x285,
-       0x2d8, 0xfff, 0xfff, 0xfff, 0x349, 0x18d, 0x098, 0xfff,
-       0x0df, 0x4bf, 0xfff, 0xfff, 0x0b2, 0xfff, 0x346, 0x24d,
-       0xfff, 0xfff, 0xfff, 0x24f, 0x4fa, 0x2f9, 0xfff, 0xfff,
-       0x3c9, 0xfff, 0x2b4, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x056, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x179, 0xfff, 0x0e9, 0x3f0, 0x33d, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x1fd, 0xfff, 0xfff, 0x526, 0xfff,
-       0xfff, 0xfff, 0x53d, 0xfff, 0xfff, 0xfff, 0x170, 0x331,
-       0xfff, 0x068, 0xfff, 0xfff, 0xfff, 0x3f7, 0xfff, 0x3d8,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x09f, 0x556, 0xfff, 0xfff, 0x02d, 0xfff, 0xfff,
-       0x553, 0xfff, 0xfff, 0xfff, 0x1f0, 0xfff, 0xfff, 0x4d6,
-       0x41e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d5, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x248, 0xfff, 0xfff, 0xfff, 0x0a3,
-       0xfff, 0x217, 0xfff, 0xfff, 0xfff, 0x4f1, 0x209, 0xfff,
-       0xfff, 0x475, 0x234, 0x52b, 0x398, 0xfff, 0x08b, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x2c2, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x268, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x4a3, 0xfff, 0x0aa, 0xfff, 0x1d9, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x155, 0xfff, 0xfff, 0xfff, 0xfff, 0x0bf,
-       0x539, 0xfff, 0xfff, 0x2f1, 0x545, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x2a7, 0x06f, 0xfff, 0x378, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x25e, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x15d, 0x02a, 0xfff, 0xfff, 0x0bc,
-       0x235, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x150, 0xfff, 0x1a9, 0xfff, 0xfff, 0xfff, 0xfff, 0x381,
-       0xfff, 0x04e, 0x270, 0x13f, 0xfff, 0xfff, 0x405, 0xfff,
-       0x3cd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x2ef, 0xfff, 0x06a, 0xfff, 0xfff, 0xfff, 0x34f,
-       0x212, 0xfff, 0xfff, 0x0e2, 0xfff, 0x083, 0x298, 0xfff,
-       0xfff, 0xfff, 0x0c2, 0xfff, 0xfff, 0x52e, 0xfff, 0x488,
-       0xfff, 0xfff, 0xfff, 0x36b, 0xfff, 0xfff, 0xfff, 0x442,
-       0x091, 0xfff, 0x41c, 0xfff, 0xfff, 0x3a5, 0xfff, 0x4e6,
-       0xfff, 0xfff, 0x40d, 0x31d, 0xfff, 0xfff, 0xfff, 0x4c1,
-       0x053, 0xfff, 0x418, 0x13c, 0xfff, 0x350, 0xfff, 0x0ae,
-       0xfff, 0xfff, 0x41f, 0xfff, 0x470, 0xfff, 0x4ca, 0xfff,
-       0xfff, 0xfff, 0x02b, 0x450, 0xfff, 0x1f8, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x293, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x411, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x0b8, 0xfff, 0xfff, 0xfff,
-       0x3e1, 0xfff, 0xfff, 0xfff, 0xfff, 0x43c, 0xfff, 0x2b2,
-       0x2ab, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ec,
-       0xfff, 0xfff, 0xfff, 0x3f8, 0x034, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x11a, 0xfff, 0x541, 0x45c, 0x134,
-       0x1cc, 0xfff, 0xfff, 0xfff, 0x469, 0xfff, 0xfff, 0x44b,
-       0x161, 0xfff, 0xfff, 0xfff, 0x055, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x307, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d1, 0xfff,
-       0xfff, 0xfff, 0x124, 0x37b, 0x26b, 0x336, 0xfff, 0xfff,
-       0x2e4, 0x3cb, 0xfff, 0xfff, 0x0f8, 0x3c8, 0xfff, 0xfff,
-       0xfff, 0x461, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4b5,
-       0x2cf, 0xfff, 0xfff, 0xfff, 0x20f, 0xfff, 0x35a, 0xfff,
-       0x490, 0xfff, 0x185, 0xfff, 0xfff, 0xfff, 0xfff, 0x42e,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x54b, 0xfff, 0xfff, 0xfff,
-       0x146, 0xfff, 0x412, 0xfff, 0xfff, 0xfff, 0x1ff, 0xfff,
-       0xfff, 0x3e0, 0xfff, 0xfff, 0xfff, 0xfff, 0x2d5, 0xfff,
-       0x4df, 0x505, 0xfff, 0x413, 0xfff, 0x1a5, 0xfff, 0x3b2,
-       0xfff, 0xfff, 0xfff, 0x35b, 0xfff, 0x116, 0xfff, 0xfff,
-       0x171, 0x4d0, 0xfff, 0x154, 0x12d, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x468, 0x4db, 0xfff,
-       0xfff, 0x1df, 0xfff, 0xfff, 0xfff, 0xfff, 0x05a, 0xfff,
-       0x0f1, 0x403, 0xfff, 0x22b, 0x2e0, 0xfff, 0xfff, 0xfff,
-       0x2b7, 0x373, 0xfff, 0xfff, 0xfff, 0xfff, 0x13e, 0xfff,
-       0xfff, 0xfff, 0x0d0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x329, 0x1d2, 0x3fa, 0x047, 0xfff, 0x2f2, 0xfff, 0xfff,
-       0x141, 0x0ac, 0x1d7, 0xfff, 0x07d, 0xfff, 0xfff, 0xfff,
-       0x1c1, 0xfff, 0x487, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x045, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x288, 0x0cd, 0xfff, 0xfff, 0xfff, 0xfff, 0x226, 0x1d8,
-       0xfff, 0x153, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4cb,
-       0x528, 0xfff, 0xfff, 0xfff, 0x20a, 0x343, 0x3a1, 0xfff,
-       0xfff, 0xfff, 0x2d7, 0x2d3, 0x1aa, 0x4c5, 0xfff, 0xfff,
-       0xfff, 0x42b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3e9, 0xfff, 0x20b, 0x260,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x37c, 0x2fd,
-       0xfff, 0xfff, 0x2c8, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x31e, 0xfff, 0x335, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x135, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x35c, 0x4dd, 0x129, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x1ef, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x34e, 0xfff, 0xfff, 0xfff, 0xfff, 0x407, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3ad, 0xfff, 0xfff, 0xfff,
-       0x379, 0xfff, 0xfff, 0x1d0, 0x38d, 0xfff, 0xfff, 0x1e8,
-       0x184, 0x3c1, 0x1c4, 0xfff, 0x1f9, 0xfff, 0xfff, 0x424,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x1d3, 0x0d4, 0xfff, 0x4e9,
-       0xfff, 0xfff, 0xfff, 0x530, 0x107, 0xfff, 0x106, 0x04f,
-       0xfff, 0xfff, 0x4c7, 0x503, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x15c, 0xfff, 0x23f, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x4f3, 0xfff, 0xfff, 0x3c7,
-       0xfff, 0x278, 0xfff, 0xfff, 0x0a6, 0xfff, 0xfff, 0xfff,
-       0x122, 0x1cf, 0xfff, 0x327, 0xfff, 0x2e5, 0xfff, 0x29d,
-       0xfff, 0xfff, 0x3f1, 0xfff, 0xfff, 0x48d, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x054, 0xfff, 0xfff, 0xfff, 0xfff, 0x178,
-       0x27e, 0x4e0, 0x352, 0x02f, 0x09c, 0xfff, 0x2a0, 0xfff,
-       0xfff, 0x46a, 0x457, 0xfff, 0xfff, 0x501, 0xfff, 0x2ba,
-       0xfff, 0xfff, 0xfff, 0x54e, 0x2e7, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x551, 0xfff, 0xfff, 0x1db, 0x2aa, 0xfff,
-       0xfff, 0x4bc, 0xfff, 0xfff, 0x395, 0xfff, 0x0de, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x455, 0xfff, 0x17e,
-       0xfff, 0x221, 0x4a7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x388, 0xfff, 0xfff, 0xfff, 0x308, 0xfff, 0xfff, 0xfff,
-       0x20e, 0x4b9, 0xfff, 0x273, 0x20c, 0x09e, 0xfff, 0x057,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3f2, 0xfff, 0x1a8, 0x3a6,
-       0x14c, 0xfff, 0xfff, 0x071, 0xfff, 0xfff, 0x53a, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x109, 0xfff, 0xfff, 0x399, 0xfff,
-       0x061, 0x4f0, 0x39e, 0x244, 0xfff, 0x035, 0xfff, 0xfff,
-       0x305, 0x47e, 0x297, 0xfff, 0xfff, 0x2b8, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1bc, 0xfff, 0x2fc,
-       0xfff, 0xfff, 0x554, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b6,
-       0xfff, 0xfff, 0xfff, 0x515, 0x397, 0xfff, 0xfff, 0x12f,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e5,
-       0xfff, 0x4fc, 0xfff, 0xfff, 0x05e, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x0a8, 0x3af, 0x015, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x138, 0xfff, 0xfff, 0xfff, 0x540, 0xfff, 0xfff,
-       0xfff, 0x027, 0x523, 0x2f0, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x16c, 0xfff, 0x27d, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x04c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4dc,
-       0xfff, 0xfff, 0x059, 0x301, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x1a3, 0xfff, 0x15a, 0xfff, 0xfff,
-       0x0a5, 0xfff, 0x435, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x051, 0xfff, 0xfff, 0x131, 0xfff, 0x4f4, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x441, 0xfff, 0x4fb, 0xfff, 0x03b,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ed, 0x274,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d3, 0x55e, 0x1b3,
-       0xfff, 0x0bd, 0xfff, 0xfff, 0xfff, 0xfff, 0x225, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x4b7, 0xfff, 0xfff, 0x2ff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c3, 0xfff,
-       0x383, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2f6,
-       0xfff, 0xfff, 0x1ee, 0xfff, 0x03d, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x26f, 0x1dc, 0xfff, 0x0db, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x0ce, 0xfff, 0xfff, 0x127, 0x03a,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x311, 0xfff,
-       0xfff, 0x13d, 0x09d, 0x47b, 0x2a6, 0x50d, 0x510, 0x19a,
-       0xfff, 0x354, 0x414, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x44c, 0x3b0, 0xfff, 0x23d, 0x429, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x4c0, 0x416, 0xfff, 0x05b, 0xfff, 0xfff, 0x137, 0xfff,
-       0x25f, 0x49f, 0xfff, 0x279, 0x013, 0xfff, 0xfff, 0xfff,
-       0x269, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3d0, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x077, 0xfff, 0xfff, 0x3fb,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x271, 0x3a0, 0xfff, 0xfff,
-       0x40f, 0xfff, 0xfff, 0x3de, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ab, 0x26a,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x489, 0xfff, 0xfff,
-       0x252, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b7, 0x42f, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x3b7,
-       0xfff, 0x2bb, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x0f7, 0x01d, 0xfff, 0x067, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x4e2, 0xfff, 0xfff, 0x4bb, 0xfff,
-       0xfff, 0xfff, 0x17b, 0xfff, 0x0ee, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x36e, 0xfff, 0xfff, 0xfff, 0x533, 0xfff,
-       0xfff, 0xfff, 0x4d4, 0x356, 0xfff, 0xfff, 0x375, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x4a4, 0x513, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4ff, 0xfff, 0x2af,
-       0xfff, 0xfff, 0x026, 0xfff, 0x0ad, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x26e, 0xfff, 0xfff, 0xfff, 0xfff, 0x493, 0xfff,
-       0x463, 0x4d2, 0x4be, 0xfff, 0xfff, 0xfff, 0xfff, 0x4f2,
-       0x0b6, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x32d, 0x315, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x13a, 0x4a1, 0xfff, 0x27a, 0xfff, 0xfff, 0xfff,
-       0x47a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x334, 0xfff, 0xfff, 0xfff, 0xfff, 0x54c, 0xfff, 0xfff,
-       0xfff, 0x0c9, 0x007, 0xfff, 0xfff, 0x12e, 0xfff, 0x0ff,
-       0xfff, 0xfff, 0x3f5, 0x509, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x1c3, 0x2ad, 0xfff, 0xfff, 0x47c, 0x261, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x152, 0xfff, 0xfff, 0xfff, 0x339,
-       0xfff, 0x243, 0x1c0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x063, 0xfff, 0xfff, 0x254, 0xfff, 0xfff, 0x173, 0xfff,
-       0x0c7, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x362, 0x259, 0x485, 0x374, 0x0dc, 0x3ab, 0xfff,
-       0x1c5, 0x534, 0x544, 0xfff, 0xfff, 0x508, 0xfff, 0x402,
-       0x408, 0xfff, 0x0e7, 0xfff, 0xfff, 0x00a, 0x205, 0xfff,
-       0xfff, 0x2b9, 0xfff, 0xfff, 0xfff, 0x465, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x23a, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x147, 0x19d, 0x115, 0x214, 0xfff, 0x090, 0x368,
-       0xfff, 0x210, 0xfff, 0xfff, 0x280, 0x52a, 0x163, 0x148,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x326, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x2de, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x206, 0x2c1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x189, 0xfff, 0xfff, 0xfff, 0xfff, 0x367, 0xfff, 0x1a4,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x443, 0xfff, 0x27b,
-       0xfff, 0xfff, 0x251, 0x549, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x188, 0x04b, 0xfff, 0xfff, 0xfff, 0x31f,
-       0x4a6, 0xfff, 0x246, 0x1de, 0x156, 0xfff, 0xfff, 0xfff,
-       0x3a9, 0xfff, 0xfff, 0xfff, 0x2fa, 0xfff, 0x128, 0x0d1,
-       0x449, 0x255, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x258, 0xfff, 0xfff, 0xfff,
-       0x532, 0xfff, 0xfff, 0xfff, 0x303, 0x517, 0xfff, 0xfff,
-       0x2a9, 0x24a, 0xfff, 0xfff, 0x231, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x4b6, 0x516, 0xfff, 0xfff, 0x0e4, 0x0eb,
-       0xfff, 0x4e4, 0xfff, 0x275, 0xfff, 0xfff, 0x031, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x025, 0x21a, 0xfff, 0x0cc,
-       0x45f, 0x3d9, 0x289, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x23e, 0xfff, 0xfff, 0xfff, 0x438, 0x097,
-       0x419, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x0a9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x37e, 0x0e0, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x431,
-       0x372, 0xfff, 0xfff, 0xfff, 0x1ba, 0x06e, 0xfff, 0x1b1,
-       0xfff, 0xfff, 0x12a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x193, 0xfff, 0xfff, 0xfff, 0xfff, 0x10a,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x048, 0x1b4,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x295, 0x140, 0x108, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x16f, 0xfff, 0x0a4, 0x37a, 0xfff,
-       0x29a, 0xfff, 0x284, 0xfff, 0xfff, 0xfff, 0xfff, 0x4c6,
-       0x2a2, 0x3a3, 0xfff, 0x201, 0xfff, 0xfff, 0xfff, 0x4bd,
-       0x005, 0x54a, 0x3b5, 0x204, 0x2ee, 0x11d, 0x436, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3ec, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x11f, 0x498, 0x21c, 0xfff,
-       0xfff, 0xfff, 0x3d6, 0xfff, 0x4ab, 0xfff, 0x432, 0x2eb,
-       0x542, 0x4fd, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x4ce, 0xfff, 0xfff, 0x2fb, 0xfff,
-       0xfff, 0x2e1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x1b9, 0x037, 0x0dd,
-       0xfff, 0xfff, 0xfff, 0x2bf, 0x521, 0x496, 0x095, 0xfff,
-       0xfff, 0x328, 0x070, 0x1bf, 0xfff, 0x393, 0xfff, 0xfff,
-       0x102, 0xfff, 0xfff, 0x21b, 0xfff, 0x142, 0x263, 0x519,
-       0xfff, 0x2a5, 0x177, 0xfff, 0x14d, 0x471, 0x4ae, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x1f6, 0xfff, 0x481, 0xfff, 0xfff, 0xfff, 0x151, 0xfff,
-       0xfff, 0xfff, 0x085, 0x33f, 0xfff, 0xfff, 0xfff, 0x084,
-       0xfff, 0xfff, 0xfff, 0x345, 0x3a2, 0xfff, 0xfff, 0x0a0,
-       0x0da, 0x024, 0xfff, 0xfff, 0xfff, 0x1bd, 0xfff, 0x55c,
-       0x467, 0x445, 0xfff, 0xfff, 0xfff, 0x052, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x51e, 0xfff, 0xfff, 0x39d, 0xfff, 0x35f,
-       0xfff, 0x376, 0x3ee, 0xfff, 0xfff, 0xfff, 0xfff, 0x448,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x16a,
-       0xfff, 0x036, 0x38f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x211,
-       0xfff, 0xfff, 0xfff, 0x230, 0xfff, 0xfff, 0x3ba, 0xfff,
-       0xfff, 0xfff, 0x3ce, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x229, 0xfff, 0x176, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x00b, 0xfff, 0x162, 0x018, 0xfff,
-       0xfff, 0x233, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x400, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x12b, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x3f4, 0xfff, 0x0f0, 0xfff, 0x1ac, 0xfff, 0xfff,
-       0x119, 0xfff, 0x2c0, 0xfff, 0xfff, 0xfff, 0x49b, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x23c, 0xfff,
-       0x4b3, 0x010, 0x064, 0xfff, 0xfff, 0x4ba, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x3c2, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x006, 0x196, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x100, 0x191, 0xfff,
-       0x1ea, 0x29f, 0xfff, 0xfff, 0xfff, 0x276, 0xfff, 0xfff,
-       0x2b1, 0x3b9, 0xfff, 0x03c, 0xfff, 0xfff, 0xfff, 0x180,
-       0xfff, 0x08f, 0xfff, 0xfff, 0x19e, 0x019, 0xfff, 0x0b0,
-       0x0fd, 0x332, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x06b, 0x2e8, 0xfff, 0x446, 0xfff, 0xfff, 0x004,
-       0x247, 0x197, 0xfff, 0x112, 0x169, 0x292, 0xfff, 0x302,
-       0xfff, 0xfff, 0x33b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x287, 0x21f, 0xfff, 0x3ea, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x4e7, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x3a8, 0xfff, 0xfff, 0x2bc, 0xfff,
-       0x484, 0x296, 0xfff, 0x1c9, 0x08c, 0x1e5, 0x48a, 0xfff,
-       0x360, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x1ca, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x10d, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x066, 0x2ea, 0x28b, 0x25b, 0xfff, 0x072,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x2b6, 0xfff, 0xfff, 0x272,
-       0xfff, 0xfff, 0x525, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x2ca, 0xfff, 0xfff, 0xfff, 0x299, 0xfff, 0xfff, 0xfff,
-       0x558, 0x41a, 0xfff, 0x4f7, 0x557, 0xfff, 0x4a0, 0x344,
-       0x12c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x125,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x40e, 0xfff, 0xfff, 0x502, 0xfff, 0x103, 0x3e6, 0xfff,
-       0x527, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x45d, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x44e, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d2, 0x4c9, 0x35e,
-       0x459, 0x2d9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x17d,
-       0x0c4, 0xfff, 0xfff, 0xfff, 0x3ac, 0x390, 0x094, 0xfff,
-       0x483, 0x0ab, 0xfff, 0x253, 0xfff, 0x391, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x123, 0x0ef, 0xfff, 0xfff, 0xfff, 0x330,
-       0x38c, 0xfff, 0xfff, 0x2ae, 0xfff, 0xfff, 0xfff, 0x042,
-       0x012, 0x06d, 0xfff, 0xfff, 0xfff, 0x32a, 0x3db, 0x364,
-       0x2dc, 0xfff, 0x30f, 0x3d7, 0x4a5, 0x050, 0xfff, 0xfff,
-       0x029, 0xfff, 0xfff, 0xfff, 0xfff, 0x1d1, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x480, 0xfff,
-       0x4ed, 0x081, 0x0a1, 0xfff, 0xfff, 0xfff, 0x30e, 0x52f,
-       0x257, 0xfff, 0xfff, 0x447, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x401, 0x3cc, 0xfff, 0xfff, 0x0fb,
-       0x2c9, 0x42a, 0x314, 0x33e, 0x3bd, 0x318, 0xfff, 0x10e,
-       0x2a1, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x24c,
-       0x506, 0xfff, 0x267, 0xfff, 0xfff, 0x219, 0xfff, 0x1eb,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x309, 0x3e2, 0x46c, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x384, 0xfff, 0xfff, 0xfff, 0xfff, 0x50c, 0xfff, 0x24b,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x038,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x194,
-       0x143, 0x3e3, 0xfff, 0xfff, 0xfff, 0x4c2, 0xfff, 0xfff,
-       0x0e1, 0x25c, 0xfff, 0x237, 0xfff, 0x1fe, 0xfff, 0xfff,
-       0xfff, 0x065, 0x2a4, 0xfff, 0x386, 0x55a, 0x11b, 0xfff,
-       0xfff, 0x192, 0xfff, 0x183, 0x00e, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x4b2, 0x18e, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x486, 0x4ef, 0x0c6, 0x380, 0xfff, 0x4a8, 0xfff,
-       0x0c5, 0xfff, 0xfff, 0xfff, 0xfff, 0x093, 0x1b8, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e6,
-       0xfff, 0x0f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x28e, 0xfff, 0x53b, 0x420, 0x22a, 0x33a, 0xfff, 0x387,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2a3, 0xfff, 0xfff,
-       0xfff, 0x428, 0x500, 0xfff, 0xfff, 0x120, 0x2c6, 0x290,
-       0x2f5, 0x0e3, 0xfff, 0x0b7, 0xfff, 0x319, 0x474, 0xfff,
-       0xfff, 0xfff, 0x529, 0x014, 0xfff, 0x41b, 0x40a, 0x18b,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x0d9,
-       0xfff, 0x38a, 0xfff, 0xfff, 0xfff, 0xfff, 0x1ce, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3b1, 0xfff, 0xfff, 0x05d,
-       0x2c4, 0xfff, 0xfff, 0x4af, 0xfff, 0x030, 0xfff, 0xfff,
-       0x203, 0xfff, 0x277, 0x256, 0xfff, 0xfff, 0xfff, 0x4f9,
-       0xfff, 0x2c7, 0xfff, 0x466, 0x016, 0x1cd, 0xfff, 0x167,
-       0xfff, 0xfff, 0x0c8, 0xfff, 0x43d, 0xfff, 0xfff, 0x020,
-       0xfff, 0xfff, 0x232, 0x1cb, 0x1e0, 0xfff, 0xfff, 0x347,
-       0xfff, 0x478, 0xfff, 0x365, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x358, 0xfff, 0x10b, 0xfff, 0x35d, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x452, 0x22d, 0xfff, 0xfff, 0x47d, 0xfff,
-       0x2f3, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x460, 0xfff,
-       0xfff, 0xfff, 0x50b, 0xfff, 0xfff, 0xfff, 0x2ec, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x4b1, 0x422, 0xfff, 0xfff,
-       0xfff, 0x2d4, 0xfff, 0x239, 0xfff, 0xfff, 0xfff, 0x439,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x491, 0x075, 0xfff, 0xfff, 0xfff, 0x06c, 0xfff,
-       0xfff, 0x0f9, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x139, 0xfff, 0x4f6, 0xfff, 0xfff, 0x409, 0xfff,
-       0xfff, 0x15b, 0xfff, 0xfff, 0x348, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x4a2, 0x49d, 0xfff, 0x033, 0x175, 0xfff, 0x039,
-       0xfff, 0x312, 0x40c, 0xfff, 0xfff, 0x325, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x4aa, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0x165, 0x3bc, 0x48c, 0x310, 0x096,
-       0xfff, 0xfff, 0x250, 0x1a2, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x20d, 0x2ac, 0xfff, 0xfff, 0x39b, 0xfff, 0x377, 0xfff,
-       0x512, 0x495, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x357, 0x4ea, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x198, 0xfff, 0xfff, 0xfff, 0x434, 0x04a,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x062, 0xfff, 0x1d6, 0x1c8,
-       0xfff, 0x1f3, 0x281, 0xfff, 0x462, 0xfff, 0xfff, 0xfff,
-       0x4b0, 0xfff, 0x207, 0xfff, 0xfff, 0xfff, 0xfff, 0x3dd,
-       0xfff, 0xfff, 0x55d, 0xfff, 0x552, 0x494, 0x1af, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x227, 0xfff, 0xfff, 0x069,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x43e,
-       0x0b5, 0xfff, 0x524, 0x2d2, 0xfff, 0xfff, 0xfff, 0x28f,
-       0xfff, 0x01b, 0x50e, 0xfff, 0xfff, 0x1bb, 0xfff, 0xfff,
-       0x41d, 0xfff, 0x32e, 0x48e, 0xfff, 0x1f7, 0x224, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x394, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x52c, 0xfff, 0xfff, 0xfff, 0x392, 0xfff, 0x1e7,
-       0xfff, 0xfff, 0x3f9, 0x3a7, 0xfff, 0x51f, 0xfff, 0x0bb,
-       0x118, 0x3ca, 0xfff, 0x1dd, 0xfff, 0x48b, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x50f, 0xfff, 0x0d6, 0xfff, 0x1fa, 0xfff,
-       0x11e, 0xfff, 0xfff, 0xfff, 0xfff, 0x4d7, 0xfff, 0x078,
-       0x008, 0xfff, 0x25d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x032, 0x33c, 0xfff, 0x4d9, 0x160, 0xfff, 0xfff, 0x300,
-       0x0b1, 0xfff, 0x322, 0xfff, 0x4ec, 0xfff, 0xfff, 0x200,
-       0x00c, 0x369, 0x473, 0xfff, 0xfff, 0x32c, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x53e, 0x3d4, 0x417, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x34b, 0x001, 0x39a, 0x02c, 0xfff, 0xfff, 0x2ce, 0x00f,
-       0xfff, 0x0ba, 0xfff, 0xfff, 0xfff, 0xfff, 0x060, 0xfff,
-       0x406, 0xfff, 0xfff, 0xfff, 0x4ee, 0x4ac, 0xfff, 0x43f,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x29b, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x216,
-       0x190, 0xfff, 0x396, 0x464, 0xfff, 0xfff, 0x323, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x2e9, 0xfff, 0x26d,
-       0x2cd, 0x040, 0xfff, 0xfff, 0xfff, 0xfff, 0x38b, 0x3c0,
-       0xfff, 0xfff, 0xfff, 0x1f2, 0xfff, 0x0ea, 0xfff, 0xfff,
-       0x472, 0xfff, 0x1fb, 0xfff, 0xfff, 0x0af, 0x27f, 0xfff,
-       0xfff, 0xfff, 0x479, 0x023, 0xfff, 0x0d8, 0x3b3, 0xfff,
-       0xfff, 0xfff, 0x121, 0xfff, 0xfff, 0x3bf, 0xfff, 0xfff,
-       0x16b, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x45a, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x0be, 0xfff, 0xfff, 0xfff, 0x111, 0xfff, 0x220,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x09b, 0x218, 0xfff, 0x022, 0x202, 0xfff,
-       0x4c8, 0xfff, 0x0ed, 0xfff, 0xfff, 0x182, 0xfff, 0xfff,
-       0xfff, 0x17f, 0x213, 0xfff, 0x321, 0x36a, 0xfff, 0x086,
-       0xfff, 0xfff, 0xfff, 0x43b, 0x088, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x26c, 0xfff, 0x2f8, 0x3b4, 0xfff, 0xfff, 0xfff,
-       0x132, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x333, 0x444,
-       0x0c1, 0x4d8, 0x46d, 0x264, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x426, 0xfff, 0xfff, 0xfff, 0xfff, 0x2fe, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x011, 0xfff, 0x05f, 0xfff, 0xfff, 0xfff,
-       0xfff, 0x10c, 0x101, 0xfff, 0xfff, 0xfff, 0xfff, 0x110,
-       0xfff, 0x044, 0x304, 0x361, 0x404, 0xfff, 0x51b, 0x099,
-       0xfff, 0x440, 0xfff, 0xfff, 0xfff, 0x222, 0xfff, 0xfff,
-       0xfff, 0xfff, 0x1b5, 0xfff, 0x136, 0x430, 0xfff, 0x1da,
-       0xfff, 0xfff, 0xfff, 0x043, 0xfff, 0x17c, 0xfff, 0xfff,
-       0xfff, 0x01c, 0xfff, 0xfff, 0xfff, 0x425, 0x236, 0xfff,
-       0x317, 0xfff, 0xfff, 0x437, 0x3fc, 0xfff, 0x1f1, 0xfff,
-       0x324, 0xfff, 0xfff, 0x0ca, 0x306, 0xfff, 0x548, 0xfff,
-       0x46e, 0xfff, 0xfff, 0xfff, 0x4b8, 0x1c2, 0x286, 0xfff,
-       0xfff, 0x087, 0x18a, 0x19f, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x18c, 0xfff, 0x215, 0xfff, 0xfff, 0xfff, 0xfff, 0x283,
-       0xfff, 0xfff, 0xfff, 0x126, 0xfff, 0xfff, 0x370, 0xfff,
-       0x53f, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0x31c, 0xfff,
-       0x4d1, 0xfff, 0xfff, 0xfff, 0x021, 0xfff, 0x157, 0xfff,
-       0xfff, 0x028, 0x16e, 0xfff, 0x421, 0xfff, 0x1c6, 0xfff,
-       0xfff, 0x511, 0xfff, 0xfff, 0x39c, 0x46f, 0x1b2, 0xfff,
-       0xfff, 0x316, 0xfff, 0xfff, 0x009, 0xfff, 0xfff, 0x195,
-       0xfff, 0x240, 0x546, 0xfff, 0xfff, 0x520, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x454, 0xfff, 0xfff, 0xfff,
-       0x3f3, 0xfff, 0xfff, 0x187, 0xfff, 0x4a9, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x51c, 0x453, 0x1e6, 0xfff,
-       0xfff, 0xfff, 0x1b0, 0xfff, 0x477, 0xfff, 0xfff, 0xfff,
-       0x4fe, 0xfff, 0x32f, 0xfff, 0xfff, 0x15e, 0x1d4, 0xfff,
-       0x0e5, 0xfff, 0xfff, 0xfff, 0x242, 0x14b, 0x046, 0xfff,
-       0x3f6, 0x3bb, 0x3e4, 0xfff, 0xfff, 0x2e3, 0xfff, 0x245,
-       0xfff, 0x149, 0xfff, 0xfff, 0xfff, 0x2db, 0xfff, 0xfff,
-       0x181, 0xfff, 0x089, 0x2c5, 0xfff, 0x1f5, 0xfff, 0x2d6,
-       0x507, 0xfff, 0x42d, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0x080, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
-       0xfff, 0xfff, 0xfff, 0xfff, 0x3c3, 0x320, 0xfff, 0x1e1,
-       0xfff, 0x0f5, 0x13b, 0xfff, 0xfff, 0xfff, 0x003, 0x4da,
-       0xfff, 0xfff, 0xfff, 0x42c, 0xfff, 0xfff, 0x0cb, 0xfff,
-       0x536, 0x2c3, 0xfff, 0xfff, 0xfff, 0xfff, 0x199, 0xfff,
-       0xfff, 0x0c0, 0xfff, 0x01e, 0x497, 0xfff, 0xfff, 0x3e5,
-       0xfff, 0xfff, 0xfff, 0x0cf, 0xfff, 0x2bd, 0xfff, 0x223,
-       0xfff, 0x3ff, 0xfff, 0x058, 0x174, 0x3ef, 0xfff, 0x002
-};
-
-static unsigned short err_pos(unsigned short din)
-{
-       BUG_ON(din >= ARRAY_SIZE(err_pos_lut));
-       return err_pos_lut[din];
-}
-static int chk_no_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-       if ((chk_syndrome_list[0] | chk_syndrome_list[1] |
-            chk_syndrome_list[2] | chk_syndrome_list[3] |
-            chk_syndrome_list[4] | chk_syndrome_list[5] |
-            chk_syndrome_list[6] | chk_syndrome_list[7]) != 0x0) {
-               return -EINVAL;
-       } else {
-               err_info[0] = 0x0;
-               return 0;
-       }
-}
-static int chk_1_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-       unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
-       tmp0 = gf4096_mul(chk_syndrome_list[1], gf4096_inv(chk_syndrome_list[0]));
-       tmp1 = gf4096_mul(chk_syndrome_list[2], gf4096_inv(chk_syndrome_list[1]));
-       tmp2 = gf4096_mul(chk_syndrome_list[3], gf4096_inv(chk_syndrome_list[2]));
-       tmp3 = gf4096_mul(chk_syndrome_list[4], gf4096_inv(chk_syndrome_list[3]));
-       tmp4 = gf4096_mul(chk_syndrome_list[5], gf4096_inv(chk_syndrome_list[4]));
-       tmp5 = gf4096_mul(chk_syndrome_list[6], gf4096_inv(chk_syndrome_list[5]));
-       tmp6 = gf4096_mul(chk_syndrome_list[7], gf4096_inv(chk_syndrome_list[6]));
-       if ((tmp0 == tmp1) & (tmp1 == tmp2) & (tmp2 == tmp3) & (tmp3 == tmp4) & (tmp4 == tmp5) & (tmp5 == tmp6)) {
-               err_info[0] = 0x1;      // encode 1-symbol error as 0x1
-               err_info[1] = err_pos(tmp0);
-               err_info[1] = (unsigned short)(0x55e - err_info[1]);
-               err_info[5] = chk_syndrome_list[0];
-               return 0;
-       } else
-               return -EINVAL;
-}
-static int chk_2_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-       unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
-       unsigned short coefs[4];
-       unsigned short err_pats[4];
-       int found_num_root = 0;
-       unsigned short bit2_root0, bit2_root1;
-       unsigned short bit2_root0_inv, bit2_root1_inv;
-       unsigned short err_loc_eqn, test_root;
-       unsigned short bit2_loc0, bit2_loc1;
-       unsigned short bit2_pat0, bit2_pat1;
-
-       find_2x2_soln(chk_syndrome_list[1],
-                     chk_syndrome_list[0],
-                     chk_syndrome_list[2], chk_syndrome_list[1], chk_syndrome_list[2], chk_syndrome_list[3], coefs);
-       for (test_root = 0x1; test_root < 0xfff; test_root++) {
-               err_loc_eqn =
-                   gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root) ^ 0x1;
-               if (err_loc_eqn == 0x0) {
-                       if (found_num_root == 0) {
-                               bit2_root0 = test_root;
-                               found_num_root = 1;
-                       } else if (found_num_root == 1) {
-                               bit2_root1 = test_root;
-                               found_num_root = 2;
-                               break;
-                       }
-               }
-       }
-       if (found_num_root != 2)
-               return -EINVAL;
-       else {
-               bit2_root0_inv = gf4096_inv(bit2_root0);
-               bit2_root1_inv = gf4096_inv(bit2_root1);
-               find_2bit_err_pats(chk_syndrome_list[0],
-                                  chk_syndrome_list[1], bit2_root0_inv, bit2_root1_inv, err_pats);
-               bit2_pat0 = err_pats[0];
-               bit2_pat1 = err_pats[1];
-               //for(x+1)
-               tmp0 = gf4096_mul(gf4096_mul(bit2_root0_inv, bit2_root0_inv), gf4096_mul(bit2_root0_inv, bit2_root0_inv));      //rinv0^4
-               tmp1 = gf4096_mul(bit2_root0_inv, tmp0);        //rinv0^5
-               tmp2 = gf4096_mul(bit2_root0_inv, tmp1);        //rinv0^6
-               tmp3 = gf4096_mul(bit2_root0_inv, tmp2);        //rinv0^7
-               tmp4 = gf4096_mul(gf4096_mul(bit2_root1_inv, bit2_root1_inv), gf4096_mul(bit2_root1_inv, bit2_root1_inv));      //rinv1^4
-               tmp5 = gf4096_mul(bit2_root1_inv, tmp4);        //rinv1^5
-               tmp6 = gf4096_mul(bit2_root1_inv, tmp5);        //rinv1^6
-               tmp7 = gf4096_mul(bit2_root1_inv, tmp6);        //rinv1^7
-               //check if only 2-bit error
-               if ((chk_syndrome_list[4] ==
-                    (gf4096_mul(bit2_pat0, tmp0) ^
-                     gf4096_mul(bit2_pat1,
-                                tmp4))) & (chk_syndrome_list[5] ==
-                                           (gf4096_mul(bit2_pat0, tmp1) ^
-                                            gf4096_mul(bit2_pat1,
-                                                       tmp5))) &
-                   (chk_syndrome_list[6] ==
-                    (gf4096_mul(bit2_pat0, tmp2) ^
-                     gf4096_mul(bit2_pat1,
-                                tmp6))) & (chk_syndrome_list[7] ==
-                                           (gf4096_mul(bit2_pat0, tmp3) ^ gf4096_mul(bit2_pat1, tmp7)))) {
-                       if ((err_pos(bit2_root0_inv) == 0xfff) | (err_pos(bit2_root1_inv) == 0xfff)) {
-                               return -EINVAL;
-                       } else {
-                               bit2_loc0 = 0x55e - err_pos(bit2_root0_inv);
-                               bit2_loc1 = 0x55e - err_pos(bit2_root1_inv);
-                               err_info[0] = 0x2;      // encode 2-symbol error as 0x2
-                               err_info[1] = bit2_loc0;
-                               err_info[2] = bit2_loc1;
-                               err_info[5] = bit2_pat0;
-                               err_info[6] = bit2_pat1;
-                               return 0;
-                       }
-               } else
-                       return -EINVAL;
-       }
-}
-static int chk_3_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-       unsigned short tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
-       unsigned short coefs[4];
-       unsigned short err_pats[4];
-       int found_num_root = 0;
-       unsigned short bit3_root0, bit3_root1, bit3_root2;
-       unsigned short bit3_root0_inv, bit3_root1_inv, bit3_root2_inv;
-       unsigned short err_loc_eqn, test_root;
-
-       find_3bit_err_coefs(chk_syndrome_list[0], chk_syndrome_list[1],
-                           chk_syndrome_list[2], chk_syndrome_list[3],
-                           chk_syndrome_list[4], chk_syndrome_list[5], coefs);
-
-       for (test_root = 0x1; test_root < 0xfff; test_root++) {
-               err_loc_eqn = gf4096_mul(coefs[2],
-                                        gf4096_mul(gf4096_mul(test_root, test_root),
-                                                   test_root)) ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root))
-                       ^ gf4096_mul(coefs[0], test_root) ^ 0x1;
-
-               if (err_loc_eqn == 0x0) {
-                       if (found_num_root == 0) {
-                               bit3_root0 = test_root;
-                               found_num_root = 1;
-                       } else if (found_num_root == 1) {
-                               bit3_root1 = test_root;
-                               found_num_root = 2;
-                       } else if (found_num_root == 2) {
-                               bit3_root2 = test_root;
-                               found_num_root = 3;
-                               break;
-                       }
-               }
-       }
-       if (found_num_root != 3)
-               return -EINVAL;
-       else {
-               bit3_root0_inv = gf4096_inv(bit3_root0);
-               bit3_root1_inv = gf4096_inv(bit3_root1);
-               bit3_root2_inv = gf4096_inv(bit3_root2);
-
-               find_3bit_err_pats(chk_syndrome_list[0], chk_syndrome_list[1],
-                                  chk_syndrome_list[2], bit3_root0_inv,
-                                  bit3_root1_inv, bit3_root2_inv, err_pats);
-
-               //check if only 3-bit error
-               tmp0 = gf4096_mul(bit3_root0_inv, bit3_root0_inv);
-               tmp0 = gf4096_mul(tmp0, tmp0);
-               tmp0 = gf4096_mul(tmp0, bit3_root0_inv);
-               tmp0 = gf4096_mul(tmp0, bit3_root0_inv);        //rinv0^6
-               tmp1 = gf4096_mul(tmp0, bit3_root0_inv);        //rinv0^7
-               tmp2 = gf4096_mul(bit3_root1_inv, bit3_root1_inv);
-               tmp2 = gf4096_mul(tmp2, tmp2);
-               tmp2 = gf4096_mul(tmp2, bit3_root1_inv);
-               tmp2 = gf4096_mul(tmp2, bit3_root1_inv);        //rinv1^6
-               tmp3 = gf4096_mul(tmp2, bit3_root1_inv);        //rinv1^7
-               tmp4 = gf4096_mul(bit3_root2_inv, bit3_root2_inv);
-               tmp4 = gf4096_mul(tmp4, tmp4);
-               tmp4 = gf4096_mul(tmp4, bit3_root2_inv);
-               tmp4 = gf4096_mul(tmp4, bit3_root2_inv);        //rinv2^6
-               tmp5 = gf4096_mul(tmp4, bit3_root2_inv);        //rinv2^7
-
-               //check if only 3 errors
-               if ((chk_syndrome_list[6] == (gf4096_mul(err_pats[0], tmp0) ^
-                                             gf4096_mul(err_pats[1], tmp2) ^
-                                             gf4096_mul(err_pats[2], tmp4))) &
-                   (chk_syndrome_list[7] == (gf4096_mul(err_pats[0], tmp1) ^
-                                             gf4096_mul(err_pats[1], tmp3) ^ gf4096_mul(err_pats[2], tmp5)))) {
-                       if ((err_pos(bit3_root0_inv) == 0xfff) |
-                           (err_pos(bit3_root1_inv) == 0xfff) | (err_pos(bit3_root2_inv) == 0xfff)) {
-                               return -EINVAL;
-                       } else {
-                               err_info[0] = 0x3;
-                               err_info[1] = (0x55e - err_pos(bit3_root0_inv));
-                               err_info[2] = (0x55e - err_pos(bit3_root1_inv));
-                               err_info[3] = (0x55e - err_pos(bit3_root2_inv));
-                               err_info[5] = err_pats[0];
-                               err_info[6] = err_pats[1];
-                               err_info[7] = err_pats[2];
-                               return 0;
-                       }
-               } else
-                       return -EINVAL;
-       }
-}
-static int chk_4_err_only(unsigned short *chk_syndrome_list, unsigned short *err_info)
-{
-       unsigned short coefs[4];
-       unsigned short err_pats[4];
-       int found_num_root = 0;
-       unsigned short bit4_root0, bit4_root1, bit4_root2, bit4_root3;
-       unsigned short bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv;
-       unsigned short err_loc_eqn, test_root;
-
-       find_4bit_err_coefs(chk_syndrome_list[0],
-                           chk_syndrome_list[1],
-                           chk_syndrome_list[2],
-                           chk_syndrome_list[3],
-                           chk_syndrome_list[4],
-                           chk_syndrome_list[5], chk_syndrome_list[6], chk_syndrome_list[7], coefs);
-
-       for (test_root = 0x1; test_root < 0xfff; test_root++) {
-               err_loc_eqn =
-                   gf4096_mul(coefs[3],
-                              gf4096_mul(gf4096_mul
-                                         (gf4096_mul(test_root, test_root),
-                                          test_root),
-                                         test_root)) ^ gf4096_mul(coefs[2],
-                                                                  gf4096_mul
-                                                                  (gf4096_mul(test_root, test_root), test_root))
-                   ^ gf4096_mul(coefs[1], gf4096_mul(test_root, test_root)) ^ gf4096_mul(coefs[0], test_root)
-                   ^ 0x1;
-               if (err_loc_eqn == 0x0) {
-                       if (found_num_root == 0) {
-                               bit4_root0 = test_root;
-                               found_num_root = 1;
-                       } else if (found_num_root == 1) {
-                               bit4_root1 = test_root;
-                               found_num_root = 2;
-                       } else if (found_num_root == 2) {
-                               bit4_root2 = test_root;
-                               found_num_root = 3;
-                       } else {
-                               found_num_root = 4;
-                               bit4_root3 = test_root;
-                               break;
-                       }
-               }
-       }
-       if (found_num_root != 4) {
-               return -EINVAL;
-       } else {
-               bit4_root0_inv = gf4096_inv(bit4_root0);
-               bit4_root1_inv = gf4096_inv(bit4_root1);
-               bit4_root2_inv = gf4096_inv(bit4_root2);
-               bit4_root3_inv = gf4096_inv(bit4_root3);
-               find_4bit_err_pats(chk_syndrome_list[0],
-                                  chk_syndrome_list[1],
-                                  chk_syndrome_list[2],
-                                  chk_syndrome_list[3],
-                                  bit4_root0_inv, bit4_root1_inv, bit4_root2_inv, bit4_root3_inv, err_pats);
-               err_info[0] = 0x4;
-               err_info[1] = (0x55e - err_pos(bit4_root0_inv));
-               err_info[2] = (0x55e - err_pos(bit4_root1_inv));
-               err_info[3] = (0x55e - err_pos(bit4_root2_inv));
-               err_info[4] = (0x55e - err_pos(bit4_root3_inv));
-               err_info[5] = err_pats[0];
-               err_info[6] = err_pats[1];
-               err_info[7] = err_pats[2];
-               err_info[8] = err_pats[3];
-               return 0;
-       }
-}
-
-void correct_12bit_symbol(unsigned char *buf, unsigned short sym,
-                         unsigned short val)
-{
-       if (unlikely(sym > 1366)) {
-               printk(KERN_ERR "Error: symbol %d out of range; cannot correct\n", sym);
-       } else if (sym == 0) {
-               buf[0] ^= val;
-       } else if (sym & 1) {
-               buf[1+(3*(sym-1))/2] ^= (val >> 4);
-               buf[2+(3*(sym-1))/2] ^= ((val & 0xf) << 4);
-       } else {
-               buf[2+(3*(sym-2))/2] ^= (val >> 8);
-               buf[3+(3*(sym-2))/2] ^= (val & 0xff);
-       }
-}
-
-static int debugecc = 0;
-module_param(debugecc, int, 0644);
-
-int cafe_correct_ecc(unsigned char *buf,
-                    unsigned short *chk_syndrome_list)
-{
-       unsigned short err_info[9];
-       int i;
-
-       if (debugecc) {
-               printk(KERN_WARNING "cafe_correct_ecc invoked. Syndromes %x %x %x %x %x %x %x %x\n",
-                      chk_syndrome_list[0], chk_syndrome_list[1],
-                      chk_syndrome_list[2], chk_syndrome_list[3],
-                      chk_syndrome_list[4], chk_syndrome_list[5],
-                      chk_syndrome_list[6], chk_syndrome_list[7]);
-               for (i=0; i < 2048; i+=16) {
-                       printk(KERN_WARNING "D %04x: %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x\n",
-                              i,
-                              buf[i], buf[i+1], buf[i+2], buf[i+3],
-                              buf[i+4], buf[i+5], buf[i+6], buf[i+7],
-                              buf[i+8], buf[i+9], buf[i+10], buf[i+11],
-                              buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
-               }
-               for ( ; i < 2112; i+=16) {
-                       printk(KERN_WARNING "O   %02x: %02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x\n",
-                              i - 2048,
-                              buf[i], buf[i+1], buf[i+2], buf[i+3],
-                              buf[i+4], buf[i+5], buf[i+6], buf[i+7],
-                              buf[i+8], buf[i+9], buf[i+10], buf[i+11],
-                              buf[i+12], buf[i+13], buf[i+14], buf[i+15]);
-               }
-       }
-
-
-
-       if (chk_no_err_only(chk_syndrome_list, err_info) &&
-           chk_1_err_only(chk_syndrome_list, err_info) &&
-           chk_2_err_only(chk_syndrome_list, err_info) &&
-           chk_3_err_only(chk_syndrome_list, err_info) &&
-           chk_4_err_only(chk_syndrome_list, err_info)) {
-               return -EIO;
-       }
-
-       for (i=0; i < err_info[0]; i++) {
-               if (debugecc)
-                       printk(KERN_WARNING "Correct symbol %d with 0x%03x\n",
-                              err_info[1+i], err_info[5+i]);
-
-               correct_12bit_symbol(buf, err_info[1+i], err_info[5+i]);
-       }
-
-       return err_info[0];
-}
-
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
new file mode 100644 (file)
index 0000000..cff969d
--- /dev/null
@@ -0,0 +1,849 @@
+/*
+ * Driver for One Laptop Per Child ‘CAFÉ’ controller, aka Marvell 88ALP01
+ *
+ * Copyright © 2006 Red Hat, Inc.
+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
+ */
+
+#define DEBUG
+
+#include <linux/device.h>
+#undef DEBUG
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/rslib.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+
+#define CAFE_NAND_CTRL1                0x00
+#define CAFE_NAND_CTRL2                0x04
+#define CAFE_NAND_CTRL3                0x08
+#define CAFE_NAND_STATUS       0x0c
+#define CAFE_NAND_IRQ          0x10
+#define CAFE_NAND_IRQ_MASK     0x14
+#define CAFE_NAND_DATA_LEN     0x18
+#define CAFE_NAND_ADDR1                0x1c
+#define CAFE_NAND_ADDR2                0x20
+#define CAFE_NAND_TIMING1      0x24
+#define CAFE_NAND_TIMING2      0x28
+#define CAFE_NAND_TIMING3      0x2c
+#define CAFE_NAND_NONMEM       0x30
+#define CAFE_NAND_ECC_RESULT   0x3C
+#define CAFE_NAND_DMA_CTRL     0x40
+#define CAFE_NAND_DMA_ADDR0    0x44
+#define CAFE_NAND_DMA_ADDR1    0x48
+#define CAFE_NAND_ECC_SYN01    0x50
+#define CAFE_NAND_ECC_SYN23    0x54
+#define CAFE_NAND_ECC_SYN45    0x58
+#define CAFE_NAND_ECC_SYN67    0x5c
+#define CAFE_NAND_READ_DATA    0x1000
+#define CAFE_NAND_WRITE_DATA   0x2000
+
+#define CAFE_GLOBAL_CTRL       0x3004
+#define CAFE_GLOBAL_IRQ                0x3008
+#define CAFE_GLOBAL_IRQ_MASK   0x300c
+#define CAFE_NAND_RESET                0x3034
+
+/* Missing from the datasheet: bit 19 of CTRL1 sets CE0 vs. CE1 */
+#define CTRL1_CHIPSELECT       (1<<19)
+
+struct cafe_priv {
+       struct nand_chip nand;
+       struct pci_dev *pdev;
+       void __iomem *mmio;
+       struct rs_control *rs;
+       uint32_t ctl1;
+       uint32_t ctl2;
+       int datalen;
+       int nr_data;
+       int data_pos;
+       int page_addr;
+       dma_addr_t dmaaddr;
+       unsigned char *dmabuf;
+};
+
+static int usedma = 1;
+module_param(usedma, int, 0644);
+
+static int skipbbt = 0;
+module_param(skipbbt, int, 0644);
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+static int regdebug = 0;
+module_param(regdebug, int, 0644);
+
+static int checkecc = 1;
+module_param(checkecc, int, 0644);
+
+static int numtimings;
+static int timing[3];
+module_param_array(timing, int, &numtimings, 0644);
+
+/* Hrm. Why isn't this already conditional on something in the struct device? */
+#define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
+
+/* Make it easier to switch to PIO if we need to */
+#define cafe_readl(cafe, addr)                 readl((cafe)->mmio + CAFE_##addr)
+#define cafe_writel(cafe, datum, addr)         writel(datum, (cafe)->mmio + CAFE_##addr)
+
+static int cafe_device_ready(struct mtd_info *mtd)
+{
+       struct cafe_priv *cafe = mtd->priv;
+       int result = !!(cafe_readl(cafe, NAND_STATUS) | 0x40000000);
+       uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
+
+       cafe_writel(cafe, irqs, NAND_IRQ);
+
+       cafe_dev_dbg(&cafe->pdev->dev, "NAND device is%s ready, IRQ %x (%x) (%x,%x)\n",
+               result?"":" not", irqs, cafe_readl(cafe, NAND_IRQ),
+               cafe_readl(cafe, GLOBAL_IRQ), cafe_readl(cafe, GLOBAL_IRQ_MASK));
+
+       return result;
+}
+
+
+static void cafe_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+       struct cafe_priv *cafe = mtd->priv;
+
+       if (usedma)
+               memcpy(cafe->dmabuf + cafe->datalen, buf, len);
+       else
+               memcpy_toio(cafe->mmio + CAFE_NAND_WRITE_DATA + cafe->datalen, buf, len);
+
+       cafe->datalen += len;
+
+       cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes to write buffer. datalen 0x%x\n",
+               len, cafe->datalen);
+}
+
+static void cafe_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+       struct cafe_priv *cafe = mtd->priv;
+
+       if (usedma)
+               memcpy(buf, cafe->dmabuf + cafe->datalen, len);
+       else
+               memcpy_fromio(buf, cafe->mmio + CAFE_NAND_READ_DATA + cafe->datalen, len);
+
+       cafe_dev_dbg(&cafe->pdev->dev, "Copy 0x%x bytes from position 0x%x in read buffer.\n",
+                 len, cafe->datalen);
+       cafe->datalen += len;
+}
+
+static uint8_t cafe_read_byte(struct mtd_info *mtd)
+{
+       struct cafe_priv *cafe = mtd->priv;
+       uint8_t d;
+
+       cafe_read_buf(mtd, &d, 1);
+       cafe_dev_dbg(&cafe->pdev->dev, "Read %02x\n", d);
+
+       return d;
+}
+
+static void cafe_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+                             int column, int page_addr)
+{
+       struct cafe_priv *cafe = mtd->priv;
+       int adrbytes = 0;
+       uint32_t ctl1;
+       uint32_t doneint = 0x80000000;
+
+       cafe_dev_dbg(&cafe->pdev->dev, "cmdfunc %02x, 0x%x, 0x%x\n",
+               command, column, page_addr);
+
+       if (command == NAND_CMD_ERASE2 || command == NAND_CMD_PAGEPROG) {
+               /* Second half of a command we already calculated */
+               cafe_writel(cafe, cafe->ctl2 | 0x100 | command, NAND_CTRL2);
+               ctl1 = cafe->ctl1;
+               cafe->ctl2 &= ~(1<<30);
+               cafe_dev_dbg(&cafe->pdev->dev, "Continue command, ctl1 %08x, #data %d\n",
+                         cafe->ctl1, cafe->nr_data);
+               goto do_command;
+       }
+       /* Reset ECC engine */
+       cafe_writel(cafe, 0, NAND_CTRL2);
+
+       /* Emulate NAND_CMD_READOOB on large-page chips */
+       if (mtd->writesize > 512 &&
+           command == NAND_CMD_READOOB) {
+               column += mtd->writesize;
+               command = NAND_CMD_READ0;
+       }
+
+       /* FIXME: Do we need to send read command before sending data
+          for small-page chips, to position the buffer correctly? */
+
+       if (column != -1) {
+               cafe_writel(cafe, column, NAND_ADDR1);
+               adrbytes = 2;
+               if (page_addr != -1)
+                       goto write_adr2;
+       } else if (page_addr != -1) {
+               cafe_writel(cafe, page_addr & 0xffff, NAND_ADDR1);
+               page_addr >>= 16;
+       write_adr2:
+               cafe_writel(cafe, page_addr, NAND_ADDR2);
+               adrbytes += 2;
+               if (mtd->size > mtd->writesize << 16)
+                       adrbytes++;
+       }
+
+       cafe->data_pos = cafe->datalen = 0;
+
+       /* Set command valid bit, mask in the chip select bit  */
+       ctl1 = 0x80000000 | command | (cafe->ctl1 & CTRL1_CHIPSELECT);
+
+       /* Set RD or WR bits as appropriate */
+       if (command == NAND_CMD_READID || command == NAND_CMD_STATUS) {
+               ctl1 |= (1<<26); /* rd */
+               /* Always 5 bytes, for now */
+               cafe->datalen = 4;
+               /* And one address cycle -- even for STATUS, since the controller doesn't work without */
+               adrbytes = 1;
+       } else if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 ||
+                  command == NAND_CMD_READOOB || command == NAND_CMD_RNDOUT) {
+               ctl1 |= 1<<26; /* rd */
+               /* For now, assume just read to end of page */
+               cafe->datalen = mtd->writesize + mtd->oobsize - column;
+       } else if (command == NAND_CMD_SEQIN)
+               ctl1 |= 1<<25; /* wr */
+
+       /* Set number of address bytes */
+       if (adrbytes)
+               ctl1 |= ((adrbytes-1)|8) << 27;
+
+       if (command == NAND_CMD_SEQIN || command == NAND_CMD_ERASE1) {
+               /* Ignore the first command of a pair; the hardware
+                  deals with them both at once, later */
+               cafe->ctl1 = ctl1;
+               cafe_dev_dbg(&cafe->pdev->dev, "Setup for delayed command, ctl1 %08x, dlen %x\n",
+                         cafe->ctl1, cafe->datalen);
+               return;
+       }
+       /* RNDOUT and READ0 commands need a following byte */
+       if (command == NAND_CMD_RNDOUT)
+               cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_RNDOUTSTART, NAND_CTRL2);
+       else if (command == NAND_CMD_READ0 && mtd->writesize > 512)
+               cafe_writel(cafe, cafe->ctl2 | 0x100 | NAND_CMD_READSTART, NAND_CTRL2);
+
+ do_command:
+       cafe_dev_dbg(&cafe->pdev->dev, "dlen %x, ctl1 %x, ctl2 %x\n",
+               cafe->datalen, ctl1, cafe_readl(cafe, NAND_CTRL2));
+
+       /* NB: The datasheet lies -- we really should be subtracting 1 here */
+       cafe_writel(cafe, cafe->datalen, NAND_DATA_LEN);
+       cafe_writel(cafe, 0x90000000, NAND_IRQ);
+       if (usedma && (ctl1 & (3<<25))) {
+               uint32_t dmactl = 0xc0000000 + cafe->datalen;
+               /* If WR or RD bits set, set up DMA */
+               if (ctl1 & (1<<26)) {
+                       /* It's a read */
+                       dmactl |= (1<<29);
+                       /* ... so it's done when the DMA is done, not just
+                          the command. */
+                       doneint = 0x10000000;
+               }
+               cafe_writel(cafe, dmactl, NAND_DMA_CTRL);
+       }
+       cafe->datalen = 0;
+
+       if (unlikely(regdebug)) {
+               int i;
+               printk("About to write command %08x to register 0\n", ctl1);
+               for (i=4; i< 0x5c; i+=4)
+                       printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
+       }
+
+       cafe_writel(cafe, ctl1, NAND_CTRL1);
+       /* Apply this short delay always to ensure that we do wait tWB in
+        * any case on any machine. */
+       ndelay(100);
+
+       if (1) {
+               int c;
+               uint32_t irqs;
+
+               for (c = 500000; c != 0; c--) {
+                       irqs = cafe_readl(cafe, NAND_IRQ);
+                       if (irqs & doneint)
+                               break;
+                       udelay(1);
+                       if (!(c % 100000))
+                               cafe_dev_dbg(&cafe->pdev->dev, "Wait for ready, IRQ %x\n", irqs);
+                       cpu_relax();
+               }
+               cafe_writel(cafe, doneint, NAND_IRQ);
+               cafe_dev_dbg(&cafe->pdev->dev, "Command %x completed after %d usec, irqs %x (%x)\n",
+                            command, 500000-c, irqs, cafe_readl(cafe, NAND_IRQ));
+       }
+
+       WARN_ON(cafe->ctl2 & (1<<30));
+
+       switch (command) {
+
+       case NAND_CMD_CACHEDPROG:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_ERASE1:
+       case NAND_CMD_ERASE2:
+       case NAND_CMD_SEQIN:
+       case NAND_CMD_RNDIN:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_DEPLETE1:
+       case NAND_CMD_RNDOUT:
+       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:
+               cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
+               return;
+       }
+       nand_wait_ready(mtd);
+       cafe_writel(cafe, cafe->ctl2, NAND_CTRL2);
+}
+
+static void cafe_select_chip(struct mtd_info *mtd, int chipnr)
+{
+       struct cafe_priv *cafe = mtd->priv;
+
+       cafe_dev_dbg(&cafe->pdev->dev, "select_chip %d\n", chipnr);
+
+       /* Mask the appropriate bit into the stored value of ctl1
+          which will be used by cafe_nand_cmdfunc() */
+       if (chipnr)
+               cafe->ctl1 |= CTRL1_CHIPSELECT;
+       else
+               cafe->ctl1 &= ~CTRL1_CHIPSELECT;
+}
+
+static int cafe_nand_interrupt(int irq, void *id)
+{
+       struct mtd_info *mtd = id;
+       struct cafe_priv *cafe = mtd->priv;
+       uint32_t irqs = cafe_readl(cafe, NAND_IRQ);
+       cafe_writel(cafe, irqs & ~0x90000000, NAND_IRQ);
+       if (!irqs)
+               return IRQ_NONE;
+
+       cafe_dev_dbg(&cafe->pdev->dev, "irq, bits %x (%x)\n", irqs, cafe_readl(cafe, NAND_IRQ));
+       return IRQ_HANDLED;
+}
+
+static void cafe_nand_bug(struct mtd_info *mtd)
+{
+       BUG();
+}
+
+static int cafe_nand_write_oob(struct mtd_info *mtd,
+                              struct nand_chip *chip, int page)
+{
+       int status = 0;
+
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       status = chip->waitfunc(mtd, chip);
+
+       return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+/* Don't use -- use nand_read_oob_std for now */
+static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+                             int page, int sndcmd)
+{
+       chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+       return 1;
+}
+/**
+ * cafe_nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
+ * @mtd:       mtd info structure
+ * @chip:      nand chip info structure
+ * @buf:       buffer to store read data
+ *
+ * The hw generator calculates the error syndrome automatically. Therefor
+ * we need a special oob layout and handling.
+ */
+static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                              uint8_t *buf)
+{
+       struct cafe_priv *cafe = mtd->priv;
+
+       cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
+                    cafe_readl(cafe, NAND_ECC_RESULT),
+                    cafe_readl(cafe, NAND_ECC_SYN01));
+
+       chip->read_buf(mtd, buf, mtd->writesize);
+       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       if (checkecc && cafe_readl(cafe, NAND_ECC_RESULT) & (1<<18)) {
+               unsigned short syn[8], pat[4];
+               int pos[4];
+               u8 *oob = chip->oob_poi;
+               int i, n;
+
+               for (i=0; i<8; i+=2) {
+                       uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
+                       syn[i] = cafe->rs->index_of[tmp & 0xfff];
+                       syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff];
+               }
+
+               n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0,
+                               pat);
+
+               for (i = 0; i < n; i++) {
+                       int p = pos[i];
+
+                       /* The 12-bit symbols are mapped to bytes here */
+
+                       if (p > 1374) {
+                               /* out of range */
+                               n = -1374;
+                       } else if (p == 0) {
+                               /* high four bits do not correspond to data */
+                               if (pat[i] > 0xff)
+                                       n = -2048;
+                               else
+                                       buf[0] ^= pat[i];
+                       } else if (p == 1365) {
+                               buf[2047] ^= pat[i] >> 4;
+                               oob[0] ^= pat[i] << 4;
+                       } else if (p > 1365) {
+                               if ((p & 1) == 1) {
+                                       oob[3*p/2 - 2048] ^= pat[i] >> 4;
+                                       oob[3*p/2 - 2047] ^= pat[i] << 4;
+                               } else {
+                                       oob[3*p/2 - 2049] ^= pat[i] >> 8;
+                                       oob[3*p/2 - 2048] ^= pat[i];
+                               }
+                       } else if ((p & 1) == 1) {
+                               buf[3*p/2] ^= pat[i] >> 4;
+                               buf[3*p/2 + 1] ^= pat[i] << 4;
+                       } else {
+                               buf[3*p/2 - 1] ^= pat[i] >> 8;
+                               buf[3*p/2] ^= pat[i];
+                       }
+               }
+
+               if (n < 0) {
+                       dev_dbg(&cafe->pdev->dev, "Failed to correct ECC at %08x\n",
+                               cafe_readl(cafe, NAND_ADDR2) * 2048);
+                       for (i = 0; i < 0x5c; i += 4)
+                               printk("Register %x: %08x\n", i, readl(cafe->mmio + i));
+                       mtd->ecc_stats.failed++;
+               } else {
+                       dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
+                       mtd->ecc_stats.corrected += n;
+               }
+       }
+
+       return 0;
+}
+
+static struct nand_ecclayout cafe_oobinfo_2048 = {
+       .eccbytes = 14,
+       .eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
+       .oobfree = {{14, 50}}
+};
+
+/* Ick. The BBT code really ought to be able to work this bit out
+   for itself from the above, at least for the 2KiB case */
+static uint8_t cafe_bbt_pattern_2048[] = { 'B', 'b', 't', '0' };
+static uint8_t cafe_mirror_pattern_2048[] = { '1', 't', 'b', 'B' };
+
+static uint8_t cafe_bbt_pattern_512[] = { 0xBB };
+static uint8_t cafe_mirror_pattern_512[] = { 0xBC };
+
+
+static struct nand_bbt_descr cafe_bbt_main_descr_2048 = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION,
+       .offs = 14,
+       .len = 4,
+       .veroffs = 18,
+       .maxblocks = 4,
+       .pattern = cafe_bbt_pattern_2048
+};
+
+static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION,
+       .offs = 14,
+       .len = 4,
+       .veroffs = 18,
+       .maxblocks = 4,
+       .pattern = cafe_mirror_pattern_2048
+};
+
+static struct nand_ecclayout cafe_oobinfo_512 = {
+       .eccbytes = 14,
+       .eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
+       .oobfree = {{14, 2}}
+};
+
+static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION,
+       .offs = 14,
+       .len = 1,
+       .veroffs = 15,
+       .maxblocks = 4,
+       .pattern = cafe_bbt_pattern_512
+};
+
+static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION,
+       .offs = 14,
+       .len = 1,
+       .veroffs = 15,
+       .maxblocks = 4,
+       .pattern = cafe_mirror_pattern_512
+};
+
+
+static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
+                                         struct nand_chip *chip, const uint8_t *buf)
+{
+       struct cafe_priv *cafe = mtd->priv;
+
+       chip->write_buf(mtd, buf, mtd->writesize);
+       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       /* Set up ECC autogeneration */
+       cafe->ctl2 |= (1<<30);
+}
+
+static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                               const uint8_t *buf, int page, int cached, int raw)
+{
+       int status;
+
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+
+       if (unlikely(raw))
+               chip->ecc.write_page_raw(mtd, chip, buf);
+       else
+               chip->ecc.write_page(mtd, chip, buf);
+
+       /*
+        * Cached progamming disabled for now, Not sure if its worth the
+        * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
+        */
+       cached = 0;
+
+       if (!cached || !(chip->options & NAND_CACHEPRG)) {
+
+               chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+               status = chip->waitfunc(mtd, chip);
+               /*
+                * See if operation failed and additional status checks are
+                * available
+                */
+               if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+                       status = chip->errstat(mtd, chip, FL_WRITING, status,
+                                              page);
+
+               if (status & NAND_STATUS_FAIL)
+                       return -EIO;
+       } else {
+               chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
+               status = chip->waitfunc(mtd, chip);
+       }
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+       /* Send command to read back the data */
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+       if (chip->verify_buf(mtd, buf, mtd->writesize))
+               return -EIO;
+#endif
+       return 0;
+}
+
+static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
+{
+       return 0;
+}
+
+/* F_2[X]/(X**6+X+1)  */
+static unsigned short __devinit gf64_mul(u8 a, u8 b)
+{
+       u8 c;
+       unsigned int i;
+
+       c = 0;
+       for (i = 0; i < 6; i++) {
+               if (a & 1)
+                       c ^= b;
+               a >>= 1;
+               b <<= 1;
+               if ((b & 0x40) != 0)
+                       b ^= 0x43;
+       }
+
+       return c;
+}
+
+/* F_64[X]/(X**2+X+A**-1) with A the generator of F_64[X]  */
+static u16 __devinit gf4096_mul(u16 a, u16 b)
+{
+       u8 ah, al, bh, bl, ch, cl;
+
+       ah = a >> 6;
+       al = a & 0x3f;
+       bh = b >> 6;
+       bl = b & 0x3f;
+
+       ch = gf64_mul(ah ^ al, bh ^ bl) ^ gf64_mul(al, bl);
+       cl = gf64_mul(gf64_mul(ah, bh), 0x21) ^ gf64_mul(al, bl);
+
+       return (ch << 6) ^ cl;
+}
+
+static int __devinit cafe_mul(int x)
+{
+       if (x == 0)
+               return 1;
+       return gf4096_mul(x, 0xe01);
+}
+
+static int __devinit cafe_nand_probe(struct pci_dev *pdev,
+                                    const struct pci_device_id *ent)
+{
+       struct mtd_info *mtd;
+       struct cafe_priv *cafe;
+       uint32_t ctrl;
+       int err = 0;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+
+       pci_set_master(pdev);
+
+       mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL);
+       if (!mtd) {
+               dev_warn(&pdev->dev, "failed to alloc mtd_info\n");
+               return  -ENOMEM;
+       }
+       cafe = (void *)(&mtd[1]);
+
+       mtd->priv = cafe;
+       mtd->owner = THIS_MODULE;
+
+       cafe->pdev = pdev;
+       cafe->mmio = pci_iomap(pdev, 0, 0);
+       if (!cafe->mmio) {
+               dev_warn(&pdev->dev, "failed to iomap\n");
+               err = -ENOMEM;
+               goto out_free_mtd;
+       }
+       cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112 + sizeof(struct nand_buffers),
+                                         &cafe->dmaaddr, GFP_KERNEL);
+       if (!cafe->dmabuf) {
+               err = -ENOMEM;
+               goto out_ior;
+       }
+       cafe->nand.buffers = (void *)cafe->dmabuf + 2112;
+
+       cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
+       if (!cafe->rs) {
+               err = -ENOMEM;
+               goto out_ior;
+       }
+
+       cafe->nand.cmdfunc = cafe_nand_cmdfunc;
+       cafe->nand.dev_ready = cafe_device_ready;
+       cafe->nand.read_byte = cafe_read_byte;
+       cafe->nand.read_buf = cafe_read_buf;
+       cafe->nand.write_buf = cafe_write_buf;
+       cafe->nand.select_chip = cafe_select_chip;
+
+       cafe->nand.chip_delay = 0;
+
+       /* Enable the following for a flash based bad block table */
+       cafe->nand.options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR | NAND_OWN_BUFFERS;
+
+       if (skipbbt) {
+               cafe->nand.options |= NAND_SKIP_BBTSCAN;
+               cafe->nand.block_bad = cafe_nand_block_bad;
+       }
+
+       if (numtimings && numtimings != 3) {
+               dev_warn(&cafe->pdev->dev, "%d timing register values ignored; precisely three are required\n", numtimings);
+       }
+
+       if (numtimings == 3) {
+               cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n",
+                            timing[0], timing[1], timing[2]);
+       } else {
+               timing[0] = cafe_readl(cafe, NAND_TIMING1);
+               timing[1] = cafe_readl(cafe, NAND_TIMING2);
+               timing[2] = cafe_readl(cafe, NAND_TIMING3);
+
+               if (timing[0] | timing[1] | timing[2]) {
+                       cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n",
+                                    timing[0], timing[1], timing[2]);
+               } else {
+                       dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n");
+                       timing[0] = timing[1] = timing[2] = 0xffffffff;
+               }
+       }
+
+       /* Start off by resetting the NAND controller completely */
+       cafe_writel(cafe, 1, NAND_RESET);
+       cafe_writel(cafe, 0, NAND_RESET);
+
+       cafe_writel(cafe, timing[0], NAND_TIMING1);
+       cafe_writel(cafe, timing[1], NAND_TIMING2);
+       cafe_writel(cafe, timing[2], NAND_TIMING3);
+
+       cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+       err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED,
+                         "CAFE NAND", mtd);
+       if (err) {
+               dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
+               goto out_free_dma;
+       }
+
+       /* Disable master reset, enable NAND clock */
+       ctrl = cafe_readl(cafe, GLOBAL_CTRL);
+       ctrl &= 0xffffeff0;
+       ctrl |= 0x00007000;
+       cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
+       cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
+       cafe_writel(cafe, 0, NAND_DMA_CTRL);
+
+       cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
+       cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
+
+       /* Set up DMA address */
+       cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
+       if (sizeof(cafe->dmaaddr) > 4)
+               /* Shift in two parts to shut the compiler up */
+               cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
+       else
+               cafe_writel(cafe, 0, NAND_DMA_ADDR1);
+
+       cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
+               cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
+
+       /* Enable NAND IRQ in global IRQ mask register */
+       cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+       cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
+               cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
+
+       /* Scan to find existence of the device */
+       if (nand_scan_ident(mtd, 2)) {
+               err = -ENXIO;
+               goto out_irq;
+       }
+
+       cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
+       if (mtd->writesize == 2048)
+               cafe->ctl2 |= 1<<29; /* 2KiB page size */
+
+       /* Set up ECC according to the type of chip we found */
+       if (mtd->writesize == 2048) {
+               cafe->nand.ecc.layout = &cafe_oobinfo_2048;
+               cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
+               cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
+       } else if (mtd->writesize == 512) {
+               cafe->nand.ecc.layout = &cafe_oobinfo_512;
+               cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
+               cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
+       } else {
+               printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
+                      mtd->writesize);
+               goto out_irq;
+       }
+       cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
+       cafe->nand.ecc.size = mtd->writesize;
+       cafe->nand.ecc.bytes = 14;
+       cafe->nand.ecc.hwctl  = (void *)cafe_nand_bug;
+       cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
+       cafe->nand.ecc.correct  = (void *)cafe_nand_bug;
+       cafe->nand.write_page = cafe_nand_write_page;
+       cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
+       cafe->nand.ecc.write_oob = cafe_nand_write_oob;
+       cafe->nand.ecc.read_page = cafe_nand_read_page;
+       cafe->nand.ecc.read_oob = cafe_nand_read_oob;
+
+       err = nand_scan_tail(mtd);
+       if (err)
+               goto out_irq;
+
+       pci_set_drvdata(pdev, mtd);
+       add_mtd_device(mtd);
+       goto out;
+
+ out_irq:
+       /* Disable NAND IRQ in global IRQ mask register */
+       cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
+       free_irq(pdev->irq, mtd);
+ out_free_dma:
+       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+ out_ior:
+       pci_iounmap(pdev, cafe->mmio);
+ out_free_mtd:
+       kfree(mtd);
+ out:
+       return err;
+}
+
+static void __devexit cafe_nand_remove(struct pci_dev *pdev)
+{
+       struct mtd_info *mtd = pci_get_drvdata(pdev);
+       struct cafe_priv *cafe = mtd->priv;
+
+       del_mtd_device(mtd);
+       /* Disable NAND IRQ in global IRQ mask register */
+       cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
+       free_irq(pdev->irq, mtd);
+       nand_release(mtd);
+       free_rs(cafe->rs);
+       pci_iounmap(pdev, cafe->mmio);
+       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+       kfree(mtd);
+}
+
+static struct pci_device_id cafe_nand_tbl[] = {
+       { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 }
+};
+
+MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
+
+static struct pci_driver cafe_nand_pci_driver = {
+       .name = "CAFÉ NAND",
+       .id_table = cafe_nand_tbl,
+       .probe = cafe_nand_probe,
+       .remove = __devexit_p(cafe_nand_remove),
+#ifdef CONFIG_PMx
+       .suspend = cafe_nand_suspend,
+       .resume = cafe_nand_resume,
+#endif
+};
+
+static int cafe_nand_init(void)
+{
+       return pci_register_driver(&cafe_nand_pci_driver);
+}
+
+static void cafe_nand_exit(void)
+{
+       pci_unregister_driver(&cafe_nand_pci_driver);
+}
+module_init(cafe_nand_init);
+module_exit(cafe_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
index 04de315e4937c0e650025983b4364ad647c69dac..7e68203fe1ba1c46c779d55a5ae2c9151c5659bf 100644 (file)
@@ -303,28 +303,27 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
        struct nand_chip *chip = mtd->priv;
        u16 bad;
 
+       page = (int)(ofs >> chip->page_shift) & chip->pagemask;
+
        if (getchip) {
-               page = (int)(ofs >> chip->page_shift);
                chipnr = (int)(ofs >> chip->chip_shift);
 
                nand_get_device(chip, mtd, FL_READING);
 
                /* Select the NAND device */
                chip->select_chip(mtd, chipnr);
-       } else
-               page = (int)(ofs >> chip->page_shift);
+       }
 
        if (chip->options & NAND_BUSWIDTH_16) {
                chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,
-                             page & chip->pagemask);
+                             page);
                bad = cpu_to_le16(chip->read_word(mtd));
                if (chip->badblockpos & 0x1)
                        bad >>= 8;
                if ((bad & 0xFF) != 0xff)
                        res = 1;
        } else {
-               chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
-                             page & chip->pagemask);
+               chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);
                if (chip->read_byte(mtd) != 0xff)
                        res = 1;
        }
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
new file mode 100644 (file)
index 0000000..cd725fc
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Generic NAND driver
+ *
+ * Author: Vitaly Wool <vitalywool@gmail.com>
+ *
+ * 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/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+struct plat_nand_data {
+       struct nand_chip        chip;
+       struct mtd_info         mtd;
+       void __iomem            *io_base;
+#ifdef CONFIG_MTD_PARTITIONS
+       int                     nr_parts;
+       struct mtd_partition    *parts;
+#endif
+};
+
+/*
+ * Probe for the NAND device.
+ */
+static int __init plat_nand_probe(struct platform_device *pdev)
+{
+       struct platform_nand_data *pdata = pdev->dev.platform_data;
+       struct plat_nand_data *data;
+       int res = 0;
+
+       /* Allocate memory for the device structure (and zero it) */
+       data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL);
+       if (!data) {
+               dev_err(&pdev->dev, "failed to allocate device structure.\n");
+               return -ENOMEM;
+       }
+
+       data->io_base = ioremap(pdev->resource[0].start,
+                               pdev->resource[0].end - pdev->resource[0].start + 1);
+       if (data->io_base == NULL) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               kfree(data);
+               return -EIO;
+       }
+
+       data->chip.priv = &data;
+       data->mtd.priv = &data->chip;
+       data->mtd.owner = THIS_MODULE;
+
+       data->chip.IO_ADDR_R = data->io_base;
+       data->chip.IO_ADDR_W = data->io_base;
+       data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
+       data->chip.dev_ready = pdata->ctrl.dev_ready;
+       data->chip.select_chip = pdata->ctrl.select_chip;
+       data->chip.chip_delay = pdata->chip.chip_delay;
+       data->chip.options |= pdata->chip.options;
+
+       data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
+       data->chip.ecc.layout = pdata->chip.ecclayout;
+       data->chip.ecc.mode = NAND_ECC_SOFT;
+
+       platform_set_drvdata(pdev, data);
+
+       /* Scan to find existance of the device */
+       if (nand_scan(&data->mtd, 1)) {
+               res = -ENXIO;
+               goto out;
+       }
+
+#ifdef CONFIG_MTD_PARTITIONS
+       if (pdata->chip.part_probe_types) {
+               res = parse_mtd_partitions(&data->mtd,
+                                       pdata->chip.part_probe_types,
+                                       &data->parts, 0);
+               if (res > 0) {
+                       add_mtd_partitions(&data->mtd, data->parts, res);
+                       return 0;
+               }
+       }
+       if (pdata->chip.partitions) {
+               data->parts = pdata->chip.partitions;
+               res = add_mtd_partitions(&data->mtd, data->parts,
+                       pdata->chip.nr_partitions);
+       } else
+#endif
+       res = add_mtd_device(&data->mtd);
+
+       if (!res)
+               return res;
+
+       nand_release(&data->mtd);
+out:
+       platform_set_drvdata(pdev, NULL);
+       iounmap(data->io_base);
+       kfree(data);
+       return res;
+}
+
+/*
+ * Remove a NAND device.
+ */
+static int __devexit plat_nand_remove(struct platform_device *pdev)
+{
+       struct plat_nand_data *data = platform_get_drvdata(pdev);
+       struct platform_nand_data *pdata = pdev->dev.platform_data;
+
+       nand_release(&data->mtd);
+#ifdef CONFIG_MTD_PARTITIONS
+       if (data->parts && data->parts != pdata->chip.partitions)
+               kfree(data->parts);
+#endif
+       iounmap(data->io_base);
+       kfree(data);
+
+       return 0;
+}
+
+static struct platform_driver plat_nand_driver = {
+       .probe          = plat_nand_probe,
+       .remove         = plat_nand_remove,
+       .driver         = {
+               .name   = "gen_nand",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init plat_nand_init(void)
+{
+       return platform_driver_register(&plat_nand_driver);
+}
+
+static void __exit plat_nand_exit(void)
+{
+       platform_driver_unregister(&plat_nand_driver);
+}
+
+module_init(plat_nand_init);
+module_exit(plat_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vitaly Wool");
+MODULE_DESCRIPTION("Simple generic NAND driver");
diff --git a/fs/jffs2/histo_mips.h b/fs/jffs2/histo_mips.h
deleted file mode 100644 (file)
index fa3dac1..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#define BIT_DIVIDER_MIPS 1043
-static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */
index 6aff38930b50619475e4e2974341427f185298b8..4884d5edfe658282d626c6674497231a9ff4d20a 100644 (file)
@@ -219,9 +219,9 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                struct jffs2_tmp_dnode_info *tn)
 {
        uint32_t fn_end = tn->fn->ofs + tn->fn->size;
-       struct jffs2_tmp_dnode_info *insert_point = NULL, *this;
+       struct jffs2_tmp_dnode_info *this;
 
-       dbg_readinode("insert fragment %#04x-%#04x, ver %u\n", tn->fn->ofs, fn_end, tn->version);
+       dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw));
 
        /* If a node has zero dsize, we only have to keep if it if it might be the
           node with highest version -- i.e. the one which will end up as f->metadata.
@@ -240,23 +240,16 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
 
        /* Find the earliest node which _may_ be relevant to this one */
        this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs);
-       if (!this) {
-               /* First addition to empty tree. $DEITY how I love the easy cases */
-               rb_link_node(&tn->rb, NULL, &rii->tn_root.rb_node);
-               rb_insert_color(&tn->rb, &rii->tn_root);
-               dbg_readinode("keep new frag\n");
-               return 0;
-       }
-
-       /* If we add a new node it'll be somewhere under here. */
-       insert_point = this;
-
-       /* If the node is coincident with another at a lower address,
-          back up until the other node is found. It may be relevant */
-       while (tn->overlapped)
-               tn = tn_prev(tn);
+       if (this) {
+               /* If the node is coincident with another at a lower address,
+                  back up until the other node is found. It may be relevant */
+               while (this->overlapped)
+                       this = tn_prev(this);
 
-       dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
+               /* First node should never be marked overlapped */
+               BUG_ON(!this);
+               dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
+       }
 
        while (this) {
                if (this->fn->ofs > fn_end)
@@ -274,11 +267,10 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                return 0;
                        } else {
                                /* Who cares if the new one is good; keep it for now anyway. */
+                               dbg_readinode("Like new node. Throw away old\n");
                                rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
-                               /* Same overlapping from in front and behind */
-                               tn->overlapped = this->overlapped;
                                jffs2_kill_tn(c, this);
-                               dbg_readinode("Like new node. Throw away old\n");
+                               /* Same overlapping from in front and behind */
                                return 0;
                        }
                }
@@ -291,13 +283,8 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                jffs2_kill_tn(c, tn);
                                return 0;
                        }
-                       /* ... and is good. Kill 'this'... */
-                       rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
-                       tn->overlapped = this->overlapped;
-                       jffs2_kill_tn(c, this);
-                       /* ... and any subsequent nodes which are also overlapped */
-                       this = tn_next(tn);
-                       while (this && this->fn->ofs + this->fn->size < fn_end) {
+                       /* ... and is good. Kill 'this' and any subsequent nodes which are also overlapped */
+                       while (this && this->fn->ofs + this->fn->size <= fn_end) {
                                struct jffs2_tmp_dnode_info *next = tn_next(this);
                                if (this->version < tn->version) {
                                        tn_erase(this, &rii->tn_root);
@@ -308,8 +295,8 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                }
                                this = next;
                        }
-                       dbg_readinode("Done inserting new\n");
-                       return 0;
+                       dbg_readinode("Done killing overlapped nodes\n");
+                       continue;
                }
                if (this->version > tn->version &&
                    this->fn->ofs <= tn->fn->ofs &&
@@ -321,29 +308,21 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                return 0;
                        }
                        /* ... but 'this' was bad. Replace it... */
-                       rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
                        dbg_readinode("Bad CRC on old overlapping node. Kill it\n");
+                       tn_erase(this, &rii->tn_root);
                        jffs2_kill_tn(c, this);
-                       return 0;
+                       break;
                }
-               /* We want to be inserted under the last node which is
-                  either at a lower offset _or_ has a smaller range */
-               if (this->fn->ofs < tn->fn->ofs ||
-                   (this->fn->ofs == tn->fn->ofs &&
-                    this->fn->size <= tn->fn->size))
-                       insert_point = this;
 
                this = tn_next(this);
        }
-       dbg_readinode("insert_point %p, ver %d, 0x%x-0x%x, ov %d\n",
-                     insert_point, insert_point->version, insert_point->fn->ofs,
-                     insert_point->fn->ofs+insert_point->fn->size,
-                     insert_point->overlapped);
+
        /* We neither completely obsoleted nor were completely
-          obsoleted by an earlier node. Insert under insert_point */
+          obsoleted by an earlier node. Insert into the tree */
        {
-               struct rb_node *parent = &insert_point->rb;
-               struct rb_node **link = &parent;
+               struct rb_node *parent;
+               struct rb_node **link = &rii->tn_root.rb_node;
+               struct jffs2_tmp_dnode_info *insert_point = NULL;
 
                while (*link) {
                        parent = *link;
@@ -359,6 +338,7 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                rb_link_node(&tn->rb, &insert_point->rb, link);
                rb_insert_color(&tn->rb, &rii->tn_root);
        }
+
        /* If there's anything behind that overlaps us, note it */
        this = tn_prev(tn);
        if (this) {
@@ -457,7 +437,7 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c,
        this = tn_last(&rii->tn_root);
        while (this) {
                dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs,
-                            this->fn->ofs+this->fn->size, this->overlapped);
+                             this->fn->ofs+this->fn->size, this->overlapped);
                this = tn_prev(this);
        }
 #endif
@@ -483,7 +463,7 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c,
                        vers_next = tn_prev(this);
                        eat_last(&ver_root, &this->rb);
                        if (check_tn_node(c, this)) {
-                               dbg_readinode("node ver %x, 0x%x-0x%x failed CRC\n",
+                               dbg_readinode("node ver %d, 0x%x-0x%x failed CRC\n",
                                             this->version, this->fn->ofs,
                                             this->fn->ofs+this->fn->size);
                                jffs2_kill_tn(c, this);
@@ -496,7 +476,7 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c,
                                        high_ver = this->version;
                                        rii->latest_ref = this->fn->raw;
                                }
-                               dbg_readinode("Add %p (v %x, 0x%x-0x%x, ov %d) to fragtree\n",
+                               dbg_readinode("Add %p (v %d, 0x%x-0x%x, ov %d) to fragtree\n",
                                             this, this->version, this->fn->ofs,
                                             this->fn->ofs+this->fn->size, this->overlapped);
 
@@ -850,7 +830,7 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                return ret;
        }
 #ifdef JFFS2_DBG_READINODE_MESSAGES
-       dbg_readinode("After adding ver %d:\n", tn->version);
+       dbg_readinode("After adding ver %d:\n", je32_to_cpu(rd->version));
        tn = tn_first(&rii->tn_root);
        while (tn) {
                dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n",
index c556e85a565cea44fbceca308514fa51e5c80c3e..91d1d0f1c66c72c1d0c925d383f8e2a02973e2c4 100644 (file)
@@ -637,7 +637,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
 
        memset(c->wbuf,0xff,c->wbuf_pagesize);
        /* adjust write buffer offset, else we get a non contiguous write bug */
-       c->wbuf_ofs += c->wbuf_pagesize;
+       if (SECTOR_ADDR(c->wbuf_ofs) == SECTOR_ADDR(c->wbuf_ofs+c->wbuf_pagesize))
+               c->wbuf_ofs += c->wbuf_pagesize;
+       else
+               c->wbuf_ofs = 0xffffffff;
        c->wbuf_len = 0;
        return 0;
 }
index 45d482ce8397cf2920ac44919121bf3cb334100a..fd64ccfbce02874fd2600b79dc02d84767bde7ae 100644 (file)
@@ -9,10 +9,6 @@
 #ifndef __MTD_MTD_H__
 #define __MTD_MTD_H__
 
-#ifndef __KERNEL__
-#error This is a kernel header. Perhaps include mtd-user.h instead?
-#endif
-
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/uio.h>
@@ -137,9 +133,6 @@ struct mtd_info {
        int numeraseregions;
        struct mtd_erase_region_info *eraseregions;
 
-       /* This really shouldn't be here. It can go away in 2.5 */
-       u_int32_t bank_size;
-
        int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
 
        /* This stuff for eXecute-In-Place */
index cf197ad62da6cd8801102946609ad1bd3fd5549b..d2365c8dcacc86ebf872a2124b3dc16201c09877 100644 (file)
@@ -560,6 +560,7 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
  * @chip_delay:                R/B delay value in us
  * @options:           Option flags, e.g. 16bit buswidth
  * @ecclayout:         ecc layout info structure
+ * @part_probe_types:  NULL-terminated array of probe types
  * @priv:              hardware controller specific settings
  */
 struct platform_nand_chip {
@@ -570,6 +571,7 @@ struct platform_nand_chip {
        struct nand_ecclayout   *ecclayout;
        int                     chip_delay;
        unsigned int            options;
+       const char              **part_probe_types;
        void                    *priv;
 };
 
@@ -578,6 +580,8 @@ struct platform_nand_chip {
  * @hwcontrol:         platform specific hardware control structure
  * @dev_ready:         platform specific function to read ready/busy pin
  * @select_chip:       platform specific chip select function
+ * @cmd_ctrl:          platform specific function for controlling
+ *                     ALE/CLE/nCE. Also used to write command and address
  * @priv:              private data to transport driver specific settings
  *
  * All fields are optional and depend on the hardware driver requirements
@@ -586,9 +590,21 @@ struct platform_nand_ctrl {
        void            (*hwcontrol)(struct mtd_info *mtd, int cmd);
        int             (*dev_ready)(struct mtd_info *mtd);
        void            (*select_chip)(struct mtd_info *mtd, int chip);
+       void            (*cmd_ctrl)(struct mtd_info *mtd, int dat,
+                                   unsigned int ctrl);
        void            *priv;
 };
 
+/**
+ * struct platform_nand_data - container structure for platform-specific data
+ * @chip:              chip level chip structure
+ * @ctrl:              controller level device structure
+ */
+struct platform_nand_data {
+       struct platform_nand_chip       chip;
+       struct platform_nand_ctrl       ctrl;
+};
+
 /* Some helpers to access the data structures */
 static inline
 struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
index ace25acfdc97375d0d403afb4bf12c08443e6309..746580c1939c028d8f8ef8dc6bb460e5ed6dfc17 100644 (file)
@@ -34,6 +34,7 @@
  * @prim:      Primitive element, index form
  * @iprim:     prim-th root of 1, index form
  * @gfpoly:    The primitive generator polynominal
+ * @gffunc:    Function to generate the field, if non-canonical representation
  * @users:     Users of this structure
  * @list:      List entry for the rs control list
 */
@@ -48,6 +49,7 @@ struct rs_control {
        int             prim;
        int             iprim;
        int             gfpoly;
+       int             (*gffunc)(int);
        int             users;
        struct list_head list;
 };
@@ -77,6 +79,8 @@ int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
 /* Create or get a matching rs control structure */
 struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
                           int nroots);
+struct rs_control *init_rs_non_canonical(int symsize, int (*func)(int),
+                                         int fcr, int prim, int nroots);
 
 /* Release a rs control structure */
 void free_rs(struct rs_control *rs);
index a4b730a2180cc129a46df390c4707ee247cf012f..5b0d8522b7ca16882b54cee337536a665cb825d0 100644 (file)
@@ -56,6 +56,7 @@ static DEFINE_MUTEX(rslistlock);
  * rs_init - Initialize a Reed-Solomon codec
  * @symsize:   symbol size, bits (1-8)
  * @gfpoly:    Field generator polynomial coefficients
+ * @gffunc:    Field generator function
  * @fcr:       first root of RS code generator polynomial, index form
  * @prim:      primitive element to generate polynomial roots
  * @nroots:    RS code generator polynomial degree (number of roots)
@@ -63,8 +64,8 @@ static DEFINE_MUTEX(rslistlock);
  * Allocate a control structure and the polynom arrays for faster
  * en/decoding. Fill the arrays according to the given parameters.
  */
-static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
-                                  int prim, int nroots)
+static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int),
+                                  int fcr, int prim, int nroots)
 {
        struct rs_control *rs;
        int i, j, sr, root, iprim;
@@ -82,6 +83,7 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
        rs->prim = prim;
        rs->nroots = nroots;
        rs->gfpoly = gfpoly;
+       rs->gffunc = gffunc;
 
        /* Allocate the arrays */
        rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
@@ -99,17 +101,26 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
        /* Generate Galois field lookup tables */
        rs->index_of[0] = rs->nn;       /* log(zero) = -inf */
        rs->alpha_to[rs->nn] = 0;       /* alpha**-inf = 0 */
-       sr = 1;
-       for (i = 0; i < rs->nn; i++) {
-               rs->index_of[sr] = i;
-               rs->alpha_to[i] = sr;
-               sr <<= 1;
-               if (sr & (1 << symsize))
-                       sr ^= gfpoly;
-               sr &= rs->nn;
+       if (gfpoly) {
+               sr = 1;
+               for (i = 0; i < rs->nn; i++) {
+                       rs->index_of[sr] = i;
+                       rs->alpha_to[i] = sr;
+                       sr <<= 1;
+                       if (sr & (1 << symsize))
+                               sr ^= gfpoly;
+                       sr &= rs->nn;
+               }
+       } else {
+               sr = gffunc(0);
+               for (i = 0; i < rs->nn; i++) {
+                       rs->index_of[sr] = i;
+                       rs->alpha_to[i] = sr;
+                       sr = gffunc(sr);
+               }
        }
        /* If it's not primitive, exit */
-       if(sr != 1)
+       if(sr != rs->alpha_to[0])
                goto errpol;
 
        /* Find prim-th root of 1, used in decoding */
@@ -173,18 +184,22 @@ void free_rs(struct rs_control *rs)
 }
 
 /**
- * init_rs - Find a matching or allocate a new rs control structure
+ * init_rs_internal - Find a matching or allocate a new rs control structure
  *  @symsize:  the symbol size (number of bits)
  *  @gfpoly:   the extended Galois field generator polynomial coefficients,
  *             with the 0th coefficient in the low order bit. The polynomial
  *             must be primitive;
+ *  @gffunc:   pointer to function to generate the next field element,
+ *             or the multiplicative identity element if given 0.  Used
+ *             instead of gfpoly if gfpoly is 0
  *  @fcr:      the first consecutive root of the rs code generator polynomial
  *             in index form
  *  @prim:     primitive element to generate polynomial roots
  *  @nroots:   RS code generator polynomial degree (number of roots)
  */
-struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
-                          int nroots)
+static struct rs_control *init_rs_internal(int symsize, int gfpoly,
+                                           int (*gffunc)(int), int fcr,
+                                           int prim, int nroots)
 {
        struct list_head        *tmp;
        struct rs_control       *rs;
@@ -208,6 +223,8 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
                        continue;
                if (gfpoly != rs->gfpoly)
                        continue;
+               if (gffunc != rs->gffunc)
+                       continue;
                if (fcr != rs->fcr)
                        continue;
                if (prim != rs->prim)
@@ -220,7 +237,7 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
        }
 
        /* Create a new one */
-       rs = rs_init(symsize, gfpoly, fcr, prim, nroots);
+       rs = rs_init(symsize, gfpoly, gffunc, fcr, prim, nroots);
        if (rs) {
                rs->users = 1;
                list_add(&rs->list, &rslist);
@@ -230,6 +247,42 @@ out:
        return rs;
 }
 
+/**
+ * init_rs - Find a matching or allocate a new rs control structure
+ *  @symsize:  the symbol size (number of bits)
+ *  @gfpoly:   the extended Galois field generator polynomial coefficients,
+ *             with the 0th coefficient in the low order bit. The polynomial
+ *             must be primitive;
+ *  @fcr:      the first consecutive root of the rs code generator polynomial
+ *             in index form
+ *  @prim:     primitive element to generate polynomial roots
+ *  @nroots:   RS code generator polynomial degree (number of roots)
+ */
+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
+                           int nroots)
+{
+       return init_rs_internal(symsize, gfpoly, NULL, fcr, prim, nroots);
+}
+
+/**
+ * init_rs_non_canonical - Find a matching or allocate a new rs control
+ *                         structure, for fields with non-canonical
+ *                         representation
+ *  @symsize:  the symbol size (number of bits)
+ *  @gffunc:   pointer to function to generate the next field element,
+ *             or the multiplicative identity element if given 0.  Used
+ *             instead of gfpoly if gfpoly is 0
+ *  @fcr:      the first consecutive root of the rs code generator polynomial
+ *             in index form
+ *  @prim:     primitive element to generate polynomial roots
+ *  @nroots:   RS code generator polynomial degree (number of roots)
+ */
+struct rs_control *init_rs_non_canonical(int symsize, int (*gffunc)(int),
+                                         int fcr, int prim, int nroots)
+{
+       return init_rs_internal(symsize, 0, gffunc, fcr, prim, nroots);
+}
+
 #ifdef CONFIG_REED_SOLOMON_ENC8
 /**
  *  encode_rs8 - Calculate the parity for data values (8bit data width)
@@ -321,6 +374,7 @@ EXPORT_SYMBOL_GPL(decode_rs16);
 #endif
 
 EXPORT_SYMBOL_GPL(init_rs);
+EXPORT_SYMBOL_GPL(init_rs_non_canonical);
 EXPORT_SYMBOL_GPL(free_rs);
 
 MODULE_LICENSE("GPL");