提交 f5e7e844 编写于 作者: L Linus Torvalds

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
  ...
......@@ -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
......@@ -248,8 +248,6 @@ static struct platform_device bfin_uart0_device = {
#if defined(CONFIG_MTD_NAND_PLATFORM) || defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
const char *part_probes[] = { "cmdlinepart", NULL };
static struct mtd_partition bfin_plat_nand_partitions[] = {
{
.name = "params(nand)",
......@@ -289,7 +287,6 @@ static struct platform_nand_data bfin_plat_nand_data = {
.chip = {
.nr_chips = 1,
.chip_delay = 30,
.part_probe_types = part_probes,
.partitions = bfin_plat_nand_partitions,
.nr_partitions = ARRAY_SIZE(bfin_plat_nand_partitions),
},
......
......@@ -213,8 +213,6 @@ static int au1200_nand_device_ready(struct mtd_info *mtd)
return __raw_readl((void __iomem *)MEM_STSTAT) & 1;
}
static const char *db1200_part_probes[] = { "cmdlinepart", NULL };
static struct mtd_partition db1200_nand_parts[] = {
{
.name = "NAND FS 0",
......@@ -235,7 +233,6 @@ struct platform_nand_data db1200_nand_platdata = {
.nr_partitions = ARRAY_SIZE(db1200_nand_parts),
.partitions = db1200_nand_parts,
.chip_delay = 20,
.part_probe_types = db1200_part_probes,
},
.ctrl = {
.dev_ready = au1200_nand_device_ready,
......
......@@ -145,8 +145,6 @@ static int au1300_nand_device_ready(struct mtd_info *mtd)
return __raw_readl((void __iomem *)MEM_STSTAT) & 1;
}
static const char *db1300_part_probes[] = { "cmdlinepart", NULL };
static struct mtd_partition db1300_nand_parts[] = {
{
.name = "NAND FS 0",
......@@ -167,7 +165,6 @@ struct platform_nand_data db1300_nand_platdata = {
.nr_partitions = ARRAY_SIZE(db1300_nand_parts),
.partitions = db1300_nand_parts,
.chip_delay = 20,
.part_probe_types = db1300_part_probes,
},
.ctrl = {
.dev_ready = au1300_nand_device_ready,
......
......@@ -149,8 +149,6 @@ static int au1550_nand_device_ready(struct mtd_info *mtd)
return __raw_readl((void __iomem *)MEM_STSTAT) & 1;
}
static const char *db1550_part_probes[] = { "cmdlinepart", NULL };
static struct mtd_partition db1550_nand_parts[] = {
{
.name = "NAND FS 0",
......@@ -171,7 +169,6 @@ struct platform_nand_data db1550_nand_platdata = {
.nr_partitions = ARRAY_SIZE(db1550_nand_parts),
.partitions = db1550_nand_parts,
.chip_delay = 20,
.part_probe_types = db1550_part_probes,
},
.ctrl = {
.dev_ready = au1550_nand_device_ready,
......
......@@ -244,11 +244,6 @@ static struct platform_device pnx833x_sata_device = {
.resource = pnx833x_sata_resources,
};
static const char *part_probes[] = {
"cmdlinepart",
NULL
};
static void
pnx833x_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
......@@ -268,7 +263,6 @@ static struct platform_nand_data pnx833x_flash_nand_data = {
.chip = {
.nr_chips = 1,
.chip_delay = 25,
.part_probe_types = part_probes,
},
.ctrl = {
.cmd_ctrl = pnx833x_flash_nand_cmd_ctrl
......
......@@ -293,7 +293,6 @@ static void __init rb532_nand_setup(void)
rb532_nand_data.chip.nr_partitions = ARRAY_SIZE(rb532_partition_info);
rb532_nand_data.chip.partitions = rb532_partition_info;
rb532_nand_data.chip.chip_delay = NAND_CHIP_DELAY;
rb532_nand_data.chip.options = NAND_NO_AUTOINCR;
}
......
......@@ -188,7 +188,6 @@ static struct platform_nand_data migor_nand_flash_data = {
.partitions = migor_nand_flash_partitions,
.nr_partitions = ARRAY_SIZE(migor_nand_flash_partitions),
.chip_delay = 20,
.part_probe_types = (const char *[]) { "cmdlinepart", NULL },
},
.ctrl = {
.dev_ready = migor_nand_flash_ready,
......
......@@ -128,7 +128,7 @@ config MTD_AFS_PARTS
config MTD_OF_PARTS
tristate "OpenFirmware partitioning information support"
default Y
default y
depends on OF
help
This provides a partition parsing function which derives
......
......@@ -4,7 +4,7 @@
* Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org>
* Mike Albon <malbon@openwrt.org>
* Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net>
* Copyright © 2011 Jonas Gorski <jonas.gorski@gmail.com>
* Copyright © 2011-2012 Jonas Gorski <jonas.gorski@gmail.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
......@@ -82,6 +82,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
int namelen = 0;
int i;
u32 computed_crc;
bool rootfs_first = false;
if (bcm63xx_detect_cfe(master))
return -EINVAL;
......@@ -109,6 +110,7 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
char *boardid = &(buf->board_id[0]);
char *tagversion = &(buf->tag_version[0]);
sscanf(buf->flash_image_start, "%u", &rootfsaddr);
sscanf(buf->kernel_address, "%u", &kerneladdr);
sscanf(buf->kernel_length, "%u", &kernellen);
sscanf(buf->total_length, "%u", &totallen);
......@@ -117,10 +119,19 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
tagversion, boardid);
kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE;
rootfsaddr = kerneladdr + kernellen;
rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE;
spareaddr = roundup(totallen, master->erasesize) + cfelen;
sparelen = master->size - spareaddr - nvramlen;
rootfslen = spareaddr - rootfsaddr;
if (rootfsaddr < kerneladdr) {
/* default Broadcom layout */
rootfslen = kerneladdr - rootfsaddr;
rootfs_first = true;
} else {
/* OpenWrt layout */
rootfsaddr = kerneladdr + kernellen;
rootfslen = spareaddr - rootfsaddr;
}
} else {
pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n",
buf->header_crc, computed_crc);
......@@ -156,18 +167,26 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
curpart++;
if (kernellen > 0) {
parts[curpart].name = "kernel";
parts[curpart].offset = kerneladdr;
parts[curpart].size = kernellen;
int kernelpart = curpart;
if (rootfslen > 0 && rootfs_first)
kernelpart++;
parts[kernelpart].name = "kernel";
parts[kernelpart].offset = kerneladdr;
parts[kernelpart].size = kernellen;
curpart++;
}
if (rootfslen > 0) {
parts[curpart].name = "rootfs";
parts[curpart].offset = rootfsaddr;
parts[curpart].size = rootfslen;
if (sparelen > 0)
parts[curpart].size += sparelen;
int rootfspart = curpart;
if (kernellen > 0 && rootfs_first)
rootfspart--;
parts[rootfspart].name = "rootfs";
parts[rootfspart].offset = rootfsaddr;
parts[rootfspart].size = rootfslen;
if (sparelen > 0 && !rootfs_first)
parts[rootfspart].size += sparelen;
curpart++;
}
......
......@@ -317,7 +317,7 @@ static void fixup_s29gl064n_sectors(struct mtd_info *mtd)
if ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0x003f) {
cfi->cfiq->EraseRegionInfo[0] |= 0x0040;
pr_warning("%s: Bad S29GL064N CFI data, adjust from 64 to 128 sectors\n", mtd->name);
pr_warning("%s: Bad S29GL064N CFI data; adjust from 64 to 128 sectors\n", mtd->name);
}
}
......@@ -328,10 +328,23 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd)
if ((cfi->cfiq->EraseRegionInfo[1] & 0xffff) == 0x007e) {
cfi->cfiq->EraseRegionInfo[1] &= ~0x0040;
pr_warning("%s: Bad S29GL032N CFI data, adjust from 127 to 63 sectors\n", mtd->name);
pr_warning("%s: Bad S29GL032N CFI data; adjust from 127 to 63 sectors\n", mtd->name);
}
}
static void fixup_s29ns512p_sectors(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
/*
* S29NS512P flash uses more than 8bits to report number of sectors,
* which is not permitted by CFI.
*/
cfi->cfiq->EraseRegionInfo[0] = 0x020001ff;
pr_warning("%s: Bad S29NS512P CFI data; adjust to 512 sectors\n", mtd->name);
}
/* Used to fix CFI-Tables of chips without Extended Query Tables */
static struct cfi_fixup cfi_nopri_fixup_table[] = {
{ CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */
......@@ -362,6 +375,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors },
{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors },
{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors },
{ CFI_MFR_AMD, 0x3f00, fixup_s29ns512p_sectors },
{ CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */
{ CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */
{ CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */
......
......@@ -70,7 +70,7 @@ struct cmdline_mtd_partition {
/* mtdpart_setup() parses into here */
static struct cmdline_mtd_partition *partitions;
/* the command line passed to mtdpart_setupd() */
/* the command line passed to mtdpart_setup() */
static char *cmdline;
static int cmdline_parsed = 0;
......
......@@ -52,8 +52,6 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
while (pages) {
page = page_read(mapping, index);
if (!page)
return -ENOMEM;
if (IS_ERR(page))
return PTR_ERR(page);
......@@ -112,8 +110,6 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
len = len - cpylen;
page = page_read(dev->blkdev->bd_inode->i_mapping, index);
if (!page)
return -ENOMEM;
if (IS_ERR(page))
return PTR_ERR(page);
......@@ -148,8 +144,6 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
len = len - cpylen;
page = page_read(mapping, index);
if (!page)
return -ENOMEM;
if (IS_ERR(page))
return PTR_ERR(page);
......@@ -271,7 +265,6 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
dev->mtd.flags = MTD_CAP_RAM;
dev->mtd._erase = block2mtd_erase;
dev->mtd._write = block2mtd_write;
dev->mtd._writev = mtd_writev;
dev->mtd._sync = block2mtd_sync;
dev->mtd._read = block2mtd_read;
dev->mtd.priv = dev;
......
......@@ -227,7 +227,7 @@ static void doc_read_data_area(struct docg3 *docg3, void *buf, int len,
u8 data8, *dst8;
doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len);
cdr = len & 0x3;
cdr = len & 0x1;
len4 = len - cdr;
if (first)
......@@ -732,12 +732,24 @@ static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1,
* @len: the number of bytes to be read (must be a multiple of 4)
* @buf: the buffer to be filled in (or NULL is forget bytes)
* @first: 1 if first time read, DOC_READADDRESS should be set
* @last_odd: 1 if last read ended up on an odd byte
*
* Reads bytes from a prepared page. There is a trickery here : if the last read
* ended up on an odd offset in the 1024 bytes double page, ie. between the 2
* planes, the first byte must be read apart. If a word (16bit) read was used,
* the read would return the byte of plane 2 as low *and* high endian, which
* will mess the read.
*
*/
static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf,
int first)
int first, int last_odd)
{
doc_read_data_area(docg3, buf, len, first);
if (last_odd && len > 0) {
doc_read_data_area(docg3, buf, 1, first);
doc_read_data_area(docg3, buf ? buf + 1 : buf, len - 1, 0);
} else {
doc_read_data_area(docg3, buf, len, first);
}
doc_delay(docg3, 2);
return len;
}
......@@ -850,6 +862,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
u8 *buf = ops->datbuf;
size_t len, ooblen, nbdata, nboob;
u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1;
int max_bitflips = 0;
if (buf)
len = ops->len;
......@@ -876,7 +889,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
ret = 0;
skip = from % DOC_LAYOUT_PAGE_SIZE;
mutex_lock(&docg3->cascade->lock);
while (!ret && (len > 0 || ooblen > 0)) {
while (ret >= 0 && (len > 0 || ooblen > 0)) {
calc_block_sector(from - skip, &block0, &block1, &page, &ofs,
docg3->reliable);
nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip);
......@@ -887,20 +900,20 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES);
if (ret < 0)
goto err_in_read;
ret = doc_read_page_getbytes(docg3, skip, NULL, 1);
ret = doc_read_page_getbytes(docg3, skip, NULL, 1, 0);
if (ret < skip)
goto err_in_read;
ret = doc_read_page_getbytes(docg3, nbdata, buf, 0);
ret = doc_read_page_getbytes(docg3, nbdata, buf, 0, skip % 2);
if (ret < nbdata)
goto err_in_read;
doc_read_page_getbytes(docg3,
DOC_LAYOUT_PAGE_SIZE - nbdata - skip,
NULL, 0);
ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0);
NULL, 0, (skip + nbdata) % 2);
ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0, 0);
if (ret < nboob)
goto err_in_read;
doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob,
NULL, 0);
NULL, 0, nboob % 2);
doc_get_bch_hw_ecc(docg3, hwecc);
eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1);
......@@ -936,7 +949,8 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
}
if (ret > 0) {
mtd->ecc_stats.corrected += ret;
ret = -EUCLEAN;
max_bitflips = max(max_bitflips, ret);
ret = max_bitflips;
}
}
......@@ -1004,7 +1018,7 @@ static int doc_reload_bbt(struct docg3 *docg3)
DOC_LAYOUT_PAGE_SIZE);
if (!ret)
doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE,
buf, 1);
buf, 1, 0);
buf += DOC_LAYOUT_PAGE_SIZE;
}
doc_read_page_finish(docg3);
......@@ -1064,10 +1078,10 @@ static int doc_get_erase_count(struct docg3 *docg3, loff_t from)
ret = doc_reset_seq(docg3);
if (!ret)
ret = doc_read_page_prepare(docg3, block0, block1, page,
ofs + DOC_LAYOUT_WEAR_OFFSET);
ofs + DOC_LAYOUT_WEAR_OFFSET, 0);
if (!ret)
ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE,
buf, 1);
buf, 1, 0);
doc_read_page_finish(docg3);
if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK))
......
......@@ -639,12 +639,16 @@ static const struct spi_device_id m25p_ids[] = {
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) },
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
/* Everspin */
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) },
/* Intel/Numonyx -- xxxs33b */
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
{ "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) },
{ "640s33b", INFO(0x898913, 0, 64 * 1024, 128, 0) },
/* Macronix */
{ "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) },
{ "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) },
{ "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) },
{ "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) },
......@@ -728,6 +732,7 @@ static const struct spi_device_id m25p_ids[] = {
{ "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
/* Catalyst / On Semiconductor -- non-JEDEC */
{ "cat25c11", CAT25_INFO( 16, 8, 16, 1) },
......
......@@ -990,9 +990,9 @@ static int __devinit spear_smi_probe(struct platform_device *pdev)
goto err_clk;
}
ret = clk_enable(dev->clk);
ret = clk_prepare_enable(dev->clk);
if (ret)
goto err_clk_enable;
goto err_clk_prepare_enable;
ret = request_irq(irq, spear_smi_int_handler, 0, pdev->name, dev);
if (ret) {
......@@ -1020,8 +1020,8 @@ static int __devinit spear_smi_probe(struct platform_device *pdev)
free_irq(irq, dev);
platform_set_drvdata(pdev, NULL);
err_irq:
clk_disable(dev->clk);
err_clk_enable:
clk_disable_unprepare(dev->clk);
err_clk_prepare_enable:
clk_put(dev->clk);
err_clk:
iounmap(dev->io_base);
......@@ -1074,7 +1074,7 @@ static int __devexit spear_smi_remove(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
free_irq(irq, dev);
clk_disable(dev->clk);
clk_disable_unprepare(dev->clk);
clk_put(dev->clk);
iounmap(dev->io_base);
kfree(dev);
......@@ -1091,7 +1091,7 @@ int spear_smi_suspend(struct platform_device *pdev, pm_message_t state)
struct spear_smi *dev = platform_get_drvdata(pdev);
if (dev && dev->clk)
clk_disable(dev->clk);
clk_disable_unprepare(dev->clk);
return 0;
}
......@@ -1102,7 +1102,7 @@ int spear_smi_resume(struct platform_device *pdev)
int ret = -EPERM;
if (dev && dev->clk)
ret = clk_enable(dev->clk);
ret = clk_prepare_enable(dev->clk);
if (!ret)
spear_smi_hw_init(dev);
......
......@@ -57,7 +57,7 @@ static struct qinfo_query_info qinfo_array[] = {
static long lpddr_get_qinforec_pos(struct map_info *map, char *id_str)
{
int qinfo_lines = sizeof(qinfo_array)/sizeof(struct qinfo_query_info);
int qinfo_lines = ARRAY_SIZE(qinfo_array);
int i;
int bankwidth = map_bankwidth(map) * 8;
int major, minor;
......
......@@ -224,7 +224,7 @@ config MTD_CK804XROM
config MTD_SCB2_FLASH
tristate "BIOS flash chip on Intel SCB2 boards"
depends on X86 && MTD_JEDECPROBE
depends on X86 && MTD_JEDECPROBE && PCI
help
Support for treating the BIOS flash chip on Intel SCB2 boards
as an MTD device - with this you can reprogram your BIOS.
......
......@@ -260,18 +260,7 @@ static struct pci_driver vr_nor_pci_driver = {
.id_table = vr_nor_pci_ids,
};
static int __init vr_nor_mtd_init(void)
{
return pci_register_driver(&vr_nor_pci_driver);
}
static void __exit vr_nor_mtd_exit(void)
{
pci_unregister_driver(&vr_nor_pci_driver);
}
module_init(vr_nor_mtd_init);
module_exit(vr_nor_mtd_exit);
module_pci_driver(vr_nor_pci_driver);
MODULE_AUTHOR("Andy Lowe");
MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range");
......
......@@ -352,18 +352,7 @@ static struct pci_driver mtd_pci_driver = {
.id_table = mtd_pci_ids,
};
static int __init mtd_pci_maps_init(void)
{
return pci_register_driver(&mtd_pci_driver);
}
static void __exit mtd_pci_maps_exit(void)
{
pci_unregister_driver(&mtd_pci_driver);
}
module_init(mtd_pci_maps_init);
module_exit(mtd_pci_maps_exit);
module_pci_driver(mtd_pci_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
......
......@@ -234,20 +234,7 @@ static struct pci_driver scb2_flash_driver = {
.remove = __devexit_p(scb2_flash_remove),
};
static int __init
scb2_flash_init(void)
{
return pci_register_driver(&scb2_flash_driver);
}
static void __exit
scb2_flash_exit(void)
{
pci_unregister_driver(&scb2_flash_driver);
}
module_init(scb2_flash_init);
module_exit(scb2_flash_exit);
module_pci_driver(scb2_flash_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tim Hockin <thockin@sun.com>");
......
......@@ -59,7 +59,7 @@ static struct mtd_partition bigflash_parts[] = {
}
};
static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
static const char *part_probes[] __initconst = {"cmdlinepart", "RedBoot", NULL};
#define init_sbc82xx_one_flash(map, br, or) \
do { \
......
......@@ -250,6 +250,43 @@ static ssize_t mtd_name_show(struct device *dev,
}
static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL);
static ssize_t mtd_ecc_strength_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_strength);
}
static DEVICE_ATTR(ecc_strength, S_IRUGO, mtd_ecc_strength_show, NULL);
static ssize_t mtd_bitflip_threshold_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%u\n", mtd->bitflip_threshold);
}
static ssize_t mtd_bitflip_threshold_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
unsigned int bitflip_threshold;
int retval;
retval = kstrtouint(buf, 0, &bitflip_threshold);
if (retval)
return retval;
mtd->bitflip_threshold = bitflip_threshold;
return count;
}
static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR,
mtd_bitflip_threshold_show,
mtd_bitflip_threshold_store);
static struct attribute *mtd_attrs[] = {
&dev_attr_type.attr,
&dev_attr_flags.attr,
......@@ -260,6 +297,8 @@ static struct attribute *mtd_attrs[] = {
&dev_attr_oobsize.attr,
&dev_attr_numeraseregions.attr,
&dev_attr_name.attr,
&dev_attr_ecc_strength.attr,
&dev_attr_bitflip_threshold.attr,
NULL,
};
......@@ -322,6 +361,10 @@ int add_mtd_device(struct mtd_info *mtd)
mtd->index = i;
mtd->usecount = 0;
/* default value if not set by driver */
if (mtd->bitflip_threshold == 0)
mtd->bitflip_threshold = mtd->ecc_strength;
if (is_power_of_2(mtd->erasesize))
mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
else
......@@ -757,12 +800,24 @@ EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
u_char *buf)
{
int ret_code;
*retlen = 0;
if (from < 0 || from > mtd->size || len > mtd->size - from)
return -EINVAL;
if (!len)
return 0;
return mtd->_read(mtd, from, len, retlen, buf);
/*
* In the absence of an error, drivers return a non-negative integer
* representing the maximum number of bitflips that were corrected on
* any one ecc region (if applicable; zero otherwise).
*/
ret_code = mtd->_read(mtd, from, len, retlen, buf);
if (unlikely(ret_code < 0))
return ret_code;
if (mtd->ecc_strength == 0)
return 0; /* device lacks ecc */
return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
}
EXPORT_SYMBOL_GPL(mtd_read);
......
......@@ -67,12 +67,12 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
stats = part->master->ecc_stats;
res = part->master->_read(part->master, from + part->offset, len,
retlen, buf);
if (unlikely(res)) {
if (mtd_is_bitflip(res))
mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
if (mtd_is_eccerr(res))
mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
}
if (unlikely(mtd_is_eccerr(res)))
mtd->ecc_stats.failed +=
part->master->ecc_stats.failed - stats.failed;
else
mtd->ecc_stats.corrected +=
part->master->ecc_stats.corrected - stats.corrected;
return res;
}
......@@ -517,6 +517,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.ecclayout = master->ecclayout;
slave->mtd.ecc_strength = master->ecc_strength;
slave->mtd.bitflip_threshold = master->bitflip_threshold;
if (master->_block_isbad) {
uint64_t offs = 0;
......
......@@ -115,6 +115,46 @@ config MTD_NAND_OMAP2
Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4
platforms.
config MTD_NAND_OMAP_BCH
depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3
bool "Enable support for hardware BCH error correction"
default n
select BCH
select BCH_CONST_PARAMS
help
Support for hardware BCH error correction.
choice
prompt "BCH error correction capability"
depends on MTD_NAND_OMAP_BCH
config MTD_NAND_OMAP_BCH8
bool "8 bits / 512 bytes (recommended)"
help
Support correcting up to 8 bitflips per 512-byte block.
This will use 13 bytes of spare area per 512 bytes of page data.
This is the recommended mode, as 4-bit mode does not work
on some OMAP3 revisions, due to a hardware bug.
config MTD_NAND_OMAP_BCH4
bool "4 bits / 512 bytes"
help
Support correcting up to 4 bitflips per 512-byte block.
This will use 7 bytes of spare area per 512 bytes of page data.
Note that this mode does not work on some OMAP3 revisions, due to a
hardware bug. Please check your OMAP datasheet before selecting this
mode.
endchoice
if MTD_NAND_OMAP_BCH
config BCH_CONST_M
default 13
config BCH_CONST_T
default 4 if MTD_NAND_OMAP_BCH4
default 8 if MTD_NAND_OMAP_BCH8
endif
config MTD_NAND_IDS
tristate
......@@ -440,7 +480,7 @@ config MTD_NAND_NANDSIM
config MTD_NAND_GPMI_NAND
bool "GPMI NAND Flash Controller driver"
depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28)
depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q)
help
Enables NAND Flash support for IMX23 or IMX28.
The GPMI controller is very powerful, with the help of BCH
......
......@@ -414,7 +414,7 @@ static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
}
err = 0;
if (corrected)
err = -EUCLEAN;
err = 1; /* return max_bitflips per ecc step */
if (uncorrected)
err = -EBADMSG;
out:
......@@ -446,7 +446,7 @@ static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,
}
err = 0;
if (corrected)
err = -EUCLEAN;
err = 1; /* return max_bitflips per ecc step */
if (uncorrected)
err = -EBADMSG;
return err;
......
......@@ -324,9 +324,10 @@ static int atmel_nand_calculate(struct mtd_info *mtd,
* mtd: mtd info structure
* chip: nand chip info structure
* buf: buffer to store read data
* oob_required: caller expects OOB data read to chip->oob_poi
*/
static int atmel_nand_read_page(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int page)
static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
int eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
......@@ -335,6 +336,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd,
uint8_t *oob = chip->oob_poi;
uint8_t *ecc_pos;
int stat;
unsigned int max_bitflips = 0;
/*
* Errata: ALE is incorrectly wired up to the ECC controller
......@@ -371,10 +373,12 @@ static int atmel_nand_read_page(struct mtd_info *mtd,
/* check if there's an error */
stat = chip->ecc.correct(mtd, p, oob, NULL);
if (stat < 0)
if (stat < 0) {
mtd->ecc_stats.failed++;
else
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
/* get back to oob start (end of page) */
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
......@@ -382,7 +386,7 @@ static int atmel_nand_read_page(struct mtd_info *mtd,
/* read the oob */
chip->read_buf(mtd, oob, mtd->oobsize);
return 0;
return max_bitflips;
}
/*
......
......@@ -508,8 +508,6 @@ static int __devinit au1550nd_probe(struct platform_device *pdev)
this->chip_delay = 30;
this->ecc.mode = NAND_ECC_SOFT;
this->options = NAND_NO_AUTOINCR;
if (pd->devwidth)
this->options |= NAND_BUSWIDTH_16;
......
......@@ -22,9 +22,9 @@
/* ---- Private Function Prototypes -------------------------------------- */
static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int page);
struct nand_chip *chip, uint8_t *buf, int oob_required, int page);
static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf);
struct nand_chip *chip, const uint8_t *buf, int oob_required);
/* ---- Private Variables ------------------------------------------------ */
......@@ -103,11 +103,12 @@ static struct nand_ecclayout nand_hw_eccoob_4096 = {
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller expects OOB data read to chip->oob_poi
*
***************************************************************************/
static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t * buf,
int page)
int oob_required, int page)
{
int sectorIdx = 0;
int eccsize = chip->ecc.size;
......@@ -116,6 +117,7 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
uint8_t eccCalc[NAND_ECC_NUM_BYTES];
int sectorOobSize = mtd->oobsize / eccsteps;
int stat;
unsigned int max_bitflips = 0;
for (sectorIdx = 0; sectorIdx < eccsteps;
sectorIdx++, datap += eccsize) {
......@@ -177,9 +179,10 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
}
#endif
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return 0;
return max_bitflips;
}
/****************************************************************************
......@@ -188,10 +191,11 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
* @oob_required: must write chip->oob_poi to OOB
*
***************************************************************************/
static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf)
struct nand_chip *chip, const uint8_t *buf, int oob_required)
{
int sectorIdx = 0;
int eccsize = chip->ecc.size;
......
......@@ -341,7 +341,7 @@ static int bcm_umi_nand_verify_buf(struct mtd_info *mtd, const u_char * buf,
* for MLC parts which may have permanently stuck bits.
*/
struct nand_chip *chip = mtd->priv;
int ret = chip->ecc.read_page(mtd, chip, readbackbuf, 0);
int ret = chip->ecc.read_page(mtd, chip, readbackbuf, 0, 0);
if (ret < 0)
return -EFAULT;
else {
......@@ -476,12 +476,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev)
this->badblock_pattern = &largepage_bbt;
}
/*
* FIXME: ecc strength value of 6 bits per 512 bytes of data is a
* conservative guess, given 13 ecc bytes and using bch alg.
* (Assume Galois field order m=15 to allow a margin of error.)
*/
this->ecc.strength = 6;
this->ecc.strength = 8;
#endif
......
......@@ -558,7 +558,7 @@ static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
}
static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
uint8_t *buf, int oob_required, int page)
{
bf5xx_nand_read_buf(mtd, buf, mtd->writesize);
bf5xx_nand_read_buf(mtd, chip->oob_poi, mtd->oobsize);
......@@ -567,7 +567,7 @@ static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip
}
static void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf)
const uint8_t *buf, int oob_required)
{
bf5xx_nand_write_buf(mtd, buf, mtd->writesize);
bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
......
......@@ -364,25 +364,27 @@ static int cafe_nand_write_oob(struct mtd_info *mtd,
/* Don't use -- use nand_read_oob_std for now */
static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page, int sndcmd)
int page)
{
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return 1;
return 0;
}
/**
* cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller expects OOB data read to chip->oob_poi
*
* The hw generator calculates the error syndrome automatically. Therefor
* we need a special oob layout and handling.
*/
static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
uint8_t *buf, int oob_required, int page)
{
struct cafe_priv *cafe = mtd->priv;
unsigned int max_bitflips = 0;
cafe_dev_dbg(&cafe->pdev->dev, "ECC result %08x SYN1,2 %08x\n",
cafe_readl(cafe, NAND_ECC_RESULT),
......@@ -449,10 +451,11 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
} else {
dev_dbg(&cafe->pdev->dev, "Corrected %d symbol errors\n", n);
mtd->ecc_stats.corrected += n;
max_bitflips = max_t(unsigned int, max_bitflips, n);
}
}
return 0;
return max_bitflips;
}
static struct nand_ecclayout cafe_oobinfo_2048 = {
......@@ -518,7 +521,8 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf)
struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
struct cafe_priv *cafe = mtd->priv;
......@@ -530,16 +534,17 @@ static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
}
static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int page, int cached, int raw)
const uint8_t *buf, int oob_required, int page,
int cached, int raw)
{
int status;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
if (unlikely(raw))
chip->ecc.write_page_raw(mtd, chip, buf);
chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
else
chip->ecc.write_page(mtd, chip, buf);
chip->ecc.write_page(mtd, chip, buf, oob_required);
/*
* Cached progamming disabled for now, Not sure if its worth the
......@@ -685,7 +690,7 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
/* Enable the following for a flash based bad block table */
cafe->nand.bbt_options = NAND_BBT_USE_FLASH;
cafe->nand.options = NAND_NO_AUTOINCR | NAND_OWN_BUFFERS;
cafe->nand.options = NAND_OWN_BUFFERS;
if (skipbbt) {
cafe->nand.options |= NAND_SKIP_BBTSCAN;
......@@ -888,17 +893,7 @@ static struct pci_driver cafe_nand_pci_driver = {
.resume = cafe_nand_resume,
};
static int __init cafe_nand_init(void)
{
return pci_register_driver(&cafe_nand_pci_driver);
}
static void __exit cafe_nand_exit(void)
{
pci_unregister_driver(&cafe_nand_pci_driver);
}
module_init(cafe_nand_init);
module_exit(cafe_nand_exit);
module_pci_driver(cafe_nand_pci_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
......
......@@ -240,7 +240,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
/* Enable the following for a flash based bad block table */
this->bbt_options = NAND_BBT_USE_FLASH;
this->options = NAND_NO_AUTOINCR;
/* Scan to find existence of the device */
if (nand_scan(new_mtd, 1)) {
......
......@@ -924,9 +924,10 @@ bool is_erased(uint8_t *buf, int len)
#define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO)
static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
uint32_t irq_status)
uint32_t irq_status, unsigned int *max_bitflips)
{
bool check_erased_page = false;
unsigned int bitflips = 0;
if (irq_status & INTR_STATUS__ECC_ERR) {
/* read the ECC errors. we'll ignore them for now */
......@@ -965,6 +966,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
/* correct the ECC error */
buf[offset] ^= err_correction_value;
denali->mtd.ecc_stats.corrected++;
bitflips++;
}
} else {
/* if the error is not correctable, need to
......@@ -984,6 +986,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf,
clear_interrupts(denali);
denali_set_intr_modes(denali, true);
}
*max_bitflips = bitflips;
return check_erased_page;
}
......@@ -1084,7 +1087,7 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
* by write_page above.
* */
static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf)
const uint8_t *buf, int oob_required)
{
/* for regular page writes, we let HW handle all the ECC
* data written to the device. */
......@@ -1096,7 +1099,7 @@ static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
* write_page() function above.
*/
static void denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf)
const uint8_t *buf, int oob_required)
{
/* for raw page writes, we want to disable ECC and simply write
whatever data is in the buffer. */
......@@ -1110,17 +1113,17 @@ static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
}
static int denali_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page, int sndcmd)
int page)
{
read_oob_data(mtd, chip->oob_poi, page);
return 0; /* notify NAND core to send command to
NAND device. */
return 0;
}
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
uint8_t *buf, int oob_required, int page)
{
unsigned int max_bitflips;
struct denali_nand_info *denali = mtd_to_denali(mtd);
dma_addr_t addr = denali->buf.dma_buf;
......@@ -1153,7 +1156,7 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
memcpy(buf, denali->buf.buf, mtd->writesize);
check_erased_page = handle_ecc(denali, buf, irq_status);
check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips);
denali_enable_dma(denali, false);
if (check_erased_page) {
......@@ -1167,11 +1170,11 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip,
denali->mtd.ecc_stats.failed++;
}
}
return 0;
return max_bitflips;
}
static int denali_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
uint8_t *buf, int oob_required, int page)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
......@@ -1702,17 +1705,4 @@ static struct pci_driver denali_pci_driver = {
.remove = denali_pci_remove,
};
static int __devinit denali_init(void)
{
printk(KERN_INFO "Spectra MTD driver\n");
return pci_register_driver(&denali_pci_driver);
}
/* Free memory */
static void __devexit denali_exit(void)
{
pci_unregister_driver(&denali_pci_driver);
}
module_init(denali_init);
module_exit(denali_exit);
module_pci_driver(denali_pci_driver);
......@@ -720,6 +720,7 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
struct docg4_priv *doc = nand->priv;
void __iomem *docptr = doc->virtadr;
uint16_t status, edc_err, *buf16;
int bits_corrected = 0;
dev_dbg(doc->dev, "%s: page %08x\n", __func__, page);
......@@ -772,7 +773,7 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
/* If bitflips are reported, attempt to correct with ecc */
if (edc_err & DOC_ECCCONF1_BCH_SYNDROM_ERR) {
int bits_corrected = correct_data(mtd, buf, page);
bits_corrected = correct_data(mtd, buf, page);
if (bits_corrected == -EBADMSG)
mtd->ecc_stats.failed++;
else
......@@ -781,24 +782,24 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand,
}
writew(0, docptr + DOC_DATAEND);
return 0;
return bits_corrected;
}
static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
uint8_t *buf, int page)
uint8_t *buf, int oob_required, int page)
{
return read_page(mtd, nand, buf, page, false);
}
static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand,
uint8_t *buf, int page)
uint8_t *buf, int oob_required, int page)
{
return read_page(mtd, nand, buf, page, true);
}
static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand,
int page, int sndcmd)
int page)
{
struct docg4_priv *doc = nand->priv;
void __iomem *docptr = doc->virtadr;
......@@ -952,13 +953,13 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *nand,
}
static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
const uint8_t *buf)
const uint8_t *buf, int oob_required)
{
return write_page(mtd, nand, buf, false);
}
static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
const uint8_t *buf)
const uint8_t *buf, int oob_required)
{
return write_page(mtd, nand, buf, true);
}
......@@ -1002,7 +1003,7 @@ static int __init read_factory_bbt(struct mtd_info *mtd)
return -ENOMEM;
read_page_prologue(mtd, g4_addr);
status = docg4_read_page(mtd, nand, buf, DOCG4_FACTORY_BBT_PAGE);
status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE);
if (status)
goto exit;
......@@ -1079,7 +1080,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* write first page of block */
write_page_prologue(mtd, g4_addr);
docg4_write_page(mtd, nand, buf);
docg4_write_page(mtd, nand, buf, 1);
ret = pageprog(mtd);
if (!ret)
mtd->ecc_stats.badblocks++;
......@@ -1192,8 +1193,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->ecc.prepad = 8;
nand->ecc.bytes = 8;
nand->ecc.strength = DOCG4_T;
nand->options =
NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE | NAND_NO_AUTOINCR;
nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
nand->controller = &nand->hwcontrol;
spin_lock_init(&nand->controller->lock);
......
......@@ -75,6 +75,7 @@ struct fsl_elbc_fcm_ctrl {
unsigned int use_mdr; /* Non zero if the MDR is to be set */
unsigned int oob; /* Non zero if operating on OOB data */
unsigned int counter; /* counter for the initializations */
unsigned int max_bitflips; /* Saved during READ0 cmd */
};
/* These map to the positions used by the FCM hardware ECC generator */
......@@ -253,6 +254,8 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
if (chip->ecc.mode != NAND_ECC_HW)
return 0;
elbc_fcm_ctrl->max_bitflips = 0;
if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) {
uint32_t lteccr = in_be32(&lbc->lteccr);
/*
......@@ -262,11 +265,16 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
* bits 28-31 are uncorrectable errors, marked elsewhere.
* for small page nand only 1 bit is used.
* if the ELBC doesn't have the lteccr register it reads 0
* FIXME: 4 bits can be corrected on NANDs with 2k pages, so
* count the number of sub-pages with bitflips and update
* ecc_stats.corrected accordingly.
*/
if (lteccr & 0x000F000F)
out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */
if (lteccr & 0x000F0000)
if (lteccr & 0x000F0000) {
mtd->ecc_stats.corrected++;
elbc_fcm_ctrl->max_bitflips = 1;
}
}
return 0;
......@@ -738,26 +746,28 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
return 0;
}
static int fsl_elbc_read_page(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf,
int page)
static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
fsl_elbc_read_buf(mtd, buf, mtd->writesize);
fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (oob_required)
fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL)
mtd->ecc_stats.failed++;
return 0;
return elbc_fcm_ctrl->max_bitflips;
}
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc.
*/
static void fsl_elbc_write_page(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf)
static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
fsl_elbc_write_buf(mtd, buf, mtd->writesize);
fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
......@@ -795,7 +805,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->bbt_md = &bbt_mirror_descr;
/* set up nand options */
chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
chip->options = NAND_NO_READRDY;
chip->bbt_options = NAND_BBT_USE_FLASH;
chip->controller = &elbc_fcm_ctrl->controller;
......@@ -814,11 +824,6 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
chip->ecc.size = 512;
chip->ecc.bytes = 3;
chip->ecc.strength = 1;
/*
* FIXME: can hardware ecc correct 4 bitflips if page size is
* 2k? Then does hardware report number of corrections for this
* case? If so, ecc_stats reporting needs to be fixed as well.
*/
} else {
/* otherwise fall back to default software ECC */
chip->ecc.mode = NAND_ECC_SOFT;
......
......@@ -63,6 +63,7 @@ struct fsl_ifc_nand_ctrl {
unsigned int oob; /* Non zero if operating on OOB data */
unsigned int eccread; /* Non zero for a full-page ECC read */
unsigned int counter; /* counter for the initializations */
unsigned int max_bitflips; /* Saved during READ0 cmd */
};
static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl;
......@@ -262,6 +263,8 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER)
dev_err(priv->dev, "NAND Flash Write Protect Error\n");
nctrl->max_bitflips = 0;
if (nctrl->eccread) {
int errors;
int bufnum = nctrl->page & priv->bufnum_mask;
......@@ -290,6 +293,9 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
}
mtd->ecc_stats.corrected += errors;
nctrl->max_bitflips = max_t(unsigned int,
nctrl->max_bitflips,
errors);
}
nctrl->eccread = 0;
......@@ -375,21 +381,31 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
return;
/* READID must read all 8 possible bytes */
case NAND_CMD_READID:
case NAND_CMD_PARAM: {
int timing = IFC_FIR_OP_RB;
if (command == NAND_CMD_PARAM)
timing = IFC_FIR_OP_RBCD;
out_be32(&ifc->ifc_nand.nand_fir0,
(IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) |
(IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) |
(IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT));
(timing << IFC_NAND_FIR0_OP2_SHIFT));
out_be32(&ifc->ifc_nand.nand_fcr0,
NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT);
/* 8 bytes for manuf, device and exts */
out_be32(&ifc->ifc_nand.nand_fbcr, 8);
ifc_nand_ctrl->read_bytes = 8;
command << IFC_NAND_FCR0_CMD0_SHIFT);
out_be32(&ifc->ifc_nand.row3, column);
/*
* 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);
ifc_nand_ctrl->read_bytes = 256;
set_addr(mtd, 0, 0, 0);
fsl_ifc_run_command(mtd);
return;
}
/* ERASE1 stores the block and page address */
case NAND_CMD_ERASE1:
......@@ -682,15 +698,16 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
return nand_fsr | NAND_STATUS_WP;
}
static int fsl_ifc_read_page(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf, int page)
static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
struct fsl_ifc_mtd *priv = chip->priv;
struct fsl_ifc_ctrl *ctrl = priv->ctrl;
struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
fsl_ifc_read_buf(mtd, buf, mtd->writesize);
fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (oob_required)
fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER)
dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n");
......@@ -698,15 +715,14 @@ static int fsl_ifc_read_page(struct mtd_info *mtd,
if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
mtd->ecc_stats.failed++;
return 0;
return nctrl->max_bitflips;
}
/* ECC will be calculated automatically, and errors will be detected in
* waitfunc.
*/
static void fsl_ifc_write_page(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf)
static void fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
fsl_ifc_write_buf(mtd, buf, mtd->writesize);
fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
......@@ -789,7 +805,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
out_be32(&ifc->ifc_nand.ncfgr, 0x0);
/* set up nand options */
chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR;
chip->options = NAND_NO_READRDY;
chip->bbt_options = NAND_BBT_USE_FLASH;
......@@ -811,6 +827,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
/* Hardware generates ECC per 512 Bytes */
chip->ecc.size = 512;
chip->ecc.bytes = 8;
chip->ecc.strength = 4;
switch (csor & CSOR_NAND_PGS_MASK) {
case CSOR_NAND_PGS_512:
......
......@@ -692,6 +692,7 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller expects OOB data read to chip->oob_poi
* @page: page number to read
*
* This routine is needed for fsmc version 8 as reading from NAND chip has to be
......@@ -701,7 +702,7 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf,
* max of 8 bits)
*/
static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
uint8_t *buf, int oob_required, int page)
{
struct fsmc_nand_data *host = container_of(mtd,
struct fsmc_nand_data, mtd);
......@@ -720,6 +721,7 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
*/
uint16_t ecc_oob[7];
uint8_t *oob = (uint8_t *)&ecc_oob[0];
unsigned int max_bitflips = 0;
for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page);
......@@ -748,13 +750,15 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
chip->ecc.calculate(mtd, p, &ecc_calc[i]);
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
if (stat < 0)
if (stat < 0) {
mtd->ecc_stats.failed++;
else
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return 0;
return max_bitflips;
}
/*
......@@ -994,9 +998,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
return PTR_ERR(host->clk);
}
ret = clk_enable(host->clk);
ret = clk_prepare_enable(host->clk);
if (ret)
goto err_clk_enable;
goto err_clk_prepare_enable;
/*
* This device ID is actually a common AMBA ID as used on the
......@@ -1176,8 +1180,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (host->mode == USE_DMA_ACCESS)
dma_release_channel(host->read_dma_chan);
err_req_read_chnl:
clk_disable(host->clk);
err_clk_enable:
clk_disable_unprepare(host->clk);
err_clk_prepare_enable:
clk_put(host->clk);
return ret;
}
......@@ -1198,7 +1202,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
dma_release_channel(host->write_dma_chan);
dma_release_channel(host->read_dma_chan);
}
clk_disable(host->clk);
clk_disable_unprepare(host->clk);
clk_put(host->clk);
}
......@@ -1210,7 +1214,7 @@ static int fsmc_nand_suspend(struct device *dev)
{
struct fsmc_nand_data *host = dev_get_drvdata(dev);
if (host)
clk_disable(host->clk);
clk_disable_unprepare(host->clk);
return 0;
}
......@@ -1218,7 +1222,7 @@ static int fsmc_nand_resume(struct device *dev)
{
struct fsmc_nand_data *host = dev_get_drvdata(dev);
if (host) {
clk_enable(host->clk);
clk_prepare_enable(host->clk);
fsmc_nand_setup(host->regs_va, host->bank,
host->nand.options & NAND_BUSWIDTH_16,
host->dev_timings);
......
......@@ -51,15 +51,26 @@
#define BP_BCH_FLASH0LAYOUT0_ECC0 12
#define BM_BCH_FLASH0LAYOUT0_ECC0 (0xf << BP_BCH_FLASH0LAYOUT0_ECC0)
#define BF_BCH_FLASH0LAYOUT0_ECC0(v) \
(((v) << BP_BCH_FLASH0LAYOUT0_ECC0) & BM_BCH_FLASH0LAYOUT0_ECC0)
#define MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0 11
#define MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0 (0x1f << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0)
#define BF_BCH_FLASH0LAYOUT0_ECC0(v, x) \
(GPMI_IS_MX6Q(x) \
? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT0_ECC0) \
& MX6Q_BM_BCH_FLASH0LAYOUT0_ECC0) \
: (((v) << BP_BCH_FLASH0LAYOUT0_ECC0) \
& BM_BCH_FLASH0LAYOUT0_ECC0) \
)
#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0
#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \
(0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \
(((v) << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)\
& BM_BCH_FLASH0LAYOUT0_DATA0_SIZE)
#define MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \
(0x3ff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)
#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v, x) \
(GPMI_IS_MX6Q(x) \
? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) \
: ((v) & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) \
)
#define HW_BCH_FLASH0LAYOUT1 0x00000090
......@@ -72,13 +83,24 @@
#define BP_BCH_FLASH0LAYOUT1_ECCN 12
#define BM_BCH_FLASH0LAYOUT1_ECCN (0xf << BP_BCH_FLASH0LAYOUT1_ECCN)
#define BF_BCH_FLASH0LAYOUT1_ECCN(v) \
(((v) << BP_BCH_FLASH0LAYOUT1_ECCN) & BM_BCH_FLASH0LAYOUT1_ECCN)
#define MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN 11
#define MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN (0x1f << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN)
#define BF_BCH_FLASH0LAYOUT1_ECCN(v, x) \
(GPMI_IS_MX6Q(x) \
? (((v) << MX6Q_BP_BCH_FLASH0LAYOUT1_ECCN) \
& MX6Q_BM_BCH_FLASH0LAYOUT1_ECCN) \
: (((v) << BP_BCH_FLASH0LAYOUT1_ECCN) \
& BM_BCH_FLASH0LAYOUT1_ECCN) \
)
#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0
#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \
(0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \
(((v) << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) \
& BM_BCH_FLASH0LAYOUT1_DATAN_SIZE)
#define MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \
(0x3ff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE)
#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v, x) \
(GPMI_IS_MX6Q(x) \
? (((v) >> 2) & MX6Q_BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) \
: ((v) & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) \
)
#endif
......@@ -21,7 +21,6 @@
#include <linux/mtd/gpmi-nand.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <mach/mxs.h>
#include "gpmi-nand.h"
#include "gpmi-regs.h"
......@@ -37,6 +36,8 @@ struct timing_threshod timing_default_threshold = {
.max_dll_delay_in_ns = 16,
};
#define MXS_SET_ADDR 0x4
#define MXS_CLR_ADDR 0x8
/*
* Clear the bit and poll it cleared. This is usually called with
* a reset address and mask being either SFTRST(bit 31) or CLKGATE
......@@ -47,7 +48,7 @@ static int clear_poll_bit(void __iomem *addr, u32 mask)
int timeout = 0x400;
/* clear the bit */
__mxs_clrl(mask, addr);
writel(mask, addr + MXS_CLR_ADDR);
/*
* SFTRST needs 3 GPMI clocks to settle, the reference manual
......@@ -92,11 +93,11 @@ static int gpmi_reset_block(void __iomem *reset_addr, bool just_enable)
goto error;
/* clear CLKGATE */
__mxs_clrl(MODULE_CLKGATE, reset_addr);
writel(MODULE_CLKGATE, reset_addr + MXS_CLR_ADDR);
if (!just_enable) {
/* set SFTRST to reset the block */
__mxs_setl(MODULE_SFTRST, reset_addr);
writel(MODULE_SFTRST, reset_addr + MXS_SET_ADDR);
udelay(1);
/* poll CLKGATE becoming set */
......@@ -223,13 +224,13 @@ int bch_set_geometry(struct gpmi_nand_data *this)
/* Configure layout 0. */
writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count)
| BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size)
| BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength)
| BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size),
| BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength, 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)
| BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size),
| BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength, this)
| BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size, this),
r->bch_regs + HW_BCH_FLASH0LAYOUT1);
/* Set *all* chip selects to use layout 0. */
......@@ -255,11 +256,12 @@ static unsigned int ns_to_cycles(unsigned int time,
return max(k, min);
}
#define DEF_MIN_PROP_DELAY 5
#define DEF_MAX_PROP_DELAY 9
/* Apply timing to current hardware conditions. */
static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
struct gpmi_nfc_hardware_timing *hw)
{
struct gpmi_nand_platform_data *pdata = this->pdata;
struct timing_threshod *nfc = &timing_default_threshold;
struct nand_chip *nand = &this->nand;
struct nand_timing target = this->timing;
......@@ -276,8 +278,8 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
int ideal_sample_delay_in_ns;
unsigned int sample_delay_factor;
int tEYE;
unsigned int min_prop_delay_in_ns = pdata->min_prop_delay_in_ns;
unsigned int max_prop_delay_in_ns = pdata->max_prop_delay_in_ns;
unsigned int min_prop_delay_in_ns = DEF_MIN_PROP_DELAY;
unsigned int max_prop_delay_in_ns = DEF_MAX_PROP_DELAY;
/*
* If there are multiple chips, we need to relax the timings to allow
......@@ -803,7 +805,8 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
if (GPMI_IS_MX23(this)) {
mask = MX23_BM_GPMI_DEBUG_READY0 << chip;
reg = readl(r->gpmi_regs + HW_GPMI_DEBUG);
} else if (GPMI_IS_MX28(this)) {
} else if (GPMI_IS_MX28(this) || GPMI_IS_MX6Q(this)) {
/* MX28 shares the same R/B register as MX6Q. */
mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
reg = readl(r->gpmi_regs + HW_GPMI_STAT);
} else
......
......@@ -25,6 +25,8 @@
#include <linux/mtd/gpmi-nand.h>
#include <linux/mtd/partitions.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include "gpmi-nand.h"
/* add our owner bbt descriptor */
......@@ -387,7 +389,7 @@ static void release_bch_irq(struct gpmi_nand_data *this)
static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
{
struct gpmi_nand_data *this = param;
struct resource *r = this->private;
int dma_channel = (int)this->private;
if (!mxs_dma_is_apbh(chan))
return false;
......@@ -399,7 +401,7 @@ static bool gpmi_dma_filter(struct dma_chan *chan, void *param)
* for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7
* (These eight channels share the same IRQ!)
*/
if (r->start <= chan->chan_id && chan->chan_id <= r->end) {
if (dma_channel == chan->chan_id) {
chan->private = &this->dma_data;
return true;
}
......@@ -419,57 +421,45 @@ static void release_dma_channels(struct gpmi_nand_data *this)
static int __devinit acquire_dma_channels(struct gpmi_nand_data *this)
{
struct platform_device *pdev = this->pdev;
struct gpmi_nand_platform_data *pdata = this->pdata;
struct resources *res = &this->resources;
struct resource *r, *r_dma;
unsigned int i;
struct resource *r_dma;
struct device_node *dn;
int dma_channel;
unsigned int ret;
struct dma_chan *dma_chan;
dma_cap_mask_t mask;
/* dma channel, we only use the first one. */
dn = pdev->dev.of_node;
ret = of_property_read_u32(dn, "fsl,gpmi-dma-channel", &dma_channel);
if (ret) {
pr_err("unable to get DMA channel from dt.\n");
goto acquire_err;
}
this->private = (void *)dma_channel;
r = platform_get_resource_byname(pdev, IORESOURCE_DMA,
GPMI_NAND_DMA_CHANNELS_RES_NAME);
/* gpmi dma interrupt */
r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
GPMI_NAND_DMA_INTERRUPT_RES_NAME);
if (!r || !r_dma) {
if (!r_dma) {
pr_err("Can't get resource for DMA\n");
return -ENXIO;
goto acquire_err;
}
this->dma_data.chan_irq = r_dma->start;
/* used in gpmi_dma_filter() */
this->private = r;
for (i = r->start; i <= r->end; i++) {
struct dma_chan *dma_chan;
dma_cap_mask_t mask;
/* request dma channel */
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
if (i - r->start >= pdata->max_chip_count)
break;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
/* get the DMA interrupt */
if (r_dma->start == r_dma->end) {
/* only register the first. */
if (i == r->start)
this->dma_data.chan_irq = r_dma->start;
else
this->dma_data.chan_irq = NO_IRQ;
} else
this->dma_data.chan_irq = r_dma->start + (i - r->start);
dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
if (!dma_chan)
goto acquire_err;
/* fill the first empty item */
this->dma_chans[i - r->start] = dma_chan;
dma_chan = dma_request_channel(mask, gpmi_dma_filter, this);
if (!dma_chan) {
pr_err("dma_request_channel failed.\n");
goto acquire_err;
}
res->dma_low_channel = r->start;
res->dma_high_channel = i;
this->dma_chans[0] = dma_chan;
return 0;
acquire_err:
pr_err("Can't acquire DMA channel %u\n", i);
release_dma_channels(this);
return -EINVAL;
}
......@@ -851,7 +841,7 @@ static void block_mark_swapping(struct gpmi_nand_data *this,
}
static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
uint8_t *buf, int oob_required, int page)
{
struct gpmi_nand_data *this = chip->priv;
struct bch_geometry *nfc_geo = &this->bch_geometry;
......@@ -917,28 +907,31 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
mtd->ecc_stats.corrected += corrected;
}
/*
* It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() for
* details about our policy for delivering the OOB.
*
* We fill the caller's buffer with set bits, and then copy the block
* mark to th caller's buffer. Note that, if block mark swapping was
* necessary, it has already been done, so we can rely on the first
* byte of the auxiliary buffer to contain the block mark.
*/
memset(chip->oob_poi, ~0, mtd->oobsize);
chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
if (oob_required) {
/*
* It's time to deliver the OOB bytes. See gpmi_ecc_read_oob()
* for details about our policy for delivering the OOB.
*
* We fill the caller's buffer with set bits, and then copy the
* block mark to th caller's buffer. Note that, if block mark
* swapping was necessary, it has already been done, so we can
* rely on the first byte of the auxiliary buffer to contain
* the block mark.
*/
memset(chip->oob_poi, ~0, mtd->oobsize);
chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
read_page_swap_end(this, buf, mtd->writesize,
this->payload_virt, this->payload_phys,
nfc_geo->payload_size,
payload_virt, payload_phys);
read_page_swap_end(this, buf, mtd->writesize,
this->payload_virt, this->payload_phys,
nfc_geo->payload_size,
payload_virt, payload_phys);
}
exit_nfc:
return ret;
}
static void gpmi_ecc_write_page(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf)
static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
struct gpmi_nand_data *this = chip->priv;
struct bch_geometry *nfc_geo = &this->bch_geometry;
......@@ -1077,7 +1070,7 @@ static void gpmi_ecc_write_page(struct mtd_info *mtd,
* this driver.
*/
static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page, int sndcmd)
int page)
{
struct gpmi_nand_data *this = chip->priv;
......@@ -1100,11 +1093,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
chip->oob_poi[0] = chip->read_byte(mtd);
}
/*
* Return true, indicating that the next call to this function must send
* a command.
*/
return true;
return 0;
}
static int
......@@ -1318,7 +1307,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
/* Write the first page of the current stride. */
dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
chip->ecc.write_page_raw(mtd, chip, buffer);
chip->ecc.write_page_raw(mtd, chip, buffer, 0);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
/* Wait for the write to finish. */
......@@ -1444,6 +1433,10 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this)
if (ret)
return ret;
/* Adjust the ECC strength according to the chip. */
this->nand.ecc.strength = this->bch_geometry.ecc_strength;
this->mtd.ecc_strength = this->bch_geometry.ecc_strength;
/* NAND boot init, depends on the gpmi_set_geometry(). */
return nand_boot_init(this);
}
......@@ -1471,9 +1464,9 @@ void gpmi_nfc_exit(struct gpmi_nand_data *this)
static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
{
struct gpmi_nand_platform_data *pdata = this->pdata;
struct mtd_info *mtd = &this->mtd;
struct nand_chip *chip = &this->nand;
struct mtd_part_parser_data ppdata = {};
int ret;
/* init current chip */
......@@ -1502,6 +1495,7 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
chip->options |= NAND_NO_SUBPAGE_WRITE;
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 1;
chip->ecc.strength = 8;
chip->ecc.layout = &gpmi_hw_ecclayout;
/* Allocate a temporary DMA buffer for reading ID in the nand_scan() */
......@@ -1511,14 +1505,14 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
if (ret)
goto err_out;
ret = nand_scan(mtd, pdata->max_chip_count);
ret = nand_scan(mtd, 1);
if (ret) {
pr_err("Chip scan failed\n");
goto err_out;
}
ret = mtd_device_parse_register(mtd, NULL, NULL,
pdata->partitions, pdata->partition_count);
ppdata.of_node = this->pdev->dev.of_node;
ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
if (ret)
goto err_out;
return 0;
......@@ -1528,12 +1522,41 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
return ret;
}
static const struct platform_device_id gpmi_ids[] = {
{ .name = "imx23-gpmi-nand", .driver_data = IS_MX23, },
{ .name = "imx28-gpmi-nand", .driver_data = IS_MX28, },
{ .name = "imx6q-gpmi-nand", .driver_data = IS_MX6Q, },
{},
};
static const struct of_device_id gpmi_nand_id_table[] = {
{
.compatible = "fsl,imx23-gpmi-nand",
.data = (void *)&gpmi_ids[IS_MX23]
}, {
.compatible = "fsl,imx28-gpmi-nand",
.data = (void *)&gpmi_ids[IS_MX28]
}, {
.compatible = "fsl,imx6q-gpmi-nand",
.data = (void *)&gpmi_ids[IS_MX6Q]
}, {}
};
MODULE_DEVICE_TABLE(of, gpmi_nand_id_table);
static int __devinit gpmi_nand_probe(struct platform_device *pdev)
{
struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data;
struct gpmi_nand_data *this;
const struct of_device_id *of_id;
int ret;
of_id = of_match_device(gpmi_nand_id_table, &pdev->dev);
if (of_id) {
pdev->id_entry = of_id->data;
} else {
pr_err("Failed to find the right device id.\n");
return -ENOMEM;
}
this = kzalloc(sizeof(*this), GFP_KERNEL);
if (!this) {
pr_err("Failed to allocate per-device memory\n");
......@@ -1543,13 +1566,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, this);
this->pdev = pdev;
this->dev = &pdev->dev;
this->pdata = pdata;
if (pdata->platform_init) {
ret = pdata->platform_init();
if (ret)
goto platform_init_error;
}
ret = acquire_resources(this);
if (ret)
......@@ -1567,7 +1583,6 @@ static int __devinit gpmi_nand_probe(struct platform_device *pdev)
exit_nfc_init:
release_resources(this);
platform_init_error:
exit_acquire_resources:
platform_set_drvdata(pdev, NULL);
kfree(this);
......@@ -1585,19 +1600,10 @@ static int __exit gpmi_nand_remove(struct platform_device *pdev)
return 0;
}
static const struct platform_device_id gpmi_ids[] = {
{
.name = "imx23-gpmi-nand",
.driver_data = IS_MX23,
}, {
.name = "imx28-gpmi-nand",
.driver_data = IS_MX28,
}, {},
};
static struct platform_driver gpmi_nand_driver = {
.driver = {
.name = "gpmi-nand",
.of_match_table = gpmi_nand_id_table,
},
.probe = gpmi_nand_probe,
.remove = __exit_p(gpmi_nand_remove),
......
......@@ -266,8 +266,10 @@ extern int gpmi_read_page(struct gpmi_nand_data *,
#define STATUS_UNCORRECTABLE 0xfe
/* Use the platform_id to distinguish different Archs. */
#define IS_MX23 0x1
#define IS_MX28 0x2
#define IS_MX23 0x0
#define IS_MX28 0x1
#define IS_MX6Q 0x2
#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23)
#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28)
#define GPMI_IS_MX6Q(x) ((x)->pdev->id_entry->driver_data == IS_MX6Q)
#endif
......@@ -124,7 +124,6 @@ static int __init h1910_init(void)
/* 15 us command delay time */
this->chip_delay = 50;
this->ecc.mode = NAND_ECC_SOFT;
this->options = NAND_NO_AUTOINCR;
/* Scan to find existence of the device */
if (nand_scan(h1910_nand_mtd, 1)) {
......
......@@ -332,11 +332,7 @@ static int __devinit jz_nand_probe(struct platform_device *pdev)
chip->ecc.mode = NAND_ECC_HW_OOB_FIRST;
chip->ecc.size = 512;
chip->ecc.bytes = 9;
chip->ecc.strength = 2;
/*
* FIXME: ecc_strength value of 2 bits per 512 bytes of data is a
* conservative guess, given 9 ecc bytes and reed-solomon alg.
*/
chip->ecc.strength = 4;
if (pdata)
chip->ecc.layout = pdata->ecc_layout;
......
......@@ -734,7 +734,6 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op)
chip->write_buf = mpc5121_nfc_write_buf;
chip->verify_buf = mpc5121_nfc_verify_buf;
chip->select_chip = mpc5121_nfc_select_chip;
chip->options = NAND_NO_AUTOINCR;
chip->bbt_options = NAND_BBT_USE_FLASH;
chip->ecc.mode = NAND_ECC_SOFT;
......
此差异已折叠。
此差异已折叠。
......@@ -324,6 +324,7 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
buf += mtd->oobsize + mtd->writesize;
len -= mtd->writesize;
offs += mtd->writesize;
}
return 0;
}
......
......@@ -70,7 +70,7 @@ struct nand_flash_dev nand_flash_ids[] = {
* These are the new chips with large page size. The pagesize and the
* erasesize is determined from the extended id bytes
*/
#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)
#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY)
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
/* 512 Megabit */
......@@ -157,9 +157,7 @@ struct nand_flash_dev nand_flash_ids[] = {
* writes possible, but not implemented now
*/
{"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000,
NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
BBT_AUTO_REFRESH
},
NAND_IS_AND | NAND_NO_READRDY | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
{NULL,}
};
......
......@@ -268,7 +268,6 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
#define OPT_PAGE512 0x00000002 /* 512-byte page chips */
#define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */
#define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */
#define OPT_AUTOINCR 0x00000020 /* page number auto incrementation is possible */
#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
#define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */
#define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
......@@ -594,7 +593,7 @@ static int init_nandsim(struct mtd_info *mtd)
ns->options |= OPT_PAGE256;
}
else if (ns->geom.pgsz == 512) {
ns->options |= (OPT_PAGE512 | OPT_AUTOINCR);
ns->options |= OPT_PAGE512;
if (ns->busw == 8)
ns->options |= OPT_PAGE512_8BIT;
} else if (ns->geom.pgsz == 2048) {
......@@ -663,8 +662,6 @@ static int init_nandsim(struct mtd_info *mtd)
for (i = 0; nand_flash_ids[i].name != NULL; i++) {
if (second_id_byte != nand_flash_ids[i].id)
continue;
if (!(nand_flash_ids[i].options & NAND_NO_AUTOINCR))
ns->options |= OPT_AUTOINCR;
}
if (ns->busw == 16)
......@@ -1936,20 +1933,8 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd)
if (ns->regs.count == ns->regs.num) {
NS_DBG("read_byte: all bytes were read\n");
/*
* The OPT_AUTOINCR allows to read next consecutive pages without
* new read operation cycle.
*/
if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) {
ns->regs.count = 0;
if (ns->regs.row + 1 < ns->geom.pgnum)
ns->regs.row += 1;
NS_DBG("read_byte: switch to the next page (%#x)\n", ns->regs.row);
do_state_action(ns, ACTION_CPY);
}
else if (NS_STATE(ns->nxstate) == STATE_READY)
if (NS_STATE(ns->nxstate) == STATE_READY)
switch_state(ns);
}
return outb;
......@@ -2203,14 +2188,7 @@ static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
ns->regs.count += len;
if (ns->regs.count == ns->regs.num) {
if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) {
ns->regs.count = 0;
if (ns->regs.row + 1 < ns->geom.pgnum)
ns->regs.row += 1;
NS_DBG("read_buf: switch to the next page (%#x)\n", ns->regs.row);
do_state_action(ns, ACTION_CPY);
}
else if (NS_STATE(ns->nxstate) == STATE_READY)
if (NS_STATE(ns->nxstate) == STATE_READY)
switch_state(ns);
}
......
......@@ -21,6 +21,10 @@
#include <linux/io.h>
#include <linux/slab.h>
#ifdef CONFIG_MTD_NAND_OMAP_BCH
#include <linux/bch.h>
#endif
#include <plat/dma.h>
#include <plat/gpmc.h>
#include <plat/nand.h>
......@@ -127,6 +131,11 @@ struct omap_nand_info {
} iomode;
u_char *buf;
int buf_len;
#ifdef CONFIG_MTD_NAND_OMAP_BCH
struct bch_control *bch;
struct nand_ecclayout ecclayout;
#endif
};
/**
......@@ -402,7 +411,7 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
PREFETCH_FIFOTHRESHOLD_MAX, 0x1, len, is_write);
if (ret)
/* PFPW engine is busy, use cpu copy method */
goto out_copy;
goto out_copy_unmap;
init_completion(&info->comp);
......@@ -421,6 +430,8 @@ static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
dma_unmap_single(&info->pdev->dev, dma_addr, len, dir);
return 0;
out_copy_unmap:
dma_unmap_single(&info->pdev->dev, dma_addr, len, dir);
out_copy:
if (info->nand.options & NAND_BUSWIDTH_16)
is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len)
......@@ -879,7 +890,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
unsigned long timeo = jiffies;
int status = NAND_STATUS_FAIL, state = this->state;
int status, state = this->state;
if (state == FL_ERASING)
timeo += (HZ * 400) / 1000;
......@@ -894,6 +905,8 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
break;
cond_resched();
}
status = gpmc_nand_read(info->gpmc_cs, GPMC_NAND_DATA);
return status;
}
......@@ -925,6 +938,226 @@ static int omap_dev_ready(struct mtd_info *mtd)
return 1;
}
#ifdef CONFIG_MTD_NAND_OMAP_BCH
/**
* omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction
* @mtd: MTD device structure
* @mode: Read/Write mode
*/
static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
{
int nerrors;
unsigned int dev_width;
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
struct nand_chip *chip = mtd->priv;
nerrors = (info->nand.ecc.bytes == 13) ? 8 : 4;
dev_width = (chip->options & NAND_BUSWIDTH_16) ? 1 : 0;
/*
* 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).
*/
(void)gpmc_enable_hwecc_bch(info->gpmc_cs, mode, dev_width, 1, nerrors);
}
/**
* omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes
* @mtd: MTD device structure
* @dat: The pointer to data on which ecc is computed
* @ecc_code: The ecc_code buffer
*/
static int omap3_calculate_ecc_bch4(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);
return gpmc_calculate_ecc_bch4(info->gpmc_cs, dat, ecc_code);
}
/**
* omap3_calculate_ecc_bch8 - Generate 13 bytes of ECC bytes
* @mtd: MTD device structure
* @dat: The pointer to data on which ecc is computed
* @ecc_code: The ecc_code buffer
*/
static int omap3_calculate_ecc_bch8(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);
return gpmc_calculate_ecc_bch8(info->gpmc_cs, dat, ecc_code);
}
/**
* omap3_correct_data_bch - Decode received data and correct errors
* @mtd: MTD device structure
* @data: page data
* @read_ecc: ecc read from nand flash
* @calc_ecc: ecc read from HW ECC registers
*/
static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data,
u_char *read_ecc, u_char *calc_ecc)
{
int i, count;
/* cannot correct more than 8 errors */
unsigned int errloc[8];
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL,
errloc);
if (count > 0) {
/* correct errors */
for (i = 0; i < count; i++) {
/* correct data only, not ecc bytes */
if (errloc[i] < 8*512)
data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
pr_debug("corrected bitflip %u\n", errloc[i]);
}
} else if (count < 0) {
pr_err("ecc unrecoverable error\n");
}
return count;
}
/**
* omap3_free_bch - Release BCH ecc resources
* @mtd: MTD device structure
*/
static void omap3_free_bch(struct mtd_info *mtd)
{
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
if (info->bch) {
free_bch(info->bch);
info->bch = NULL;
}
}
/**
* omap3_init_bch - Initialize BCH ECC
* @mtd: MTD device structure
* @ecc_opt: OMAP ECC mode (OMAP_ECC_BCH4_CODE_HW or OMAP_ECC_BCH8_CODE_HW)
*/
static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
{
int ret, max_errors;
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
#ifdef CONFIG_MTD_NAND_OMAP_BCH8
const int hw_errors = 8;
#else
const int hw_errors = 4;
#endif
info->bch = NULL;
max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ? 8 : 4;
if (max_errors != hw_errors) {
pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported",
max_errors, hw_errors);
goto fail;
}
/* initialize GPMC BCH engine */
ret = gpmc_init_hwecc_bch(info->gpmc_cs, 1, max_errors);
if (ret)
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.correct = omap3_correct_data_bch;
info->nand.ecc.mode = NAND_ECC_HW;
/*
* 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.strength = 8;
info->nand.ecc.bytes = 13;
info->nand.ecc.calculate = omap3_calculate_ecc_bch8;
} else {
info->nand.ecc.strength = 4;
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);
return 0;
fail:
omap3_free_bch(mtd);
return -1;
}
/**
* omap3_init_bch_tail - Build an oob layout for BCH ECC correction.
* @mtd: MTD device structure
*/
static int omap3_init_bch_tail(struct mtd_info *mtd)
{
int i, steps;
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
struct nand_ecclayout *layout = &info->ecclayout;
/* build oob layout */
steps = mtd->writesize/info->nand.ecc.size;
layout->eccbytes = steps*info->nand.ecc.bytes;
/* do not bother creating special oob layouts for small page devices */
if (mtd->oobsize < 64) {
pr_err("BCH ecc is not supported on small page devices\n");
goto fail;
}
/* reserve 2 bytes for bad block marker */
if (layout->eccbytes+2 > mtd->oobsize) {
pr_err("no oob layout available for oobsize %d eccbytes %u\n",
mtd->oobsize, layout->eccbytes);
goto fail;
}
/* put ecc bytes at oob tail */
for (i = 0; i < layout->eccbytes; i++)
layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
layout->oobfree[0].offset = 2;
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
info->nand.ecc.layout = layout;
if (!(info->nand.options & NAND_BUSWIDTH_16))
info->nand.badblock_pattern = &bb_descrip_flashbased;
return 0;
fail:
omap3_free_bch(mtd);
return -1;
}
#else
static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt)
{
pr_err("CONFIG_MTD_NAND_OMAP_BCH is not enabled\n");
return -1;
}
static int omap3_init_bch_tail(struct mtd_info *mtd)
{
return -1;
}
static void omap3_free_bch(struct mtd_info *mtd)
{
}
#endif /* CONFIG_MTD_NAND_OMAP_BCH */
static int __devinit omap_nand_probe(struct platform_device *pdev)
{
struct omap_nand_info *info;
......@@ -1063,6 +1296,13 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
info->nand.ecc.hwctl = omap_enable_hwecc;
info->nand.ecc.correct = omap_correct_data;
info->nand.ecc.mode = NAND_ECC_HW;
} else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
(pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
err = omap3_init_bch(&info->mtd, pdata->ecc_opt);
if (err) {
err = -EINVAL;
goto out_release_mem_region;
}
}
/* DIP switches on some boards change between 8 and 16 bit
......@@ -1094,6 +1334,14 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
(offset + omap_oobinfo.eccbytes);
info->nand.ecc.layout = &omap_oobinfo;
} else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) ||
(pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) {
/* build OOB layout for BCH ECC correction */
err = omap3_init_bch_tail(&info->mtd);
if (err) {
err = -EINVAL;
goto out_release_mem_region;
}
}
/* second phase scan */
......@@ -1122,6 +1370,7 @@ static int omap_nand_remove(struct platform_device *pdev)
struct mtd_info *mtd = platform_get_drvdata(pdev);
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
omap3_free_bch(&info->mtd);
platform_set_drvdata(pdev, NULL);
if (info->dma_ch != -1)
......
......@@ -155,7 +155,6 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev)
chip->ecc.mode = NAND_ECC_SOFT;
/* Enable the following for a flash based bad block table */
chip->options = NAND_NO_AUTOINCR;
chip->bbt_options = NAND_BBT_USE_FLASH;
/* Scan to find existence of the device */
......
......@@ -23,14 +23,18 @@ struct plat_nand_data {
void __iomem *io_base;
};
static const char *part_probe_types[] = { "cmdlinepart", NULL };
/*
* Probe for the NAND device.
*/
static int __devinit plat_nand_probe(struct platform_device *pdev)
{
struct platform_nand_data *pdata = pdev->dev.platform_data;
struct mtd_part_parser_data ppdata;
struct plat_nand_data *data;
struct resource *res;
const char **part_types;
int err = 0;
if (pdata->chip.nr_chips < 1) {
......@@ -75,6 +79,7 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
data->chip.select_chip = pdata->ctrl.select_chip;
data->chip.write_buf = pdata->ctrl.write_buf;
data->chip.read_buf = pdata->ctrl.read_buf;
data->chip.read_byte = pdata->ctrl.read_byte;
data->chip.chip_delay = pdata->chip.chip_delay;
data->chip.options |= pdata->chip.options;
data->chip.bbt_options |= pdata->chip.bbt_options;
......@@ -98,8 +103,10 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
goto out;
}
err = mtd_device_parse_register(&data->mtd,
pdata->chip.part_probe_types, NULL,
part_types = pdata->chip.part_probe_types ? : part_probe_types;
ppdata.of_node = pdev->dev.of_node;
err = mtd_device_parse_register(&data->mtd, part_types, &ppdata,
pdata->chip.partitions,
pdata->chip.nr_partitions);
......@@ -140,12 +147,19 @@ static int __devexit plat_nand_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id plat_nand_match[] = {
{ .compatible = "gen_nand" },
{},
};
MODULE_DEVICE_TABLE(of, plat_nand_match);
static struct platform_driver plat_nand_driver = {
.probe = plat_nand_probe,
.remove = __devexit_p(plat_nand_remove),
.driver = {
.name = "gen_nand",
.owner = THIS_MODULE,
.probe = plat_nand_probe,
.remove = __devexit_p(plat_nand_remove),
.driver = {
.name = "gen_nand",
.owner = THIS_MODULE,
.of_match_table = plat_nand_match,
},
};
......
......@@ -682,14 +682,15 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
}
static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, const uint8_t *buf)
struct nand_chip *chip, const uint8_t *buf, int oob_required)
{
chip->write_buf(mtd, buf, mtd->writesize);
chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
}
static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf, int page)
struct nand_chip *chip, uint8_t *buf, int oob_required,
int page)
{
struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
......@@ -1004,7 +1005,6 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
chip->ecc.size = host->page_size;
chip->ecc.strength = 1;
chip->options = NAND_NO_AUTOINCR;
chip->options |= NAND_NO_READRDY;
if (host->reg_ndcr & NDCR_DWIDTH_M)
chip->options |= NAND_BUSWIDTH_16;
......
......@@ -539,14 +539,11 @@ int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
* nand_read_oob_syndrome assumes we can send column address - we can't
*/
static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page, int sndcmd)
int page)
{
if (sndcmd) {
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
sndcmd = 0;
}
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
return sndcmd;
return 0;
}
/*
......@@ -1104,18 +1101,7 @@ static struct pci_driver r852_pci_driver = {
.driver.pm = &r852_pm_ops,
};
static __init int r852_module_init(void)
{
return pci_register_driver(&r852_pci_driver);
}
static void __exit r852_module_exit(void)
{
pci_unregister_driver(&r852_pci_driver);
}
module_init(r852_module_init);
module_exit(r852_module_exit);
module_pci_driver(r852_pci_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Maxim Levitsky <maximlevitsky@gmail.com>");
......
......@@ -344,7 +344,7 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
}
static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
uint8_t *buf, int oob_required, int page)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
......@@ -359,14 +359,14 @@ static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
if (flctl->hwecc_cant_correct[i])
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += 0;
mtd->ecc_stats.corrected += 0; /* FIXME */
}
return 0;
}
static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf)
const uint8_t *buf, int oob_required)
{
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
......@@ -881,8 +881,6 @@ static int __devinit flctl_probe(struct platform_device *pdev)
flctl->hwecc = pdata->has_hwecc;
flctl->holden = pdata->use_holden;
nand->options = NAND_NO_AUTOINCR;
/* Set address of hardware control function */
/* 20 us command delay time */
nand->chip_delay = 20;
......
......@@ -94,17 +94,16 @@ static struct nand_flash_dev nand_smartmedia_flash_ids[] = {
{NULL,}
};
#define XD_TYPEM (NAND_NO_AUTOINCR | NAND_BROKEN_XD)
static struct nand_flash_dev nand_xd_flash_ids[] = {
{"xD 16MiB 3,3V", 0x73, 512, 16, 0x4000, 0},
{"xD 32MiB 3,3V", 0x75, 512, 32, 0x4000, 0},
{"xD 64MiB 3,3V", 0x76, 512, 64, 0x4000, 0},
{"xD 128MiB 3,3V", 0x79, 512, 128, 0x4000, 0},
{"xD 256MiB 3,3V", 0x71, 512, 256, 0x4000, XD_TYPEM},
{"xD 512MiB 3,3V", 0xdc, 512, 512, 0x4000, XD_TYPEM},
{"xD 1GiB 3,3V", 0xd3, 512, 1024, 0x4000, XD_TYPEM},
{"xD 2GiB 3,3V", 0xd5, 512, 2048, 0x4000, XD_TYPEM},
{"xD 256MiB 3,3V", 0x71, 512, 256, 0x4000, NAND_BROKEN_XD},
{"xD 512MiB 3,3V", 0xdc, 512, 512, 0x4000, NAND_BROKEN_XD},
{"xD 1GiB 3,3V", 0xd3, 512, 1024, 0x4000, NAND_BROKEN_XD},
{"xD 2GiB 3,3V", 0xd5, 512, 2048, 0x4000, NAND_BROKEN_XD},
{NULL,}
};
......
......@@ -1201,7 +1201,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
if (mtd->ecc_stats.failed - stats.failed)
return -EBADMSG;
return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
/* return max bitflips per ecc step; ONENANDs correct 1 bit only */
return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
}
/**
......@@ -1333,7 +1334,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
if (mtd->ecc_stats.failed - stats.failed)
return -EBADMSG;
return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
/* return max bitflips per ecc step; ONENANDs correct 1 bit only */
return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
}
/**
......
......@@ -32,6 +32,13 @@ struct jffs2_inodirty;
struct jffs2_mount_opts {
bool override_compr;
unsigned int compr;
/* The size of the reserved pool. The reserved pool is the JFFS2 flash
* space which may only be used by root cannot be used by the other
* users. This is implemented simply by means of not allowing the
* latter users to write to the file system if the amount if the
* available space is less then 'rp_size'. */
unsigned int rp_size;
};
/* A struct for the overall file system control. Pointers to
......
......@@ -18,6 +18,37 @@
#include "nodelist.h"
#include "debug.h"
/*
* Check whether the user is allowed to write.
*/
static int jffs2_rp_can_write(struct jffs2_sb_info *c)
{
uint32_t avail;
struct jffs2_mount_opts *opts = &c->mount_opts;
avail = c->dirty_size + c->free_size + c->unchecked_size +
c->erasing_size - c->resv_blocks_write * c->sector_size
- c->nospc_dirty_size;
if (avail < 2 * opts->rp_size)
jffs2_dbg(1, "rpsize %u, dirty_size %u, free_size %u, "
"erasing_size %u, unchecked_size %u, "
"nr_erasing_blocks %u, avail %u, resrv %u\n",
opts->rp_size, c->dirty_size, c->free_size,
c->erasing_size, c->unchecked_size,
c->nr_erasing_blocks, avail, c->nospc_dirty_size);
if (avail > opts->rp_size)
return 1;
/* Always allow root */
if (capable(CAP_SYS_RESOURCE))
return 1;
jffs2_dbg(1, "forbid writing\n");
return 0;
}
/**
* jffs2_reserve_space - request physical space to write nodes to flash
* @c: superblock info
......@@ -55,6 +86,15 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
spin_lock(&c->erase_completion_lock);
/*
* Check if the free space is greater then size of the reserved pool.
* If not, only allow root to proceed with writing.
*/
if (prio != ALLOC_DELETION && !jffs2_rp_can_write(c)) {
ret = -ENOSPC;
goto out;
}
/* this needs a little more thought (true <tglx> :)) */
while(ret == -EAGAIN) {
while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) {
......@@ -158,6 +198,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
jffs2_dbg(1, "%s(): ret is %d\n", __func__, ret);
}
}
out:
spin_unlock(&c->erase_completion_lock);
if (!ret)
ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1);
......
......@@ -1266,19 +1266,25 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
/* Symlink's inode data is the target path. Read it and
* keep in RAM to facilitate quick follow symlink
* operation. */
f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
uint32_t csize = je32_to_cpu(latest_node->csize);
if (csize > JFFS2_MAX_NAME_LEN) {
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -ENAMETOOLONG;
}
f->target = kmalloc(csize + 1, GFP_KERNEL);
if (!f->target) {
JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize));
JFFS2_ERROR("can't allocate %u bytes of memory for the symlink target path cache\n", csize);
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
return -ENOMEM;
}
ret = jffs2_flash_read(c, ref_offset(rii.latest_ref) + sizeof(*latest_node),
je32_to_cpu(latest_node->csize), &retlen, (char *)f->target);
csize, &retlen, (char *)f->target);
if (ret || retlen != je32_to_cpu(latest_node->csize)) {
if (retlen != je32_to_cpu(latest_node->csize))
if (ret || retlen != csize) {
if (retlen != csize)
ret = -EIO;
kfree(f->target);
f->target = NULL;
......@@ -1287,7 +1293,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
return ret;
}
f->target[je32_to_cpu(latest_node->csize)] = '\0';
f->target[csize] = '\0';
dbg_readinode("symlink's target '%s' cached\n", f->target);
}
......@@ -1415,6 +1421,7 @@ int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i
mutex_unlock(&f->sem);
jffs2_do_clear_inode(c, f);
}
jffs2_xattr_do_crccheck_inode(c, ic);
kfree (f);
return ret;
}
......
......@@ -90,6 +90,8 @@ static int jffs2_show_options(struct seq_file *s, struct dentry *root)
if (opts->override_compr)
seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
if (opts->rp_size)
seq_printf(s, ",rp_size=%u", opts->rp_size / 1024);
return 0;
}
......@@ -154,15 +156,18 @@ static const struct export_operations jffs2_export_ops = {
* JFFS2 mount options.
*
* Opt_override_compr: override default compressor
* Opt_rp_size: size of reserved pool in KiB
* Opt_err: just end of array marker
*/
enum {
Opt_override_compr,
Opt_rp_size,
Opt_err,
};
static const match_table_t tokens = {
{Opt_override_compr, "compr=%s"},
{Opt_rp_size, "rp_size=%u"},
{Opt_err, NULL},
};
......@@ -170,6 +175,7 @@ static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
{
substring_t args[MAX_OPT_ARGS];
char *p, *name;
unsigned int opt;
if (!data)
return 0;
......@@ -207,6 +213,17 @@ static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
kfree(name);
c->mount_opts.override_compr = true;
break;
case Opt_rp_size:
if (match_int(&args[0], &opt))
return -EINVAL;
opt *= 1024;
if (opt > c->mtd->size) {
pr_warn("Too large reserve pool specified, max "
"is %llu KB\n", c->mtd->size / 1024);
return -EINVAL;
}
c->mount_opts.rp_size = opt;
break;
default:
pr_err("Error: unrecognized mount option '%s' or missing value\n",
p);
......
......@@ -11,6 +11,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define JFFS2_XATTR_IS_CORRUPTED 1
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
......@@ -153,7 +155,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
offset, je32_to_cpu(rx.hdr_crc), crc);
xd->flags |= JFFS2_XFLAGS_INVALID;
return -EIO;
return JFFS2_XATTR_IS_CORRUPTED;
}
totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len));
if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK
......@@ -169,7 +171,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat
je32_to_cpu(rx.xid), xd->xid,
je32_to_cpu(rx.version), xd->version);
xd->flags |= JFFS2_XFLAGS_INVALID;
return -EIO;
return JFFS2_XATTR_IS_CORRUPTED;
}
xd->xprefix = rx.xprefix;
xd->name_len = rx.name_len;
......@@ -227,12 +229,12 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum
data[xd->name_len] = '\0';
crc = crc32(0, data, length);
if (crc != xd->data_crc) {
JFFS2_WARNING("node CRC failed (JFFS2_NODETYPE_XREF)"
JFFS2_WARNING("node CRC failed (JFFS2_NODETYPE_XATTR)"
" at %#08x, read: 0x%08x calculated: 0x%08x\n",
ref_offset(xd->node), xd->data_crc, crc);
kfree(data);
xd->flags |= JFFS2_XFLAGS_INVALID;
return -EIO;
return JFFS2_XATTR_IS_CORRUPTED;
}
xd->flags |= JFFS2_XFLAGS_HOT;
......@@ -270,7 +272,7 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x
if (xd->xname)
return 0;
if (xd->flags & JFFS2_XFLAGS_INVALID)
return -EIO;
return JFFS2_XATTR_IS_CORRUPTED;
if (unlikely(is_xattr_datum_unchecked(c, xd)))
rc = do_verify_xattr_datum(c, xd);
if (!rc)
......@@ -435,6 +437,8 @@ static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datu
* is called to release xattr related objects when unmounting.
* check_xattr_ref_inode(c, ic)
* is used to confirm inode does not have duplicate xattr name/value pair.
* jffs2_xattr_do_crccheck_inode(c, ic)
* is used to force xattr data integrity check during the initial gc scan.
* -------------------------------------------------- */
static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref)
{
......@@ -462,7 +466,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
if (crc != je32_to_cpu(rr.node_crc)) {
JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n",
offset, je32_to_cpu(rr.node_crc), crc);
return -EIO;
return JFFS2_XATTR_IS_CORRUPTED;
}
if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK
|| je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF
......@@ -472,7 +476,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref
offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK,
je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF,
je32_to_cpu(rr.totlen), PAD(sizeof(rr)));
return -EIO;
return JFFS2_XATTR_IS_CORRUPTED;
}
ref->ino = je32_to_cpu(rr.ino);
ref->xid = je32_to_cpu(rr.xid);
......@@ -682,6 +686,11 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac
return rc;
}
void jffs2_xattr_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
{
check_xattr_ref_inode(c, ic);
}
/* -------- xattr subsystem functions ---------------
* jffs2_init_xattr_subsystem(c)
* is used to initialize semaphore and list_head, and some variables.
......
......@@ -77,6 +77,7 @@ extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c);
extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c,
uint32_t xid, uint32_t version);
extern void jffs2_xattr_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
extern void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
extern void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
......@@ -108,6 +109,7 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
#define jffs2_build_xattr_subsystem(c)
#define jffs2_clear_xattr_subsystem(c)
#define jffs2_xattr_do_crccheck_inode(c, ic)
#define jffs2_xattr_delete_inode(c, ic)
#define jffs2_xattr_free_inode(c, ic)
#define jffs2_verify_xattr(c) (1)
......
......@@ -23,12 +23,12 @@
#define GPMI_NAND_RES_SIZE 6
/* Resource names for the GPMI NAND driver. */
#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "GPMI NAND GPMI Registers"
#define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME "gpmi-nand"
#define GPMI_NAND_GPMI_INTERRUPT_RES_NAME "GPMI NAND GPMI Interrupt"
#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "GPMI NAND BCH Registers"
#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "GPMI NAND BCH Interrupt"
#define GPMI_NAND_BCH_REGS_ADDR_RES_NAME "bch"
#define GPMI_NAND_BCH_INTERRUPT_RES_NAME "bch"
#define GPMI_NAND_DMA_CHANNELS_RES_NAME "GPMI NAND DMA Channels"
#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "GPMI NAND DMA Interrupt"
#define GPMI_NAND_DMA_INTERRUPT_RES_NAME "gpmi-dma"
/**
* struct gpmi_nand_platform_data - GPMI NAND driver platform data.
......
......@@ -157,6 +157,15 @@ struct mtd_info {
unsigned int erasesize_mask;
unsigned int writesize_mask;
/*
* read ops return -EUCLEAN if max number of bitflips corrected on any
* one region comprising an ecc step equals or exceeds this value.
* Settable by driver, else defaults to ecc_strength. User can override
* in sysfs. N.B. The meaning of the -EUCLEAN return code has changed;
* see Documentation/ABI/testing/sysfs-class-mtd for more detail.
*/
unsigned int bitflip_threshold;
// Kernel-only stuff starts here.
const char *name;
int index;
......@@ -164,7 +173,7 @@ struct mtd_info {
/* ECC layout structure pointer - read only! */
struct nand_ecclayout *ecclayout;
/* max number of correctible bit errors per writesize */
/* max number of correctible bit errors per ecc step */
unsigned int ecc_strength;
/* Data for variable erase regions. If numeraseregions is zero,
......
......@@ -161,8 +161,6 @@ typedef enum {
* Option constants for bizarre disfunctionality and real
* features.
*/
/* Chip can not auto increment pages */
#define NAND_NO_AUTOINCR 0x00000001
/* Buswidth is 16 bit */
#define NAND_BUSWIDTH_16 0x00000002
/* Device supports partial programming without padding */
......@@ -207,7 +205,6 @@ typedef enum {
(NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
/* Macros to identify the above */
#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
......@@ -216,7 +213,7 @@ typedef enum {
&& (chip->page_shift > 9))
/* Mask to zero out the chip options, which come from the id table */
#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR)
#define NAND_CHIPOPTIONS_MSK 0x0000ffff
/* Non chip related options */
/* This option skips the bbt scan during initialization. */
......@@ -363,21 +360,20 @@ struct nand_ecc_ctrl {
int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc,
uint8_t *calc_ecc);
int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page);
uint8_t *buf, int oob_required, int page);
void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf);
const uint8_t *buf, int oob_required);
int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page);
uint8_t *buf, int oob_required, int page);
int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offs, uint32_t len, uint8_t *buf);
void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf);
const uint8_t *buf, int oob_required);
int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
int page);
int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
int page, int sndcmd);
int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page,
int sndcmd);
int page);
int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page);
int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip,
int page);
};
......@@ -459,6 +455,8 @@ struct nand_buffers {
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
* @pagebuf: [INTERN] holds the pagenumber which is currently in
* data_buf.
* @pagebuf_bitflips: [INTERN] holds the bitflip count for the page which is
* currently in data_buf.
* @subpagesize: [INTERN] holds the subpagesize
* @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded),
* non 0 if ONFI supported.
......@@ -505,7 +503,8 @@ struct nand_chip {
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
int status, int page);
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int page, int cached, int raw);
const uint8_t *buf, int oob_required, int page,
int cached, int raw);
int chip_delay;
unsigned int options;
......@@ -519,6 +518,7 @@ struct nand_chip {
uint64_t chipsize;
int pagemask;
int pagebuf;
unsigned int pagebuf_bitflips;
int subpagesize;
uint8_t cellinfo;
int badblockpos;
......@@ -654,6 +654,7 @@ struct platform_nand_ctrl {
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
unsigned char (*read_byte)(struct mtd_info *mtd);
void *priv;
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册