Commit 8f40842e authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MTD updates from Brian Norris:
 "NAND:
   - Add sunxi_nand randomizer support
   - begin refactoring NAND ecclayout structs
   - fix pxa3xx_nand dmaengine usage
   - brcmnand: fix support for v7.1 controller
   - add Qualcomm NAND controller driver

  SPI NOR:
   - add new ls1021a, ls2080a support to Freescale QuadSPI
   - add new flash ID entries
   - support bottom-block protection for Winbond flash
   - support Status Register Write Protect
   - remove broken QPI support for Micron SPI flash

  JFFS2:
   - improve post-mount CRC scan efficiency

  General:
   - refactor bcm63xxpart parser, to later extend for NAND
   - add writebuf size parameter to mtdram

  Other minor code quality improvements"

* tag 'for-linus-20160324' of git://git.infradead.org/linux-mtd: (72 commits)
  mtd: nand: remove kerneldoc for removed function parameter
  mtd: nand: Qualcomm NAND controller driver
  dt/bindings: qcom_nandc: Add DT bindings
  mtd: nand: don't select chip in nand_chip's block_bad op
  mtd: spi-nor: support lock/unlock for a few Winbond chips
  mtd: spi-nor: add TB (Top/Bottom) protect support
  mtd: spi-nor: add SPI_NOR_HAS_LOCK flag
  mtd: spi-nor: use BIT() for flash_info flags
  mtd: spi-nor: disallow further writes to SR if WP# is low
  mtd: spi-nor: make lock/unlock bounds checks more obvious and robust
  mtd: spi-nor: silently drop lock/unlock for already locked/unlocked region
  mtd: spi-nor: wait for SR_WIP to clear on initial unlock
  mtd: nand: simplify nand_bch_init() usage
  mtd: mtdswap: remove useless if (!mtd->ecclayout) test
  mtd: create an mtd_oobavail() helper and make use of it
  mtd: kill the ecclayout->oobavail field
  mtd: nand: check status before reporting timeout
  mtd: bcm63xxpart: give width specifier an 'int', not 'size_t'
  mtd: mtdram: Add parameter for setting writebuf size
  mtd: nand: pxa3xx_nand: kill unused field 'drcmr_cmd'
  ...
parents 88875667 6871c1b9
Atmel NAND flash Atmel NAND flash
Required properties: Required properties:
- compatible : should be "atmel,at91rm9200-nand" or "atmel,sama5d4-nand". - compatible: The possible values are:
"atmel,at91rm9200-nand"
"atmel,sama5d2-nand"
"atmel,sama5d4-nand"
- reg : should specify localbus address and size used for the chip, - reg : should specify localbus address and size used for the chip,
and hardware ECC controller if available. and hardware ECC controller if available.
If the hardware ECC is PMECC, it should contain address and size for If the hardware ECC is PMECC, it should contain address and size for
...@@ -21,10 +24,11 @@ Optional properties: ...@@ -21,10 +24,11 @@ Optional properties:
- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default. - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first", Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
"soft_bch". "soft_bch".
- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware. - atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware,
Only supported by at91sam9x5 or later sam9 product. capable of BCH encoding and decoding, on devices where it is present.
- atmel,pmecc-cap : error correct capability for Programmable Multibit ECC - atmel,pmecc-cap : error correct capability for Programmable Multibit ECC
Controller. Supported values are: 2, 4, 8, 12, 24. Controller. Supported values are: 2, 4, 8, 12, 24. If the compatible string
is "atmel,sama5d2-nand", 32 is also valid.
- atmel,pmecc-sector-size : sector size for ECC computation. Supported values - atmel,pmecc-sector-size : sector size for ECC computation. Supported values
are: 512, 1024. are: 512, 1024.
- atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM - atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM
...@@ -32,15 +36,16 @@ Optional properties: ...@@ -32,15 +36,16 @@ Optional properties:
sector size 1024. If not specified, driver will build the table in runtime. sector size 1024. If not specified, driver will build the table in runtime.
- nand-bus-width : 8 or 16 bus width if not present 8 - nand-bus-width : 8 or 16 bus width if not present 8
- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
- Nand Flash Controller(NFC) is a slave driver under Atmel nand flash
- Required properties: Nand Flash Controller(NFC) is an optional sub-node
- compatible : "atmel,sama5d3-nfc". Required properties:
- reg : should specify the address and size used for NFC command registers, - compatible : "atmel,sama5d3-nfc" or "atmel,sama5d4-nfc".
NFC registers and NFC Sram. NFC Sram address and size can be absent - reg : should specify the address and size used for NFC command registers,
if don't want to use it. NFC registers and NFC SRAM. NFC SRAM address and size can be absent
- clocks: phandle to the peripheral clock if don't want to use it.
- Optional properties: - clocks: phandle to the peripheral clock
- atmel,write-by-sram: boolean to enable NFC write by sram. Optional properties:
- atmel,write-by-sram: boolean to enable NFC write by SRAM.
Examples: Examples:
nand0: nand@40000000,0 { nand0: nand@40000000,0 {
......
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
Required properties: Required properties:
- compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi", - compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi",
"fsl,imx7d-qspi", "fsl,imx6ul-qspi", "fsl,imx7d-qspi", "fsl,imx6ul-qspi",
"fsl,ls1021-qspi" "fsl,ls1021a-qspi"
or
"fsl,ls2080a-qspi" followed by "fsl,ls1021a-qspi"
- reg : the first contains the register location and length, - reg : the first contains the register location and length,
the second contains the memory mapping address and length the second contains the memory mapping address and length
- reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory"
...@@ -19,6 +21,7 @@ Optional properties: ...@@ -19,6 +21,7 @@ Optional properties:
But if there are two NOR flashes connected to the But if there are two NOR flashes connected to the
bus, you should enable this property. bus, you should enable this property.
(Please check the board's schematic.) (Please check the board's schematic.)
- big-endian : That means the IP register is big endian
Example: Example:
......
* Qualcomm NAND controller
Required properties:
- compatible: should be "qcom,ipq806x-nand"
- reg: MMIO address range
- clocks: must contain core clock and always on clock
- clock-names: must contain "core" for the core clock and "aon" for the
always on clock
- dmas: DMA specifier, consisting of a phandle to the ADM DMA
controller node and the channel number to be used for
NAND. Refer to dma.txt and qcom_adm.txt for more details
- dma-names: must be "rxtx"
- qcom,cmd-crci: must contain the ADM command type CRCI block instance
number specified for the NAND controller on the given
platform
- qcom,data-crci: must contain the ADM data type CRCI block instance
number specified for the NAND controller on the given
platform
- #address-cells: <1> - subnodes give the chip-select number
- #size-cells: <0>
* NAND chip-select
Each controller may contain one or more subnodes to represent enabled
chip-selects which (may) contain NAND flash chips. Their properties are as
follows.
Required properties:
- compatible: should contain "qcom,nandcs"
- reg: a single integer representing the chip-select
number (e.g., 0, 1, 2, etc.)
- #address-cells: see partition.txt
- #size-cells: see partition.txt
- nand-ecc-strength: see nand.txt
- nand-ecc-step-size: must be 512. see nand.txt for more details.
Optional properties:
- nand-bus-width: see nand.txt
Each nandcs device node may optionally contain a 'partitions' sub-node, which
further contains sub-nodes describing the flash partition mapping. See
partition.txt for more detail.
Example:
nand@1ac00000 {
compatible = "qcom,ebi2-nandc";
reg = <0x1ac00000 0x800>;
clocks = <&gcc EBI2_CLK>,
<&gcc EBI2_AON_CLK>;
clock-names = "core", "aon";
dmas = <&adm_dma 3>;
dma-names = "rxtx";
qcom,cmd-crci = <15>;
qcom,data-crci = <3>;
#address-cells = <1>;
#size-cells = <0>;
nandcs@0 {
compatible = "qcom,nandcs";
reg = <0>;
nand-ecc-strength = <4>;
nand-ecc-step-size = <512>;
nand-bus-width = <8>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "boot-nand";
reg = <0 0x58a0000>;
};
partition@58a0000 {
label = "fs-nand";
reg = <0x58a0000 0x4000000>;
};
};
};
};
...@@ -727,15 +727,6 @@ static int __init s3c_nand_copy_set(struct s3c2410_nand_set *set) ...@@ -727,15 +727,6 @@ static int __init s3c_nand_copy_set(struct s3c2410_nand_set *set)
return -ENOMEM; return -ENOMEM;
} }
if (set->ecc_layout) {
ptr = kmemdup(set->ecc_layout,
sizeof(struct nand_ecclayout), GFP_KERNEL);
set->ecc_layout = ptr;
if (!ptr)
return -ENOMEM;
}
return 0; return 0;
} }
......
...@@ -25,8 +25,6 @@ struct jz_nand_platform_data { ...@@ -25,8 +25,6 @@ struct jz_nand_platform_data {
int num_partitions; int num_partitions;
struct mtd_partition *partitions; struct mtd_partition *partitions;
struct nand_ecclayout *ecc_layout;
unsigned char banks[JZ_NAND_NUM_BANKS]; unsigned char banks[JZ_NAND_NUM_BANKS];
void (*ident_callback)(struct platform_device *, struct nand_chip *, void (*ident_callback)(struct platform_device *, struct nand_chip *,
......
...@@ -260,7 +260,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev) ...@@ -260,7 +260,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
/* get the Controller level irq */ /* get the Controller level irq */
fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0); fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
if (fsl_ifc_ctrl_dev->irq == NO_IRQ) { if (fsl_ifc_ctrl_dev->irq == 0) {
dev_err(&dev->dev, "failed to get irq resource " dev_err(&dev->dev, "failed to get irq resource "
"for IFC\n"); "for IFC\n");
ret = -ENODEV; ret = -ENODEV;
......
...@@ -142,7 +142,7 @@ config MTD_AR7_PARTS ...@@ -142,7 +142,7 @@ config MTD_AR7_PARTS
config MTD_BCM63XX_PARTS config MTD_BCM63XX_PARTS
tristate "BCM63XX CFE partitioning support" tristate "BCM63XX CFE partitioning support"
depends on BCM63XX depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST
select CRC32 select CRC32
help help
This provides partions parsing for BCM63xx devices with CFE This provides partions parsing for BCM63xx devices with CFE
......
...@@ -66,11 +66,13 @@ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master, ...@@ -66,11 +66,13 @@ static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
{ {
uint32_t buf; uint32_t buf;
size_t bytes_read; size_t bytes_read;
int err;
if (mtd_read(master, offset, sizeof(buf), &bytes_read, err = mtd_read(master, offset, sizeof(buf), &bytes_read,
(uint8_t *)&buf) < 0) { (uint8_t *)&buf);
pr_err("mtd_read error while parsing (offset: 0x%X)!\n", if (err && !mtd_is_bitflip(err)) {
offset); pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
offset, err);
goto out_default; goto out_default;
} }
...@@ -95,6 +97,7 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -95,6 +97,7 @@ static int bcm47xxpart_parse(struct mtd_info *master,
int trx_part = -1; int trx_part = -1;
int last_trx_part = -1; int last_trx_part = -1;
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, }; int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
int err;
/* /*
* Some really old flashes (like AT45DB*) had smaller erasesize-s, but * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
...@@ -118,8 +121,8 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -118,8 +121,8 @@ static int bcm47xxpart_parse(struct mtd_info *master,
/* Parse block by block looking for magics */ /* Parse block by block looking for magics */
for (offset = 0; offset <= master->size - blocksize; for (offset = 0; offset <= master->size - blocksize;
offset += blocksize) { offset += blocksize) {
/* Nothing more in higher memory */ /* Nothing more in higher memory on BCM47XX (MIPS) */
if (offset >= 0x2000000) if (config_enabled(CONFIG_BCM47XX) && offset >= 0x2000000)
break; break;
if (curr_part >= BCM47XXPART_MAX_PARTS) { if (curr_part >= BCM47XXPART_MAX_PARTS) {
...@@ -128,10 +131,11 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -128,10 +131,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
} }
/* Read beginning of the block */ /* Read beginning of the block */
if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ, err = mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
&bytes_read, (uint8_t *)buf) < 0) { &bytes_read, (uint8_t *)buf);
pr_err("mtd_read error while parsing (offset: 0x%X)!\n", if (err && !mtd_is_bitflip(err)) {
offset); pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
offset, err);
continue; continue;
} }
...@@ -254,10 +258,11 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -254,10 +258,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
} }
/* Read middle of the block */ /* Read middle of the block */
if (mtd_read(master, offset + 0x8000, 0x4, err = mtd_read(master, offset + 0x8000, 0x4, &bytes_read,
&bytes_read, (uint8_t *)buf) < 0) { (uint8_t *)buf);
pr_err("mtd_read error while parsing (offset: 0x%X)!\n", if (err && !mtd_is_bitflip(err)) {
offset); pr_err("mtd_read error while parsing (offset: 0x%X): %d\n",
offset, err);
continue; continue;
} }
...@@ -277,10 +282,11 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -277,10 +282,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
} }
offset = master->size - possible_nvram_sizes[i]; offset = master->size - possible_nvram_sizes[i];
if (mtd_read(master, offset, 0x4, &bytes_read, err = mtd_read(master, offset, 0x4, &bytes_read,
(uint8_t *)buf) < 0) { (uint8_t *)buf);
pr_err("mtd_read error while reading at offset 0x%X!\n", if (err && !mtd_is_bitflip(err)) {
offset); pr_err("mtd_read error while reading (offset 0x%X): %d\n",
offset, err);
continue; continue;
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bcm963xx_nvram.h>
#include <linux/bcm963xx_tag.h> #include <linux/bcm963xx_tag.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -34,12 +35,15 @@ ...@@ -34,12 +35,15 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <asm/mach-bcm63xx/bcm63xx_nvram.h> #define BCM963XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */
#include <asm/mach-bcm63xx/board_bcm963xx.h>
#define BCM63XX_CFE_BLOCK_SIZE SZ_64K /* always at least 64KiB */ #define BCM963XX_CFE_MAGIC_OFFSET 0x4e0
#define BCM963XX_CFE_VERSION_OFFSET 0x570
#define BCM963XX_NVRAM_OFFSET 0x580
#define BCM63XX_CFE_MAGIC_OFFSET 0x4e0 /* Ensure strings read from flash structs are null terminated */
#define STR_NULL_TERMINATE(x) \
do { char *_str = (x); _str[sizeof(x) - 1] = 0; } while (0)
static int bcm63xx_detect_cfe(struct mtd_info *master) static int bcm63xx_detect_cfe(struct mtd_info *master)
{ {
...@@ -58,68 +62,130 @@ static int bcm63xx_detect_cfe(struct mtd_info *master) ...@@ -58,68 +62,130 @@ static int bcm63xx_detect_cfe(struct mtd_info *master)
return 0; return 0;
/* very old CFE's do not have the cfe-v string, so check for magic */ /* very old CFE's do not have the cfe-v string, so check for magic */
ret = mtd_read(master, BCM63XX_CFE_MAGIC_OFFSET, 8, &retlen, ret = mtd_read(master, BCM963XX_CFE_MAGIC_OFFSET, 8, &retlen,
(void *)buf); (void *)buf);
buf[retlen] = 0; buf[retlen] = 0;
return strncmp("CFE1CFE1", buf, 8); return strncmp("CFE1CFE1", buf, 8);
} }
static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, static int bcm63xx_read_nvram(struct mtd_info *master,
const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram)
struct mtd_part_parser_data *data) {
u32 actual_crc, expected_crc;
size_t retlen;
int ret;
/* extract nvram data */
ret = mtd_read(master, BCM963XX_NVRAM_OFFSET, BCM963XX_NVRAM_V5_SIZE,
&retlen, (void *)nvram);
if (ret)
return ret;
ret = bcm963xx_nvram_checksum(nvram, &expected_crc, &actual_crc);
if (ret)
pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
expected_crc, actual_crc);
if (!nvram->psi_size)
nvram->psi_size = BCM963XX_DEFAULT_PSI_SIZE;
return 0;
}
static int bcm63xx_read_image_tag(struct mtd_info *master, const char *name,
loff_t tag_offset, struct bcm_tag *buf)
{
int ret;
size_t retlen;
u32 computed_crc;
ret = mtd_read(master, tag_offset, sizeof(*buf), &retlen, (void *)buf);
if (ret)
return ret;
if (retlen != sizeof(*buf))
return -EIO;
computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf,
offsetof(struct bcm_tag, header_crc));
if (computed_crc == buf->header_crc) {
STR_NULL_TERMINATE(buf->board_id);
STR_NULL_TERMINATE(buf->tag_version);
pr_info("%s: CFE image tag found at 0x%llx with version %s, board type %s\n",
name, tag_offset, buf->tag_version, buf->board_id);
return 0;
}
pr_warn("%s: CFE image tag at 0x%llx CRC invalid (expected %08x, actual %08x)\n",
name, tag_offset, buf->header_crc, computed_crc);
return 1;
}
static int bcm63xx_parse_cfe_nor_partitions(struct mtd_info *master,
const struct mtd_partition **pparts, struct bcm963xx_nvram *nvram)
{ {
/* CFE, NVRAM and global Linux are always present */ /* CFE, NVRAM and global Linux are always present */
int nrparts = 3, curpart = 0; int nrparts = 3, curpart = 0;
struct bcm_tag *buf; struct bcm_tag *buf = NULL;
struct mtd_partition *parts; struct mtd_partition *parts;
int ret; int ret;
size_t retlen;
unsigned int rootfsaddr, kerneladdr, spareaddr; unsigned int rootfsaddr, kerneladdr, spareaddr;
unsigned int rootfslen, kernellen, sparelen, totallen; unsigned int rootfslen, kernellen, sparelen, totallen;
unsigned int cfelen, nvramlen; unsigned int cfelen, nvramlen;
unsigned int cfe_erasesize; unsigned int cfe_erasesize;
int i; int i;
u32 computed_crc;
bool rootfs_first = false; bool rootfs_first = false;
if (bcm63xx_detect_cfe(master))
return -EINVAL;
cfe_erasesize = max_t(uint32_t, master->erasesize, cfe_erasesize = max_t(uint32_t, master->erasesize,
BCM63XX_CFE_BLOCK_SIZE); BCM963XX_CFE_BLOCK_SIZE);
cfelen = cfe_erasesize; cfelen = cfe_erasesize;
nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K; nvramlen = nvram->psi_size * SZ_1K;
nvramlen = roundup(nvramlen, cfe_erasesize); nvramlen = roundup(nvramlen, cfe_erasesize);
/* Allocate memory for buffer */
buf = vmalloc(sizeof(struct bcm_tag)); buf = vmalloc(sizeof(struct bcm_tag));
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
/* Get the tag */ /* Get the tag */
ret = mtd_read(master, cfelen, sizeof(struct bcm_tag), &retlen, ret = bcm63xx_read_image_tag(master, "rootfs", cfelen, buf);
(void *)buf); if (!ret) {
STR_NULL_TERMINATE(buf->flash_image_start);
if (retlen != sizeof(struct bcm_tag)) { if (kstrtouint(buf->flash_image_start, 10, &rootfsaddr) ||
vfree(buf); rootfsaddr < BCM963XX_EXTENDED_SIZE) {
return -EIO; pr_err("invalid rootfs address: %*ph\n",
} (int)sizeof(buf->flash_image_start),
buf->flash_image_start);
goto invalid_tag;
}
computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf, STR_NULL_TERMINATE(buf->kernel_address);
offsetof(struct bcm_tag, header_crc)); if (kstrtouint(buf->kernel_address, 10, &kerneladdr) ||
if (computed_crc == buf->header_crc) { kerneladdr < BCM963XX_EXTENDED_SIZE) {
char *boardid = &(buf->board_id[0]); pr_err("invalid kernel address: %*ph\n",
char *tagversion = &(buf->tag_version[0]); (int)sizeof(buf->kernel_address),
buf->kernel_address);
goto invalid_tag;
}
sscanf(buf->flash_image_start, "%u", &rootfsaddr); STR_NULL_TERMINATE(buf->kernel_length);
sscanf(buf->kernel_address, "%u", &kerneladdr); if (kstrtouint(buf->kernel_length, 10, &kernellen)) {
sscanf(buf->kernel_length, "%u", &kernellen); pr_err("invalid kernel length: %*ph\n",
sscanf(buf->total_length, "%u", &totallen); (int)sizeof(buf->kernel_length),
buf->kernel_length);
goto invalid_tag;
}
pr_info("CFE boot tag found with version %s and board type %s\n", STR_NULL_TERMINATE(buf->total_length);
tagversion, boardid); if (kstrtouint(buf->total_length, 10, &totallen)) {
pr_err("invalid total length: %*ph\n",
(int)sizeof(buf->total_length),
buf->total_length);
goto invalid_tag;
}
kerneladdr = kerneladdr - BCM963XX_EXTENDED_SIZE; kerneladdr = kerneladdr - BCM963XX_EXTENDED_SIZE;
rootfsaddr = rootfsaddr - BCM963XX_EXTENDED_SIZE; rootfsaddr = rootfsaddr - BCM963XX_EXTENDED_SIZE;
...@@ -134,13 +200,14 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, ...@@ -134,13 +200,14 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
rootfsaddr = kerneladdr + kernellen; rootfsaddr = kerneladdr + kernellen;
rootfslen = spareaddr - rootfsaddr; rootfslen = spareaddr - rootfsaddr;
} }
} else { } else if (ret > 0) {
pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n", invalid_tag:
buf->header_crc, computed_crc);
kernellen = 0; kernellen = 0;
rootfslen = 0; rootfslen = 0;
rootfsaddr = 0; rootfsaddr = 0;
spareaddr = cfelen; spareaddr = cfelen;
} else {
goto out;
} }
sparelen = master->size - spareaddr - nvramlen; sparelen = master->size - spareaddr - nvramlen;
...@@ -151,11 +218,10 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, ...@@ -151,11 +218,10 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
if (kernellen > 0) if (kernellen > 0)
nrparts++; nrparts++;
/* Ask kernel for more memory */
parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL);
if (!parts) { if (!parts) {
vfree(buf); ret = -ENOMEM;
return -ENOMEM; goto out;
} }
/* Start building partition list */ /* Start building partition list */
...@@ -206,9 +272,43 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, ...@@ -206,9 +272,43 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
sparelen); sparelen);
*pparts = parts; *pparts = parts;
ret = 0;
out:
vfree(buf); vfree(buf);
if (ret)
return ret;
return nrparts; return nrparts;
}
static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
const struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
{
struct bcm963xx_nvram *nvram = NULL;
int ret;
if (bcm63xx_detect_cfe(master))
return -EINVAL;
nvram = vzalloc(sizeof(*nvram));
if (!nvram)
return -ENOMEM;
ret = bcm63xx_read_nvram(master, nvram);
if (ret)
goto out;
if (!mtd_type_is_nand(master))
ret = bcm63xx_parse_cfe_nor_partitions(master, pparts, nvram);
else
ret = -EINVAL;
out:
vfree(nvram);
return ret;
}; };
static struct mtd_part_parser bcm63xx_cfe_parser = { static struct mtd_part_parser bcm63xx_cfe_parser = {
......
...@@ -72,13 +72,11 @@ MODULE_PARM_DESC(reliable_mode, "Set the docg3 mode (0=normal MLC, 1=fast, " ...@@ -72,13 +72,11 @@ MODULE_PARM_DESC(reliable_mode, "Set the docg3 mode (0=normal MLC, 1=fast, "
* @eccbytes: 8 bytes are used (1 for Hamming ECC, 7 for BCH ECC) * @eccbytes: 8 bytes are used (1 for Hamming ECC, 7 for BCH ECC)
* @eccpos: ecc positions (byte 7 is Hamming ECC, byte 8-14 are BCH ECC) * @eccpos: ecc positions (byte 7 is Hamming ECC, byte 8-14 are BCH ECC)
* @oobfree: free pageinfo bytes (byte 0 until byte 6, byte 15 * @oobfree: free pageinfo bytes (byte 0 until byte 6, byte 15
* @oobavail: 8 available bytes remaining after ECC toll
*/ */
static struct nand_ecclayout docg3_oobinfo = { static struct nand_ecclayout docg3_oobinfo = {
.eccbytes = 8, .eccbytes = 8,
.eccpos = {7, 8, 9, 10, 11, 12, 13, 14}, .eccpos = {7, 8, 9, 10, 11, 12, 13, 14},
.oobfree = {{0, 7}, {15, 1} }, .oobfree = {{0, 7}, {15, 1} },
.oobavail = 8,
}; };
static inline u8 doc_readb(struct docg3 *docg3, u16 reg) static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
...@@ -1438,7 +1436,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, ...@@ -1438,7 +1436,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
oobdelta = mtd->oobsize; oobdelta = mtd->oobsize;
break; break;
case MTD_OPS_AUTO_OOB: case MTD_OPS_AUTO_OOB:
oobdelta = mtd->ecclayout->oobavail; oobdelta = mtd->oobavail;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -1860,6 +1858,7 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) ...@@ -1860,6 +1858,7 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
mtd->_write_oob = doc_write_oob; mtd->_write_oob = doc_write_oob;
mtd->_block_isbad = doc_block_isbad; mtd->_block_isbad = doc_block_isbad;
mtd->ecclayout = &docg3_oobinfo; mtd->ecclayout = &docg3_oobinfo;
mtd->oobavail = 8;
mtd->ecc_strength = DOC_ECC_BCH_T; mtd->ecc_strength = DOC_ECC_BCH_T;
return 0; return 0;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE; static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE; static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
static unsigned long writebuf_size = 64;
#define MTDRAM_TOTAL_SIZE (total_size * 1024) #define MTDRAM_TOTAL_SIZE (total_size * 1024)
#define MTDRAM_ERASE_SIZE (erase_size * 1024) #define MTDRAM_ERASE_SIZE (erase_size * 1024)
...@@ -27,6 +28,8 @@ module_param(total_size, ulong, 0); ...@@ -27,6 +28,8 @@ module_param(total_size, ulong, 0);
MODULE_PARM_DESC(total_size, "Total device size in KiB"); MODULE_PARM_DESC(total_size, "Total device size in KiB");
module_param(erase_size, ulong, 0); module_param(erase_size, ulong, 0);
MODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
module_param(writebuf_size, ulong, 0);
MODULE_PARM_DESC(writebuf_size, "Device write buf size in Bytes (Default: 64)");
#endif #endif
// We could store these in the mtd structure, but we only support 1 device.. // We could store these in the mtd structure, but we only support 1 device..
...@@ -123,7 +126,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, ...@@ -123,7 +126,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
mtd->flags = MTD_CAP_RAM; mtd->flags = MTD_CAP_RAM;
mtd->size = size; mtd->size = size;
mtd->writesize = 1; mtd->writesize = 1;
mtd->writebufsize = 64; /* Mimic CFI NOR flashes */ mtd->writebufsize = writebuf_size;
mtd->erasesize = MTDRAM_ERASE_SIZE; mtd->erasesize = MTDRAM_ERASE_SIZE;
mtd->priv = mapped_address; mtd->priv = mapped_address;
......
...@@ -126,10 +126,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -126,10 +126,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
if (ops->oobbuf) { if (ops->oobbuf) {
size_t len, pages; size_t len, pages;
if (ops->mode == MTD_OPS_AUTO_OOB) len = mtd_oobavail(mtd, ops);
len = mtd->oobavail;
else
len = mtd->oobsize;
pages = mtd_div_by_ws(mtd->size, mtd); pages = mtd_div_by_ws(mtd->size, mtd);
pages -= mtd_div_by_ws(from, mtd); pages -= mtd_div_by_ws(from, mtd);
if (ops->ooboffs + ops->ooblen > pages * len) if (ops->ooboffs + ops->ooblen > pages * len)
......
...@@ -346,7 +346,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) ...@@ -346,7 +346,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)
if (mtd_can_have_bb(d->mtd) && mtd_block_isbad(d->mtd, offset)) if (mtd_can_have_bb(d->mtd) && mtd_block_isbad(d->mtd, offset))
return MTDSWAP_SCANNED_BAD; return MTDSWAP_SCANNED_BAD;
ops.ooblen = 2 * d->mtd->ecclayout->oobavail; ops.ooblen = 2 * d->mtd->oobavail;
ops.oobbuf = d->oob_buf; ops.oobbuf = d->oob_buf;
ops.ooboffs = 0; ops.ooboffs = 0;
ops.datbuf = NULL; ops.datbuf = NULL;
...@@ -359,7 +359,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) ...@@ -359,7 +359,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)
data = (struct mtdswap_oobdata *)d->oob_buf; data = (struct mtdswap_oobdata *)d->oob_buf;
data2 = (struct mtdswap_oobdata *) data2 = (struct mtdswap_oobdata *)
(d->oob_buf + d->mtd->ecclayout->oobavail); (d->oob_buf + d->mtd->oobavail);
if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) { if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) {
eb->erase_count = le32_to_cpu(data->count); eb->erase_count = le32_to_cpu(data->count);
...@@ -933,7 +933,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, ...@@ -933,7 +933,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,
ops.mode = MTD_OPS_AUTO_OOB; ops.mode = MTD_OPS_AUTO_OOB;
ops.len = mtd->writesize; ops.len = mtd->writesize;
ops.ooblen = mtd->ecclayout->oobavail; ops.ooblen = mtd->oobavail;
ops.ooboffs = 0; ops.ooboffs = 0;
ops.datbuf = d->page_buf; ops.datbuf = d->page_buf;
ops.oobbuf = d->oob_buf; ops.oobbuf = d->oob_buf;
...@@ -945,7 +945,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, ...@@ -945,7 +945,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,
for (i = 0; i < mtd_pages; i++) { for (i = 0; i < mtd_pages; i++) {
patt = mtdswap_test_patt(test + i); patt = mtdswap_test_patt(test + i);
memset(d->page_buf, patt, mtd->writesize); memset(d->page_buf, patt, mtd->writesize);
memset(d->oob_buf, patt, mtd->ecclayout->oobavail); memset(d->oob_buf, patt, mtd->oobavail);
ret = mtd_write_oob(mtd, pos, &ops); ret = mtd_write_oob(mtd, pos, &ops);
if (ret) if (ret)
goto error; goto error;
...@@ -964,7 +964,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, ...@@ -964,7 +964,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,
if (p1[j] != patt) if (p1[j] != patt)
goto error; goto error;
for (j = 0; j < mtd->ecclayout->oobavail; j++) for (j = 0; j < mtd->oobavail; j++)
if (p2[j] != (unsigned char)patt) if (p2[j] != (unsigned char)patt)
goto error; goto error;
...@@ -1387,7 +1387,7 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks, ...@@ -1387,7 +1387,7 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks,
if (!d->page_buf) if (!d->page_buf)
goto page_buf_fail; goto page_buf_fail;
d->oob_buf = kmalloc(2 * mtd->ecclayout->oobavail, GFP_KERNEL); d->oob_buf = kmalloc(2 * mtd->oobavail, GFP_KERNEL);
if (!d->oob_buf) if (!d->oob_buf)
goto oob_buf_fail; goto oob_buf_fail;
...@@ -1417,7 +1417,6 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -1417,7 +1417,6 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
unsigned long part; unsigned long part;
unsigned int eblocks, eavailable, bad_blocks, spare_cnt; unsigned int eblocks, eavailable, bad_blocks, spare_cnt;
uint64_t swap_size, use_size, size_limit; uint64_t swap_size, use_size, size_limit;
struct nand_ecclayout *oinfo;
int ret; int ret;
parts = &partitions[0]; parts = &partitions[0];
...@@ -1447,17 +1446,10 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ...@@ -1447,17 +1446,10 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
return; return;
} }
oinfo = mtd->ecclayout; if (!mtd->oobsize || mtd->oobavail < MTDSWAP_OOBSIZE) {
if (!oinfo) {
printk(KERN_ERR "%s: mtd%d does not have OOB\n",
MTDSWAP_PREFIX, mtd->index);
return;
}
if (!mtd->oobsize || oinfo->oobavail < MTDSWAP_OOBSIZE) {
printk(KERN_ERR "%s: Not enough free bytes in OOB, " printk(KERN_ERR "%s: Not enough free bytes in OOB, "
"%d available, %zu needed.\n", "%d available, %zu needed.\n",
MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE); MTDSWAP_PREFIX, mtd->oobavail, MTDSWAP_OOBSIZE);
return; return;
} }
......
...@@ -74,6 +74,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR ...@@ -74,6 +74,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
config MTD_NAND_GPIO config MTD_NAND_GPIO
tristate "GPIO assisted NAND Flash driver" tristate "GPIO assisted NAND Flash driver"
depends on GPIOLIB || COMPILE_TEST depends on GPIOLIB || COMPILE_TEST
depends on HAS_IOMEM
help help
This enables a NAND flash driver where control signals are This enables a NAND flash driver where control signals are
connected to GPIO pins, and commands and data are communicated connected to GPIO pins, and commands and data are communicated
...@@ -310,6 +311,7 @@ config MTD_NAND_CAFE ...@@ -310,6 +311,7 @@ config MTD_NAND_CAFE
config MTD_NAND_CS553X config MTD_NAND_CS553X
tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
depends on X86_32 depends on X86_32
depends on !UML && HAS_IOMEM
help help
The CS553x companion chips for the AMD Geode processor The CS553x companion chips for the AMD Geode processor
include NAND flash controllers with built-in hardware ECC include NAND flash controllers with built-in hardware ECC
...@@ -463,6 +465,7 @@ config MTD_NAND_MPC5121_NFC ...@@ -463,6 +465,7 @@ config MTD_NAND_MPC5121_NFC
config MTD_NAND_VF610_NFC config MTD_NAND_VF610_NFC
tristate "Support for Freescale NFC for VF610/MPC5125" tristate "Support for Freescale NFC for VF610/MPC5125"
depends on (SOC_VF610 || COMPILE_TEST) depends on (SOC_VF610 || COMPILE_TEST)
depends on HAS_IOMEM
help help
Enables support for NAND Flash Controller on some Freescale Enables support for NAND Flash Controller on some Freescale
processors like the VF610, MPC5125, MCF54418 or Kinetis K70. processors like the VF610, MPC5125, MCF54418 or Kinetis K70.
...@@ -553,4 +556,11 @@ config MTD_NAND_HISI504 ...@@ -553,4 +556,11 @@ config MTD_NAND_HISI504
help help
Enables support for NAND controller on Hisilicon SoC Hip04. Enables support for NAND controller on Hisilicon SoC Hip04.
config MTD_NAND_QCOM
tristate "Support for NAND on QCOM SoCs"
depends on ARCH_QCOM
help
Enables support for NAND flash chips on SoCs containing the EBI2 NAND
controller. This controller is found on IPQ806x SoC.
endif # MTD_NAND endif # MTD_NAND
...@@ -56,5 +56,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ ...@@ -56,5 +56,6 @@ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o nand-objs := nand_base.o nand_bbt.o nand_timings.o
...@@ -65,6 +65,11 @@ module_param(on_flash_bbt, int, 0); ...@@ -65,6 +65,11 @@ module_param(on_flash_bbt, int, 0);
struct atmel_nand_caps { struct atmel_nand_caps {
bool pmecc_correct_erase_page; bool pmecc_correct_erase_page;
uint8_t pmecc_max_correction;
};
struct atmel_nand_nfc_caps {
uint32_t rb_mask;
}; };
/* oob layout for large page size /* oob layout for large page size
...@@ -111,6 +116,7 @@ struct atmel_nfc { ...@@ -111,6 +116,7 @@ struct atmel_nfc {
/* Point to the sram bank which include readed data via NFC */ /* Point to the sram bank which include readed data via NFC */
void *data_in_sram; void *data_in_sram;
bool will_write_sram; bool will_write_sram;
const struct atmel_nand_nfc_caps *caps;
}; };
static struct atmel_nfc nand_nfc; static struct atmel_nfc nand_nfc;
...@@ -140,6 +146,7 @@ struct atmel_nand_host { ...@@ -140,6 +146,7 @@ struct atmel_nand_host {
int pmecc_cw_len; /* Length of codeword */ int pmecc_cw_len; /* Length of codeword */
void __iomem *pmerrloc_base; void __iomem *pmerrloc_base;
void __iomem *pmerrloc_el_base;
void __iomem *pmecc_rom_base; void __iomem *pmecc_rom_base;
/* lookup table for alpha_to and index_of */ /* lookup table for alpha_to and index_of */
...@@ -468,6 +475,7 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) ...@@ -468,6 +475,7 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
* 8-bits 13-bytes 14-bytes * 8-bits 13-bytes 14-bytes
* 12-bits 20-bytes 21-bytes * 12-bits 20-bytes 21-bytes
* 24-bits 39-bytes 42-bytes * 24-bits 39-bytes 42-bytes
* 32-bits 52-bytes 56-bytes
*/ */
static int pmecc_get_ecc_bytes(int cap, int sector_size) static int pmecc_get_ecc_bytes(int cap, int sector_size)
{ {
...@@ -813,7 +821,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, ...@@ -813,7 +821,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
sector_size = host->pmecc_sector_size; sector_size = host->pmecc_sector_size;
while (err_nbr) { while (err_nbr) {
tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_base, i) - 1; tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_el_base, i) - 1;
byte_pos = tmp / 8; byte_pos = tmp / 8;
bit_pos = tmp % 8; bit_pos = tmp % 8;
...@@ -825,7 +833,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, ...@@ -825,7 +833,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
*(buf + byte_pos) ^= (1 << bit_pos); *(buf + byte_pos) ^= (1 << bit_pos);
pos = sector_num * host->pmecc_sector_size + byte_pos; pos = sector_num * host->pmecc_sector_size + byte_pos;
dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
pos, bit_pos, err_byte, *(buf + byte_pos)); pos, bit_pos, err_byte, *(buf + byte_pos));
} else { } else {
/* Bit flip in OOB area */ /* Bit flip in OOB area */
...@@ -835,7 +843,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc, ...@@ -835,7 +843,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
ecc[tmp] ^= (1 << bit_pos); ecc[tmp] ^= (1 << bit_pos);
pos = tmp + nand_chip->ecc.layout->eccpos[0]; pos = tmp + nand_chip->ecc.layout->eccpos[0];
dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n", dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
pos, bit_pos, err_byte, ecc[tmp]); pos, bit_pos, err_byte, ecc[tmp]);
} }
...@@ -1017,6 +1025,9 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd) ...@@ -1017,6 +1025,9 @@ static void atmel_pmecc_core_init(struct mtd_info *mtd)
case 24: case 24:
val = PMECC_CFG_BCH_ERR24; val = PMECC_CFG_BCH_ERR24;
break; break;
case 32:
val = PMECC_CFG_BCH_ERR32;
break;
} }
if (host->pmecc_sector_size == 512) if (host->pmecc_sector_size == 512)
...@@ -1078,6 +1089,9 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, ...@@ -1078,6 +1089,9 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
/* If device tree doesn't specify, use NAND's minimum ECC parameters */ /* If device tree doesn't specify, use NAND's minimum ECC parameters */
if (host->pmecc_corr_cap == 0) { if (host->pmecc_corr_cap == 0) {
if (*cap > host->caps->pmecc_max_correction)
return -EINVAL;
/* use the most fitable ecc bits (the near bigger one ) */ /* use the most fitable ecc bits (the near bigger one ) */
if (*cap <= 2) if (*cap <= 2)
host->pmecc_corr_cap = 2; host->pmecc_corr_cap = 2;
...@@ -1089,6 +1103,8 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, ...@@ -1089,6 +1103,8 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
host->pmecc_corr_cap = 12; host->pmecc_corr_cap = 12;
else if (*cap <= 24) else if (*cap <= 24)
host->pmecc_corr_cap = 24; host->pmecc_corr_cap = 24;
else if (*cap <= 32)
host->pmecc_corr_cap = 32;
else else
return -EINVAL; return -EINVAL;
} }
...@@ -1205,6 +1221,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, ...@@ -1205,6 +1221,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
err_no = PTR_ERR(host->pmerrloc_base); err_no = PTR_ERR(host->pmerrloc_base);
goto err; goto err;
} }
host->pmerrloc_el_base = host->pmerrloc_base + ATMEL_PMERRLOC_SIGMAx +
(host->caps->pmecc_max_correction + 1) * 4;
if (!host->has_no_lookup_table) { if (!host->has_no_lookup_table) {
regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
...@@ -1486,8 +1504,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) ...@@ -1486,8 +1504,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
ecc_writel(host->ecc, CR, ATMEL_ECC_RST); ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
} }
static const struct of_device_id atmel_nand_dt_ids[];
static int atmel_of_init_port(struct atmel_nand_host *host, static int atmel_of_init_port(struct atmel_nand_host *host,
struct device_node *np) struct device_node *np)
{ {
...@@ -1498,7 +1514,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host, ...@@ -1498,7 +1514,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
enum of_gpio_flags flags = 0; enum of_gpio_flags flags = 0;
host->caps = (struct atmel_nand_caps *) host->caps = (struct atmel_nand_caps *)
of_match_device(atmel_nand_dt_ids, host->dev)->data; of_device_get_match_data(host->dev);
if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) { if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
if (val >= 32) { if (val >= 32) {
...@@ -1547,10 +1563,16 @@ static int atmel_of_init_port(struct atmel_nand_host *host, ...@@ -1547,10 +1563,16 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
* them from NAND ONFI parameters. * them from NAND ONFI parameters.
*/ */
if (of_property_read_u32(np, "atmel,pmecc-cap", &val) == 0) { if (of_property_read_u32(np, "atmel,pmecc-cap", &val) == 0) {
if ((val != 2) && (val != 4) && (val != 8) && (val != 12) && if (val > host->caps->pmecc_max_correction) {
(val != 24)) {
dev_err(host->dev, dev_err(host->dev,
"Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n", "Required ECC strength too high: %u max %u\n",
val, host->caps->pmecc_max_correction);
return -EINVAL;
}
if ((val != 2) && (val != 4) && (val != 8) &&
(val != 12) && (val != 24) && (val != 32)) {
dev_err(host->dev,
"Required ECC strength not supported: %u\n",
val); val);
return -EINVAL; return -EINVAL;
} }
...@@ -1560,7 +1582,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host, ...@@ -1560,7 +1582,7 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) == 0) { if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) == 0) {
if ((val != 512) && (val != 1024)) { if ((val != 512) && (val != 1024)) {
dev_err(host->dev, dev_err(host->dev,
"Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n", "Required ECC sector size not supported: %u\n",
val); val);
return -EINVAL; return -EINVAL;
} }
...@@ -1677,9 +1699,9 @@ static irqreturn_t hsmc_interrupt(int irq, void *dev_id) ...@@ -1677,9 +1699,9 @@ static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE); nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
if (pending & NFC_SR_RB_EDGE) { if (pending & host->nfc->caps->rb_mask) {
complete(&host->nfc->comp_ready); complete(&host->nfc->comp_ready);
nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE); nfc_writel(host->nfc->hsmc_regs, IDR, host->nfc->caps->rb_mask);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
} }
if (pending & NFC_SR_CMD_DONE) { if (pending & NFC_SR_CMD_DONE) {
...@@ -1697,7 +1719,7 @@ static void nfc_prepare_interrupt(struct atmel_nand_host *host, u32 flag) ...@@ -1697,7 +1719,7 @@ static void nfc_prepare_interrupt(struct atmel_nand_host *host, u32 flag)
if (flag & NFC_SR_XFR_DONE) if (flag & NFC_SR_XFR_DONE)
init_completion(&host->nfc->comp_xfer_done); init_completion(&host->nfc->comp_xfer_done);
if (flag & NFC_SR_RB_EDGE) if (flag & host->nfc->caps->rb_mask)
init_completion(&host->nfc->comp_ready); init_completion(&host->nfc->comp_ready);
if (flag & NFC_SR_CMD_DONE) if (flag & NFC_SR_CMD_DONE)
...@@ -1715,7 +1737,7 @@ static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag) ...@@ -1715,7 +1737,7 @@ static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
if (flag & NFC_SR_XFR_DONE) if (flag & NFC_SR_XFR_DONE)
comp[index++] = &host->nfc->comp_xfer_done; comp[index++] = &host->nfc->comp_xfer_done;
if (flag & NFC_SR_RB_EDGE) if (flag & host->nfc->caps->rb_mask)
comp[index++] = &host->nfc->comp_ready; comp[index++] = &host->nfc->comp_ready;
if (flag & NFC_SR_CMD_DONE) if (flag & NFC_SR_CMD_DONE)
...@@ -1783,7 +1805,7 @@ static int nfc_device_ready(struct mtd_info *mtd) ...@@ -1783,7 +1805,7 @@ static int nfc_device_ready(struct mtd_info *mtd)
dev_err(host->dev, "Lost the interrupt flags: 0x%08x\n", dev_err(host->dev, "Lost the interrupt flags: 0x%08x\n",
mask & status); mask & status);
return status & NFC_SR_RB_EDGE; return status & host->nfc->caps->rb_mask;
} }
static void nfc_select_chip(struct mtd_info *mtd, int chip) static void nfc_select_chip(struct mtd_info *mtd, int chip)
...@@ -1956,8 +1978,8 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command, ...@@ -1956,8 +1978,8 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
} }
/* fall through */ /* fall through */
default: default:
nfc_prepare_interrupt(host, NFC_SR_RB_EDGE); nfc_prepare_interrupt(host, host->nfc->caps->rb_mask);
nfc_wait_interrupt(host, NFC_SR_RB_EDGE); nfc_wait_interrupt(host, host->nfc->caps->rb_mask);
} }
} }
...@@ -2304,17 +2326,34 @@ static int atmel_nand_remove(struct platform_device *pdev) ...@@ -2304,17 +2326,34 @@ static int atmel_nand_remove(struct platform_device *pdev)
return 0; return 0;
} }
/*
* AT91RM9200 does not have PMECC or PMECC Errloc peripherals for
* BCH ECC. Combined with the "atmel,has-pmecc", it is used to describe
* devices from the SAM9 family that have those.
*/
static const struct atmel_nand_caps at91rm9200_caps = { static const struct atmel_nand_caps at91rm9200_caps = {
.pmecc_correct_erase_page = false, .pmecc_correct_erase_page = false,
.pmecc_max_correction = 24,
}; };
static const struct atmel_nand_caps sama5d4_caps = { static const struct atmel_nand_caps sama5d4_caps = {
.pmecc_correct_erase_page = true, .pmecc_correct_erase_page = true,
.pmecc_max_correction = 24,
};
/*
* The PMECC Errloc controller starting in SAMA5D2 is not compatible,
* as the increased correction strength requires more registers.
*/
static const struct atmel_nand_caps sama5d2_caps = {
.pmecc_correct_erase_page = true,
.pmecc_max_correction = 32,
}; };
static const struct of_device_id atmel_nand_dt_ids[] = { static const struct of_device_id atmel_nand_dt_ids[] = {
{ .compatible = "atmel,at91rm9200-nand", .data = &at91rm9200_caps }, { .compatible = "atmel,at91rm9200-nand", .data = &at91rm9200_caps },
{ .compatible = "atmel,sama5d4-nand", .data = &sama5d4_caps }, { .compatible = "atmel,sama5d4-nand", .data = &sama5d4_caps },
{ .compatible = "atmel,sama5d2-nand", .data = &sama5d2_caps },
{ /* sentinel */ } { /* sentinel */ }
}; };
...@@ -2354,6 +2393,11 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) ...@@ -2354,6 +2393,11 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
} }
} }
nfc->caps = (const struct atmel_nand_nfc_caps *)
of_device_get_match_data(&pdev->dev);
if (!nfc->caps)
return -ENODEV;
nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff); nfc_writel(nfc->hsmc_regs, IDR, 0xffffffff);
nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */ nfc_readl(nfc->hsmc_regs, SR); /* clear the NFC_SR */
...@@ -2382,8 +2426,17 @@ static int atmel_nand_nfc_remove(struct platform_device *pdev) ...@@ -2382,8 +2426,17 @@ static int atmel_nand_nfc_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct atmel_nand_nfc_caps sama5d3_nfc_caps = {
.rb_mask = NFC_SR_RB_EDGE0,
};
static const struct atmel_nand_nfc_caps sama5d4_nfc_caps = {
.rb_mask = NFC_SR_RB_EDGE3,
};
static const struct of_device_id atmel_nand_nfc_match[] = { static const struct of_device_id atmel_nand_nfc_match[] = {
{ .compatible = "atmel,sama5d3-nfc" }, { .compatible = "atmel,sama5d3-nfc", .data = &sama5d3_nfc_caps },
{ .compatible = "atmel,sama5d4-nfc", .data = &sama5d4_nfc_caps },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, atmel_nand_nfc_match); MODULE_DEVICE_TABLE(of, atmel_nand_nfc_match);
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#define PMECC_CFG_BCH_ERR8 (2 << 0) #define PMECC_CFG_BCH_ERR8 (2 << 0)
#define PMECC_CFG_BCH_ERR12 (3 << 0) #define PMECC_CFG_BCH_ERR12 (3 << 0)
#define PMECC_CFG_BCH_ERR24 (4 << 0) #define PMECC_CFG_BCH_ERR24 (4 << 0)
#define PMECC_CFG_BCH_ERR32 (5 << 0)
#define PMECC_CFG_SECTOR512 (0 << 4) #define PMECC_CFG_SECTOR512 (0 << 4)
#define PMECC_CFG_SECTOR1024 (1 << 4) #define PMECC_CFG_SECTOR1024 (1 << 4)
...@@ -108,7 +109,11 @@ ...@@ -108,7 +109,11 @@
#define PMERRLOC_ERR_NUM_MASK (0x1f << 8) #define PMERRLOC_ERR_NUM_MASK (0x1f << 8)
#define PMERRLOC_CALC_DONE (1 << 0) #define PMERRLOC_CALC_DONE (1 << 0)
#define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */ #define ATMEL_PMERRLOC_SIGMAx 0x028 /* Error location SIGMA x */
#define ATMEL_PMERRLOC_ELx 0x08c /* Error location x */
/*
* The ATMEL_PMERRLOC_ELx register location depends from the number of
* bits corrected by the PMECC controller. Do not use it.
*/
/* Register access macros for PMECC */ /* Register access macros for PMECC */
#define pmecc_readl_relaxed(addr, reg) \ #define pmecc_readl_relaxed(addr, reg) \
...@@ -136,7 +141,7 @@ ...@@ -136,7 +141,7 @@
readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4)) readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
#define pmerrloc_readl_el_relaxed(addr, n) \ #define pmerrloc_readl_el_relaxed(addr, n) \
readl_relaxed((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4)) readl_relaxed((addr) + ((n) * 4))
/* Galois field dimension */ /* Galois field dimension */
#define PMECC_GF_DIMENSION_13 13 #define PMECC_GF_DIMENSION_13 13
......
...@@ -42,7 +42,8 @@ ...@@ -42,7 +42,8 @@
#define NFC_SR_UNDEF (1 << 21) #define NFC_SR_UNDEF (1 << 21)
#define NFC_SR_AWB (1 << 22) #define NFC_SR_AWB (1 << 22)
#define NFC_SR_ASE (1 << 23) #define NFC_SR_ASE (1 << 23)
#define NFC_SR_RB_EDGE (1 << 24) #define NFC_SR_RB_EDGE0 (1 << 24)
#define NFC_SR_RB_EDGE3 (1 << 27)
#define ATMEL_HSMC_NFC_IER 0x0c #define ATMEL_HSMC_NFC_IER 0x0c
#define ATMEL_HSMC_NFC_IDR 0x10 #define ATMEL_HSMC_NFC_IDR 0x10
......
...@@ -311,6 +311,36 @@ static const u16 brcmnand_regs_v60[] = { ...@@ -311,6 +311,36 @@ static const u16 brcmnand_regs_v60[] = {
[BRCMNAND_FC_BASE] = 0x400, [BRCMNAND_FC_BASE] = 0x400,
}; };
/* BRCMNAND v7.1 */
static const u16 brcmnand_regs_v71[] = {
[BRCMNAND_CMD_START] = 0x04,
[BRCMNAND_CMD_EXT_ADDRESS] = 0x08,
[BRCMNAND_CMD_ADDRESS] = 0x0c,
[BRCMNAND_INTFC_STATUS] = 0x14,
[BRCMNAND_CS_SELECT] = 0x18,
[BRCMNAND_CS_XOR] = 0x1c,
[BRCMNAND_LL_OP] = 0x20,
[BRCMNAND_CS0_BASE] = 0x50,
[BRCMNAND_CS1_BASE] = 0,
[BRCMNAND_CORR_THRESHOLD] = 0xdc,
[BRCMNAND_CORR_THRESHOLD_EXT] = 0xe0,
[BRCMNAND_UNCORR_COUNT] = 0xfc,
[BRCMNAND_CORR_COUNT] = 0x100,
[BRCMNAND_CORR_EXT_ADDR] = 0x10c,
[BRCMNAND_CORR_ADDR] = 0x110,
[BRCMNAND_UNCORR_EXT_ADDR] = 0x114,
[BRCMNAND_UNCORR_ADDR] = 0x118,
[BRCMNAND_SEMAPHORE] = 0x150,
[BRCMNAND_ID] = 0x194,
[BRCMNAND_ID_EXT] = 0x198,
[BRCMNAND_LL_RDATA] = 0x19c,
[BRCMNAND_OOB_READ_BASE] = 0x200,
[BRCMNAND_OOB_READ_10_BASE] = 0,
[BRCMNAND_OOB_WRITE_BASE] = 0x280,
[BRCMNAND_OOB_WRITE_10_BASE] = 0,
[BRCMNAND_FC_BASE] = 0x400,
};
enum brcmnand_cs_reg { enum brcmnand_cs_reg {
BRCMNAND_CS_CFG_EXT = 0, BRCMNAND_CS_CFG_EXT = 0,
BRCMNAND_CS_CFG, BRCMNAND_CS_CFG,
...@@ -406,7 +436,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl) ...@@ -406,7 +436,9 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
} }
/* Register offsets */ /* Register offsets */
if (ctrl->nand_version >= 0x0600) if (ctrl->nand_version >= 0x0701)
ctrl->reg_offsets = brcmnand_regs_v71;
else if (ctrl->nand_version >= 0x0600)
ctrl->reg_offsets = brcmnand_regs_v60; ctrl->reg_offsets = brcmnand_regs_v60;
else if (ctrl->nand_version >= 0x0500) else if (ctrl->nand_version >= 0x0500)
ctrl->reg_offsets = brcmnand_regs_v50; ctrl->reg_offsets = brcmnand_regs_v50;
...@@ -796,7 +828,8 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level, ...@@ -796,7 +828,8 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1) idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
break; break;
} }
goto out;
return layout;
} }
/* /*
...@@ -847,10 +880,7 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level, ...@@ -847,10 +880,7 @@ static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1) idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
break; break;
} }
out:
/* Sum available OOB */
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE; i++)
layout->oobavail += layout->oobfree[i].length;
return layout; return layout;
} }
......
...@@ -537,7 +537,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd, ...@@ -537,7 +537,7 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
return 0; return 0;
} }
static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) static int cafe_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
{ {
return 0; return 0;
} }
......
...@@ -794,7 +794,7 @@ static int doc200x_dev_ready(struct mtd_info *mtd) ...@@ -794,7 +794,7 @@ static int doc200x_dev_ready(struct mtd_info *mtd)
} }
} }
static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs)
{ {
/* This is our last resort if we couldn't find or create a BBT. Just /* This is our last resort if we couldn't find or create a BBT. Just
pretend all blocks are good. */ pretend all blocks are good. */
......
...@@ -225,7 +225,6 @@ struct docg4_priv { ...@@ -225,7 +225,6 @@ struct docg4_priv {
static struct nand_ecclayout docg4_oobinfo = { static struct nand_ecclayout docg4_oobinfo = {
.eccbytes = 9, .eccbytes = 9,
.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15}, .eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
.oobavail = 5,
.oobfree = { {.offset = 2, .length = 5} } .oobfree = { {.offset = 2, .length = 5} }
}; };
...@@ -1121,7 +1120,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1121,7 +1120,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
return ret; return ret;
} }
static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs, int getchip) static int docg4_block_neverbad(struct mtd_info *mtd, loff_t ofs)
{ {
/* only called when module_param ignore_badblocks is set */ /* only called when module_param ignore_badblocks is set */
return 0; return 0;
......
/* /*
* Freescale GPMI NAND Flash Driver * Freescale GPMI NAND Flash Driver
* *
* Copyright (C) 2010-2011 Freescale Semiconductor, Inc. * Copyright (C) 2010-2015 Freescale Semiconductor, Inc.
* Copyright (C) 2008 Embedded Alley Solutions, Inc. * Copyright (C) 2008 Embedded Alley Solutions, Inc.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -136,7 +136,7 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this) ...@@ -136,7 +136,7 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
* *
* We may have available oob space in this case. * We may have available oob space in this case.
*/ */
static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this) static int set_geometry_by_ecc_info(struct gpmi_nand_data *this)
{ {
struct bch_geometry *geo = &this->bch_geometry; struct bch_geometry *geo = &this->bch_geometry;
struct nand_chip *chip = &this->nand; struct nand_chip *chip = &this->nand;
...@@ -145,7 +145,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this) ...@@ -145,7 +145,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
unsigned int block_mark_bit_offset; unsigned int block_mark_bit_offset;
if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0)) if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
return false; return -EINVAL;
switch (chip->ecc_step_ds) { switch (chip->ecc_step_ds) {
case SZ_512: case SZ_512:
...@@ -158,19 +158,19 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this) ...@@ -158,19 +158,19 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
dev_err(this->dev, dev_err(this->dev,
"unsupported nand chip. ecc bits : %d, ecc size : %d\n", "unsupported nand chip. ecc bits : %d, ecc size : %d\n",
chip->ecc_strength_ds, chip->ecc_step_ds); chip->ecc_strength_ds, chip->ecc_step_ds);
return false; return -EINVAL;
} }
geo->ecc_chunk_size = chip->ecc_step_ds; geo->ecc_chunk_size = chip->ecc_step_ds;
geo->ecc_strength = round_up(chip->ecc_strength_ds, 2); geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
if (!gpmi_check_ecc(this)) if (!gpmi_check_ecc(this))
return false; return -EINVAL;
/* Keep the C >= O */ /* Keep the C >= O */
if (geo->ecc_chunk_size < mtd->oobsize) { if (geo->ecc_chunk_size < mtd->oobsize) {
dev_err(this->dev, dev_err(this->dev,
"unsupported nand chip. ecc size: %d, oob size : %d\n", "unsupported nand chip. ecc size: %d, oob size : %d\n",
chip->ecc_step_ds, mtd->oobsize); chip->ecc_step_ds, mtd->oobsize);
return false; return -EINVAL;
} }
/* The default value, see comment in the legacy_set_geometry(). */ /* The default value, see comment in the legacy_set_geometry(). */
...@@ -242,7 +242,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this) ...@@ -242,7 +242,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
+ ALIGN(geo->ecc_chunk_count, 4); + ALIGN(geo->ecc_chunk_count, 4);
if (!this->swap_block_mark) if (!this->swap_block_mark)
return true; return 0;
/* For bit swap. */ /* For bit swap. */
block_mark_bit_offset = mtd->writesize * 8 - block_mark_bit_offset = mtd->writesize * 8 -
...@@ -251,7 +251,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this) ...@@ -251,7 +251,7 @@ static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
geo->block_mark_byte_offset = block_mark_bit_offset / 8; geo->block_mark_byte_offset = block_mark_bit_offset / 8;
geo->block_mark_bit_offset = block_mark_bit_offset % 8; geo->block_mark_bit_offset = block_mark_bit_offset % 8;
return true; return 0;
} }
static int legacy_set_geometry(struct gpmi_nand_data *this) static int legacy_set_geometry(struct gpmi_nand_data *this)
...@@ -285,7 +285,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this) ...@@ -285,7 +285,8 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
geo->ecc_strength = get_ecc_strength(this); geo->ecc_strength = get_ecc_strength(this);
if (!gpmi_check_ecc(this)) { if (!gpmi_check_ecc(this)) {
dev_err(this->dev, dev_err(this->dev,
"required ecc strength of the NAND chip: %d is not supported by the GPMI controller (%d)\n", "ecc strength: %d cannot be supported by the controller (%d)\n"
"try to use minimum ecc strength that NAND chip required\n",
geo->ecc_strength, geo->ecc_strength,
this->devdata->bch_max_ecc_strength); this->devdata->bch_max_ecc_strength);
return -EINVAL; return -EINVAL;
...@@ -366,10 +367,11 @@ static int legacy_set_geometry(struct gpmi_nand_data *this) ...@@ -366,10 +367,11 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
int common_nfc_set_geometry(struct gpmi_nand_data *this) int common_nfc_set_geometry(struct gpmi_nand_data *this)
{ {
if (of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc") if ((of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc"))
&& set_geometry_by_ecc_info(this)) || legacy_set_geometry(this))
return 0; return set_geometry_by_ecc_info(this);
return legacy_set_geometry(this);
return 0;
} }
struct dma_chan *get_dma_chan(struct gpmi_nand_data *this) struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
...@@ -2033,9 +2035,54 @@ static int gpmi_nand_remove(struct platform_device *pdev) ...@@ -2033,9 +2035,54 @@ static int gpmi_nand_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP
static int gpmi_pm_suspend(struct device *dev)
{
struct gpmi_nand_data *this = dev_get_drvdata(dev);
release_dma_channels(this);
return 0;
}
static int gpmi_pm_resume(struct device *dev)
{
struct gpmi_nand_data *this = dev_get_drvdata(dev);
int ret;
ret = acquire_dma_channels(this);
if (ret < 0)
return ret;
/* re-init the GPMI registers */
this->flags &= ~GPMI_TIMING_INIT_OK;
ret = gpmi_init(this);
if (ret) {
dev_err(this->dev, "Error setting GPMI : %d\n", ret);
return ret;
}
/* re-init the BCH registers */
ret = bch_set_geometry(this);
if (ret) {
dev_err(this->dev, "Error setting BCH : %d\n", ret);
return ret;
}
/* re-init others */
gpmi_extra_init(this);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops gpmi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(gpmi_pm_suspend, gpmi_pm_resume)
};
static struct platform_driver gpmi_nand_driver = { static struct platform_driver gpmi_nand_driver = {
.driver = { .driver = {
.name = "gpmi-nand", .name = "gpmi-nand",
.pm = &gpmi_pm_ops,
.of_match_table = gpmi_nand_id_table, .of_match_table = gpmi_nand_id_table,
}, },
.probe = gpmi_nand_probe, .probe = gpmi_nand_probe,
......
...@@ -632,7 +632,6 @@ static void hisi_nfc_host_init(struct hinfc_host *host) ...@@ -632,7 +632,6 @@ static void hisi_nfc_host_init(struct hinfc_host *host)
} }
static struct nand_ecclayout nand_ecc_2K_16bits = { static struct nand_ecclayout nand_ecc_2K_16bits = {
.oobavail = 6,
.oobfree = { {2, 6} }, .oobfree = { {2, 6} },
}; };
......
...@@ -427,9 +427,6 @@ static int jz_nand_probe(struct platform_device *pdev) ...@@ -427,9 +427,6 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->ecc.strength = 4; chip->ecc.strength = 4;
chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK; chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
if (pdata)
chip->ecc.layout = pdata->ecc_layout;
chip->chip_delay = 50; chip->chip_delay = 50;
chip->cmd_ctrl = jz_nand_cmd_ctrl; chip->cmd_ctrl = jz_nand_cmd_ctrl;
chip->select_chip = jz_nand_select_chip; chip->select_chip = jz_nand_select_chip;
......
...@@ -750,7 +750,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) ...@@ -750,7 +750,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
} }
nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = mtd->writesize; nand_chip->ecc.size = 512;
nand_chip->ecc.layout = &lpc32xx_nand_oob; nand_chip->ecc.layout = &lpc32xx_nand_oob;
host->mlcsubpages = mtd->writesize / 512; host->mlcsubpages = mtd->writesize / 512;
......
...@@ -626,7 +626,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd) ...@@ -626,7 +626,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
static int mpc5121_nfc_probe(struct platform_device *op) static int mpc5121_nfc_probe(struct platform_device *op)
{ {
struct device_node *rootnode, *dn = op->dev.of_node; struct device_node *dn = op->dev.of_node;
struct clk *clk; struct clk *clk;
struct device *dev = &op->dev; struct device *dev = &op->dev;
struct mpc5121_nfc_prv *prv; struct mpc5121_nfc_prv *prv;
...@@ -712,18 +712,15 @@ static int mpc5121_nfc_probe(struct platform_device *op) ...@@ -712,18 +712,15 @@ static int mpc5121_nfc_probe(struct platform_device *op)
chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.mode = NAND_ECC_SOFT;
/* Support external chip-select logic on ADS5121 board */ /* Support external chip-select logic on ADS5121 board */
rootnode = of_find_node_by_path("/"); if (of_machine_is_compatible("fsl,mpc5121ads")) {
if (of_device_is_compatible(rootnode, "fsl,mpc5121ads")) {
retval = ads5121_chipselect_init(mtd); retval = ads5121_chipselect_init(mtd);
if (retval) { if (retval) {
dev_err(dev, "Chipselect init error!\n"); dev_err(dev, "Chipselect init error!\n");
of_node_put(rootnode);
return retval; return retval;
} }
chip->select_chip = ads5121_select_chip; chip->select_chip = ads5121_select_chip;
} }
of_node_put(rootnode);
/* Enable NFC clock */ /* Enable NFC clock */
clk = devm_clk_get(dev, "ipg"); clk = devm_clk_get(dev, "ipg");
......
...@@ -313,13 +313,12 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) ...@@ -313,13 +313,12 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
* nand_block_bad - [DEFAULT] Read bad block marker from the chip * nand_block_bad - [DEFAULT] Read bad block marker from the chip
* @mtd: MTD device structure * @mtd: MTD device structure
* @ofs: offset from device start * @ofs: offset from device start
* @getchip: 0, if the chip is already selected
* *
* Check, if the block is bad. * Check, if the block is bad.
*/ */
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
{ {
int page, chipnr, res = 0, i = 0; int page, res = 0, i = 0;
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
u16 bad; u16 bad;
...@@ -328,15 +327,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) ...@@ -328,15 +327,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
page = (int)(ofs >> chip->page_shift) & chip->pagemask; page = (int)(ofs >> chip->page_shift) & chip->pagemask;
if (getchip) {
chipnr = (int)(ofs >> chip->chip_shift);
nand_get_device(mtd, FL_READING);
/* Select the NAND device */
chip->select_chip(mtd, chipnr);
}
do { do {
if (chip->options & NAND_BUSWIDTH_16) { if (chip->options & NAND_BUSWIDTH_16) {
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->cmdfunc(mtd, NAND_CMD_READOOB,
...@@ -361,11 +351,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) ...@@ -361,11 +351,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
i++; i++;
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
if (getchip) {
chip->select_chip(mtd, -1);
nand_release_device(mtd);
}
return res; return res;
} }
...@@ -503,19 +488,17 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs) ...@@ -503,19 +488,17 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
* nand_block_checkbad - [GENERIC] Check if a block is marked bad * nand_block_checkbad - [GENERIC] Check if a block is marked bad
* @mtd: MTD device structure * @mtd: MTD device structure
* @ofs: offset from device start * @ofs: offset from device start
* @getchip: 0, if the chip is already selected
* @allowbbt: 1, if its allowed to access the bbt area * @allowbbt: 1, if its allowed to access the bbt area
* *
* Check, if the block is bad. Either by reading the bad block table or * Check, if the block is bad. Either by reading the bad block table or
* calling of the scan function. * calling of the scan function.
*/ */
static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt)
int allowbbt)
{ {
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
if (!chip->bbt) if (!chip->bbt)
return chip->block_bad(mtd, ofs, getchip); return chip->block_bad(mtd, ofs);
/* Return info from the table */ /* Return info from the table */
return nand_isbad_bbt(mtd, ofs, allowbbt); return nand_isbad_bbt(mtd, ofs, allowbbt);
...@@ -566,8 +549,8 @@ void nand_wait_ready(struct mtd_info *mtd) ...@@ -566,8 +549,8 @@ void nand_wait_ready(struct mtd_info *mtd)
cond_resched(); cond_resched();
} while (time_before(jiffies, timeo)); } while (time_before(jiffies, timeo));
pr_warn_ratelimited( if (!chip->dev_ready(mtd))
"timeout while waiting for chip to become ready\n"); pr_warn_ratelimited("timeout while waiting for chip to become ready\n");
out: out:
led_trigger_event(nand_led_trigger, LED_OFF); led_trigger_event(nand_led_trigger, LED_OFF);
} }
...@@ -1723,8 +1706,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, ...@@ -1723,8 +1706,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
int ret = 0; int ret = 0;
uint32_t readlen = ops->len; uint32_t readlen = ops->len;
uint32_t oobreadlen = ops->ooblen; uint32_t oobreadlen = ops->ooblen;
uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ? uint32_t max_oobsize = mtd_oobavail(mtd, ops);
mtd->oobavail : mtd->oobsize;
uint8_t *bufpoi, *oob, *buf; uint8_t *bufpoi, *oob, *buf;
int use_bufpoi; int use_bufpoi;
...@@ -2075,10 +2057,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -2075,10 +2057,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
stats = mtd->ecc_stats; stats = mtd->ecc_stats;
if (ops->mode == MTD_OPS_AUTO_OOB) len = mtd_oobavail(mtd, ops);
len = chip->ecc.layout->oobavail;
else
len = mtd->oobsize;
if (unlikely(ops->ooboffs >= len)) { if (unlikely(ops->ooboffs >= len)) {
pr_debug("%s: attempt to start read outside oob\n", pr_debug("%s: attempt to start read outside oob\n",
...@@ -2575,8 +2554,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, ...@@ -2575,8 +2554,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
uint32_t writelen = ops->len; uint32_t writelen = ops->len;
uint32_t oobwritelen = ops->ooblen; uint32_t oobwritelen = ops->ooblen;
uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ? uint32_t oobmaxlen = mtd_oobavail(mtd, ops);
mtd->oobavail : mtd->oobsize;
uint8_t *oob = ops->oobbuf; uint8_t *oob = ops->oobbuf;
uint8_t *buf = ops->datbuf; uint8_t *buf = ops->datbuf;
...@@ -2766,10 +2744,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, ...@@ -2766,10 +2744,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
pr_debug("%s: to = 0x%08x, len = %i\n", pr_debug("%s: to = 0x%08x, len = %i\n",
__func__, (unsigned int)to, (int)ops->ooblen); __func__, (unsigned int)to, (int)ops->ooblen);
if (ops->mode == MTD_OPS_AUTO_OOB) len = mtd_oobavail(mtd, ops);
len = chip->ecc.layout->oobavail;
else
len = mtd->oobsize;
/* Do not allow write past end of page */ /* Do not allow write past end of page */
if ((ops->ooboffs + ops->ooblen) > len) { if ((ops->ooboffs + ops->ooblen) > len) {
...@@ -2957,7 +2932,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, ...@@ -2957,7 +2932,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
while (len) { while (len) {
/* Check if we have a bad block, we do not erase bad blocks! */ /* Check if we have a bad block, we do not erase bad blocks! */
if (nand_block_checkbad(mtd, ((loff_t) page) << if (nand_block_checkbad(mtd, ((loff_t) page) <<
chip->page_shift, 0, allowbbt)) { chip->page_shift, allowbbt)) {
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
__func__, page); __func__, page);
instr->state = MTD_ERASE_FAILED; instr->state = MTD_ERASE_FAILED;
...@@ -3044,7 +3019,20 @@ static void nand_sync(struct mtd_info *mtd) ...@@ -3044,7 +3019,20 @@ static void nand_sync(struct mtd_info *mtd)
*/ */
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
{ {
return nand_block_checkbad(mtd, offs, 1, 0); struct nand_chip *chip = mtd_to_nand(mtd);
int chipnr = (int)(offs >> chip->chip_shift);
int ret;
/* Select the NAND device */
nand_get_device(mtd, FL_READING);
chip->select_chip(mtd, chipnr);
ret = nand_block_checkbad(mtd, offs, 0);
chip->select_chip(mtd, -1);
nand_release_device(mtd);
return ret;
} }
/** /**
...@@ -4287,10 +4275,8 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -4287,10 +4275,8 @@ int nand_scan_tail(struct mtd_info *mtd)
} }
/* See nand_bch_init() for details. */ /* See nand_bch_init() for details. */
ecc->bytes = DIV_ROUND_UP( ecc->bytes = 0;
ecc->strength * fls(8 * ecc->size), 8); ecc->priv = nand_bch_init(mtd);
ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
&ecc->layout);
if (!ecc->priv) { if (!ecc->priv) {
pr_warn("BCH ECC initialization failed!\n"); pr_warn("BCH ECC initialization failed!\n");
BUG(); BUG();
...@@ -4325,11 +4311,11 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -4325,11 +4311,11 @@ int nand_scan_tail(struct mtd_info *mtd)
* The number of bytes available for a client to place data into * The number of bytes available for a client to place data into
* the out of band area. * the out of band area.
*/ */
ecc->layout->oobavail = 0; mtd->oobavail = 0;
for (i = 0; ecc->layout->oobfree[i].length if (ecc->layout) {
&& i < ARRAY_SIZE(ecc->layout->oobfree); i++) for (i = 0; ecc->layout->oobfree[i].length; i++)
ecc->layout->oobavail += ecc->layout->oobfree[i].length; mtd->oobavail += ecc->layout->oobfree[i].length;
mtd->oobavail = ecc->layout->oobavail; }
/* ECC sanity check: warn if it's too weak */ /* ECC sanity check: warn if it's too weak */
if (!nand_ecc_strength_good(mtd)) if (!nand_ecc_strength_good(mtd))
......
...@@ -1373,5 +1373,3 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs) ...@@ -1373,5 +1373,3 @@ int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
return ret; return ret;
} }
EXPORT_SYMBOL(nand_scan_bbt);
...@@ -107,9 +107,6 @@ EXPORT_SYMBOL(nand_bch_correct_data); ...@@ -107,9 +107,6 @@ EXPORT_SYMBOL(nand_bch_correct_data);
/** /**
* nand_bch_init - [NAND Interface] Initialize NAND BCH error correction * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
* @mtd: MTD block structure * @mtd: MTD block structure
* @eccsize: ecc block size in bytes
* @eccbytes: ecc length in bytes
* @ecclayout: output default layout
* *
* Returns: * Returns:
* a pointer to a new NAND BCH control structure, or NULL upon failure * a pointer to a new NAND BCH control structure, or NULL upon failure
...@@ -123,14 +120,21 @@ EXPORT_SYMBOL(nand_bch_correct_data); ...@@ -123,14 +120,21 @@ EXPORT_SYMBOL(nand_bch_correct_data);
* @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8) * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
* @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits) * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
*/ */
struct nand_bch_control * struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
struct nand_ecclayout **ecclayout)
{ {
struct nand_chip *nand = mtd_to_nand(mtd);
unsigned int m, t, eccsteps, i; unsigned int m, t, eccsteps, i;
struct nand_ecclayout *layout; struct nand_ecclayout *layout = nand->ecc.layout;
struct nand_bch_control *nbc = NULL; struct nand_bch_control *nbc = NULL;
unsigned char *erased_page; unsigned char *erased_page;
unsigned int eccsize = nand->ecc.size;
unsigned int eccbytes = nand->ecc.bytes;
unsigned int eccstrength = nand->ecc.strength;
if (!eccbytes && eccstrength) {
eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
nand->ecc.bytes = eccbytes;
}
if (!eccsize || !eccbytes) { if (!eccsize || !eccbytes) {
printk(KERN_WARNING "ecc parameters not supplied\n"); printk(KERN_WARNING "ecc parameters not supplied\n");
...@@ -158,7 +162,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes, ...@@ -158,7 +162,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
eccsteps = mtd->writesize/eccsize; eccsteps = mtd->writesize/eccsize;
/* if no ecc placement scheme was provided, build one */ /* if no ecc placement scheme was provided, build one */
if (!*ecclayout) { if (!layout) {
/* handle large page devices only */ /* handle large page devices only */
if (mtd->oobsize < 64) { if (mtd->oobsize < 64) {
...@@ -184,7 +188,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes, ...@@ -184,7 +188,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
layout->oobfree[0].offset = 2; layout->oobfree[0].offset = 2;
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
*ecclayout = layout; nand->ecc.layout = layout;
} }
/* sanity checks */ /* sanity checks */
...@@ -192,7 +196,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes, ...@@ -192,7 +196,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
printk(KERN_WARNING "eccsize %u is too large\n", eccsize); printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
goto fail; goto fail;
} }
if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) { if (layout->eccbytes != (eccsteps*eccbytes)) {
printk(KERN_WARNING "invalid ecc layout\n"); printk(KERN_WARNING "invalid ecc layout\n");
goto fail; goto fail;
} }
...@@ -216,6 +220,9 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes, ...@@ -216,6 +220,9 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
for (i = 0; i < eccbytes; i++) for (i = 0; i < eccbytes; i++)
nbc->eccmask[i] ^= 0xff; nbc->eccmask[i] ^= 0xff;
if (!eccstrength)
nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
return nbc; return nbc;
fail: fail:
nand_bch_free(nbc); nand_bch_free(nbc);
......
...@@ -50,8 +50,8 @@ struct nand_flash_dev nand_flash_ids[] = { ...@@ -50,8 +50,8 @@ struct nand_flash_dev nand_flash_ids[] = {
SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) }, SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
{"H27UCG8T2ATR-BC 64G 3.3V 8-bit", {"H27UCG8T2ATR-BC 64G 3.3V 8-bit",
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} }, { .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K), SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
4 }, NAND_ECC_INFO(40, SZ_1K), 4 },
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS), LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
......
...@@ -113,7 +113,7 @@ static int nuc900_check_rb(struct nuc900_nand *nand) ...@@ -113,7 +113,7 @@ static int nuc900_check_rb(struct nuc900_nand *nand)
{ {
unsigned int val; unsigned int val;
spin_lock(&nand->lock); spin_lock(&nand->lock);
val = __raw_readl(REG_SMISR); val = __raw_readl(nand->reg + REG_SMISR);
val &= READYBUSY; val &= READYBUSY;
spin_unlock(&nand->lock); spin_unlock(&nand->lock);
......
...@@ -1807,13 +1807,19 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1807,13 +1807,19 @@ static int omap_nand_probe(struct platform_device *pdev)
goto return_error; goto return_error;
} }
/*
* Bail out earlier to let NAND_ECC_SOFT code create its own
* ecclayout instead of using ours.
*/
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW) {
nand_chip->ecc.mode = NAND_ECC_SOFT;
goto scan_tail;
}
/* populate MTD interface based on ECC scheme */ /* populate MTD interface based on ECC scheme */
ecclayout = &info->oobinfo; ecclayout = &info->oobinfo;
nand_chip->ecc.layout = ecclayout;
switch (info->ecc_opt) { switch (info->ecc_opt) {
case OMAP_ECC_HAM1_CODE_SW:
nand_chip->ecc.mode = NAND_ECC_SOFT;
break;
case OMAP_ECC_HAM1_CODE_HW: case OMAP_ECC_HAM1_CODE_HW:
pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n"); pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
nand_chip->ecc.mode = NAND_ECC_HW; nand_chip->ecc.mode = NAND_ECC_HW;
...@@ -1861,10 +1867,7 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1861,10 +1867,7 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->oobfree->offset = 1 + ecclayout->oobfree->offset = 1 +
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* software bch library is used for locating errors */ /* software bch library is used for locating errors */
nand_chip->ecc.priv = nand_bch_init(mtd, nand_chip->ecc.priv = nand_bch_init(mtd);
nand_chip->ecc.size,
nand_chip->ecc.bytes,
&ecclayout);
if (!nand_chip->ecc.priv) { if (!nand_chip->ecc.priv) {
dev_err(&info->pdev->dev, "unable to use BCH library\n"); dev_err(&info->pdev->dev, "unable to use BCH library\n");
err = -EINVAL; err = -EINVAL;
...@@ -1925,10 +1928,7 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1925,10 +1928,7 @@ static int omap_nand_probe(struct platform_device *pdev)
ecclayout->oobfree->offset = 1 + ecclayout->oobfree->offset = 1 +
ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
/* software bch library is used for locating errors */ /* software bch library is used for locating errors */
nand_chip->ecc.priv = nand_bch_init(mtd, nand_chip->ecc.priv = nand_bch_init(mtd);
nand_chip->ecc.size,
nand_chip->ecc.bytes,
&ecclayout);
if (!nand_chip->ecc.priv) { if (!nand_chip->ecc.priv) {
dev_err(&info->pdev->dev, "unable to use BCH library\n"); dev_err(&info->pdev->dev, "unable to use BCH library\n");
err = -EINVAL; err = -EINVAL;
...@@ -2002,9 +2002,6 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -2002,9 +2002,6 @@ static int omap_nand_probe(struct platform_device *pdev)
goto return_error; goto return_error;
} }
if (info->ecc_opt == OMAP_ECC_HAM1_CODE_SW)
goto scan_tail;
/* all OOB bytes from oobfree->offset till end off OOB are free */ /* all OOB bytes from oobfree->offset till end off OOB are free */
ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
/* check if NAND device's OOB is enough to store ECC signatures */ /* check if NAND device's OOB is enough to store ECC signatures */
...@@ -2015,7 +2012,6 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -2015,7 +2012,6 @@ static int omap_nand_probe(struct platform_device *pdev)
err = -EINVAL; err = -EINVAL;
goto return_error; goto return_error;
} }
nand_chip->ecc.layout = ecclayout;
scan_tail: scan_tail:
/* second phase scan */ /* second phase scan */
......
...@@ -73,7 +73,6 @@ static int plat_nand_probe(struct platform_device *pdev) ...@@ -73,7 +73,6 @@ static int plat_nand_probe(struct platform_device *pdev)
data->chip.bbt_options |= pdata->chip.bbt_options; data->chip.bbt_options |= pdata->chip.bbt_options;
data->chip.ecc.hwctl = pdata->ctrl.hwcontrol; data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
data->chip.ecc.layout = pdata->chip.ecclayout;
data->chip.ecc.mode = NAND_ECC_SOFT; data->chip.ecc.mode = NAND_ECC_SOFT;
platform_set_drvdata(pdev, data); platform_set_drvdata(pdev, data);
......
This diff is collapsed.
This diff is collapsed.
...@@ -861,9 +861,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, ...@@ -861,9 +861,6 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.mode = NAND_ECC_SOFT;
#endif #endif
if (set->ecc_layout != NULL)
chip->ecc.layout = set->ecc_layout;
if (set->disable_ecc) if (set->disable_ecc)
chip->ecc.mode = NAND_ECC_NONE; chip->ecc.mode = NAND_ECC_NONE;
......
This diff is collapsed.
...@@ -795,8 +795,6 @@ static int vf610_nfc_probe(struct platform_device *pdev) ...@@ -795,8 +795,6 @@ static int vf610_nfc_probe(struct platform_device *pdev)
goto error; goto error;
} }
/* propagate ecc.layout to mtd_info */
mtd->ecclayout = chip->ecc.layout;
chip->ecc.read_page = vf610_nfc_read_page; chip->ecc.read_page = vf610_nfc_read_page;
chip->ecc.write_page = vf610_nfc_write_page; chip->ecc.write_page = vf610_nfc_write_page;
......
...@@ -1124,11 +1124,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, ...@@ -1124,11 +1124,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
(int)len); (int)len);
if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = mtd_oobavail(mtd, ops);
oobsize = this->ecclayout->oobavail;
else
oobsize = mtd->oobsize;
oobcolumn = from & (mtd->oobsize - 1); oobcolumn = from & (mtd->oobsize - 1);
/* Do not allow reads past end of device */ /* Do not allow reads past end of device */
...@@ -1229,11 +1225,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, ...@@ -1229,11 +1225,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from,
(int)len); (int)len);
if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = mtd_oobavail(mtd, ops);
oobsize = this->ecclayout->oobavail;
else
oobsize = mtd->oobsize;
oobcolumn = from & (mtd->oobsize - 1); oobcolumn = from & (mtd->oobsize - 1);
/* Do not allow reads past end of device */ /* Do not allow reads past end of device */
...@@ -1365,7 +1357,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, ...@@ -1365,7 +1357,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
ops->oobretlen = 0; ops->oobretlen = 0;
if (mode == MTD_OPS_AUTO_OOB) if (mode == MTD_OPS_AUTO_OOB)
oobsize = this->ecclayout->oobavail; oobsize = mtd->oobavail;
else else
oobsize = mtd->oobsize; oobsize = mtd->oobsize;
...@@ -1885,12 +1877,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, ...@@ -1885,12 +1877,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
/* Check zero length */ /* Check zero length */
if (!len) if (!len)
return 0; return 0;
oobsize = mtd_oobavail(mtd, ops);
if (ops->mode == MTD_OPS_AUTO_OOB)
oobsize = this->ecclayout->oobavail;
else
oobsize = mtd->oobsize;
oobcolumn = to & (mtd->oobsize - 1); oobcolumn = to & (mtd->oobsize - 1);
column = to & (mtd->writesize - 1); column = to & (mtd->writesize - 1);
...@@ -2063,7 +2050,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, ...@@ -2063,7 +2050,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
ops->oobretlen = 0; ops->oobretlen = 0;
if (mode == MTD_OPS_AUTO_OOB) if (mode == MTD_OPS_AUTO_OOB)
oobsize = this->ecclayout->oobavail; oobsize = mtd->oobavail;
else else
oobsize = mtd->oobsize; oobsize = mtd->oobsize;
...@@ -2599,6 +2586,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -2599,6 +2586,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
*/ */
static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
{ {
struct onenand_chip *this = mtd->priv;
int ret; int ret;
ret = onenand_block_isbad(mtd, ofs); ret = onenand_block_isbad(mtd, ofs);
...@@ -2610,7 +2598,7 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -2610,7 +2598,7 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
} }
onenand_get_device(mtd, FL_WRITING); onenand_get_device(mtd, FL_WRITING);
ret = mtd_block_markbad(mtd, ofs); ret = this->block_markbad(mtd, ofs);
onenand_release_device(mtd); onenand_release_device(mtd);
return ret; return ret;
} }
...@@ -4049,12 +4037,10 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) ...@@ -4049,12 +4037,10 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
* The number of bytes available for a client to place data into * The number of bytes available for a client to place data into
* the out of band area * the out of band area
*/ */
this->ecclayout->oobavail = 0; mtd->oobavail = 0;
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
this->ecclayout->oobfree[i].length; i++) this->ecclayout->oobfree[i].length; i++)
this->ecclayout->oobavail += mtd->oobavail += this->ecclayout->oobfree[i].length;
this->ecclayout->oobfree[i].length;
mtd->oobavail = this->ecclayout->oobavail;
mtd->ecclayout = this->ecclayout; mtd->ecclayout = this->ecclayout;
mtd->ecc_strength = 1; mtd->ecc_strength = 1;
......
...@@ -179,7 +179,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) ...@@ -179,7 +179,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
* by the onenand_release function. * by the onenand_release function.
* *
*/ */
int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) static int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{ {
struct onenand_chip *this = mtd->priv; struct onenand_chip *this = mtd->priv;
struct bbm_info *bbm = this->bbm; struct bbm_info *bbm = this->bbm;
...@@ -247,6 +247,3 @@ int onenand_default_bbt(struct mtd_info *mtd) ...@@ -247,6 +247,3 @@ int onenand_default_bbt(struct mtd_info *mtd)
return onenand_scan_bbt(mtd, bbm->badblock_pattern); return onenand_scan_bbt(mtd, bbm->badblock_pattern);
} }
EXPORT_SYMBOL(onenand_scan_bbt);
EXPORT_SYMBOL(onenand_default_bbt);
...@@ -9,6 +9,7 @@ if MTD_SPI_NOR ...@@ -9,6 +9,7 @@ if MTD_SPI_NOR
config MTD_MT81xx_NOR config MTD_MT81xx_NOR
tristate "Mediatek MT81xx SPI NOR flash controller" tristate "Mediatek MT81xx SPI NOR flash controller"
depends on HAS_IOMEM
help help
This enables access to SPI NOR flash, using MT81xx SPI NOR flash This enables access to SPI NOR flash, using MT81xx SPI NOR flash
controller. This controller does not support generic SPI BUS, it only controller. This controller does not support generic SPI BUS, it only
...@@ -30,7 +31,7 @@ config MTD_SPI_NOR_USE_4K_SECTORS ...@@ -30,7 +31,7 @@ config MTD_SPI_NOR_USE_4K_SECTORS
config SPI_FSL_QUADSPI config SPI_FSL_QUADSPI
tristate "Freescale Quad SPI controller" tristate "Freescale Quad SPI controller"
depends on ARCH_MXC || COMPILE_TEST depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
depends on HAS_IOMEM depends on HAS_IOMEM
help help
This enables support for the Quad SPI controller in master mode. This enables support for the Quad SPI controller in master mode.
......
This diff is collapsed.
...@@ -371,8 +371,8 @@ static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, ...@@ -371,8 +371,8 @@ static int mt8173_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
return ret; return ret;
} }
static int __init mtk_nor_init(struct mt8173_nor *mt8173_nor, static int mtk_nor_init(struct mt8173_nor *mt8173_nor,
struct device_node *flash_node) struct device_node *flash_node)
{ {
int ret; int ret;
struct spi_nor *nor; struct spi_nor *nor;
......
This diff is collapsed.
...@@ -215,19 +215,19 @@ static int verify_eraseblock(int ebnum) ...@@ -215,19 +215,19 @@ static int verify_eraseblock(int ebnum)
pr_info("ignoring error as within bitflip_limit\n"); pr_info("ignoring error as within bitflip_limit\n");
} }
if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { if (use_offset != 0 || use_len < mtd->oobavail) {
int k; int k;
ops.mode = MTD_OPS_AUTO_OOB; ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0; ops.len = 0;
ops.retlen = 0; ops.retlen = 0;
ops.ooblen = mtd->ecclayout->oobavail; ops.ooblen = mtd->oobavail;
ops.oobretlen = 0; ops.oobretlen = 0;
ops.ooboffs = 0; ops.ooboffs = 0;
ops.datbuf = NULL; ops.datbuf = NULL;
ops.oobbuf = readbuf; ops.oobbuf = readbuf;
err = mtd_read_oob(mtd, addr, &ops); err = mtd_read_oob(mtd, addr, &ops);
if (err || ops.oobretlen != mtd->ecclayout->oobavail) { if (err || ops.oobretlen != mtd->oobavail) {
pr_err("error: readoob failed at %#llx\n", pr_err("error: readoob failed at %#llx\n",
(long long)addr); (long long)addr);
errcnt += 1; errcnt += 1;
...@@ -244,7 +244,7 @@ static int verify_eraseblock(int ebnum) ...@@ -244,7 +244,7 @@ static int verify_eraseblock(int ebnum)
/* verify post-(use_offset + use_len) area for 0xff */ /* verify post-(use_offset + use_len) area for 0xff */
k = use_offset + use_len; k = use_offset + use_len;
bitflips += memffshow(addr, k, readbuf + k, bitflips += memffshow(addr, k, readbuf + k,
mtd->ecclayout->oobavail - k); mtd->oobavail - k);
if (bitflips > bitflip_limit) { if (bitflips > bitflip_limit) {
pr_err("error: verify failed at %#llx\n", pr_err("error: verify failed at %#llx\n",
...@@ -269,8 +269,8 @@ static int verify_eraseblock_in_one_go(int ebnum) ...@@ -269,8 +269,8 @@ static int verify_eraseblock_in_one_go(int ebnum)
struct mtd_oob_ops ops; struct mtd_oob_ops ops;
int err = 0; int err = 0;
loff_t addr = (loff_t)ebnum * mtd->erasesize; loff_t addr = (loff_t)ebnum * mtd->erasesize;
size_t len = mtd->ecclayout->oobavail * pgcnt; size_t len = mtd->oobavail * pgcnt;
size_t oobavail = mtd->ecclayout->oobavail; size_t oobavail = mtd->oobavail;
size_t bitflips; size_t bitflips;
int i; int i;
...@@ -394,8 +394,8 @@ static int __init mtd_oobtest_init(void) ...@@ -394,8 +394,8 @@ static int __init mtd_oobtest_init(void)
goto out; goto out;
use_offset = 0; use_offset = 0;
use_len = mtd->ecclayout->oobavail; use_len = mtd->oobavail;
use_len_max = mtd->ecclayout->oobavail; use_len_max = mtd->oobavail;
vary_offset = 0; vary_offset = 0;
/* First test: write all OOB, read it back and verify */ /* First test: write all OOB, read it back and verify */
...@@ -460,8 +460,8 @@ static int __init mtd_oobtest_init(void) ...@@ -460,8 +460,8 @@ static int __init mtd_oobtest_init(void)
/* Write all eraseblocks */ /* Write all eraseblocks */
use_offset = 0; use_offset = 0;
use_len = mtd->ecclayout->oobavail; use_len = mtd->oobavail;
use_len_max = mtd->ecclayout->oobavail; use_len_max = mtd->oobavail;
vary_offset = 1; vary_offset = 1;
prandom_seed_state(&rnd_state, 5); prandom_seed_state(&rnd_state, 5);
...@@ -471,8 +471,8 @@ static int __init mtd_oobtest_init(void) ...@@ -471,8 +471,8 @@ static int __init mtd_oobtest_init(void)
/* Check all eraseblocks */ /* Check all eraseblocks */
use_offset = 0; use_offset = 0;
use_len = mtd->ecclayout->oobavail; use_len = mtd->oobavail;
use_len_max = mtd->ecclayout->oobavail; use_len_max = mtd->oobavail;
vary_offset = 1; vary_offset = 1;
prandom_seed_state(&rnd_state, 5); prandom_seed_state(&rnd_state, 5);
err = verify_all_eraseblocks(); err = verify_all_eraseblocks();
...@@ -480,8 +480,8 @@ static int __init mtd_oobtest_init(void) ...@@ -480,8 +480,8 @@ static int __init mtd_oobtest_init(void)
goto out; goto out;
use_offset = 0; use_offset = 0;
use_len = mtd->ecclayout->oobavail; use_len = mtd->oobavail;
use_len_max = mtd->ecclayout->oobavail; use_len_max = mtd->oobavail;
vary_offset = 0; vary_offset = 0;
/* Fourth test: try to write off end of device */ /* Fourth test: try to write off end of device */
...@@ -501,7 +501,7 @@ static int __init mtd_oobtest_init(void) ...@@ -501,7 +501,7 @@ static int __init mtd_oobtest_init(void)
ops.retlen = 0; ops.retlen = 0;
ops.ooblen = 1; ops.ooblen = 1;
ops.oobretlen = 0; ops.oobretlen = 0;
ops.ooboffs = mtd->ecclayout->oobavail; ops.ooboffs = mtd->oobavail;
ops.datbuf = NULL; ops.datbuf = NULL;
ops.oobbuf = writebuf; ops.oobbuf = writebuf;
pr_info("attempting to start write past end of OOB\n"); pr_info("attempting to start write past end of OOB\n");
...@@ -521,7 +521,7 @@ static int __init mtd_oobtest_init(void) ...@@ -521,7 +521,7 @@ static int __init mtd_oobtest_init(void)
ops.retlen = 0; ops.retlen = 0;
ops.ooblen = 1; ops.ooblen = 1;
ops.oobretlen = 0; ops.oobretlen = 0;
ops.ooboffs = mtd->ecclayout->oobavail; ops.ooboffs = mtd->oobavail;
ops.datbuf = NULL; ops.datbuf = NULL;
ops.oobbuf = readbuf; ops.oobbuf = readbuf;
pr_info("attempting to start read past end of OOB\n"); pr_info("attempting to start read past end of OOB\n");
...@@ -543,7 +543,7 @@ static int __init mtd_oobtest_init(void) ...@@ -543,7 +543,7 @@ static int __init mtd_oobtest_init(void)
ops.mode = MTD_OPS_AUTO_OOB; ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0; ops.len = 0;
ops.retlen = 0; ops.retlen = 0;
ops.ooblen = mtd->ecclayout->oobavail + 1; ops.ooblen = mtd->oobavail + 1;
ops.oobretlen = 0; ops.oobretlen = 0;
ops.ooboffs = 0; ops.ooboffs = 0;
ops.datbuf = NULL; ops.datbuf = NULL;
...@@ -563,7 +563,7 @@ static int __init mtd_oobtest_init(void) ...@@ -563,7 +563,7 @@ static int __init mtd_oobtest_init(void)
ops.mode = MTD_OPS_AUTO_OOB; ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0; ops.len = 0;
ops.retlen = 0; ops.retlen = 0;
ops.ooblen = mtd->ecclayout->oobavail + 1; ops.ooblen = mtd->oobavail + 1;
ops.oobretlen = 0; ops.oobretlen = 0;
ops.ooboffs = 0; ops.ooboffs = 0;
ops.datbuf = NULL; ops.datbuf = NULL;
...@@ -587,7 +587,7 @@ static int __init mtd_oobtest_init(void) ...@@ -587,7 +587,7 @@ static int __init mtd_oobtest_init(void)
ops.mode = MTD_OPS_AUTO_OOB; ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0; ops.len = 0;
ops.retlen = 0; ops.retlen = 0;
ops.ooblen = mtd->ecclayout->oobavail; ops.ooblen = mtd->oobavail;
ops.oobretlen = 0; ops.oobretlen = 0;
ops.ooboffs = 1; ops.ooboffs = 1;
ops.datbuf = NULL; ops.datbuf = NULL;
...@@ -607,7 +607,7 @@ static int __init mtd_oobtest_init(void) ...@@ -607,7 +607,7 @@ static int __init mtd_oobtest_init(void)
ops.mode = MTD_OPS_AUTO_OOB; ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0; ops.len = 0;
ops.retlen = 0; ops.retlen = 0;
ops.ooblen = mtd->ecclayout->oobavail; ops.ooblen = mtd->oobavail;
ops.oobretlen = 0; ops.oobretlen = 0;
ops.ooboffs = 1; ops.ooboffs = 1;
ops.datbuf = NULL; ops.datbuf = NULL;
...@@ -638,7 +638,7 @@ static int __init mtd_oobtest_init(void) ...@@ -638,7 +638,7 @@ static int __init mtd_oobtest_init(void)
for (i = 0; i < ebcnt - 1; ++i) { for (i = 0; i < ebcnt - 1; ++i) {
int cnt = 2; int cnt = 2;
int pg; int pg;
size_t sz = mtd->ecclayout->oobavail; size_t sz = mtd->oobavail;
if (bbt[i] || bbt[i + 1]) if (bbt[i] || bbt[i + 1])
continue; continue;
addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
...@@ -673,13 +673,12 @@ static int __init mtd_oobtest_init(void) ...@@ -673,13 +673,12 @@ static int __init mtd_oobtest_init(void)
for (i = 0; i < ebcnt - 1; ++i) { for (i = 0; i < ebcnt - 1; ++i) {
if (bbt[i] || bbt[i + 1]) if (bbt[i] || bbt[i + 1])
continue; continue;
prandom_bytes_state(&rnd_state, writebuf, prandom_bytes_state(&rnd_state, writebuf, mtd->oobavail * 2);
mtd->ecclayout->oobavail * 2);
addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize; addr = (loff_t)(i + 1) * mtd->erasesize - mtd->writesize;
ops.mode = MTD_OPS_AUTO_OOB; ops.mode = MTD_OPS_AUTO_OOB;
ops.len = 0; ops.len = 0;
ops.retlen = 0; ops.retlen = 0;
ops.ooblen = mtd->ecclayout->oobavail * 2; ops.ooblen = mtd->oobavail * 2;
ops.oobretlen = 0; ops.oobretlen = 0;
ops.ooboffs = 0; ops.ooboffs = 0;
ops.datbuf = NULL; ops.datbuf = NULL;
...@@ -688,7 +687,7 @@ static int __init mtd_oobtest_init(void) ...@@ -688,7 +687,7 @@ static int __init mtd_oobtest_init(void)
if (err) if (err)
goto out; goto out;
if (memcmpshow(addr, readbuf, writebuf, if (memcmpshow(addr, readbuf, writebuf,
mtd->ecclayout->oobavail * 2)) { mtd->oobavail * 2)) {
pr_err("error: verify failed at %#llx\n", pr_err("error: verify failed at %#llx\n",
(long long)addr); (long long)addr);
errcnt += 1; errcnt += 1;
......
...@@ -49,7 +49,6 @@ static struct nand_ecclayout spinand_oob_64 = { ...@@ -49,7 +49,6 @@ static struct nand_ecclayout spinand_oob_64 = {
17, 18, 19, 20, 21, 22, 17, 18, 19, 20, 21, 22,
33, 34, 35, 36, 37, 38, 33, 34, 35, 36, 37, 38,
49, 50, 51, 52, 53, 54, }, 49, 50, 51, 52, 53, 54, },
.oobavail = 32,
.oobfree = { .oobfree = {
{.offset = 8, {.offset = 8,
.length = 8}, .length = 8},
......
...@@ -78,7 +78,6 @@ ...@@ -78,7 +78,6 @@
#define BL_ALL_UNLOCKED 0 #define BL_ALL_UNLOCKED 0
struct spinand_info { struct spinand_info {
struct nand_ecclayout *ecclayout;
struct spi_device *spi; struct spi_device *spi;
void *priv; void *priv;
}; };
......
This diff is collapsed.
...@@ -49,7 +49,7 @@ struct jffs2_sb_info { ...@@ -49,7 +49,7 @@ struct jffs2_sb_info {
struct mtd_info *mtd; struct mtd_info *mtd;
uint32_t highest_ino; uint32_t highest_ino;
uint32_t checked_ino; uint32_t check_ino; /* *NEXT* inode to be checked */
unsigned int flags; unsigned int flags;
......
...@@ -846,8 +846,8 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c) ...@@ -846,8 +846,8 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c)
return 1; return 1;
if (c->unchecked_size) { if (c->unchecked_size) {
jffs2_dbg(1, "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n", jffs2_dbg(1, "jffs2_thread_should_wake(): unchecked_size %d, check_ino #%d\n",
c->unchecked_size, c->checked_ino); c->unchecked_size, c->check_ino);
return 1; return 1;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment