Commit f5e7e844 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-linus-3.5-20120601' of git://git.infradead.org/linux-mtd

Pull mtd update from David Woodhouse:
 - More robust parsing especially of xattr data in JFFS2
 - Updates to mxc_nand and gpmi drivers to support new boards and device tree
 - Improve consistency of information about ECC strength in NAND devices
 - Clean up partition handling of plat_nand
 - Support NAND drivers without dedicated access to OOB area
 - BCH hardware ECC support for OMAP
 - Other fixes and cleanups, and a few new device IDs

Fixed trivial conflict in drivers/mtd/nand/gpmi-nand/gpmi-nand.c due to
added include files next to each other.

* tag 'for-linus-3.5-20120601' of git://git.infradead.org/linux-mtd: (75 commits)
  mtd: mxc_nand: move ecc strengh setup before nand_scan_tail
  mtd: block2mtd: fix recursive call of mtd_writev
  mtd: gpmi-nand: define ecc.strength
  mtd: of_parts: fix breakage in Kconfig
  mtd: nand: fix scan_read_raw_oob
  mtd: docg3 fix in-middle of blocks reads
  mtd: cfi_cmdset_0002: Slight cleanup of fixup messages
  mtd: add fixup for S29NS512P NOR flash.
  jffs2: allow to complete xattr integrity check on first GC scan
  jffs2: allow to discriminate between recoverable and non-recoverable errors
  mtd: nand: omap: add support for hardware BCH ecc
  ARM: OMAP3: gpmc: add BCH ecc api and modes
  mtd: nand: check the return code of 'read_oob/read_oob_raw'
  mtd: nand: remove 'sndcmd' parameter of 'read_oob/read_oob_raw'
  mtd: m25p80: Add support for Winbond W25Q80BW
  jffs2: get rid of jffs2_sync_super
  jffs2: remove unnecessary GC pass on sync
  jffs2: remove unnecessary GC pass on umount
  jffs2: remove lock_super
  mtd: gpmi: add gpmi support for mx6q
  ...
parents 48445159 4a43faf5
......@@ -123,3 +123,54 @@ Description:
half page, or a quarter page).
In the case of ECC NOR, it is the ECC block size.
What: /sys/class/mtd/mtdX/ecc_strength
Date: April 2012
KernelVersion: 3.4
Contact: linux-mtd@lists.infradead.org
Description:
Maximum number of bit errors that the device is capable of
correcting within each region covering an ecc step. This will
always be a non-negative integer. Note that some devices will
have multiple ecc steps within each writesize region.
In the case of devices lacking any ECC capability, it is 0.
What: /sys/class/mtd/mtdX/bitflip_threshold
Date: April 2012
KernelVersion: 3.4
Contact: linux-mtd@lists.infradead.org
Description:
This allows the user to examine and adjust the criteria by which
mtd returns -EUCLEAN from mtd_read(). If the maximum number of
bit errors that were corrected on any single region comprising
an ecc step (as reported by the driver) equals or exceeds this
value, -EUCLEAN is returned. Otherwise, absent an error, 0 is
returned. Higher layers (e.g., UBI) use this return code as an
indication that an erase block may be degrading and should be
scrutinized as a candidate for being marked as bad.
The initial value may be specified by the flash device driver.
If not, then the default value is ecc_strength.
The introduction of this feature brings a subtle change to the
meaning of the -EUCLEAN return code. Previously, it was
interpreted to mean simply "one or more bit errors were
corrected". Its new interpretation can be phrased as "a
dangerously high number of bit errors were corrected on one or
more regions comprising an ecc step". The precise definition of
"dangerously high" can be adjusted by the user with
bitflip_threshold. Users are discouraged from doing this,
however, unless they know what they are doing and have intimate
knowledge of the properties of their device. Broadly speaking,
bitflip_threshold should be low enough to detect genuine erase
block degradation, but high enough to avoid the consequences of
a persistent return value of -EUCLEAN on devices where sticky
bitflips occur. Note that if bitflip_threshold exceeds
ecc_strength, -EUCLEAN is never returned by mtd_read().
Conversely, if bitflip_threshold is zero, -EUCLEAN is always
returned, absent a hard error.
This is generally applicable only to NAND flash devices with ECC
capability. It is ignored on devices lacking ECC capability;
i.e., devices for which ecc_strength is zero.
......@@ -1119,8 +1119,6 @@ in this page</entry>
These constants are defined in nand.h. They are ored together to describe
the chip functionality.
<programlisting>
/* Chip can not auto increment pages */
#define NAND_NO_AUTOINCR 0x00000001
/* Buswitdh is 16 bit */
#define NAND_BUSWIDTH_16 0x00000002
/* Device supports partial programming without padding */
......
* Freescale General-Purpose Media Interface (GPMI)
The GPMI nand controller provides an interface to control the
NAND flash chips. We support only one NAND chip now.
Required properties:
- compatible : should be "fsl,<chip>-gpmi-nand"
- reg : should contain registers location and length for gpmi and bch.
- reg-names: Should contain the reg names "gpmi-nand" and "bch"
- interrupts : The first is the DMA interrupt number for GPMI.
The second is the BCH interrupt number.
- interrupt-names : The interrupt names "gpmi-dma", "bch";
- fsl,gpmi-dma-channel : Should contain the dma channel it uses.
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
Examples:
gpmi-nand@8000c000 {
compatible = "fsl,imx28-gpmi-nand";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x8000c000 2000>, <0x8000a000 2000>;
reg-names = "gpmi-nand", "bch";
interrupts = <88>, <41>;
interrupt-names = "gpmi-dma", "bch";
fsl,gpmi-dma-channel = <4>;
partition@0 {
...
};
};
* Freescale's mxc_nand
Required properties:
- compatible: "fsl,imxXX-nand"
- reg: address range of the nfc block
- interrupts: irq to be used
- nand-bus-width: see nand.txt
- nand-ecc-mode: see nand.txt
- nand-on-flash-bbt: see nand.txt
Example:
nand@d8000000 {
compatible = "fsl,imx27-nand";
reg = <0xd8000000 0x1000>;
interrupts = <29>;
nand-bus-width = <8>;
nand-ecc-mode = "hw";
};
......@@ -213,5 +213,14 @@
status = "disabled";
};
};
nand@d8000000 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,imx27-nand";
reg = <0xd8000000 0x1000>;
interrupts = <29>;
status = "disabled";
};
};
};
......@@ -82,8 +82,6 @@ static int snappercl15_nand_dev_ready(struct mtd_info *mtd)
return !!(__raw_readw(NAND_CTRL_ADDR(chip)) & SNAPPERCL15_NAND_RDY);
}
static const char *snappercl15_nand_part_probes[] = {"cmdlinepart", NULL};
static struct mtd_partition snappercl15_nand_parts[] = {
{
.name = "Kernel",
......@@ -100,10 +98,8 @@ static struct mtd_partition snappercl15_nand_parts[] = {
static struct platform_nand_data snappercl15_nand_data = {
.chip = {
.nr_chips = 1,
.part_probe_types = snappercl15_nand_part_probes,
.partitions = snappercl15_nand_parts,
.nr_partitions = ARRAY_SIZE(snappercl15_nand_parts),
.options = NAND_NO_AUTOINCR,
.chip_delay = 25,
},
.ctrl = {
......
......@@ -105,8 +105,6 @@ static int ts72xx_nand_device_ready(struct mtd_info *mtd)
return !!(__raw_readb(addr) & 0x20);
}
static const char *ts72xx_nand_part_probes[] = { "cmdlinepart", NULL };
#define TS72XX_BOOTROM_PART_SIZE (SZ_16K)
#define TS72XX_REDBOOT_PART_SIZE (SZ_2M + SZ_1M)
......@@ -134,7 +132,6 @@ static struct platform_nand_data ts72xx_nand_data = {
.nr_chips = 1,
.chip_offset = 0,
.chip_delay = 15,
.part_probe_types = ts72xx_nand_part_probes,
.partitions = ts72xx_nand_parts,
.nr_partitions = ARRAY_SIZE(ts72xx_nand_parts),
},
......
......@@ -29,6 +29,7 @@ static const struct of_dev_auxdata imx27_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI2_BASE_ADDR, "imx27-cspi.1", NULL),
OF_DEV_AUXDATA("fsl,imx27-cspi", MX27_CSPI3_BASE_ADDR, "imx27-cspi.2", NULL),
OF_DEV_AUXDATA("fsl,imx27-wdt", MX27_WDOG_BASE_ADDR, "imx2-wdt.0", NULL),
OF_DEV_AUXDATA("fsl,imx27-nand", MX27_NFC_BASE_ADDR, "mxc_nand.0", NULL),
{ /* sentinel */ }
};
......
......@@ -60,8 +60,6 @@ static struct platform_device ixdp425_flash = {
#if defined(CONFIG_MTD_NAND_PLATFORM) || \
defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
const char *part_probes[] = { "cmdlinepart", NULL };
static struct mtd_partition ixdp425_partitions[] = {
{
.name = "ixp400 NAND FS 0",
......@@ -100,8 +98,6 @@ static struct platform_nand_data ixdp425_flash_nand_data = {
.chip = {
.nr_chips = 1,
.chip_delay = 30,
.options = NAND_NO_AUTOINCR,
.part_probe_types = part_probes,
.partitions = ixdp425_partitions,
.nr_partitions = ARRAY_SIZE(ixdp425_partitions),
},
......
......@@ -111,7 +111,7 @@ static struct nomadik_nand_platform_data nhk8815_nand_data = {
.parts = nhk8815_partitions,
.nparts = ARRAY_SIZE(nhk8815_partitions),
.options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING \
| NAND_NO_READRDY | NAND_NO_AUTOINCR,
| NAND_NO_READRDY,
.init = nhk8815_nand_init,
};
......
......@@ -192,14 +192,11 @@ static int nand_dev_ready(struct mtd_info *mtd)
return gpio_get_value(FSAMPLE_NAND_RB_GPIO_PIN);
}
static const char *part_probes[] = { "cmdlinepart", NULL };
static struct platform_nand_data nand_data = {
.chip = {
.nr_chips = 1,
.chip_offset = 0,
.options = NAND_SAMSUNG_LP_OPTIONS,
.part_probe_types = part_probes,
},
.ctrl = {
.cmd_ctrl = omap1_nand_cmd_ctl,
......
......@@ -186,8 +186,6 @@ static int h2_nand_dev_ready(struct mtd_info *mtd)
return gpio_get_value(H2_NAND_RB_GPIO_PIN);
}
static const char *h2_part_probes[] = { "cmdlinepart", NULL };
static struct platform_nand_data h2_nand_platdata = {
.chip = {
.nr_chips = 1,
......@@ -195,7 +193,6 @@ static struct platform_nand_data h2_nand_platdata = {
.nr_partitions = ARRAY_SIZE(h2_nand_partitions),
.partitions = h2_nand_partitions,
.options = NAND_SAMSUNG_LP_OPTIONS,
.part_probe_types = h2_part_probes,
},
.ctrl = {
.cmd_ctrl = omap1_nand_cmd_ctl,
......
......@@ -188,8 +188,6 @@ static int nand_dev_ready(struct mtd_info *mtd)
return gpio_get_value(H3_NAND_RB_GPIO_PIN);
}
static const char *part_probes[] = { "cmdlinepart", NULL };
static struct platform_nand_data nand_platdata = {
.chip = {
.nr_chips = 1,
......@@ -197,7 +195,6 @@ static struct platform_nand_data nand_platdata = {
.nr_partitions = ARRAY_SIZE(nand_partitions),
.partitions = nand_partitions,
.options = NAND_SAMSUNG_LP_OPTIONS,
.part_probe_types = part_probes,
},
.ctrl = {
.cmd_ctrl = omap1_nand_cmd_ctl,
......
......@@ -150,14 +150,11 @@ static int nand_dev_ready(struct mtd_info *mtd)
return gpio_get_value(P2_NAND_RB_GPIO_PIN);
}
static const char *part_probes[] = { "cmdlinepart", NULL };
static struct platform_nand_data nand_data = {
.chip = {
.nr_chips = 1,
.chip_offset = 0,
.options = NAND_SAMSUNG_LP_OPTIONS,
.part_probe_types = part_probes,
},
.ctrl = {
.cmd_ctrl = omap1_nand_cmd_ctl,
......
......@@ -49,6 +49,7 @@
#define GPMC_ECC_CONTROL 0x1f8
#define GPMC_ECC_SIZE_CONFIG 0x1fc
#define GPMC_ECC1_RESULT 0x200
#define GPMC_ECC_BCH_RESULT_0 0x240 /* not available on OMAP2 */
/* GPMC ECC control settings */
#define GPMC_ECC_CTRL_ECCCLEAR 0x100
......@@ -935,3 +936,186 @@ int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code)
return 0;
}
EXPORT_SYMBOL_GPL(gpmc_calculate_ecc);
#ifdef CONFIG_ARCH_OMAP3
/**
* gpmc_init_hwecc_bch - initialize hardware BCH ecc functionality
* @cs: chip select number
* @nsectors: how many 512-byte sectors to process
* @nerrors: how many errors to correct per sector (4 or 8)
*
* This function must be executed before any call to gpmc_enable_hwecc_bch.
*/
int gpmc_init_hwecc_bch(int cs, int nsectors, int nerrors)
{
/* check if ecc module is in use */
if (gpmc_ecc_used != -EINVAL)
return -EINVAL;
/* support only OMAP3 class */
if (!cpu_is_omap34xx()) {
printk(KERN_ERR "BCH ecc is not supported on this CPU\n");
return -EINVAL;
}
/*
* For now, assume 4-bit mode is only supported on OMAP3630 ES1.x, x>=1.
* Other chips may be added if confirmed to work.
*/
if ((nerrors == 4) &&
(!cpu_is_omap3630() || (GET_OMAP_REVISION() == 0))) {
printk(KERN_ERR "BCH 4-bit mode is not supported on this CPU\n");
return -EINVAL;
}
/* sanity check */
if (nsectors > 8) {
printk(KERN_ERR "BCH cannot process %d sectors (max is 8)\n",
nsectors);
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL_GPL(gpmc_init_hwecc_bch);
/**
* gpmc_enable_hwecc_bch - enable hardware BCH ecc functionality
* @cs: chip select number
* @mode: read/write mode
* @dev_width: device bus width(1 for x16, 0 for x8)
* @nsectors: how many 512-byte sectors to process
* @nerrors: how many errors to correct per sector (4 or 8)
*/
int gpmc_enable_hwecc_bch(int cs, int mode, int dev_width, int nsectors,
int nerrors)
{
unsigned int val;
/* check if ecc module is in use */
if (gpmc_ecc_used != -EINVAL)
return -EINVAL;
gpmc_ecc_used = cs;
/* clear ecc and enable bits */
gpmc_write_reg(GPMC_ECC_CONTROL, 0x1);
/*
* 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)
*/
gpmc_write_reg(GPMC_ECC_SIZE_CONFIG, (32 << 22) | (0 << 12));
/* BCH configuration */
val = ((1 << 16) | /* enable BCH */
(((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */
(0x06 << 8) | /* wrap mode = 6 */
(dev_width << 7) | /* bus width */
(((nsectors-1) & 0x7) << 4) | /* number of sectors */
(cs << 1) | /* ECC CS */
(0x1)); /* enable ECC */
gpmc_write_reg(GPMC_ECC_CONFIG, val);
gpmc_write_reg(GPMC_ECC_CONTROL, 0x101);
return 0;
}
EXPORT_SYMBOL_GPL(gpmc_enable_hwecc_bch);
/**
* gpmc_calculate_ecc_bch4 - Generate 7 ecc bytes per sector of 512 data bytes
* @cs: chip select number
* @dat: The pointer to data on which ecc is computed
* @ecc: The ecc output buffer
*/
int gpmc_calculate_ecc_bch4(int cs, const u_char *dat, u_char *ecc)
{
int i;
unsigned long nsectors, reg, val1, val2;
if (gpmc_ecc_used != cs)
return -EINVAL;
nsectors = ((gpmc_read_reg(GPMC_ECC_CONFIG) >> 4) & 0x7) + 1;
for (i = 0; i < nsectors; i++) {
reg = GPMC_ECC_BCH_RESULT_0 + 16*i;
/* Read hw-computed remainder */
val1 = gpmc_read_reg(reg + 0);
val2 = gpmc_read_reg(reg + 4);
/*
* Add constant polynomial to remainder, in order to get an ecc
* sequence of 0xFFs for a buffer filled with 0xFFs; and
* left-justify the resulting polynomial.
*/
*ecc++ = 0x28 ^ ((val2 >> 12) & 0xFF);
*ecc++ = 0x13 ^ ((val2 >> 4) & 0xFF);
*ecc++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF));
*ecc++ = 0x39 ^ ((val1 >> 20) & 0xFF);
*ecc++ = 0x96 ^ ((val1 >> 12) & 0xFF);
*ecc++ = 0xac ^ ((val1 >> 4) & 0xFF);
*ecc++ = 0x7f ^ ((val1 & 0xF) << 4);
}
gpmc_ecc_used = -EINVAL;
return 0;
}
EXPORT_SYMBOL_GPL(gpmc_calculate_ecc_bch4);
/**
* gpmc_calculate_ecc_bch8 - Generate 13 ecc bytes per block of 512 data bytes
* @cs: chip select number
* @dat: The pointer to data on which ecc is computed
* @ecc: The ecc output buffer
*/
int gpmc_calculate_ecc_bch8(int cs, const u_char *dat, u_char *ecc)
{
int i;
unsigned long nsectors, reg, val1, val2, val3, val4;
if (gpmc_ecc_used != cs)
return -EINVAL;
nsectors = ((gpmc_read_reg(GPMC_ECC_CONFIG) >> 4) & 0x7) + 1;
for (i = 0; i < nsectors; i++) {
reg = GPMC_ECC_BCH_RESULT_0 + 16*i;
/* Read hw-computed remainder */
val1 = gpmc_read_reg(reg + 0);
val2 = gpmc_read_reg(reg + 4);
val3 = gpmc_read_reg(reg + 8);
val4 = gpmc_read_reg(reg + 12);
/*
* Add constant polynomial to remainder, in order to get an ecc
* sequence of 0xFFs for a buffer filled with 0xFFs.
*/
*ecc++ = 0xef ^ (val4 & 0xFF);
*ecc++ = 0x51 ^ ((val3 >> 24) & 0xFF);
*ecc++ = 0x2e ^ ((val3 >> 16) & 0xFF);
*ecc++ = 0x09 ^ ((val3 >> 8) & 0xFF);
*ecc++ = 0xed ^ (val3 & 0xFF);
*ecc++ = 0x93 ^ ((val2 >> 24) & 0xFF);
*ecc++ = 0x9a ^ ((val2 >> 16) & 0xFF);
*ecc++ = 0xc2 ^ ((val2 >> 8) & 0xFF);
*ecc++ = 0x97 ^ (val2 & 0xFF);
*ecc++ = 0x79 ^ ((val1 >> 24) & 0xFF);
*ecc++ = 0xe5 ^ ((val1 >> 16) & 0xFF);
*ecc++ = 0x24 ^ ((val1 >> 8) & 0xFF);
*ecc++ = 0xb5 ^ (val1 & 0xFF);
}
gpmc_ecc_used = -EINVAL;
return 0;
}
EXPORT_SYMBOL_GPL(gpmc_calculate_ecc_bch8);
#endif /* CONFIG_ARCH_OMAP3 */
......@@ -251,8 +251,6 @@ static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,
readsb(io_base, buf, len);
}
const char *ts_nand_part_probes[] = { "cmdlinepart", NULL };
static struct mtd_partition ts78xx_ts_nand_parts[] = {
{
.name = "mbr",
......@@ -277,7 +275,6 @@ static struct mtd_partition ts78xx_ts_nand_parts[] = {
static struct platform_nand_data ts78xx_ts_nand_data = {
.chip = {
.nr_chips = 1,
.part_probe_types = ts_nand_part_probes,
.partitions = ts78xx_ts_nand_parts,
.nr_partitions = ARRAY_SIZE(ts78xx_ts_nand_parts),
.chip_delay = 15,
......
......@@ -679,8 +679,6 @@ static struct mtd_partition balloon3_partition_info[] = {
},
};
static const char *balloon3_part_probes[] = { "cmdlinepart", NULL };
struct platform_nand_data balloon3_nand_pdata = {
.chip = {
.nr_chips = 4,
......@@ -688,7 +686,6 @@ struct platform_nand_data balloon3_nand_pdata = {
.nr_partitions = ARRAY_SIZE(balloon3_partition_info),
.partitions = balloon3_partition_info,
.chip_delay = 50,
.part_probe_types = balloon3_part_probes,
},
.ctrl = {
.hwcontrol = 0,
......
......@@ -338,8 +338,6 @@ static struct mtd_partition em_x270_partition_info[] = {
},
};
static const char *em_x270_part_probes[] = { "cmdlinepart", NULL };
struct platform_nand_data em_x270_nand_platdata = {
.chip = {
.nr_chips = 1,
......@@ -347,7 +345,6 @@ struct platform_nand_data em_x270_nand_platdata = {
.nr_partitions = ARRAY_SIZE(em_x270_partition_info),
.partitions = em_x270_partition_info,
.chip_delay = 20,
.part_probe_types = em_x270_part_probes,
},
.ctrl = {
.hwcontrol = 0,
......
......@@ -268,8 +268,6 @@ static struct mtd_partition palmtx_partition_info[] = {
},
};
static const char *palmtx_part_probes[] = { "cmdlinepart", NULL };
struct platform_nand_data palmtx_nand_platdata = {
.chip = {
.nr_chips = 1,
......@@ -277,7 +275,6 @@ struct platform_nand_data palmtx_nand_platdata = {
.nr_partitions = ARRAY_SIZE(palmtx_partition_info),
.partitions = palmtx_partition_info,
.chip_delay = 20,
.part_probe_types = palmtx_part_probes,
},
.ctrl = {
.cmd_ctrl = palmtx_nand_cmd_ctl,
......
......@@ -92,6 +92,8 @@ enum omap_ecc {
OMAP_ECC_HAMMING_CODE_HW, /* gpmc to detect the error */
/* 1-bit ecc: stored at beginning of spare area as romcode */
OMAP_ECC_HAMMING_CODE_HW_ROMCODE, /* gpmc method & romcode layout */
OMAP_ECC_BCH4_CODE_HW, /* 4-bit BCH ecc code */
OMAP_ECC_BCH8_CODE_HW, /* 8-bit BCH ecc code */
};
/*
......@@ -157,4 +159,13 @@ extern int gpmc_nand_write(int cs, int cmd, int wval);
int gpmc_enable_hwecc(int cs, int mode, int dev_width, int ecc_size);
int gpmc_calculate_ecc(int cs, const u_char *dat, u_char *ecc_code);
#ifdef CONFIG_ARCH_OMAP3
int gpmc_init_hwecc_bch(int cs, int nsectors, int nerrors);
int gpmc_enable_hwecc_bch(int cs, int mode, int dev_width, int nsectors,
int nerrors);
int gpmc_calculate_ecc_bch4(int cs, const u_char *dat, u_char *ecc);
int gpmc_calculate_ecc_bch8(int cs, const u_char *dat, u_char *ecc);
#endif /* CONFIG_ARCH_OMAP3 */
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment