]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'for-linus-20130301' of git://git.infradead.org/linux-mtd
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 3 Mar 2013 00:33:54 +0000 (16:33 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 3 Mar 2013 00:33:54 +0000 (16:33 -0800)
Pull MTD update from David Woodhouse:
 "Fairly unexciting MTD merge for 3.9:

   - misc clean-ups in the MTD command-line partitioning parser
     (cmdlinepart)
   - add flash locking support for STmicro chips serial flash chips, as
     well as for CFI command set 2 chips.
   - new driver for the ELM error correction HW module found in various
     TI chips, enable the OMAP NAND driver to use the ELM HW error
     correction
   - added number of new serial flash IDs
   - various fixes and improvements in the gpmi NAND driver
   - bcm47xx NAND driver improvements
   - make the mtdpart module actually removable"

* tag 'for-linus-20130301' of git://git.infradead.org/linux-mtd: (45 commits)
  mtd: map: BUG() in non handled cases
  mtd: bcm47xxnflash: use pr_fmt for module prefix in messages
  mtd: davinci_nand: Use managed resources
  mtd: mtd_torturetest can cause stack overflows
  mtd: physmap_of: Convert device allocation to managed devm_kzalloc()
  mtd: at91: atmel_nand: for PMECC, add code to check the ONFI parameter ECC requirement.
  mtd: atmel_nand: make pmecc-cap, pmecc-sector-size in dts is optional.
  mtd: atmel_nand: avoid to report an error when lookup table offset is 0.
  mtd: bcm47xxsflash: adjust names of bus-specific functions
  mtd: bcm47xxpart: improve probing of nvram partition
  mtd: bcm47xxpart: add support for other erase sizes
  mtd: bcm47xxnflash: register this as normal driver
  mtd: bcm47xxnflash: fix message
  mtd: bcm47xxsflash: register this as normal driver
  mtd: bcm47xxsflash: write number of written bytes
  mtd: gpmi: add sanity check for the ECC
  mtd: gpmi: set the Golois Field bit for mx6q's BCH
  mtd: devices: elm: Removes <xx> literals in elm DT node
  mtd: gpmi: fix a dereferencing freed memory error
  mtd: fix the wrong timeo for panic_nand_wait()
  ...

38 files changed:
Documentation/devicetree/bindings/mtd/elm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/mtd-physmap.txt
drivers/mtd/Kconfig
drivers/mtd/ar7part.c
drivers/mtd/bcm47xxpart.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/Makefile
drivers/mtd/devices/bcm47xxsflash.c
drivers/mtd/devices/bcm47xxsflash.h [new file with mode: 0644]
drivers/mtd/devices/elm.c [new file with mode: 0644]
drivers/mtd/devices/m25p80.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/uclinux.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/bcm47xxnflash/bcm47xxnflash.h
drivers/mtd/nand/bcm47xxnflash/main.c
drivers/mtd/nand/bcm47xxnflash/ops_bcm4706.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/gpmi-nand/bch-regs.h
drivers/mtd/nand/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.h
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_ecc.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/omap2.c
drivers/mtd/ofpart.c
drivers/mtd/tests/mtd_nandecctest.c
drivers/mtd/tests/mtd_stresstest.c
drivers/mtd/tests/mtd_torturetest.c
drivers/mtd/ubi/debug.h
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/mtd/map.h
include/linux/platform_data/elm.h [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/mtd/elm.txt b/Documentation/devicetree/bindings/mtd/elm.txt
new file mode 100644 (file)
index 0000000..8c1528c
--- /dev/null
@@ -0,0 +1,16 @@
+Error location module
+
+Required properties:
+- compatible: Must be "ti,am33xx-elm"
+- reg: physical base address and size of the registers map.
+- interrupts: Interrupt number for the elm.
+
+Optional properties:
+- ti,hwmods: Name of the hwmod associated to the elm
+
+Example:
+elm: elm@0 {
+       compatible = "ti,am3352-elm";
+       reg = <0x48080000 0x2000>;
+       interrupts = <4>;
+};
index dab7847fc800accd94916d42ea58b57d907343bc..61c5ec850f2fb18dc150f15e4fbab0c02edc0279 100644 (file)
@@ -26,6 +26,9 @@ file systems on embedded devices.
  - linux,mtd-name: allow to specify the mtd name for retro capability with
    physmap-flash drivers as boot loader pass the mtd partition via the old
    device name physmap-flash.
+ - use-advanced-sector-protection: boolean to enable support for the
+   advanced sector protection (Spansion: PPB - Persistent Protection
+   Bits) locking.
 
 For JEDEC compatible devices, the following additional properties
 are defined:
index 03f2eb5627ecbffa06f289255314a34bd4e84596..557bec599f4f6741255a3f6c16f6aff0c6d4585b 100644 (file)
@@ -74,8 +74,8 @@ config MTD_REDBOOT_PARTS_READONLY
 endif # MTD_REDBOOT_PARTS
 
 config MTD_CMDLINE_PARTS
-       bool "Command line partition table parsing"
-       depends on MTD = "y"
+       tristate "Command line partition table parsing"
+       depends on MTD
        ---help---
          Allow generic configuration of the MTD partition tables via the kernel
          command line. Multiple flash resources are supported for hardware where
index 7c057a05adb67722613c45e3a3612f4f425dc115..ddc0a4287a4b89c8124dd3629b9647e3ca800b74 100644 (file)
@@ -142,7 +142,13 @@ static int __init ar7_parser_init(void)
        return register_mtd_parser(&ar7_parser);
 }
 
+static void __exit ar7_parser_exit(void)
+{
+       deregister_mtd_parser(&ar7_parser);
+}
+
 module_init(ar7_parser_init);
+module_exit(ar7_parser_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR( "Felix Fietkau <nbd@openwrt.org>, "
index 6a1180502cc191d1dd6c6800c24959874caf4985..63feb75cc8e01d2048949343955023b01fc7fadc 100644 (file)
 /* 10 parts were found on sflash on Netgear WNDR4500 */
 #define BCM47XXPART_MAX_PARTS          12
 
-/*
- * Amount of bytes we read when analyzing each block of flash memory.
- * Set it big enough to allow detecting partition and reading important data.
- */
-#define BCM47XXPART_BYTES_TO_READ      0x404
-
 /* Magics */
 #define BOARD_DATA_MAGIC               0x5246504D      /* MPFR */
 #define POT_MAGIC1                     0x54544f50      /* POTT */
@@ -59,13 +53,21 @@ static int bcm47xxpart_parse(struct mtd_info *master,
        uint32_t *buf;
        size_t bytes_read;
        uint32_t offset;
-       uint32_t blocksize = 0x10000;
+       uint32_t blocksize = master->erasesize;
        struct trx_header *trx;
+       int trx_part = -1;
+       int last_trx_part = -1;
+       int max_bytes_to_read = 0x8004;
+
+       if (blocksize <= 0x10000)
+               blocksize = 0x10000;
+       if (blocksize == 0x20000)
+               max_bytes_to_read = 0x18004;
 
        /* Alloc */
        parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
                        GFP_KERNEL);
-       buf = kzalloc(BCM47XXPART_BYTES_TO_READ, GFP_KERNEL);
+       buf = kzalloc(max_bytes_to_read, GFP_KERNEL);
 
        /* Parse block by block looking for magics */
        for (offset = 0; offset <= master->size - blocksize;
@@ -80,7 +82,7 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                }
 
                /* Read beginning of the block */
-               if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
+               if (mtd_read(master, offset, max_bytes_to_read,
                             &bytes_read, (uint8_t *)buf) < 0) {
                        pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
                               offset);
@@ -95,9 +97,16 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                }
 
                /* Standard NVRAM */
-               if (buf[0x000 / 4] == NVRAM_HEADER) {
+               if (buf[0x000 / 4] == NVRAM_HEADER ||
+                   buf[0x1000 / 4] == NVRAM_HEADER ||
+                   buf[0x8000 / 4] == NVRAM_HEADER ||
+                   (blocksize == 0x20000 && (
+                     buf[0x10000 / 4] == NVRAM_HEADER ||
+                     buf[0x11000 / 4] == NVRAM_HEADER ||
+                     buf[0x18000 / 4] == NVRAM_HEADER))) {
                        bcm47xxpart_add_part(&parts[curr_part++], "nvram",
                                             offset, 0);
+                       offset = rounddown(offset, blocksize);
                        continue;
                }
 
@@ -131,6 +140,10 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                if (buf[0x000 / 4] == TRX_MAGIC) {
                        trx = (struct trx_header *)buf;
 
+                       trx_part = curr_part;
+                       bcm47xxpart_add_part(&parts[curr_part++], "firmware",
+                                            offset, 0);
+
                        i = 0;
                        /* We have LZMA loader if offset[2] points to sth */
                        if (trx->offset[2]) {
@@ -154,6 +167,8 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                                             offset + trx->offset[i], 0);
                        i++;
 
+                       last_trx_part = curr_part - 1;
+
                        /*
                         * We have whole TRX scanned, skip to the next part. Use
                         * roundown (not roundup), as the loop will increase
@@ -169,11 +184,15 @@ static int bcm47xxpart_parse(struct mtd_info *master,
         * Assume that partitions end at the beginning of the one they are
         * followed by.
         */
-       for (i = 0; i < curr_part - 1; i++)
-               parts[i].size = parts[i + 1].offset - parts[i].offset;
-       if (curr_part > 0)
-               parts[curr_part - 1].size =
-                               master->size - parts[curr_part - 1].offset;
+       for (i = 0; i < curr_part; i++) {
+               u64 next_part_offset = (i < curr_part - 1) ?
+                                      parts[i + 1].offset : master->size;
+
+               parts[i].size = next_part_offset - parts[i].offset;
+               if (i == last_trx_part && trx_part >= 0)
+                       parts[trx_part].size = next_part_offset -
+                                              parts[trx_part].offset;
+       }
 
        *pparts = parts;
        return curr_part;
index b86197286f2406d4c419736a4252ab59e0403c11..fff665d59a0dba759f63854bb95e25bbb998b64f 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/cfi.h>
@@ -74,6 +76,10 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
 static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
 static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
 
+static int cfi_ppb_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+static int cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+static int cfi_ppb_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+
 static struct mtd_chip_driver cfi_amdstd_chipdrv = {
        .probe          = NULL, /* Not usable directly */
        .destroy        = cfi_amdstd_destroy,
@@ -496,6 +502,7 @@ static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi)
 struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
 {
        struct cfi_private *cfi = map->fldrv_priv;
+       struct device_node __maybe_unused *np = map->device_node;
        struct mtd_info *mtd;
        int i;
 
@@ -570,6 +577,17 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
                        cfi_tell_features(extp);
 #endif
 
+#ifdef CONFIG_OF
+                       if (np && of_property_read_bool(
+                                   np, "use-advanced-sector-protection")
+                           && extp->BlkProtUnprot == 8) {
+                               printk(KERN_INFO "  Advanced Sector Protection (PPB Locking) supported\n");
+                               mtd->_lock = cfi_ppb_lock;
+                               mtd->_unlock = cfi_ppb_unlock;
+                               mtd->_is_locked = cfi_ppb_is_locked;
+                       }
+#endif
+
                        bootloc = extp->TopBottom;
                        if ((bootloc < 2) || (bootloc > 5)) {
                                printk(KERN_WARNING "%s: CFI contains unrecognised boot "
@@ -2172,6 +2190,205 @@ static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL);
 }
 
+/*
+ * Advanced Sector Protection - PPB (Persistent Protection Bit) locking
+ */
+
+struct ppb_lock {
+       struct flchip *chip;
+       loff_t offset;
+       int locked;
+};
+
+#define MAX_SECTORS                    512
+
+#define DO_XXLOCK_ONEBLOCK_LOCK                ((void *)1)
+#define DO_XXLOCK_ONEBLOCK_UNLOCK      ((void *)2)
+#define DO_XXLOCK_ONEBLOCK_GETLOCK     ((void *)3)
+
+static int __maybe_unused do_ppb_xxlock(struct map_info *map,
+                                       struct flchip *chip,
+                                       unsigned long adr, int len, void *thunk)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       unsigned long timeo;
+       int ret;
+
+       mutex_lock(&chip->mutex);
+       ret = get_chip(map, chip, adr + chip->start, FL_LOCKING);
+       if (ret) {
+               mutex_unlock(&chip->mutex);
+               return ret;
+       }
+
+       pr_debug("MTD %s(): XXLOCK 0x%08lx len %d\n", __func__, adr, len);
+
+       cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
+                        cfi->device_type, NULL);
+       cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
+                        cfi->device_type, NULL);
+       /* PPB entry command */
+       cfi_send_gen_cmd(0xC0, cfi->addr_unlock1, chip->start, map, cfi,
+                        cfi->device_type, NULL);
+
+       if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
+               chip->state = FL_LOCKING;
+               map_write(map, CMD(0xA0), chip->start + adr);
+               map_write(map, CMD(0x00), chip->start + adr);
+       } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
+               /*
+                * Unlocking of one specific sector is not supported, so we
+                * have to unlock all sectors of this device instead
+                */
+               chip->state = FL_UNLOCKING;
+               map_write(map, CMD(0x80), chip->start);
+               map_write(map, CMD(0x30), chip->start);
+       } else if (thunk == DO_XXLOCK_ONEBLOCK_GETLOCK) {
+               chip->state = FL_JEDEC_QUERY;
+               /* Return locked status: 0->locked, 1->unlocked */
+               ret = !cfi_read_query(map, adr);
+       } else
+               BUG();
+
+       /*
+        * Wait for some time as unlocking of all sectors takes quite long
+        */
+       timeo = jiffies + msecs_to_jiffies(2000);       /* 2s max (un)locking */
+       for (;;) {
+               if (chip_ready(map, adr))
+                       break;
+
+               if (time_after(jiffies, timeo)) {
+                       printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
+                       ret = -EIO;
+                       break;
+               }
+
+               UDELAY(map, chip, adr, 1);
+       }
+
+       /* Exit BC commands */
+       map_write(map, CMD(0x90), chip->start);
+       map_write(map, CMD(0x00), chip->start);
+
+       chip->state = FL_READY;
+       put_chip(map, chip, adr + chip->start);
+       mutex_unlock(&chip->mutex);
+
+       return ret;
+}
+
+static int __maybe_unused cfi_ppb_lock(struct mtd_info *mtd, loff_t ofs,
+                                      uint64_t len)
+{
+       return cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len,
+                               DO_XXLOCK_ONEBLOCK_LOCK);
+}
+
+static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs,
+                                        uint64_t len)
+{
+       struct mtd_erase_region_info *regions = mtd->eraseregions;
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct ppb_lock *sect;
+       unsigned long adr;
+       loff_t offset;
+       uint64_t length;
+       int chipnum;
+       int i;
+       int sectors;
+       int ret;
+
+       /*
+        * PPB unlocking always unlocks all sectors of the flash chip.
+        * We need to re-lock all previously locked sectors. So lets
+        * first check the locking status of all sectors and save
+        * it for future use.
+        */
+       sect = kzalloc(MAX_SECTORS * sizeof(struct ppb_lock), GFP_KERNEL);
+       if (!sect)
+               return -ENOMEM;
+
+       /*
+        * This code to walk all sectors is a slightly modified version
+        * of the cfi_varsize_frob() code.
+        */
+       i = 0;
+       chipnum = 0;
+       adr = 0;
+       sectors = 0;
+       offset = 0;
+       length = mtd->size;
+
+       while (length) {
+               int size = regions[i].erasesize;
+
+               /*
+                * Only test sectors that shall not be unlocked. The other
+                * sectors shall be unlocked, so lets keep their locking
+                * status at "unlocked" (locked=0) for the final re-locking.
+                */
+               if ((adr < ofs) || (adr >= (ofs + len))) {
+                       sect[sectors].chip = &cfi->chips[chipnum];
+                       sect[sectors].offset = offset;
+                       sect[sectors].locked = do_ppb_xxlock(
+                               map, &cfi->chips[chipnum], adr, 0,
+                               DO_XXLOCK_ONEBLOCK_GETLOCK);
+               }
+
+               adr += size;
+               offset += size;
+               length -= size;
+
+               if (offset == regions[i].offset + size * regions[i].numblocks)
+                       i++;
+
+               if (adr >> cfi->chipshift) {
+                       adr = 0;
+                       chipnum++;
+
+                       if (chipnum >= cfi->numchips)
+                               break;
+               }
+
+               sectors++;
+               if (sectors >= MAX_SECTORS) {
+                       printk(KERN_ERR "Only %d sectors for PPB locking supported!\n",
+                              MAX_SECTORS);
+                       kfree(sect);
+                       return -EINVAL;
+               }
+       }
+
+       /* Now unlock the whole chip */
+       ret = cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len,
+                              DO_XXLOCK_ONEBLOCK_UNLOCK);
+       if (ret) {
+               kfree(sect);
+               return ret;
+       }
+
+       /*
+        * PPB unlocking always unlocks all sectors of the flash chip.
+        * We need to re-lock all previously locked sectors.
+        */
+       for (i = 0; i < sectors; i++) {
+               if (sect[i].locked)
+                       do_ppb_xxlock(map, sect[i].chip, sect[i].offset, 0,
+                                     DO_XXLOCK_ONEBLOCK_LOCK);
+       }
+
+       kfree(sect);
+       return ret;
+}
+
+static int __maybe_unused cfi_ppb_is_locked(struct mtd_info *mtd, loff_t ofs,
+                                           uint64_t len)
+{
+       return cfi_varsize_frob(mtd, do_ppb_xxlock, ofs, len,
+                               DO_XXLOCK_ONEBLOCK_GETLOCK) ? 1 : 0;
+}
 
 static void cfi_amdstd_sync (struct mtd_info *mtd)
 {
index c533f27d863f3cc44f11c212a2f326c38df7fc57..721caebbc5cc21344a58a710d466205f75f845ef 100644 (file)
  *
  * mtdparts=<mtddef>[;<mtddef]
  * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
- *              where <mtd-id> is the name from the "cat /proc/mtd" command
- * <partdef> := <size>[@offset][<name>][ro][lk]
+ * <partdef> := <size>[@<offset>][<name>][ro][lk]
  * <mtd-id>  := unique name used in mapping driver/device (mtd->name)
  * <size>    := standard linux memsize OR "-" to denote all remaining space
+ *              size is automatically truncated at end of device
+ *              if specified or trucated size is 0 the part is skipped
+ * <offset>  := standard linux memsize
+ *              if omitted the part will immediately follow the previous part
+ *              or 0 if the first part
  * <name>    := '(' NAME ')'
+ *              NAME will appear in /proc/mtd
+ *
+ * <size> and <offset> can be specified such that the parts are out of order
+ * in physical memory and may even overlap.
+ *
+ * The parts are assigned MTD numbers in the order they are specified in the
+ * command line regardless of their order in physical memory.
  *
  * Examples:
  *
@@ -70,6 +81,7 @@ struct cmdline_mtd_partition {
 static struct cmdline_mtd_partition *partitions;
 
 /* the command line passed to mtdpart_setup() */
+static char *mtdparts;
 static char *cmdline;
 static int cmdline_parsed;
 
@@ -330,6 +342,14 @@ static int parse_cmdline_partitions(struct mtd_info *master,
                if (part->parts[i].size == SIZE_REMAINING)
                        part->parts[i].size = master->size - offset;
 
+               if (offset + part->parts[i].size > master->size) {
+                       printk(KERN_WARNING ERRP
+                              "%s: partitioning exceeds flash size, truncating\n",
+                              part->mtd_id);
+                       part->parts[i].size = master->size - offset;
+               }
+               offset += part->parts[i].size;
+
                if (part->parts[i].size == 0) {
                        printk(KERN_WARNING ERRP
                               "%s: skipping zero sized partition\n",
@@ -337,16 +357,8 @@ static int parse_cmdline_partitions(struct mtd_info *master,
                        part->num_parts--;
                        memmove(&part->parts[i], &part->parts[i + 1],
                                sizeof(*part->parts) * (part->num_parts - i));
-                       continue;
-               }
-
-               if (offset + part->parts[i].size > master->size) {
-                       printk(KERN_WARNING ERRP
-                              "%s: partitioning exceeds flash size, truncating\n",
-                              part->mtd_id);
-                       part->parts[i].size = master->size - offset;
+                       i--;
                }
-               offset += part->parts[i].size;
        }
 
        *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts,
@@ -365,7 +377,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
  *
  * This function needs to be visible for bootloaders.
  */
-static int mtdpart_setup(char *s)
+static int __init mtdpart_setup(char *s)
 {
        cmdline = s;
        return 1;
@@ -381,10 +393,21 @@ static struct mtd_part_parser cmdline_parser = {
 
 static int __init cmdline_parser_init(void)
 {
+       if (mtdparts)
+               mtdpart_setup(mtdparts);
        return register_mtd_parser(&cmdline_parser);
 }
 
+static void __exit cmdline_parser_exit(void)
+{
+       deregister_mtd_parser(&cmdline_parser);
+}
+
 module_init(cmdline_parser_init);
+module_exit(cmdline_parser_exit);
+
+MODULE_PARM_DESC(mtdparts, "Partitioning specification");
+module_param(mtdparts, charp, 0);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
index 395733a30ef44e7c483e79768db3c7b5e46e68ba..369a1943ca259e6106caafeb43f04a4ca1f862fb 100644 (file)
@@ -17,8 +17,10 @@ obj-$(CONFIG_MTD_LART)               += lart.o
 obj-$(CONFIG_MTD_BLOCK2MTD)    += block2mtd.o
 obj-$(CONFIG_MTD_DATAFLASH)    += mtd_dataflash.o
 obj-$(CONFIG_MTD_M25P80)       += m25p80.o
+obj-$(CONFIG_MTD_NAND_OMAP_BCH)        += elm.o
 obj-$(CONFIG_MTD_SPEAR_SMI)    += spear_smi.o
 obj-$(CONFIG_MTD_SST25L)       += sst25l.o
 obj-$(CONFIG_MTD_BCM47XXSFLASH)        += bcm47xxsflash.o
 
-CFLAGS_docg3.o                 += -I$(src)
\ No newline at end of file
+
+CFLAGS_docg3.o                 += -I$(src)
index 4714584aa993a11772aaea7989c605d489b4084f..95266285acb16554fdfef090812cc6840b940d1a 100644 (file)
@@ -5,6 +5,8 @@
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 
+#include "bcm47xxsflash.h"
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
 
@@ -13,26 +15,28 @@ static const char *probes[] = { "bcm47xxpart", NULL };
 static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
                              size_t *retlen, u_char *buf)
 {
-       struct bcma_sflash *sflash = mtd->priv;
+       struct bcm47xxsflash *b47s = mtd->priv;
 
        /* Check address range */
        if ((from + len) > mtd->size)
                return -EINVAL;
 
-       memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(sflash->window + from),
+       memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from),
                      len);
+       *retlen = len;
 
        return len;
 }
 
-static void bcm47xxsflash_fill_mtd(struct bcma_sflash *sflash,
-                                  struct mtd_info *mtd)
+static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
 {
-       mtd->priv = sflash;
+       struct mtd_info *mtd = &b47s->mtd;
+
+       mtd->priv = b47s;
        mtd->name = "bcm47xxsflash";
        mtd->owner = THIS_MODULE;
        mtd->type = MTD_ROM;
-       mtd->size = sflash->size;
+       mtd->size = b47s->size;
        mtd->_read = bcm47xxsflash_read;
 
        /* TODO: implement writing support and verify/change following code */
@@ -40,19 +44,30 @@ static void bcm47xxsflash_fill_mtd(struct bcma_sflash *sflash,
        mtd->writebufsize = mtd->writesize = 1;
 }
 
-static int bcm47xxsflash_probe(struct platform_device *pdev)
+/**************************************************
+ * BCMA
+ **************************************************/
+
+static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 {
        struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
+       struct bcm47xxsflash *b47s;
        int err;
 
-       sflash->mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
-       if (!sflash->mtd) {
+       b47s = kzalloc(sizeof(*b47s), GFP_KERNEL);
+       if (!b47s) {
                err = -ENOMEM;
                goto out;
        }
-       bcm47xxsflash_fill_mtd(sflash, sflash->mtd);
+       sflash->priv = b47s;
 
-       err = mtd_device_parse_register(sflash->mtd, probes, NULL, NULL, 0);
+       b47s->window = sflash->window;
+       b47s->blocksize = sflash->blocksize;
+       b47s->numblocks = sflash->numblocks;
+       b47s->size = sflash->size;
+       bcm47xxsflash_fill_mtd(b47s);
+
+       err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
        if (err) {
                pr_err("Failed to register MTD device: %d\n", err);
                goto err_dev_reg;
@@ -61,34 +76,40 @@ static int bcm47xxsflash_probe(struct platform_device *pdev)
        return 0;
 
 err_dev_reg:
-       kfree(sflash->mtd);
+       kfree(&b47s->mtd);
 out:
        return err;
 }
 
-static int bcm47xxsflash_remove(struct platform_device *pdev)
+static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
 {
        struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
+       struct bcm47xxsflash *b47s = sflash->priv;
 
-       mtd_device_unregister(sflash->mtd);
-       kfree(sflash->mtd);
+       mtd_device_unregister(&b47s->mtd);
+       kfree(b47s);
 
        return 0;
 }
 
 static struct platform_driver bcma_sflash_driver = {
-       .remove = bcm47xxsflash_remove,
+       .probe  = bcm47xxsflash_bcma_probe,
+       .remove = bcm47xxsflash_bcma_remove,
        .driver = {
                .name = "bcma_sflash",
                .owner = THIS_MODULE,
        },
 };
 
+/**************************************************
+ * Init
+ **************************************************/
+
 static int __init bcm47xxsflash_init(void)
 {
        int err;
 
-       err = platform_driver_probe(&bcma_sflash_driver, bcm47xxsflash_probe);
+       err = platform_driver_register(&bcma_sflash_driver);
        if (err)
                pr_err("Failed to register BCMA serial flash driver: %d\n",
                       err);
diff --git a/drivers/mtd/devices/bcm47xxsflash.h b/drivers/mtd/devices/bcm47xxsflash.h
new file mode 100644 (file)
index 0000000..ebf6f71
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef __BCM47XXSFLASH_H
+#define __BCM47XXSFLASH_H
+
+#include <linux/mtd/mtd.h>
+
+struct bcm47xxsflash {
+       u32 window;
+       u32 blocksize;
+       u16 numblocks;
+       u32 size;
+
+       struct mtd_info mtd;
+};
+
+#endif /* BCM47XXSFLASH */
diff --git a/drivers/mtd/devices/elm.c b/drivers/mtd/devices/elm.c
new file mode 100644 (file)
index 0000000..2ec5da9
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * Error Location Module
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_data/elm.h>
+
+#define ELM_IRQSTATUS                  0x018
+#define ELM_IRQENABLE                  0x01c
+#define ELM_LOCATION_CONFIG            0x020
+#define ELM_PAGE_CTRL                  0x080
+#define ELM_SYNDROME_FRAGMENT_0                0x400
+#define ELM_SYNDROME_FRAGMENT_6                0x418
+#define ELM_LOCATION_STATUS            0x800
+#define ELM_ERROR_LOCATION_0           0x880
+
+/* ELM Interrupt Status Register */
+#define INTR_STATUS_PAGE_VALID         BIT(8)
+
+/* ELM Interrupt Enable Register */
+#define INTR_EN_PAGE_MASK              BIT(8)
+
+/* ELM Location Configuration Register */
+#define ECC_BCH_LEVEL_MASK             0x3
+
+/* ELM syndrome */
+#define ELM_SYNDROME_VALID             BIT(16)
+
+/* ELM_LOCATION_STATUS Register */
+#define ECC_CORRECTABLE_MASK           BIT(8)
+#define ECC_NB_ERRORS_MASK             0x1f
+
+/* ELM_ERROR_LOCATION_0-15 Registers */
+#define ECC_ERROR_LOCATION_MASK                0x1fff
+
+#define ELM_ECC_SIZE                   0x7ff
+
+#define SYNDROME_FRAGMENT_REG_SIZE     0x40
+#define ERROR_LOCATION_SIZE            0x100
+
+struct elm_info {
+       struct device *dev;
+       void __iomem *elm_base;
+       struct completion elm_completion;
+       struct list_head list;
+       enum bch_ecc bch_type;
+};
+
+static LIST_HEAD(elm_devices);
+
+static void elm_write_reg(struct elm_info *info, int offset, u32 val)
+{
+       writel(val, info->elm_base + offset);
+}
+
+static u32 elm_read_reg(struct elm_info *info, int offset)
+{
+       return readl(info->elm_base + offset);
+}
+
+/**
+ * elm_config - Configure ELM module
+ * @dev:       ELM device
+ * @bch_type:  Type of BCH ecc
+ */
+void elm_config(struct device *dev, enum bch_ecc bch_type)
+{
+       u32 reg_val;
+       struct elm_info *info = dev_get_drvdata(dev);
+
+       reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16);
+       elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val);
+       info->bch_type = bch_type;
+}
+EXPORT_SYMBOL(elm_config);
+
+/**
+ * elm_configure_page_mode - Enable/Disable page mode
+ * @info:      elm info
+ * @index:     index number of syndrome fragment vector
+ * @enable:    enable/disable flag for page mode
+ *
+ * Enable page mode for syndrome fragment index
+ */
+static void elm_configure_page_mode(struct elm_info *info, int index,
+               bool enable)
+{
+       u32 reg_val;
+
+       reg_val = elm_read_reg(info, ELM_PAGE_CTRL);
+       if (enable)
+               reg_val |= BIT(index);  /* enable page mode */
+       else
+               reg_val &= ~BIT(index); /* disable page mode */
+
+       elm_write_reg(info, ELM_PAGE_CTRL, reg_val);
+}
+
+/**
+ * elm_load_syndrome - Load ELM syndrome reg
+ * @info:      elm info
+ * @err_vec:   elm error vectors
+ * @ecc:       buffer with calculated ecc
+ *
+ * Load syndrome fragment registers with calculated ecc in reverse order.
+ */
+static void elm_load_syndrome(struct elm_info *info,
+               struct elm_errorvec *err_vec, u8 *ecc)
+{
+       int i, offset;
+       u32 val;
+
+       for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+
+               /* Check error reported */
+               if (err_vec[i].error_reported) {
+                       elm_configure_page_mode(info, i, true);
+                       offset = ELM_SYNDROME_FRAGMENT_0 +
+                               SYNDROME_FRAGMENT_REG_SIZE * i;
+
+                       /* BCH8 */
+                       if (info->bch_type) {
+
+                               /* syndrome fragment 0 = ecc[9-12B] */
+                               val = cpu_to_be32(*(u32 *) &ecc[9]);
+                               elm_write_reg(info, offset, val);
+
+                               /* syndrome fragment 1 = ecc[5-8B] */
+                               offset += 4;
+                               val = cpu_to_be32(*(u32 *) &ecc[5]);
+                               elm_write_reg(info, offset, val);
+
+                               /* syndrome fragment 2 = ecc[1-4B] */
+                               offset += 4;
+                               val = cpu_to_be32(*(u32 *) &ecc[1]);
+                               elm_write_reg(info, offset, val);
+
+                               /* syndrome fragment 3 = ecc[0B] */
+                               offset += 4;
+                               val = ecc[0];
+                               elm_write_reg(info, offset, val);
+                       } else {
+                               /* syndrome fragment 0 = ecc[20-52b] bits */
+                               val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) |
+                                       ((ecc[2] & 0xf) << 28);
+                               elm_write_reg(info, offset, val);
+
+                               /* syndrome fragment 1 = ecc[0-20b] bits */
+                               offset += 4;
+                               val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12;
+                               elm_write_reg(info, offset, val);
+                       }
+               }
+
+               /* Update ecc pointer with ecc byte size */
+               ecc += info->bch_type ? BCH8_SIZE : BCH4_SIZE;
+       }
+}
+
+/**
+ * elm_start_processing - start elm syndrome processing
+ * @info:      elm info
+ * @err_vec:   elm error vectors
+ *
+ * Set syndrome valid bit for syndrome fragment registers for which
+ * elm syndrome fragment registers are loaded. This enables elm module
+ * to start processing syndrome vectors.
+ */
+static void elm_start_processing(struct elm_info *info,
+               struct elm_errorvec *err_vec)
+{
+       int i, offset;
+       u32 reg_val;
+
+       /*
+        * Set syndrome vector valid, so that ELM module
+        * will process it for vectors error is reported
+        */
+       for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+               if (err_vec[i].error_reported) {
+                       offset = ELM_SYNDROME_FRAGMENT_6 +
+                               SYNDROME_FRAGMENT_REG_SIZE * i;
+                       reg_val = elm_read_reg(info, offset);
+                       reg_val |= ELM_SYNDROME_VALID;
+                       elm_write_reg(info, offset, reg_val);
+               }
+       }
+}
+
+/**
+ * elm_error_correction - locate correctable error position
+ * @info:      elm info
+ * @err_vec:   elm error vectors
+ *
+ * On completion of processing by elm module, error location status
+ * register updated with correctable/uncorrectable error information.
+ * In case of correctable errors, number of errors located from
+ * elm location status register & read the positions from
+ * elm error location register.
+ */
+static void elm_error_correction(struct elm_info *info,
+               struct elm_errorvec *err_vec)
+{
+       int i, j, errors = 0;
+       int offset;
+       u32 reg_val;
+
+       for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+
+               /* Check error reported */
+               if (err_vec[i].error_reported) {
+                       offset = ELM_LOCATION_STATUS + ERROR_LOCATION_SIZE * i;
+                       reg_val = elm_read_reg(info, offset);
+
+                       /* Check correctable error or not */
+                       if (reg_val & ECC_CORRECTABLE_MASK) {
+                               offset = ELM_ERROR_LOCATION_0 +
+                                       ERROR_LOCATION_SIZE * i;
+
+                               /* Read count of correctable errors */
+                               err_vec[i].error_count = reg_val &
+                                       ECC_NB_ERRORS_MASK;
+
+                               /* Update the error locations in error vector */
+                               for (j = 0; j < err_vec[i].error_count; j++) {
+
+                                       reg_val = elm_read_reg(info, offset);
+                                       err_vec[i].error_loc[j] = reg_val &
+                                               ECC_ERROR_LOCATION_MASK;
+
+                                       /* Update error location register */
+                                       offset += 4;
+                               }
+
+                               errors += err_vec[i].error_count;
+                       } else {
+                               err_vec[i].error_uncorrectable = true;
+                       }
+
+                       /* Clearing interrupts for processed error vectors */
+                       elm_write_reg(info, ELM_IRQSTATUS, BIT(i));
+
+                       /* Disable page mode */
+                       elm_configure_page_mode(info, i, false);
+               }
+       }
+}
+
+/**
+ * elm_decode_bch_error_page - Locate error position
+ * @dev:       device pointer
+ * @ecc_calc:  calculated ECC bytes from GPMC
+ * @err_vec:   elm error vectors
+ *
+ * Called with one or more error reported vectors & vectors with
+ * error reported is updated in err_vec[].error_reported
+ */
+void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
+               struct elm_errorvec *err_vec)
+{
+       struct elm_info *info = dev_get_drvdata(dev);
+       u32 reg_val;
+
+       /* Enable page mode interrupt */
+       reg_val = elm_read_reg(info, ELM_IRQSTATUS);
+       elm_write_reg(info, ELM_IRQSTATUS, reg_val & INTR_STATUS_PAGE_VALID);
+       elm_write_reg(info, ELM_IRQENABLE, INTR_EN_PAGE_MASK);
+
+       /* Load valid ecc byte to syndrome fragment register */
+       elm_load_syndrome(info, err_vec, ecc_calc);
+
+       /* Enable syndrome processing for which syndrome fragment is updated */
+       elm_start_processing(info, err_vec);
+
+       /* Wait for ELM module to finish locating error correction */
+       wait_for_completion(&info->elm_completion);
+
+       /* Disable page mode interrupt */
+       reg_val = elm_read_reg(info, ELM_IRQENABLE);
+       elm_write_reg(info, ELM_IRQENABLE, reg_val & ~INTR_EN_PAGE_MASK);
+       elm_error_correction(info, err_vec);
+}
+EXPORT_SYMBOL(elm_decode_bch_error_page);
+
+static irqreturn_t elm_isr(int this_irq, void *dev_id)
+{
+       u32 reg_val;
+       struct elm_info *info = dev_id;
+
+       reg_val = elm_read_reg(info, ELM_IRQSTATUS);
+
+       /* All error vectors processed */
+       if (reg_val & INTR_STATUS_PAGE_VALID) {
+               elm_write_reg(info, ELM_IRQSTATUS,
+                               reg_val & INTR_STATUS_PAGE_VALID);
+               complete(&info->elm_completion);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static int elm_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct resource *res, *irq;
+       struct elm_info *info;
+
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       info->dev = &pdev->dev;
+
+       irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq) {
+               dev_err(&pdev->dev, "no irq resource defined\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "no memory resource defined\n");
+               return -ENODEV;
+       }
+
+       info->elm_base = devm_request_and_ioremap(&pdev->dev, res);
+       if (!info->elm_base)
+               return -EADDRNOTAVAIL;
+
+       ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
+                       pdev->name, info);
+       if (ret) {
+               dev_err(&pdev->dev, "failure requesting irq %i\n", irq->start);
+               return ret;
+       }
+
+       pm_runtime_enable(&pdev->dev);
+       if (pm_runtime_get_sync(&pdev->dev)) {
+               ret = -EINVAL;
+               pm_runtime_disable(&pdev->dev);
+               dev_err(&pdev->dev, "can't enable clock\n");
+               return ret;
+       }
+
+       init_completion(&info->elm_completion);
+       INIT_LIST_HEAD(&info->list);
+       list_add(&info->list, &elm_devices);
+       platform_set_drvdata(pdev, info);
+       return ret;
+}
+
+static int elm_remove(struct platform_device *pdev)
+{
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id elm_of_match[] = {
+       { .compatible = "ti,am3352-elm" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, elm_of_match);
+#endif
+
+static struct platform_driver elm_driver = {
+       .driver = {
+               .name   = "elm",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(elm_of_match),
+       },
+       .probe  = elm_probe,
+       .remove = elm_remove,
+};
+
+module_platform_driver(elm_driver);
+
+MODULE_DESCRIPTION("ELM driver for BCH error correction");
+MODULE_AUTHOR("Texas Instruments");
+MODULE_ALIAS("platform: elm");
+MODULE_LICENSE("GPL v2");
index 4eeeb2d7f6ea9cb870ca712ca28abcf50808a47b..5b6b0728be21b0f4c3a7ddee475f3d02ce8f3d52 100644 (file)
@@ -565,6 +565,96 @@ time_out:
        return ret;
 }
 
+static int m25p80_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+       struct m25p *flash = mtd_to_m25p(mtd);
+       uint32_t offset = ofs;
+       uint8_t status_old, status_new;
+       int res = 0;
+
+       mutex_lock(&flash->lock);
+       /* Wait until finished previous command */
+       if (wait_till_ready(flash)) {
+               res = 1;
+               goto err;
+       }
+
+       status_old = read_sr(flash);
+
+       if (offset < flash->mtd.size-(flash->mtd.size/2))
+               status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0;
+       else if (offset < flash->mtd.size-(flash->mtd.size/4))
+               status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
+       else if (offset < flash->mtd.size-(flash->mtd.size/8))
+               status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
+       else if (offset < flash->mtd.size-(flash->mtd.size/16))
+               status_new = (status_old & ~(SR_BP0|SR_BP1)) | SR_BP2;
+       else if (offset < flash->mtd.size-(flash->mtd.size/32))
+               status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
+       else if (offset < flash->mtd.size-(flash->mtd.size/64))
+               status_new = (status_old & ~(SR_BP2|SR_BP0)) | SR_BP1;
+       else
+               status_new = (status_old & ~(SR_BP2|SR_BP1)) | SR_BP0;
+
+       /* Only modify protection if it will not unlock other areas */
+       if ((status_new&(SR_BP2|SR_BP1|SR_BP0)) >
+                                       (status_old&(SR_BP2|SR_BP1|SR_BP0))) {
+               write_enable(flash);
+               if (write_sr(flash, status_new) < 0) {
+                       res = 1;
+                       goto err;
+               }
+       }
+
+err:   mutex_unlock(&flash->lock);
+       return res;
+}
+
+static int m25p80_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+       struct m25p *flash = mtd_to_m25p(mtd);
+       uint32_t offset = ofs;
+       uint8_t status_old, status_new;
+       int res = 0;
+
+       mutex_lock(&flash->lock);
+       /* Wait until finished previous command */
+       if (wait_till_ready(flash)) {
+               res = 1;
+               goto err;
+       }
+
+       status_old = read_sr(flash);
+
+       if (offset+len > flash->mtd.size-(flash->mtd.size/64))
+               status_new = status_old & ~(SR_BP2|SR_BP1|SR_BP0);
+       else if (offset+len > flash->mtd.size-(flash->mtd.size/32))
+               status_new = (status_old & ~(SR_BP2|SR_BP1)) | SR_BP0;
+       else if (offset+len > flash->mtd.size-(flash->mtd.size/16))
+               status_new = (status_old & ~(SR_BP2|SR_BP0)) | SR_BP1;
+       else if (offset+len > flash->mtd.size-(flash->mtd.size/8))
+               status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
+       else if (offset+len > flash->mtd.size-(flash->mtd.size/4))
+               status_new = (status_old & ~(SR_BP0|SR_BP1)) | SR_BP2;
+       else if (offset+len > flash->mtd.size-(flash->mtd.size/2))
+               status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
+       else
+               status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
+
+       /* Only modify protection if it will not lock other areas */
+       if ((status_new&(SR_BP2|SR_BP1|SR_BP0)) <
+                                       (status_old&(SR_BP2|SR_BP1|SR_BP0))) {
+               write_enable(flash);
+               if (write_sr(flash, status_new) < 0) {
+                       res = 1;
+                       goto err;
+               }
+       }
+
+err:   mutex_unlock(&flash->lock);
+       return res;
+}
+
 /****************************************************************************/
 
 /*
@@ -642,6 +732,10 @@ static const struct spi_device_id m25p_ids[] = {
        /* Everspin */
        { "mr25h256", CAT25_INFO(  32 * 1024, 1, 256, 2) },
 
+       /* GigaDevice */
+       { "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
+       { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
+
        /* Intel/Numonyx -- xxxs33b */
        { "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
        { "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
@@ -899,6 +993,12 @@ static int m25p_probe(struct spi_device *spi)
        flash->mtd._erase = m25p80_erase;
        flash->mtd._read = m25p80_read;
 
+       /* flash protection support for STmicro chips */
+       if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) {
+               flash->mtd._lock = m25p80_lock;
+               flash->mtd._unlock = m25p80_unlock;
+       }
+
        /* sst flash chips use AAI word program */
        if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST)
                flash->mtd._write = sst_write;
index 62ba82c396c25af4a9a4855b8af575d59cae214b..3ed17c4d4358ad22b18ea9c77bb359b065e53ee8 100644 (file)
@@ -429,7 +429,7 @@ config MTD_GPIO_ADDR
 
 config MTD_UCLINUX
        bool "Generic uClinux RAM/ROM filesystem support"
-       depends on MTD_RAM=y && (!MMU || COLDFIRE)
+       depends on (MTD_RAM=y || MTD_ROM=y) && (!MMU || COLDFIRE)
        help
          Map driver to support image based filesystems for uClinux.
 
index 7901d72c92425dc41485947468231cf7776db372..363939dfad05afe9eb24320e31130d99b741080f 100644 (file)
@@ -68,9 +68,6 @@ static int of_flash_remove(struct platform_device *dev)
                        kfree(info->list[i].res);
                }
        }
-
-       kfree(info);
-
        return 0;
 }
 
@@ -199,8 +196,9 @@ static int of_flash_probe(struct platform_device *dev)
        map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
 
        err = -ENOMEM;
-       info = kzalloc(sizeof(struct of_flash) +
-                      sizeof(struct of_flash_list) * count, GFP_KERNEL);
+       info = devm_kzalloc(&dev->dev,
+                           sizeof(struct of_flash) +
+                           sizeof(struct of_flash_list) * count, GFP_KERNEL);
        if (!info)
                goto err_flash_remove;
 
@@ -241,6 +239,7 @@ static int of_flash_probe(struct platform_device *dev)
                info->list[i].map.phys = res.start;
                info->list[i].map.size = res_size;
                info->list[i].map.bankwidth = be32_to_cpup(width);
+               info->list[i].map.device_node = dp;
 
                err = -ENOMEM;
                info->list[i].map.virt = ioremap(info->list[i].map.phys,
index 299bf88a6f4112220c0fda6766878646c5ad0143..c1af83db5202fe46f503b68289fbc06d0ee59828 100644 (file)
 
 /****************************************************************************/
 
+#ifdef CONFIG_MTD_ROM
+#define MAP_NAME "rom"
+#else
+#define MAP_NAME "ram"
+#endif
+
+/*
+ * Blackfin uses uclinux_ram_map during startup, so it must not be static.
+ * Provide a dummy declaration to make sparse happy.
+ */
+extern struct map_info uclinux_ram_map;
+
 struct map_info uclinux_ram_map = {
-       .name = "RAM",
-       .phys = (unsigned long)__bss_stop,
+       .name = MAP_NAME,
        .size = 0,
 };
 
+static unsigned long physaddr = -1;
+module_param(physaddr, ulong, S_IRUGO);
+
 static struct mtd_info *uclinux_ram_mtdinfo;
 
 /****************************************************************************/
@@ -60,11 +74,17 @@ static int __init uclinux_mtd_init(void)
        struct map_info *mapp;
 
        mapp = &uclinux_ram_map;
+
+       if (physaddr == -1)
+               mapp->phys = (resource_size_t)__bss_stop;
+       else
+               mapp->phys = physaddr;
+
        if (!mapp->size)
                mapp->size = PAGE_ALIGN(ntohl(*((unsigned long *)(mapp->phys + 8))));
        mapp->bankwidth = 4;
 
-       printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
+       printk("uclinux[mtd]: probe address=0x%x size=0x%x\n",
                (int) mapp->phys, (int) mapp->size);
 
        /*
@@ -82,7 +102,7 @@ static int __init uclinux_mtd_init(void)
 
        simple_map_init(mapp);
 
-       mtd = do_map_probe("map_ram", mapp);
+       mtd = do_map_probe("map_" MAP_NAME, mapp);
        if (!mtd) {
                printk("uclinux[mtd]: failed to find a mapping?\n");
                return(-ENXIO);
@@ -118,6 +138,6 @@ module_exit(uclinux_mtd_cleanup);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
-MODULE_DESCRIPTION("Generic RAM based MTD for uClinux");
+MODULE_DESCRIPTION("Generic MTD for uClinux");
 
 /****************************************************************************/
index c516a9408087921a9d8c40b243e2f9005964b2e6..ffcbcca2fd2dbc67627005c177750ef5c35e5da2 100644 (file)
@@ -101,6 +101,8 @@ struct atmel_nand_host {
        u8                      pmecc_corr_cap;
        u16                     pmecc_sector_size;
        u32                     pmecc_lookup_table_offset;
+       u32                     pmecc_lookup_table_offset_512;
+       u32                     pmecc_lookup_table_offset_1024;
 
        int                     pmecc_bytes_per_sector;
        int                     pmecc_sector_number;
@@ -908,6 +910,84 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
        pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
 }
 
+/*
+ * Get ECC requirement in ONFI parameters, returns -1 if ONFI
+ * parameters is not supported.
+ * return 0 if success to get the ECC requirement.
+ */
+static int get_onfi_ecc_param(struct nand_chip *chip,
+               int *ecc_bits, int *sector_size)
+{
+       *ecc_bits = *sector_size = 0;
+
+       if (chip->onfi_params.ecc_bits == 0xff)
+               /* TODO: the sector_size and ecc_bits need to be find in
+                * extended ecc parameter, currently we don't support it.
+                */
+               return -1;
+
+       *ecc_bits = chip->onfi_params.ecc_bits;
+
+       /* The default sector size (ecc codeword size) is 512 */
+       *sector_size = 512;
+
+       return 0;
+}
+
+/*
+ * Get ecc requirement from ONFI parameters ecc requirement.
+ * If pmecc-cap, pmecc-sector-size in DTS are not specified, this function
+ * will set them according to ONFI ecc requirement. Otherwise, use the
+ * value in DTS file.
+ * return 0 if success. otherwise return error code.
+ */
+static int pmecc_choose_ecc(struct atmel_nand_host *host,
+               int *cap, int *sector_size)
+{
+       /* Get ECC requirement from ONFI parameters */
+       *cap = *sector_size = 0;
+       if (host->nand_chip.onfi_version) {
+               if (!get_onfi_ecc_param(&host->nand_chip, cap, sector_size))
+                       dev_info(host->dev, "ONFI params, minimum required ECC: %d bits in %d bytes\n",
+                               *cap, *sector_size);
+               else
+                       dev_info(host->dev, "NAND chip ECC reqirement is in Extended ONFI parameter, we don't support yet.\n");
+       } else {
+               dev_info(host->dev, "NAND chip is not ONFI compliant, assume ecc_bits is 2 in 512 bytes");
+       }
+       if (*cap == 0 && *sector_size == 0) {
+               *cap = 2;
+               *sector_size = 512;
+       }
+
+       /* If dts file doesn't specify then use the one in ONFI parameters */
+       if (host->pmecc_corr_cap == 0) {
+               /* use the most fitable ecc bits (the near bigger one ) */
+               if (*cap <= 2)
+                       host->pmecc_corr_cap = 2;
+               else if (*cap <= 4)
+                       host->pmecc_corr_cap = 4;
+               else if (*cap < 8)
+                       host->pmecc_corr_cap = 8;
+               else if (*cap < 12)
+                       host->pmecc_corr_cap = 12;
+               else if (*cap < 24)
+                       host->pmecc_corr_cap = 24;
+               else
+                       return -EINVAL;
+       }
+       if (host->pmecc_sector_size == 0) {
+               /* use the most fitable sector size (the near smaller one ) */
+               if (*sector_size >= 1024)
+                       host->pmecc_sector_size = 1024;
+               else if (*sector_size >= 512)
+                       host->pmecc_sector_size = 512;
+               else
+                       return -EINVAL;
+       }
+       return 0;
+}
+
 static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
                                         struct atmel_nand_host *host)
 {
@@ -916,8 +996,22 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
        struct resource *regs, *regs_pmerr, *regs_rom;
        int cap, sector_size, err_no;
 
+       err_no = pmecc_choose_ecc(host, &cap, &sector_size);
+       if (err_no) {
+               dev_err(host->dev, "The NAND flash's ECC requirement are not support!");
+               return err_no;
+       }
+
+       if (cap != host->pmecc_corr_cap ||
+                       sector_size != host->pmecc_sector_size)
+               dev_info(host->dev, "WARNING: Be Caution! Using different PMECC parameters from Nand ONFI ECC reqirement.\n");
+
        cap = host->pmecc_corr_cap;
        sector_size = host->pmecc_sector_size;
+       host->pmecc_lookup_table_offset = (sector_size == 512) ?
+                       host->pmecc_lookup_table_offset_512 :
+                       host->pmecc_lookup_table_offset_1024;
+
        dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n",
                 cap, sector_size);
 
@@ -1215,7 +1309,7 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 static int atmel_of_init_port(struct atmel_nand_host *host,
                              struct device_node *np)
 {
-       u32 val, table_offset;
+       u32 val;
        u32 offset[2];
        int ecc_mode;
        struct atmel_nand_data *board = &host->board;
@@ -1259,42 +1353,41 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
 
        /* use PMECC, get correction capability, sector size and lookup
         * table offset.
+        * If correction bits and sector size are not specified, then find
+        * them from NAND ONFI parameters.
         */
-       if (of_property_read_u32(np, "atmel,pmecc-cap", &val) != 0) {
-               dev_err(host->dev, "Cannot decide PMECC Capability\n");
-               return -EINVAL;
-       } else if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
-           (val != 24)) {
-               dev_err(host->dev,
-                       "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
-                       val);
-               return -EINVAL;
+       if (of_property_read_u32(np, "atmel,pmecc-cap", &val) == 0) {
+               if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
+                               (val != 24)) {
+                       dev_err(host->dev,
+                               "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
+                               val);
+                       return -EINVAL;
+               }
+               host->pmecc_corr_cap = (u8)val;
        }
-       host->pmecc_corr_cap = (u8)val;
 
-       if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) != 0) {
-               dev_err(host->dev, "Cannot decide PMECC Sector Size\n");
-               return -EINVAL;
-       } else if ((val != 512) && (val != 1024)) {
-               dev_err(host->dev,
-                       "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
-                       val);
-               return -EINVAL;
+       if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) == 0) {
+               if ((val != 512) && (val != 1024)) {
+                       dev_err(host->dev,
+                               "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
+                               val);
+                       return -EINVAL;
+               }
+               host->pmecc_sector_size = (u16)val;
        }
-       host->pmecc_sector_size = (u16)val;
 
        if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset",
                        offset, 2) != 0) {
                dev_err(host->dev, "Cannot get PMECC lookup table offset\n");
                return -EINVAL;
        }
-       table_offset = host->pmecc_sector_size == 512 ? offset[0] : offset[1];
-
-       if (!table_offset) {
+       if (!offset[0] && !offset[1]) {
                dev_err(host->dev, "Invalid PMECC lookup table offset\n");
                return -EINVAL;
        }
-       host->pmecc_lookup_table_offset = table_offset;
+       host->pmecc_lookup_table_offset_512 = offset[0];
+       host->pmecc_lookup_table_offset_1024 = offset[1];
 
        return 0;
 }
index 0bdb2ce4da7510f7630d3ec382c79092e83258b9..c005a62330b14f5444a6d5d5e65961fa27e6ce31 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef __BCM47XXNFLASH_H
 #define __BCM47XXNFLASH_H
 
+#ifndef pr_fmt
+#define pr_fmt(fmt)            KBUILD_MODNAME ": " fmt
+#endif
+
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 
index 8363a9a5fa3f7984ca4c1706be76544eb18254c4..7bae569fdc79880e5025a5db3e93dd34da274598 100644 (file)
@@ -9,14 +9,14 @@
  *
  */
 
+#include "bcm47xxnflash.h"
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 
-#include "bcm47xxnflash.h"
-
 MODULE_DESCRIPTION("NAND flash driver for BCMA bus");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("RafaÅ‚ MiÅ‚ecki");
@@ -77,6 +77,7 @@ static int bcm47xxnflash_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver bcm47xxnflash_driver = {
+       .probe  = bcm47xxnflash_probe,
        .remove = bcm47xxnflash_remove,
        .driver = {
                .name = "bcma_nflash",
@@ -88,13 +89,10 @@ static int __init bcm47xxnflash_init(void)
 {
        int err;
 
-       /*
-        * Platform device "bcma_nflash" exists on SoCs and is registered very
-        * early, it won't be added during runtime (use platform_driver_probe).
-        */
-       err = platform_driver_probe(&bcm47xxnflash_driver, bcm47xxnflash_probe);
+       err = platform_driver_register(&bcm47xxnflash_driver);
        if (err)
-               pr_err("Failed to register serial flash driver: %d\n", err);
+               pr_err("Failed to register bcm47xx nand flash driver: %d\n",
+                      err);
 
        return err;
 }
index 595de4012e71971c6453a5499334c28e6185390b..b2ab373c9eefd37c3ab970d078501a9ad423d698 100644 (file)
@@ -9,13 +9,13 @@
  *
  */
 
+#include "bcm47xxnflash.h"
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/bcma/bcma.h>
 
-#include "bcm47xxnflash.h"
-
 /* Broadcom uses 1'000'000 but it seems to be too many. Tests on WNDR4500 has
  * shown ~1000 retries as maxiumum. */
 #define NFLASH_READY_RETRIES           10000
index feae55c7b88046b3169820449b002d0ae562a5c4..94e17af8e4503b423d17f7f0f155d9af928bde90 100644 (file)
@@ -606,7 +606,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
        if (pdev->id < 0 || pdev->id > 3)
                return -ENODEV;
 
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (!info) {
                dev_err(&pdev->dev, "unable to allocate memory\n");
                ret = -ENOMEM;
@@ -623,11 +623,11 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                goto err_nomem;
        }
 
-       vaddr = ioremap(res1->start, resource_size(res1));
-       base = ioremap(res2->start, resource_size(res2));
+       vaddr = devm_request_and_ioremap(&pdev->dev, res1);
+       base = devm_request_and_ioremap(&pdev->dev, res2);
        if (!vaddr || !base) {
                dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -EINVAL;
+               ret = -EADDRNOTAVAIL;
                goto err_ioremap;
        }
 
@@ -717,7 +717,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
        }
        info->chip.ecc.mode = ecc_mode;
 
-       info->clk = clk_get(&pdev->dev, "aemif");
+       info->clk = devm_clk_get(&pdev->dev, "aemif");
        if (IS_ERR(info->clk)) {
                ret = PTR_ERR(info->clk);
                dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
@@ -845,8 +845,6 @@ err_timing:
        clk_disable_unprepare(info->clk);
 
 err_clk_enable:
-       clk_put(info->clk);
-
        spin_lock_irq(&davinci_nand_lock);
        if (ecc_mode == NAND_ECC_HW_SYNDROME)
                ecc4_busy = false;
@@ -855,13 +853,7 @@ err_clk_enable:
 err_ecc:
 err_clk:
 err_ioremap:
-       if (base)
-               iounmap(base);
-       if (vaddr)
-               iounmap(vaddr);
-
 err_nomem:
-       kfree(info);
        return ret;
 }
 
@@ -874,15 +866,9 @@ static int __exit nand_davinci_remove(struct platform_device *pdev)
                ecc4_busy = false;
        spin_unlock_irq(&davinci_nand_lock);
 
-       iounmap(info->base);
-       iounmap(info->vaddr);
-
        nand_release(&info->mtd);
 
        clk_disable_unprepare(info->clk);
-       clk_put(info->clk);
-
-       kfree(info);
 
        return 0;
 }
index ad6222627fed94c61f04f4f388570136700d80f3..f1f7f12ab50184b3bc233e360a899b998ea8c724 100644 (file)
@@ -176,8 +176,8 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
 
        ifc_nand_ctrl->page = page_addr;
        /* Program ROW0/COL0 */
-       out_be32(&ifc->ifc_nand.row0, page_addr);
-       out_be32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column);
+       iowrite32be(page_addr, &ifc->ifc_nand.row0);
+       iowrite32be((oob ? IFC_NAND_COL_MS : 0) | column, &ifc->ifc_nand.col0);
 
        buf_num = page_addr & priv->bufnum_mask;
 
@@ -239,18 +239,19 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
        int i;
 
        /* set the chip select for NAND Transaction */
-       out_be32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT);
+       iowrite32be(priv->bank << IFC_NAND_CSEL_SHIFT,
+                   &ifc->ifc_nand.nand_csel);
 
        dev_vdbg(priv->dev,
                        "%s: fir0=%08x fcr0=%08x\n",
                        __func__,
-                       in_be32(&ifc->ifc_nand.nand_fir0),
-                       in_be32(&ifc->ifc_nand.nand_fcr0));
+                       ioread32be(&ifc->ifc_nand.nand_fir0),
+                       ioread32be(&ifc->ifc_nand.nand_fcr0));
 
        ctrl->nand_stat = 0;
 
        /* start read/write seq */
-       out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
+       iowrite32be(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt);
 
        /* wait for command complete flag or timeout */
        wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
@@ -273,7 +274,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
                int sector_end = sector + chip->ecc.steps - 1;
 
                for (i = sector / 4; i <= sector_end / 4; i++)
-                       eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]);
+                       eccstat[i] = ioread32be(&ifc->ifc_nand.nand_eccstat[i]);
 
                for (i = sector; i <= sector_end; i++) {
                        errors = check_read_ecc(mtd, ctrl, eccstat, i);
@@ -313,31 +314,33 @@ static void fsl_ifc_do_read(struct nand_chip *chip,
 
        /* Program FIR/IFC_NAND_FCR0 for Small/Large page */
        if (mtd->writesize > 512) {
-               out_be32(&ifc->ifc_nand.nand_fir0,
-                        (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-                        (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
-                        (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
-                        (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
-                        (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT));
-               out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
-
-               out_be32(&ifc->ifc_nand.nand_fcr0,
-                       (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
-                       (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT));
+               iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                           (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+                           (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+                           (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) |
+                           (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT),
+                           &ifc->ifc_nand.nand_fir0);
+               iowrite32be(0x0, &ifc->ifc_nand.nand_fir1);
+
+               iowrite32be((NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) |
+                           (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT),
+                           &ifc->ifc_nand.nand_fcr0);
        } else {
-               out_be32(&ifc->ifc_nand.nand_fir0,
-                        (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-                        (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
-                        (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) |
-                        (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT));
-               out_be32(&ifc->ifc_nand.nand_fir1, 0x0);
+               iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                           (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+                           (IFC_FIR_OP_RA0  << IFC_NAND_FIR0_OP2_SHIFT) |
+                           (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT),
+                           &ifc->ifc_nand.nand_fir0);
+               iowrite32be(0x0, &ifc->ifc_nand.nand_fir1);
 
                if (oob)
-                       out_be32(&ifc->ifc_nand.nand_fcr0,
-                                NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT);
+                       iowrite32be(NAND_CMD_READOOB <<
+                                   IFC_NAND_FCR0_CMD0_SHIFT,
+                                   &ifc->ifc_nand.nand_fcr0);
                else
-                       out_be32(&ifc->ifc_nand.nand_fcr0,
-                               NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT);
+                       iowrite32be(NAND_CMD_READ0 <<
+                                   IFC_NAND_FCR0_CMD0_SHIFT,
+                                   &ifc->ifc_nand.nand_fcr0);
        }
 }
 
@@ -357,7 +360,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
        switch (command) {
        /* READ0 read the entire buffer to use hardware ECC. */
        case NAND_CMD_READ0:
-               out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+               iowrite32be(0, &ifc->ifc_nand.nand_fbcr);
                set_addr(mtd, 0, page_addr, 0);
 
                ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
@@ -372,7 +375,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 
        /* READOOB reads only the OOB because no ECC is performed. */
        case NAND_CMD_READOOB:
-               out_be32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column);
+               iowrite32be(mtd->oobsize - column, &ifc->ifc_nand.nand_fbcr);
                set_addr(mtd, column, page_addr, 1);
 
                ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
@@ -388,19 +391,19 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
                if (command == NAND_CMD_PARAM)
                        timing = IFC_FIR_OP_RBCD;
 
-               out_be32(&ifc->ifc_nand.nand_fir0,
-                               (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-                               (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
-                               (timing << IFC_NAND_FIR0_OP2_SHIFT));
-               out_be32(&ifc->ifc_nand.nand_fcr0,
-                               command << IFC_NAND_FCR0_CMD0_SHIFT);
-               out_be32(&ifc->ifc_nand.row3, column);
+               iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                           (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+                           (timing << IFC_NAND_FIR0_OP2_SHIFT),
+                           &ifc->ifc_nand.nand_fir0);
+               iowrite32be(command << IFC_NAND_FCR0_CMD0_SHIFT,
+                           &ifc->ifc_nand.nand_fcr0);
+               iowrite32be(column, &ifc->ifc_nand.row3);
 
                /*
                 * although currently it's 8 bytes for READID, we always read
                 * the maximum 256 bytes(for PARAM)
                 */
-               out_be32(&ifc->ifc_nand.nand_fbcr, 256);
+               iowrite32be(256, &ifc->ifc_nand.nand_fbcr);
                ifc_nand_ctrl->read_bytes = 256;
 
                set_addr(mtd, 0, 0, 0);
@@ -415,16 +418,16 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 
        /* ERASE2 uses the block and page address from ERASE1 */
        case NAND_CMD_ERASE2:
-               out_be32(&ifc->ifc_nand.nand_fir0,
-                        (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-                        (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
-                        (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT));
+               iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                           (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+                           (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT),
+                           &ifc->ifc_nand.nand_fir0);
 
-               out_be32(&ifc->ifc_nand.nand_fcr0,
-                        (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
-                        (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT));
+               iowrite32be((NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) |
+                           (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT),
+                           &ifc->ifc_nand.nand_fcr0);
 
-               out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+               iowrite32be(0, &ifc->ifc_nand.nand_fbcr);
                ifc_nand_ctrl->read_bytes = 0;
                fsl_ifc_run_command(mtd);
                return;
@@ -440,26 +443,28 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
                                (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
                                (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT);
 
-                       out_be32(&ifc->ifc_nand.nand_fir0,
-                                (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-                                (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
-                                (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
-                                (IFC_FIR_OP_WBCD  << IFC_NAND_FIR0_OP3_SHIFT) |
-                                (IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT));
+                       iowrite32be(
+                               (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                               (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
+                               (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+                               (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) |
+                               (IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT),
+                               &ifc->ifc_nand.nand_fir0);
                } else {
                        nand_fcr0 = ((NAND_CMD_PAGEPROG <<
                                        IFC_NAND_FCR0_CMD1_SHIFT) |
                                    (NAND_CMD_SEQIN <<
                                        IFC_NAND_FCR0_CMD2_SHIFT));
 
-                       out_be32(&ifc->ifc_nand.nand_fir0,
-                                (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-                                (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
-                                (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
-                                (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
-                                (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT));
-                       out_be32(&ifc->ifc_nand.nand_fir1,
-                                (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT));
+                       iowrite32be(
+                               (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                               (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) |
+                               (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) |
+                               (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
+                               (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT),
+                               &ifc->ifc_nand.nand_fir0);
+                       iowrite32be(IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT,
+                                   &ifc->ifc_nand.nand_fir1);
 
                        if (column >= mtd->writesize)
                                nand_fcr0 |=
@@ -474,7 +479,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
                        column -= mtd->writesize;
                        ifc_nand_ctrl->oob = 1;
                }
-               out_be32(&ifc->ifc_nand.nand_fcr0, nand_fcr0);
+               iowrite32be(nand_fcr0, &ifc->ifc_nand.nand_fcr0);
                set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob);
                return;
        }
@@ -482,10 +487,11 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
        /* PAGEPROG reuses all of the setup from SEQIN and adds the length */
        case NAND_CMD_PAGEPROG: {
                if (ifc_nand_ctrl->oob) {
-                       out_be32(&ifc->ifc_nand.nand_fbcr,
-                               ifc_nand_ctrl->index - ifc_nand_ctrl->column);
+                       iowrite32be(ifc_nand_ctrl->index -
+                                   ifc_nand_ctrl->column,
+                                   &ifc->ifc_nand.nand_fbcr);
                } else {
-                       out_be32(&ifc->ifc_nand.nand_fbcr, 0);
+                       iowrite32be(0, &ifc->ifc_nand.nand_fbcr);
                }
 
                fsl_ifc_run_command(mtd);
@@ -493,12 +499,12 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
        }
 
        case NAND_CMD_STATUS:
-               out_be32(&ifc->ifc_nand.nand_fir0,
-                               (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-                               (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT));
-               out_be32(&ifc->ifc_nand.nand_fcr0,
-                               NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT);
-               out_be32(&ifc->ifc_nand.nand_fbcr, 1);
+               iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                           (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT),
+                           &ifc->ifc_nand.nand_fir0);
+               iowrite32be(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT,
+                           &ifc->ifc_nand.nand_fcr0);
+               iowrite32be(1, &ifc->ifc_nand.nand_fbcr);
                set_addr(mtd, 0, 0, 0);
                ifc_nand_ctrl->read_bytes = 1;
 
@@ -512,10 +518,10 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
                return;
 
        case NAND_CMD_RESET:
-               out_be32(&ifc->ifc_nand.nand_fir0,
-                               IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT);
-               out_be32(&ifc->ifc_nand.nand_fcr0,
-                               NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT);
+               iowrite32be(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT,
+                           &ifc->ifc_nand.nand_fir0);
+               iowrite32be(NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT,
+                           &ifc->ifc_nand.nand_fcr0);
                fsl_ifc_run_command(mtd);
                return;
 
@@ -639,18 +645,18 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
        u32 nand_fsr;
 
        /* Use READ_STATUS command, but wait for the device to be ready */
-       out_be32(&ifc->ifc_nand.nand_fir0,
-                (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-                (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT));
-       out_be32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS <<
-                       IFC_NAND_FCR0_CMD0_SHIFT);
-       out_be32(&ifc->ifc_nand.nand_fbcr, 1);
+       iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                   (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT),
+                   &ifc->ifc_nand.nand_fir0);
+       iowrite32be(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT,
+                   &ifc->ifc_nand.nand_fcr0);
+       iowrite32be(1, &ifc->ifc_nand.nand_fbcr);
        set_addr(mtd, 0, 0, 0);
        ifc_nand_ctrl->read_bytes = 1;
 
        fsl_ifc_run_command(mtd);
 
-       nand_fsr = in_be32(&ifc->ifc_nand.nand_fsr);
+       nand_fsr = ioread32be(&ifc->ifc_nand.nand_fsr);
 
        /*
         * The chip always seems to report that it is
@@ -744,34 +750,34 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
        uint32_t cs = priv->bank;
 
        /* Save CSOR and CSOR_ext */
-       csor = in_be32(&ifc->csor_cs[cs].csor);
-       csor_ext = in_be32(&ifc->csor_cs[cs].csor_ext);
+       csor = ioread32be(&ifc->csor_cs[cs].csor);
+       csor_ext = ioread32be(&ifc->csor_cs[cs].csor_ext);
 
        /* chage PageSize 8K and SpareSize 1K*/
        csor_8k = (csor & ~(CSOR_NAND_PGS_MASK)) | 0x0018C000;
-       out_be32(&ifc->csor_cs[cs].csor, csor_8k);
-       out_be32(&ifc->csor_cs[cs].csor_ext, 0x0000400);
+       iowrite32be(csor_8k, &ifc->csor_cs[cs].csor);
+       iowrite32be(0x0000400, &ifc->csor_cs[cs].csor_ext);
 
        /* READID */
-       out_be32(&ifc->ifc_nand.nand_fir0,
-                       (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
-                       (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
-                       (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
-       out_be32(&ifc->ifc_nand.nand_fcr0,
-                       NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
-       out_be32(&ifc->ifc_nand.row3, 0x0);
+       iowrite32be((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
+                   (IFC_FIR_OP_UA  << IFC_NAND_FIR0_OP1_SHIFT) |
+                   (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT),
+                   &ifc->ifc_nand.nand_fir0);
+       iowrite32be(NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT,
+                   &ifc->ifc_nand.nand_fcr0);
+       iowrite32be(0x0, &ifc->ifc_nand.row3);
 
-       out_be32(&ifc->ifc_nand.nand_fbcr, 0x0);
+       iowrite32be(0x0, &ifc->ifc_nand.nand_fbcr);
 
        /* Program ROW0/COL0 */
-       out_be32(&ifc->ifc_nand.row0, 0x0);
-       out_be32(&ifc->ifc_nand.col0, 0x0);
+       iowrite32be(0x0, &ifc->ifc_nand.row0);
+       iowrite32be(0x0, &ifc->ifc_nand.col0);
 
        /* set the chip select for NAND Transaction */
-       out_be32(&ifc->ifc_nand.nand_csel, cs << IFC_NAND_CSEL_SHIFT);
+       iowrite32be(cs << IFC_NAND_CSEL_SHIFT, &ifc->ifc_nand.nand_csel);
 
        /* start read seq */
-       out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT);
+       iowrite32be(IFC_NAND_SEQ_STRT_FIR_STRT, &ifc->ifc_nand.nandseq_strt);
 
        /* wait for command complete flag or timeout */
        wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
@@ -781,8 +787,8 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
                printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n");
 
        /* Restore CSOR and CSOR_ext */
-       out_be32(&ifc->csor_cs[cs].csor, csor);
-       out_be32(&ifc->csor_cs[cs].csor_ext, csor_ext);
+       iowrite32be(csor, &ifc->csor_cs[cs].csor);
+       iowrite32be(csor_ext, &ifc->csor_cs[cs].csor_ext);
 }
 
 static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
@@ -799,7 +805,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
        /* fill in nand_chip structure */
        /* set up function call table */
-       if ((in_be32(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16)
+       if ((ioread32be(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16)
                chip->read_byte = fsl_ifc_read_byte16;
        else
                chip->read_byte = fsl_ifc_read_byte;
@@ -813,13 +819,13 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
        chip->bbt_td = &bbt_main_descr;
        chip->bbt_md = &bbt_mirror_descr;
 
-       out_be32(&ifc->ifc_nand.ncfgr, 0x0);
+       iowrite32be(0x0, &ifc->ifc_nand.ncfgr);
 
        /* set up nand options */
        chip->bbt_options = NAND_BBT_USE_FLASH;
 
 
-       if (in_be32(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
+       if (ioread32be(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
                chip->read_byte = fsl_ifc_read_byte16;
                chip->options |= NAND_BUSWIDTH_16;
        } else {
@@ -832,7 +838,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
        chip->ecc.read_page = fsl_ifc_read_page;
        chip->ecc.write_page = fsl_ifc_write_page;
 
-       csor = in_be32(&ifc->csor_cs[priv->bank].csor);
+       csor = ioread32be(&ifc->csor_cs[priv->bank].csor);
 
        /* Hardware generates ECC per 512 Bytes */
        chip->ecc.size = 512;
@@ -884,7 +890,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
                chip->ecc.mode = NAND_ECC_SOFT;
        }
 
-       ver = in_be32(&ifc->ifc_rev);
+       ver = ioread32be(&ifc->ifc_rev);
        if (ver == FSL_IFC_V1_1_0)
                fsl_ifc_sram_init(priv);
 
@@ -910,7 +916,7 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
 static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank,
                      phys_addr_t addr)
 {
-       u32 cspr = in_be32(&ifc->cspr_cs[bank].cspr);
+       u32 cspr = ioread32be(&ifc->cspr_cs[bank].cspr);
 
        if (!(cspr & CSPR_V))
                return 0;
@@ -997,17 +1003,16 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
 
        dev_set_drvdata(priv->dev, priv);
 
-       out_be32(&ifc->ifc_nand.nand_evter_en,
-                       IFC_NAND_EVTER_EN_OPC_EN |
-                       IFC_NAND_EVTER_EN_FTOER_EN |
-                       IFC_NAND_EVTER_EN_WPER_EN);
+       iowrite32be(IFC_NAND_EVTER_EN_OPC_EN |
+                   IFC_NAND_EVTER_EN_FTOER_EN |
+                   IFC_NAND_EVTER_EN_WPER_EN,
+                   &ifc->ifc_nand.nand_evter_en);
 
        /* enable NAND Machine Interrupts */
-       out_be32(&ifc->ifc_nand.nand_evter_intr_en,
-                       IFC_NAND_EVTER_INTR_OPCIR_EN |
-                       IFC_NAND_EVTER_INTR_FTOERIR_EN |
-                       IFC_NAND_EVTER_INTR_WPERIR_EN);
-
+       iowrite32be(IFC_NAND_EVTER_INTR_OPCIR_EN |
+                   IFC_NAND_EVTER_INTR_FTOERIR_EN |
+                   IFC_NAND_EVTER_INTR_WPERIR_EN,
+                   &ifc->ifc_nand.nand_evter_intr_en);
        priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start);
        if (!priv->mtd.name) {
                ret = -ENOMEM;
index a0924515c39644fcc9430938ded2795a2f356a4c..588f5374047c65c2f3e78219da875009c0092051 100644 (file)
                        & BM_BCH_FLASH0LAYOUT0_ECC0)            \
        )
 
+#define MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14     10
+#define MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14                     \
+                               (0x1 << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)
+#define BF_BCH_FLASH0LAYOUT0_GF(v, x)                          \
+       ((GPMI_IS_MX6Q(x) && ((v) == 14))                       \
+               ? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT0_GF_13_14)  \
+                       & MX6Q_BM_BCH_FLASH0LAYOUT0_GF_13_14)   \
+               : 0                                             \
+       )
+
 #define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE                0
 #define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE                \
                        (0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
                        & BM_BCH_FLASH0LAYOUT1_ECCN)            \
        )
 
+#define MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14     10
+#define MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14                     \
+                               (0x1 << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)
+#define BF_BCH_FLASH0LAYOUT1_GF(v, x)                          \
+       ((GPMI_IS_MX6Q(x) && ((v) == 14))                       \
+               ? (((1) << MX6Q_BP_BCH_FLASH0LAYOUT1_GF_13_14)  \
+                       & MX6Q_BM_BCH_FLASH0LAYOUT1_GF_13_14)   \
+               : 0                                             \
+       )
+
 #define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE                0
 #define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE                \
                        (0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
                ? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)   \
                : ((v) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)               \
        )
+
+#define HW_BCH_VERSION                         0x00000160
 #endif
index d84699c7968e4e854d394c94f07ec4b8fdd4fcf6..4f8857fa48a7f93f502e7b0d1a2581eebac64234 100644 (file)
@@ -208,6 +208,11 @@ void gpmi_dump_info(struct gpmi_nand_data *this)
        }
 
        /* start to print out the BCH info */
+       pr_err("Show BCH registers :\n");
+       for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
+               reg = readl(r->bch_regs + i * 0x10);
+               pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+       }
        pr_err("BCH Geometry :\n");
        pr_err("GF length              : %u\n", geo->gf_len);
        pr_err("ECC Strength           : %u\n", geo->ecc_strength);
@@ -232,6 +237,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
        unsigned int metadata_size;
        unsigned int ecc_strength;
        unsigned int page_size;
+       unsigned int gf_len;
        int ret;
 
        if (common_nfc_set_geometry(this))
@@ -242,6 +248,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
        metadata_size = bch_geo->metadata_size;
        ecc_strength  = bch_geo->ecc_strength >> 1;
        page_size     = bch_geo->page_size;
+       gf_len        = bch_geo->gf_len;
 
        ret = gpmi_enable_clk(this);
        if (ret)
@@ -263,11 +270,13 @@ int bch_set_geometry(struct gpmi_nand_data *this)
        writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count)
                        | BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size)
                        | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, this)
+                       | BF_BCH_FLASH0LAYOUT0_GF(gf_len, this)
                        | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size, this),
                        r->bch_regs + HW_BCH_FLASH0LAYOUT0);
 
        writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size)
                        | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this)
+                       | BF_BCH_FLASH0LAYOUT1_GF(gf_len, this)
                        | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
                        r->bch_regs + HW_BCH_FLASH0LAYOUT1);
 
index e9b1c47e3cf96111183b210967b3b824b7efdbe6..717881a3d1b88cc64ad87e12fe0a0d68716254b5 100644 (file)
@@ -94,6 +94,25 @@ static inline int get_ecc_strength(struct gpmi_nand_data *this)
        return round_down(ecc_strength, 2);
 }
 
+static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
+{
+       struct bch_geometry *geo = &this->bch_geometry;
+
+       /* Do the sanity check. */
+       if (GPMI_IS_MX23(this) || GPMI_IS_MX28(this)) {
+               /* The mx23/mx28 only support the GF13. */
+               if (geo->gf_len == 14)
+                       return false;
+
+               if (geo->ecc_strength > MXS_ECC_STRENGTH_MAX)
+                       return false;
+       } else if (GPMI_IS_MX6Q(this)) {
+               if (geo->ecc_strength > MX6_ECC_STRENGTH_MAX)
+                       return false;
+       }
+       return true;
+}
+
 int common_nfc_set_geometry(struct gpmi_nand_data *this)
 {
        struct bch_geometry *geo = &this->bch_geometry;
@@ -112,17 +131,24 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
        /* The default for the length of Galois Field. */
        geo->gf_len = 13;
 
-       /* The default for chunk size. There is no oobsize greater then 512. */
+       /* The default for chunk size. */
        geo->ecc_chunk_size = 512;
-       while (geo->ecc_chunk_size < mtd->oobsize)
+       while (geo->ecc_chunk_size < mtd->oobsize) {
                geo->ecc_chunk_size *= 2; /* keep C >= O */
+               geo->gf_len = 14;
+       }
 
        geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
 
        /* We use the same ECC strength for all chunks. */
        geo->ecc_strength = get_ecc_strength(this);
-       if (!geo->ecc_strength) {
-               pr_err("wrong ECC strength.\n");
+       if (!gpmi_check_ecc(this)) {
+               dev_err(this->dev,
+                       "We can not support this nand chip."
+                       " Its required ecc strength(%d) is beyond our"
+                       " capability(%d).\n", geo->ecc_strength,
+                       (GPMI_IS_MX6Q(this) ? MX6_ECC_STRENGTH_MAX
+                                       : MXS_ECC_STRENGTH_MAX));
                return -EINVAL;
        }
 
@@ -920,8 +946,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        dma_addr_t    auxiliary_phys;
        unsigned int  i;
        unsigned char *status;
-       unsigned int  failed;
-       unsigned int  corrected;
+       unsigned int  max_bitflips = 0;
        int           ret;
 
        pr_debug("page number is : %d\n", page);
@@ -945,35 +970,25 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                        payload_virt, payload_phys);
        if (ret) {
                pr_err("Error in ECC-based read: %d\n", ret);
-               goto exit_nfc;
+               return ret;
        }
 
        /* handle the block mark swapping */
        block_mark_swapping(this, payload_virt, auxiliary_virt);
 
        /* Loop over status bytes, accumulating ECC status. */
-       failed          = 0;
-       corrected       = 0;
-       status          = auxiliary_virt + nfc_geo->auxiliary_status_offset;
+       status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
 
        for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
                if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
                        continue;
 
                if (*status == STATUS_UNCORRECTABLE) {
-                       failed++;
+                       mtd->ecc_stats.failed++;
                        continue;
                }
-               corrected += *status;
-       }
-
-       /*
-        * Propagate ECC status to the owning MTD only when failed or
-        * corrected times nearly reaches our ECC correction threshold.
-        */
-       if (failed || corrected >= (nfc_geo->ecc_strength - 1)) {
-               mtd->ecc_stats.failed    += failed;
-               mtd->ecc_stats.corrected += corrected;
+               mtd->ecc_stats.corrected += *status;
+               max_bitflips = max_t(unsigned int, max_bitflips, *status);
        }
 
        if (oob_required) {
@@ -995,8 +1010,8 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                        this->payload_virt, this->payload_phys,
                        nfc_geo->payload_size,
                        payload_virt, payload_phys);
-exit_nfc:
-       return ret;
+
+       return max_bitflips;
 }
 
 static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
@@ -1668,8 +1683,8 @@ exit_nfc_init:
        release_resources(this);
 exit_acquire_resources:
        platform_set_drvdata(pdev, NULL);
-       kfree(this);
        dev_err(this->dev, "driver registration failed: %d\n", ret);
+       kfree(this);
 
        return ret;
 }
index 3d93a5e39090a936e767d59784ec22c42b47fd82..0729477312772da0e56ee13743fc5d7399200bc3 100644 (file)
@@ -284,6 +284,10 @@ extern int gpmi_read_page(struct gpmi_nand_data *,
 #define STATUS_ERASED          0xff
 #define STATUS_UNCORRECTABLE   0xfe
 
+/* BCH's bit correction capability. */
+#define MXS_ECC_STRENGTH_MAX   20      /* mx23 and mx28 */
+#define MX6_ECC_STRENGTH_MAX   40
+
 /* Use the platform_id to distinguish different Archs. */
 #define IS_MX23                        0x0
 #define IS_MX28                        0x1
index 60ac5b98b7183cc3bbdf7817ed0ecca237c1ba79..07e5784e5cd3f365e459a651368afdd6b2ab6f1b 100644 (file)
@@ -530,12 +530,23 @@ static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
 
 static void send_read_id_v3(struct mxc_nand_host *host)
 {
+       struct nand_chip *this = &host->nand;
+
        /* Read ID into main buffer */
        writel(NFC_ID, NFC_V3_LAUNCH);
 
        wait_op_done(host, true);
 
        memcpy32_fromio(host->data_buf, host->main_area0, 16);
+
+       if (this->options & NAND_BUSWIDTH_16) {
+               /* compress the ID info */
+               host->data_buf[1] = host->data_buf[2];
+               host->data_buf[2] = host->data_buf[4];
+               host->data_buf[3] = host->data_buf[6];
+               host->data_buf[4] = host->data_buf[8];
+               host->data_buf[5] = host->data_buf[10];
+       }
 }
 
 /* Request the NANDFC to perform a read of the NAND device ID. */
index 3766682a02898135ce4274b5a0baeac0eee772c9..43214151b882bcf4d2717eb48f20b1b2e0fd9a46 100644 (file)
@@ -825,13 +825,8 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip,
 static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
 {
 
-       unsigned long timeo = jiffies;
        int status, state = chip->state;
-
-       if (state == FL_ERASING)
-               timeo += (HZ * 400) / 1000;
-       else
-               timeo += (HZ * 20) / 1000;
+       unsigned long timeo = (state == FL_ERASING ? 400 : 20);
 
        led_trigger_event(nand_led_trigger, LED_FULL);
 
@@ -849,6 +844,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
        if (in_interrupt() || oops_in_progress)
                panic_nand_wait(mtd, chip, timeo);
        else {
+               timeo = jiffies + msecs_to_jiffies(timeo);
                while (time_before(jiffies, timeo)) {
                        if (chip->dev_ready) {
                                if (chip->dev_ready(mtd))
index b7cfe0d37121c8bdf78e5147f1cbed41c90b2f0c..053c9a2d47c3d02daca5589f622bb0e083c67afa 100644 (file)
@@ -55,8 +55,7 @@ struct mtd_info;
 #define MODULE_AUTHOR(x)       /* x */
 #define MODULE_DESCRIPTION(x)  /* x */
 
-#define printk printf
-#define KERN_ERR               ""
+#define pr_err printf
 #endif
 
 /*
@@ -507,7 +506,7 @@ int __nand_correct_data(unsigned char *buf,
        if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
                return 1;       /* error in ECC data; no action needed */
 
-       printk(KERN_ERR "uncorrectable error : ");
+       pr_err("%s: uncorrectable ECC error", __func__);
        return -1;
 }
 EXPORT_SYMBOL(__nand_correct_data);
index 8f30d385bfa3d82bdf47608b25d1f74ca5637137..891c52a30e6a48468d593926261ea8eee23260d9 100644 (file)
@@ -1468,12 +1468,12 @@ int do_read_error(struct nandsim *ns, int num)
 
 void do_bit_flips(struct nandsim *ns, int num)
 {
-       if (bitflips && random32() < (1 << 22)) {
+       if (bitflips && prandom_u32() < (1 << 22)) {
                int flips = 1;
                if (bitflips > 1)
-                       flips = (random32() % (int) bitflips) + 1;
+                       flips = (prandom_u32() % (int) bitflips) + 1;
                while (flips--) {
-                       int pos = random32() % (num * 8);
+                       int pos = prandom_u32() % (num * 8);
                        ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
                        NS_WARN("read_page: flipping bit %d in page %d "
                                "reading from %d ecc: corrected=%u failed=%u\n",
index 1d333497cfcb22c5ce2fd13dc52802b21b56f3d4..8e820ddf4e085ba0091c7238085395b40c4b0c39 100644 (file)
 #include <linux/omap-dma.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
 #include <linux/bch.h>
+#include <linux/platform_data/elm.h>
 #endif
 
 #include <linux/platform_data/mtd-nand-omap2.h>
 
 #define OMAP24XX_DMA_GPMC              4
 
+#define BCH8_MAX_ERROR         8       /* upto 8 bit correctable */
+#define BCH4_MAX_ERROR         4       /* upto 4 bit correctable */
+
+#define SECTOR_BYTES           512
+/* 4 bit padding to make byte aligned, 56 = 52 + 4 */
+#define BCH4_BIT_PAD           4
+#define BCH8_ECC_MAX           ((SECTOR_BYTES + BCH8_ECC_OOB_BYTES) * 8)
+#define BCH4_ECC_MAX           ((SECTOR_BYTES + BCH4_ECC_OOB_BYTES) * 8)
+
+/* GPMC ecc engine settings for read */
+#define BCH_WRAPMODE_1         1       /* BCH wrap mode 1 */
+#define BCH8R_ECC_SIZE0                0x1a    /* ecc_size0 = 26 */
+#define BCH8R_ECC_SIZE1                0x2     /* ecc_size1 = 2 */
+#define BCH4R_ECC_SIZE0                0xd     /* ecc_size0 = 13 */
+#define BCH4R_ECC_SIZE1                0x3     /* ecc_size1 = 3 */
+
+/* GPMC ecc engine settings for write */
+#define BCH_WRAPMODE_6         6       /* BCH wrap mode 6 */
+#define BCH_ECC_SIZE0          0x0     /* ecc_size0 = 0, no oob protection */
+#define BCH_ECC_SIZE1          0x20    /* ecc_size1 = 32 */
+
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
+static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
+       0xac, 0x6b, 0xff, 0x99, 0x7b};
+static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
+#endif
+
 /* oob info generated runtime depending on ecc algorithm and layout selected */
 static struct nand_ecclayout omap_oobinfo;
 /* Define some generic bad / good block scan pattern which are used
@@ -156,6 +186,9 @@ struct omap_nand_info {
 #ifdef CONFIG_MTD_NAND_OMAP_BCH
        struct bch_control             *bch;
        struct nand_ecclayout           ecclayout;
+       bool                            is_elm_used;
+       struct device                   *elm_dev;
+       struct device_node              *of_node;
 #endif
 };
 
@@ -1031,6 +1064,13 @@ static int omap_dev_ready(struct mtd_info *mtd)
  * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction
  * @mtd: MTD device structure
  * @mode: Read/Write mode
+ *
+ * When using BCH, sector size is hardcoded to 512 bytes.
+ * Using wrapping mode 6 both for reading and writing if ELM module not uses
+ * for error correction.
+ * On writing,
+ * eccsize0 = 0  (no additional protected byte in spare area)
+ * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
  */
 static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
 {
@@ -1039,32 +1079,57 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
        struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
                                                   mtd);
        struct nand_chip *chip = mtd->priv;
-       u32 val;
+       u32 val, wr_mode;
+       unsigned int ecc_size1, ecc_size0;
+
+       /* Using wrapping mode 6 for writing */
+       wr_mode = BCH_WRAPMODE_6;
 
-       nerrors = (info->nand.ecc.bytes == 13) ? 8 : 4;
-       dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
-       nsectors = 1;
        /*
-        * Program GPMC to perform correction on one 512-byte sector at a time.
-        * Using 4 sectors at a time (i.e. ecc.size = 2048) is also possible and
-        * gives a slight (5%) performance gain (but requires additional code).
+        * ECC engine enabled for valid ecc_size0 nibbles
+        * and disabled for ecc_size1 nibbles.
         */
+       ecc_size0 = BCH_ECC_SIZE0;
+       ecc_size1 = BCH_ECC_SIZE1;
+
+       /* Perform ecc calculation on 512-byte sector */
+       nsectors = 1;
+
+       /* Update number of error correction */
+       nerrors = info->nand.ecc.strength;
+
+       /* Multi sector reading/writing for NAND flash with page size < 4096 */
+       if (info->is_elm_used && (mtd->writesize <= 4096)) {
+               if (mode == NAND_ECC_READ) {
+                       /* Using wrapping mode 1 for reading */
+                       wr_mode = BCH_WRAPMODE_1;
+
+                       /*
+                        * ECC engine enabled for ecc_size0 nibbles
+                        * and disabled for ecc_size1 nibbles.
+                        */
+                       ecc_size0 = (nerrors == 8) ?
+                               BCH8R_ECC_SIZE0 : BCH4R_ECC_SIZE0;
+                       ecc_size1 = (nerrors == 8) ?
+                               BCH8R_ECC_SIZE1 : BCH4R_ECC_SIZE1;
+               }
+
+               /* Perform ecc calculation for one page (< 4096) */
+               nsectors = info->nand.ecc.steps;
+       }
 
        writel(ECC1, info->reg.gpmc_ecc_control);
 
-       /*
-        * When using BCH, sector size is hardcoded to 512 bytes.
-        * Here we are using wrapping mode 6 both for reading and writing, with:
-        *  size0 = 0  (no additional protected byte in spare area)
-        *  size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
-        */
-       val = (32 << ECCSIZE1_SHIFT) | (0 << ECCSIZE0_SHIFT);
+       /* Configure ecc size for BCH */
+       val = (ecc_size1 << ECCSIZE1_SHIFT) | (ecc_size0 << ECCSIZE0_SHIFT);
        writel(val, info->reg.gpmc_ecc_size_config);
 
+       dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
+
        /* BCH configuration */
        val = ((1                        << 16) | /* enable BCH */
               (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */
-              (0x06                     <<  8) | /* wrap mode = 6 */
+              (wr_mode                  <<  8) | /* wrap mode */
               (dev_width                <<  7) | /* bus width */
               (((nsectors-1) & 0x7)     <<  4) | /* number of sectors */
               (info->gpmc_cs            <<  1) | /* ECC CS */
@@ -1072,7 +1137,7 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
 
        writel(val, info->reg.gpmc_ecc_config);
 
-       /* clear ecc and enable bits */
+       /* Clear ecc and enable bits */
        writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
 }
 
@@ -1161,6 +1226,298 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat,
        return 0;
 }
 
+/**
+ * omap3_calculate_ecc_bch - Generate bytes of ECC bytes
+ * @mtd:       MTD device structure
+ * @dat:       The pointer to data on which ecc is computed
+ * @ecc_code:  The ecc_code buffer
+ *
+ * Support calculating of BCH4/8 ecc vectors for the page
+ */
+static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat,
+                                   u_char *ecc_code)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                                                  mtd);
+       unsigned long nsectors, bch_val1, bch_val2, bch_val3, bch_val4;
+       int i, eccbchtsel;
+
+       nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
+       /*
+        * find BCH scheme used
+        * 0 -> BCH4
+        * 1 -> BCH8
+        */
+       eccbchtsel = ((readl(info->reg.gpmc_ecc_config) >> 12) & 0x3);
+
+       for (i = 0; i < nsectors; i++) {
+
+               /* Read hw-computed remainder */
+               bch_val1 = readl(info->reg.gpmc_bch_result0[i]);
+               bch_val2 = readl(info->reg.gpmc_bch_result1[i]);
+               if (eccbchtsel) {
+                       bch_val3 = readl(info->reg.gpmc_bch_result2[i]);
+                       bch_val4 = readl(info->reg.gpmc_bch_result3[i]);
+               }
+
+               if (eccbchtsel) {
+                       /* BCH8 ecc scheme */
+                       *ecc_code++ = (bch_val4 & 0xFF);
+                       *ecc_code++ = ((bch_val3 >> 24) & 0xFF);
+                       *ecc_code++ = ((bch_val3 >> 16) & 0xFF);
+                       *ecc_code++ = ((bch_val3 >> 8) & 0xFF);
+                       *ecc_code++ = (bch_val3 & 0xFF);
+                       *ecc_code++ = ((bch_val2 >> 24) & 0xFF);
+                       *ecc_code++ = ((bch_val2 >> 16) & 0xFF);
+                       *ecc_code++ = ((bch_val2 >> 8) & 0xFF);
+                       *ecc_code++ = (bch_val2 & 0xFF);
+                       *ecc_code++ = ((bch_val1 >> 24) & 0xFF);
+                       *ecc_code++ = ((bch_val1 >> 16) & 0xFF);
+                       *ecc_code++ = ((bch_val1 >> 8) & 0xFF);
+                       *ecc_code++ = (bch_val1 & 0xFF);
+                       /*
+                        * Setting 14th byte to zero to handle
+                        * erased page & maintain compatibility
+                        * with RBL
+                        */
+                       *ecc_code++ = 0x0;
+               } else {
+                       /* BCH4 ecc scheme */
+                       *ecc_code++ = ((bch_val2 >> 12) & 0xFF);
+                       *ecc_code++ = ((bch_val2 >> 4) & 0xFF);
+                       *ecc_code++ = ((bch_val2 & 0xF) << 4) |
+                               ((bch_val1 >> 28) & 0xF);
+                       *ecc_code++ = ((bch_val1 >> 20) & 0xFF);
+                       *ecc_code++ = ((bch_val1 >> 12) & 0xFF);
+                       *ecc_code++ = ((bch_val1 >> 4) & 0xFF);
+                       *ecc_code++ = ((bch_val1 & 0xF) << 4);
+                       /*
+                        * Setting 8th byte to zero to handle
+                        * erased page
+                        */
+                       *ecc_code++ = 0x0;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * erased_sector_bitflips - count bit flips
+ * @data:      data sector buffer
+ * @oob:       oob buffer
+ * @info:      omap_nand_info
+ *
+ * Check the bit flips in erased page falls below correctable level.
+ * If falls below, report the page as erased with correctable bit
+ * flip, else report as uncorrectable page.
+ */
+static int erased_sector_bitflips(u_char *data, u_char *oob,
+               struct omap_nand_info *info)
+{
+       int flip_bits = 0, i;
+
+       for (i = 0; i < info->nand.ecc.size; i++) {
+               flip_bits += hweight8(~data[i]);
+               if (flip_bits > info->nand.ecc.strength)
+                       return 0;
+       }
+
+       for (i = 0; i < info->nand.ecc.bytes - 1; i++) {
+               flip_bits += hweight8(~oob[i]);
+               if (flip_bits > info->nand.ecc.strength)
+                       return 0;
+       }
+
+       /*
+        * Bit flips falls in correctable level.
+        * Fill data area with 0xFF
+        */
+       if (flip_bits) {
+               memset(data, 0xFF, info->nand.ecc.size);
+               memset(oob, 0xFF, info->nand.ecc.bytes);
+       }
+
+       return flip_bits;
+}
+
+/**
+ * omap_elm_correct_data - corrects page data area in case error reported
+ * @mtd:       MTD device structure
+ * @data:      page data
+ * @read_ecc:  ecc read from nand flash
+ * @calc_ecc:  ecc read from HW ECC registers
+ *
+ * Calculated ecc vector reported as zero in case of non-error pages.
+ * In case of error/erased pages non-zero error vector is reported.
+ * In case of non-zero ecc vector, check read_ecc at fixed offset
+ * (x = 13/7 in case of BCH8/4 == 0) to find page programmed or not.
+ * To handle bit flips in this data, count the number of 0's in
+ * read_ecc[x] and check if it greater than 4. If it is less, it is
+ * programmed page, else erased page.
+ *
+ * 1. If page is erased, check with standard ecc vector (ecc vector
+ * for erased page to find any bit flip). If check fails, bit flip
+ * is present in erased page. Count the bit flips in erased page and
+ * if it falls under correctable level, report page with 0xFF and
+ * update the correctable bit information.
+ * 2. If error is reported on programmed page, update elm error
+ * vector and correct the page with ELM error correction routine.
+ *
+ */
+static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
+                               u_char *read_ecc, u_char *calc_ecc)
+{
+       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+                       mtd);
+       int eccsteps = info->nand.ecc.steps;
+       int i , j, stat = 0;
+       int eccsize, eccflag, ecc_vector_size;
+       struct elm_errorvec err_vec[ERROR_VECTOR_MAX];
+       u_char *ecc_vec = calc_ecc;
+       u_char *spare_ecc = read_ecc;
+       u_char *erased_ecc_vec;
+       enum bch_ecc type;
+       bool is_error_reported = false;
+
+       /* Initialize elm error vector to zero */
+       memset(err_vec, 0, sizeof(err_vec));
+
+       if (info->nand.ecc.strength == BCH8_MAX_ERROR) {
+               type = BCH8_ECC;
+               erased_ecc_vec = bch8_vector;
+       } else {
+               type = BCH4_ECC;
+               erased_ecc_vec = bch4_vector;
+       }
+
+       ecc_vector_size = info->nand.ecc.bytes;
+
+       /*
+        * Remove extra byte padding for BCH8 RBL
+        * compatibility and erased page handling
+        */
+       eccsize = ecc_vector_size - 1;
+
+       for (i = 0; i < eccsteps ; i++) {
+               eccflag = 0;    /* initialize eccflag */
+
+               /*
+                * Check any error reported,
+                * In case of error, non zero ecc reported.
+                */
+
+               for (j = 0; (j < eccsize); j++) {
+                       if (calc_ecc[j] != 0) {
+                               eccflag = 1; /* non zero ecc, error present */
+                               break;
+                       }
+               }
+
+               if (eccflag == 1) {
+                       /*
+                        * Set threshold to minimum of 4, half of ecc.strength/2
+                        * to allow max bit flip in byte to 4
+                        */
+                       unsigned int threshold = min_t(unsigned int, 4,
+                                       info->nand.ecc.strength / 2);
+
+                       /*
+                        * Check data area is programmed by counting
+                        * number of 0's at fixed offset in spare area.
+                        * Checking count of 0's against threshold.
+                        * In case programmed page expects at least threshold
+                        * zeros in byte.
+                        * If zeros are less than threshold for programmed page/
+                        * zeros are more than threshold erased page, either
+                        * case page reported as uncorrectable.
+                        */
+                       if (hweight8(~read_ecc[eccsize]) >= threshold) {
+                               /*
+                                * Update elm error vector as
+                                * data area is programmed
+                                */
+                               err_vec[i].error_reported = true;
+                               is_error_reported = true;
+                       } else {
+                               /* Error reported in erased page */
+                               int bitflip_count;
+                               u_char *buf = &data[info->nand.ecc.size * i];
+
+                               if (memcmp(calc_ecc, erased_ecc_vec, eccsize)) {
+                                       bitflip_count = erased_sector_bitflips(
+                                                       buf, read_ecc, info);
+
+                                       if (bitflip_count)
+                                               stat += bitflip_count;
+                                       else
+                                               return -EINVAL;
+                               }
+                       }
+               }
+
+               /* Update the ecc vector */
+               calc_ecc += ecc_vector_size;
+               read_ecc += ecc_vector_size;
+       }
+
+       /* Check if any error reported */
+       if (!is_error_reported)
+               return 0;
+
+       /* Decode BCH error using ELM module */
+       elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec);
+
+       for (i = 0; i < eccsteps; i++) {
+               if (err_vec[i].error_reported) {
+                       for (j = 0; j < err_vec[i].error_count; j++) {
+                               u32 bit_pos, byte_pos, error_max, pos;
+
+                               if (type == BCH8_ECC)
+                                       error_max = BCH8_ECC_MAX;
+                               else
+                                       error_max = BCH4_ECC_MAX;
+
+                               if (info->nand.ecc.strength == BCH8_MAX_ERROR)
+                                       pos = err_vec[i].error_loc[j];
+                               else
+                                       /* Add 4 to take care 4 bit padding */
+                                       pos = err_vec[i].error_loc[j] +
+                                               BCH4_BIT_PAD;
+
+                               /* Calculate bit position of error */
+                               bit_pos = pos % 8;
+
+                               /* Calculate byte position of error */
+                               byte_pos = (error_max - pos - 1) / 8;
+
+                               if (pos < error_max) {
+                                       if (byte_pos < 512)
+                                               data[byte_pos] ^= 1 << bit_pos;
+                                       else
+                                               spare_ecc[byte_pos - 512] ^=
+                                                       1 << bit_pos;
+                               }
+                               /* else, not interested to correct ecc */
+                       }
+               }
+
+               /* Update number of correctable errors */
+               stat += err_vec[i].error_count;
+
+               /* Update page data with sector size */
+               data += info->nand.ecc.size;
+               spare_ecc += ecc_vector_size;
+       }
+
+       for (i = 0; i < eccsteps; i++)
+               /* Return error if uncorrectable error present */
+               if (err_vec[i].error_uncorrectable)
+                       return -EINVAL;
+
+       return stat;
+}
+
 /**
  * omap3_correct_data_bch - Decode received data and correct errors
  * @mtd: MTD device structure
@@ -1193,6 +1550,92 @@ static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
        return count;
 }
 
+/**
+ * omap_write_page_bch - BCH ecc based write page function for entire page
+ * @mtd:               mtd info structure
+ * @chip:              nand chip info structure
+ * @buf:               data buffer
+ * @oob_required:      must write chip->oob_poi to OOB
+ *
+ * Custom write page method evolved to support multi sector writing in one shot
+ */
+static int omap_write_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
+                                 const uint8_t *buf, int oob_required)
+{
+       int i;
+       uint8_t *ecc_calc = chip->buffers->ecccalc;
+       uint32_t *eccpos = chip->ecc.layout->eccpos;
+
+       /* Enable GPMC ecc engine */
+       chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+
+       /* Write data */
+       chip->write_buf(mtd, buf, mtd->writesize);
+
+       /* Update ecc vector from GPMC result registers */
+       chip->ecc.calculate(mtd, buf, &ecc_calc[0]);
+
+       for (i = 0; i < chip->ecc.total; i++)
+               chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+       /* Write ecc vector to OOB area */
+       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       return 0;
+}
+
+/**
+ * omap_read_page_bch - BCH ecc based page read function for entire page
+ * @mtd:               mtd info structure
+ * @chip:              nand chip info structure
+ * @buf:               buffer to store read data
+ * @oob_required:      caller requires OOB data read to chip->oob_poi
+ * @page:              page number to read
+ *
+ * For BCH ecc scheme, GPMC used for syndrome calculation and ELM module
+ * used for error correction.
+ * Custom method evolved to support ELM error correction & multi sector
+ * reading. On reading page data area is read along with OOB data with
+ * ecc engine enabled. ecc vector updated after read of OOB data.
+ * For non error pages ecc vector reported as zero.
+ */
+static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
+                               uint8_t *buf, int oob_required, int page)
+{
+       uint8_t *ecc_calc = chip->buffers->ecccalc;
+       uint8_t *ecc_code = chip->buffers->ecccode;
+       uint32_t *eccpos = chip->ecc.layout->eccpos;
+       uint8_t *oob = &chip->oob_poi[eccpos[0]];
+       uint32_t oob_pos = mtd->writesize + chip->ecc.layout->eccpos[0];
+       int stat;
+       unsigned int max_bitflips = 0;
+
+       /* Enable GPMC ecc engine */
+       chip->ecc.hwctl(mtd, NAND_ECC_READ);
+
+       /* Read data */
+       chip->read_buf(mtd, buf, mtd->writesize);
+
+       /* Read oob bytes */
+       chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
+       chip->read_buf(mtd, oob, chip->ecc.total);
+
+       /* Calculate ecc bytes */
+       chip->ecc.calculate(mtd, buf, ecc_calc);
+
+       memcpy(ecc_code, &chip->oob_poi[eccpos[0]], chip->ecc.total);
+
+       stat = chip->ecc.correct(mtd, buf, ecc_code, ecc_calc);
+
+       if (stat < 0) {
+               mtd->ecc_stats.failed++;
+       } else {
+               mtd->ecc_stats.corrected += stat;
+               max_bitflips = max_t(unsigned int, max_bitflips, stat);
+       }
+
+       return max_bitflips;
+}
+
 /**
  * omap3_free_bch - Release BCH ecc resources
  * @mtd: MTD device structure
@@ -1218,43 +1661,86 @@ static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
        struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
                                                   mtd);
 #ifdef CONFIG_MTD_NAND_OMAP_BCH8
-       const int hw_errors = 8;
+       const int hw_errors = BCH8_MAX_ERROR;
 #else
-       const int hw_errors = 4;
+       const int hw_errors = BCH4_MAX_ERROR;
 #endif
+       enum bch_ecc bch_type;
+       const __be32 *parp;
+       int lenp;
+       struct device_node *elm_node;
+
        info->bch = NULL;
 
-       max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ? 8 : 4;
+       max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ?
+               BCH8_MAX_ERROR : BCH4_MAX_ERROR;
        if (max_errors != hw_errors) {
                pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported",
                       max_errors, hw_errors);
                goto fail;
        }
 
-       /* software bch library is only used to detect and locate errors */
-       info->bch = init_bch(13, max_errors, 0x201b /* hw polynomial */);
-       if (!info->bch)
-               goto fail;
+       info->nand.ecc.size = 512;
+       info->nand.ecc.hwctl = omap3_enable_hwecc_bch;
+       info->nand.ecc.mode = NAND_ECC_HW;
+       info->nand.ecc.strength = max_errors;
 
-       info->nand.ecc.size    = 512;
-       info->nand.ecc.hwctl   = omap3_enable_hwecc_bch;
-       info->nand.ecc.correct = omap3_correct_data_bch;
-       info->nand.ecc.mode    = NAND_ECC_HW;
+       if (hw_errors == BCH8_MAX_ERROR)
+               bch_type = BCH8_ECC;
+       else
+               bch_type = BCH4_ECC;
 
-       /*
-        * The number of corrected errors in an ecc block that will trigger
-        * block scrubbing defaults to the ecc strength (4 or 8).
-        * Set mtd->bitflip_threshold here to define a custom threshold.
-        */
+       /* Detect availability of ELM module */
+       parp = of_get_property(info->of_node, "elm_id", &lenp);
+       if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) {
+               pr_err("Missing elm_id property, fall back to Software BCH\n");
+               info->is_elm_used = false;
+       } else {
+               struct platform_device *pdev;
 
-       if (max_errors == 8) {
-               info->nand.ecc.strength  = 8;
-               info->nand.ecc.bytes     = 13;
-               info->nand.ecc.calculate = omap3_calculate_ecc_bch8;
+               elm_node = of_find_node_by_phandle(be32_to_cpup(parp));
+               pdev = of_find_device_by_node(elm_node);
+               info->elm_dev = &pdev->dev;
+               elm_config(info->elm_dev, bch_type);
+               info->is_elm_used = true;
+       }
+
+       if (info->is_elm_used && (mtd->writesize <= 4096)) {
+
+               if (hw_errors == BCH8_MAX_ERROR)
+                       info->nand.ecc.bytes = BCH8_SIZE;
+               else
+                       info->nand.ecc.bytes = BCH4_SIZE;
+
+               info->nand.ecc.correct = omap_elm_correct_data;
+               info->nand.ecc.calculate = omap3_calculate_ecc_bch;
+               info->nand.ecc.read_page = omap_read_page_bch;
+               info->nand.ecc.write_page = omap_write_page_bch;
        } else {
-               info->nand.ecc.strength  = 4;
-               info->nand.ecc.bytes     = 7;
-               info->nand.ecc.calculate = omap3_calculate_ecc_bch4;
+               /*
+                * software bch library is only used to detect and
+                * locate errors
+                */
+               info->bch = init_bch(13, max_errors,
+                               0x201b /* hw polynomial */);
+               if (!info->bch)
+                       goto fail;
+
+               info->nand.ecc.correct = omap3_correct_data_bch;
+
+               /*
+                * The number of corrected errors in an ecc block that will
+                * trigger block scrubbing defaults to the ecc strength (4 or 8)
+                * Set mtd->bitflip_threshold here to define a custom threshold.
+                */
+
+               if (max_errors == 8) {
+                       info->nand.ecc.bytes = 13;
+                       info->nand.ecc.calculate = omap3_calculate_ecc_bch8;
+               } else {
+                       info->nand.ecc.bytes = 7;
+                       info->nand.ecc.calculate = omap3_calculate_ecc_bch4;
+               }
        }
 
        pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors);
@@ -1270,7 +1756,7 @@ fail:
  */
 static int omap3_init_bch_tail(struct mtd_info *mtd)
 {
-       int i, steps;
+       int i, steps, offset;
        struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
                                                   mtd);
        struct nand_ecclayout *layout = &info->ecclayout;
@@ -1292,11 +1778,21 @@ static int omap3_init_bch_tail(struct mtd_info *mtd)
                goto fail;
        }
 
+       /* ECC layout compatible with RBL for BCH8 */
+       if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
+               offset = 2;
+       else
+               offset = mtd->oobsize - layout->eccbytes;
+
        /* put ecc bytes at oob tail */
        for (i = 0; i < layout->eccbytes; i++)
-               layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
+               layout->eccpos[i] = offset + i;
+
+       if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE))
+               layout->oobfree[0].offset = 2 + layout->eccbytes * steps;
+       else
+               layout->oobfree[0].offset = 2;
 
-       layout->oobfree[0].offset = 2;
        layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
        info->nand.ecc.layout = layout;
 
@@ -1360,6 +1856,9 @@ static int omap_nand_probe(struct platform_device *pdev)
 
        info->nand.options      = pdata->devsize;
        info->nand.options      |= NAND_SKIP_BBTSCAN;
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
+       info->of_node           = pdata->of_node;
+#endif
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
index dbd3aa574eaf8462b9bce810ba9742c9c48f2eb2..30bd907a260afe19420fd84b0992018faee82e3a 100644 (file)
@@ -174,7 +174,14 @@ out:
        return rc;
 }
 
+static void __exit ofpart_parser_exit(void)
+{
+       deregister_mtd_parser(&ofpart_parser);
+       deregister_mtd_parser(&ofoldpart_parser);
+}
+
 module_init(ofpart_parser_init);
+module_exit(ofpart_parser_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree");
index db2f22e7966a140f7e8497d8651369a22489d4a8..70106607c247289b6328c9ff99321d64ffc49c81 100644 (file)
@@ -44,7 +44,7 @@ struct nand_ecc_test {
 static void single_bit_error_data(void *error_data, void *correct_data,
                                size_t size)
 {
-       unsigned int offset = random32() % (size * BITS_PER_BYTE);
+       unsigned int offset = prandom_u32() % (size * BITS_PER_BYTE);
 
        memcpy(error_data, correct_data, size);
        __change_bit_le(offset, error_data);
@@ -55,9 +55,9 @@ static void double_bit_error_data(void *error_data, void *correct_data,
 {
        unsigned int offset[2];
 
-       offset[0] = random32() % (size * BITS_PER_BYTE);
+       offset[0] = prandom_u32() % (size * BITS_PER_BYTE);
        do {
-               offset[1] = random32() % (size * BITS_PER_BYTE);
+               offset[1] = prandom_u32() % (size * BITS_PER_BYTE);
        } while (offset[0] == offset[1]);
 
        memcpy(error_data, correct_data, size);
@@ -68,7 +68,7 @@ static void double_bit_error_data(void *error_data, void *correct_data,
 
 static unsigned int random_ecc_bit(size_t size)
 {
-       unsigned int offset = random32() % (3 * BITS_PER_BYTE);
+       unsigned int offset = prandom_u32() % (3 * BITS_PER_BYTE);
 
        if (size == 256) {
                /*
@@ -76,7 +76,7 @@ static unsigned int random_ecc_bit(size_t size)
                 * and 17th bit) in ECC code for 256 byte data block
                 */
                while (offset == 16 || offset == 17)
-                       offset = random32() % (3 * BITS_PER_BYTE);
+                       offset = prandom_u32() % (3 * BITS_PER_BYTE);
        }
 
        return offset;
index 2d7e6cffd6d4d50deeca85564e39e200be34e670..787f539d16ca436099826f0626bb4c57efe6da6d 100644 (file)
@@ -55,7 +55,7 @@ static int rand_eb(void)
        unsigned int eb;
 
 again:
-       eb = random32();
+       eb = prandom_u32();
        /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
        eb %= (ebcnt - 1);
        if (bbt[eb])
@@ -67,7 +67,7 @@ static int rand_offs(void)
 {
        unsigned int offs;
 
-       offs = random32();
+       offs = prandom_u32();
        offs %= bufsize;
        return offs;
 }
@@ -76,7 +76,7 @@ static int rand_len(int offs)
 {
        unsigned int len;
 
-       len = random32();
+       len = prandom_u32();
        len %= (bufsize - offs);
        return len;
 }
@@ -191,7 +191,7 @@ static int do_write(void)
 
 static int do_operation(void)
 {
-       if (random32() & 1)
+       if (prandom_u32() & 1)
                return do_read();
        else
                return do_write();
index c4cde1e9eddbb3026d4e8a9ab0a36f87dab566ae..3a9f6a6a79f99d4c5662ab3fc90051a23e2ffbed 100644 (file)
@@ -208,7 +208,7 @@ static inline int write_pattern(int ebnum, void *buf)
 static int __init tort_init(void)
 {
        int err = 0, i, infinite = !cycles_count;
-       int bad_ebs[ebcnt];
+       int *bad_ebs;
 
        printk(KERN_INFO "\n");
        printk(KERN_INFO "=================================================\n");
@@ -250,28 +250,24 @@ static int __init tort_init(void)
 
        err = -ENOMEM;
        patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!patt_5A5) {
-               pr_err("error: cannot allocate memory\n");
+       if (!patt_5A5)
                goto out_mtd;
-       }
 
        patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!patt_A5A) {
-               pr_err("error: cannot allocate memory\n");
+       if (!patt_A5A)
                goto out_patt_5A5;
-       }
 
        patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!patt_FF) {
-               pr_err("error: cannot allocate memory\n");
+       if (!patt_FF)
                goto out_patt_A5A;
-       }
 
        check_buf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!check_buf) {
-               pr_err("error: cannot allocate memory\n");
+       if (!check_buf)
                goto out_patt_FF;
-       }
+
+       bad_ebs = kcalloc(ebcnt, sizeof(*bad_ebs), GFP_KERNEL);
+       if (!bad_ebs)
+               goto out_check_buf;
 
        err = 0;
 
@@ -290,7 +286,6 @@ static int __init tort_init(void)
        /*
         * Check if there is a bad eraseblock among those we are going to test.
         */
-       memset(&bad_ebs[0], 0, sizeof(int) * ebcnt);
        if (mtd_can_have_bb(mtd)) {
                for (i = eb; i < eb + ebcnt; i++) {
                        err = mtd_block_isbad(mtd, (loff_t)i * mtd->erasesize);
@@ -394,6 +389,8 @@ out:
 
        pr_info("finished after %u erase cycles\n",
               erase_cycles);
+       kfree(bad_ebs);
+out_check_buf:
        kfree(check_buf);
 out_patt_FF:
        kfree(patt_FF);
index 33f8f3b2c9b22ac9909aa6ad07f6a1317873ed7c..cba89fcd15877d92255a7e2fb1f125813f74dbea 100644 (file)
@@ -86,7 +86,7 @@ static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
 static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
 {
        if (ubi->dbg.emulate_bitflips)
-               return !(random32() % 200);
+               return !(prandom_u32() % 200);
        return 0;
 }
 
@@ -100,7 +100,7 @@ static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
 static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
 {
        if (ubi->dbg.emulate_io_failures)
-               return !(random32() % 500);
+               return !(prandom_u32() % 500);
        return 0;
 }
 
@@ -114,7 +114,7 @@ static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
 static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
 {
        if (ubi->dbg.emulate_io_failures)
-               return !(random32() % 400);
+               return !(prandom_u32() % 400);
        return 0;
 }
 
index 1d002b58b60babc1e7bf28728406531b0bc3addc..8390c474f69aefafdd31e8da31c1ea1ea1339516 100644 (file)
@@ -528,6 +528,7 @@ struct bcma_sflash {
        u32 size;
 
        struct mtd_info *mtd;
+       void *priv;
 };
 #endif
 
index f6eb4332ac929a4747f2457591ad9fcf2c44c2c4..4b02512e421c6601db2cd1902094193a7aa7b647 100644 (file)
@@ -245,6 +245,7 @@ struct map_info {
        unsigned long pfow_base;
        unsigned long map_priv_1;
        unsigned long map_priv_2;
+       struct device_node *device_node;
        void *fldrv_priv;
        struct mtd_chip_driver *fldrv;
 };
@@ -328,7 +329,7 @@ static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word
 
 static inline map_word map_word_load(struct map_info *map, const void *ptr)
 {
-       map_word r = {{0} };
+       map_word r;
 
        if (map_bankwidth_is_1(map))
                r.x[0] = *(unsigned char *)ptr;
@@ -342,6 +343,8 @@ static inline map_word map_word_load(struct map_info *map, const void *ptr)
 #endif
        else if (map_bankwidth_is_large(map))
                memcpy(r.x, ptr, map->bankwidth);
+       else
+               BUG();
 
        return r;
 }
@@ -391,7 +394,7 @@ static inline map_word map_word_ff(struct map_info *map)
 
 static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
 {
-       map_word uninitialized_var(r);
+       map_word r;
 
        if (map_bankwidth_is_1(map))
                r.x[0] = __raw_readb(map->virt + ofs);
@@ -425,6 +428,8 @@ static inline void inline_map_write(struct map_info *map, const map_word datum,
 #endif
        else if (map_bankwidth_is_large(map))
                memcpy_toio(map->virt+ofs, datum.x, map->bankwidth);
+       else
+               BUG();
        mb();
 }
 
diff --git a/include/linux/platform_data/elm.h b/include/linux/platform_data/elm.h
new file mode 100644 (file)
index 0000000..1bd5244
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * BCH Error Location Module
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ELM_H
+#define __ELM_H
+
+enum bch_ecc {
+       BCH4_ECC = 0,
+       BCH8_ECC,
+};
+
+/* ELM support 8 error syndrome process */
+#define ERROR_VECTOR_MAX               8
+
+#define BCH8_ECC_OOB_BYTES             13
+#define BCH4_ECC_OOB_BYTES             7
+/* RBL requires 14 byte even though BCH8 uses only 13 byte */
+#define BCH8_SIZE                      (BCH8_ECC_OOB_BYTES + 1)
+/* Uses 1 extra byte to handle erased pages */
+#define BCH4_SIZE                      (BCH4_ECC_OOB_BYTES + 1)
+
+/**
+ * struct elm_errorvec - error vector for elm
+ * @error_reported:            set true for vectors error is reported
+ * @error_uncorrectable:       number of uncorrectable errors
+ * @error_count:               number of correctable errors in the sector
+ * @error_loc:                 buffer for error location
+ *
+ */
+struct elm_errorvec {
+       bool error_reported;
+       bool error_uncorrectable;
+       int error_count;
+       int error_loc[ERROR_VECTOR_MAX];
+};
+
+void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
+               struct elm_errorvec *err_vec);
+void elm_config(struct device *dev, enum bch_ecc bch_type);
+#endif /* __ELM_H */