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

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

Pull MTD updates from Brian Norris:
 "First cycle with Boris as NAND maintainer! Many (most) bullets stolen
  from him.

  Generic:
   - Migrated NAND LED trigger to be a generic MTD trigger

  NAND:
   - Introduction of the "ECC algorithm" concept, to avoid overloading
     the ECC mode field too much more
   - Replaced the nand_ecclayout infrastructure with something a little
     more flexible (finally!) and future proof
   - Rework of the OMAP GPMC and NAND drivers; the TI folks pulled some
     of this into their own tree as well
   - Prepare the sunxi NAND driver to receive DMA support
   - Handle bitflips in erased pages on GPMI revisions that do not
     support this in hardware.

  SPI NOR:
   - Start using the spi_flash_read() API for SPI drivers that support
     it (i.e., SPI drivers with special memory-mapped flash modes)

  And other small scattered improvments"

* tag 'for-linus-20160523' of git://git.infradead.org/linux-mtd: (155 commits)
  mtd: spi-nor: support GigaDevice gd25lq64c
  mtd: nand_bch: fix spelling of "probably"
  mtd: brcmnand: respect ECC algorithm set by NAND subsystem
  gpmi-nand: Handle ECC Errors in erased pages
  Documentation: devicetree: deprecate "soft_bch" nand-ecc-mode value
  mtd: nand: add support for "nand-ecc-algo" DT property
  mtd: mtd: drop NAND_ECC_SOFT_BCH enum value
  mtd: drop support for NAND_ECC_SOFT_BCH as "soft_bch" mapping
  mtd: nand: read ECC algorithm from the new field
  mtd: nand: fsmc: validate ECC setup by checking algorithm directly
  mtd: nand: set ECC algorithm to Hamming on fallback
  staging: mt29f_spinand: set ECC algorithm explicitly
  CRIS v32: nand: set ECC algorithm explicitly
  mtd: nand: atmel: set ECC algorithm explicitly
  mtd: nand: davinci: set ECC algorithm explicitly
  mtd: nand: bf5xx: set ECC algorithm explicitly
  mtd: nand: omap2: Fix high memory dma prefetch transfer
  mtd: nand: omap2: Start dma request before enabling prefetch
  mtd: nandsim: add __init attribute
  mtd: nand: move of_get_nand_xxx() helpers into nand_base.c
  ...
parents 29567292 e5366a26
......@@ -32,6 +32,19 @@ Required properties:
bootloader) are used for the physical address decoding.
As this will change in the future, filling correct
values here is a requirement.
- interrupt-controller: The GPMC driver implements and interrupt controller for
the NAND events "fifoevent" and "termcount" plus the
rising/falling edges on the GPMC_WAIT pins.
The interrupt number mapping is as follows
0 - NAND_fifoevent
1 - NAND_termcount
2 - GPMC_WAIT0 pin edge
3 - GPMC_WAIT1 pin edge, and so on.
- interrupt-cells: Must be set to 2
- gpio-controller: The GPMC driver implements a GPIO controller for the
GPMC WAIT pins that can be used as general purpose inputs.
0 maps to GPMC_WAIT0 pin.
- gpio-cells: Must be set to 2
Timing properties for child nodes. All are optional and default to 0.
......@@ -130,6 +143,10 @@ Example for an AM33xx board:
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */
interrupt-controller;
#interrupt-cells = <2>;
gpio-controller;
#gpio-cells = <2>;
/* child nodes go here */
};
......@@ -24,6 +24,7 @@ Required properties:
brcm,brcmnand-v5.0
brcm,brcmnand-v6.0
brcm,brcmnand-v6.1
brcm,brcmnand-v6.2
brcm,brcmnand-v7.0
brcm,brcmnand-v7.1
brcm,brcmnand
......
......@@ -13,7 +13,11 @@ Documentation/devicetree/bindings/mtd/nand.txt
Required properties:
- reg: The CS line the peripheral is connected to
- compatible: "ti,omap2-nand"
- reg: range id (CS number), base offset and length of the
NAND I/O space
- interrupt-parent: must point to gpmc node
- interrupts: Two interrupt specifiers, one for fifoevent, one for termcount.
Optional properties:
......@@ -44,6 +48,7 @@ Optional properties:
locating ECC errors for BCHx algorithms. SoC devices which have
ELM hardware engines should specify this device node in .dtsi
Using ELM for ECC error correction frees some CPU cycles.
- rb-gpios: GPIO specifier for the ready/busy# pin.
For inline partition table parsing (optional):
......@@ -55,20 +60,26 @@ Example for an AM33xx board:
gpmc: gpmc@50000000 {
compatible = "ti,am3352-gpmc";
ti,hwmods = "gpmc";
reg = <0x50000000 0x1000000>;
reg = <0x50000000 0x36c>;
interrupts = <100>;
gpmc,num-cs = <8>;
gpmc,num-waitpins = <2>;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x08000000 0x2000>; /* CS0: NAND */
ranges = <0 0 0x08000000 0x1000000>; /* CS0 space, 16MB */
elm_id = <&elm>;
interrupt-controller;
#interrupt-cells = <2>;
nand@0,0 {
reg = <0 0 0>; /* CS0, offset 0 */
compatible = "ti,omap2-nand";
reg = <0 0 4>; /* CS0, offset 0, NAND I/O window 4 */
interrupt-parent = <&gpmc>;
interrupts = <0 IRQ_TYPE_NONE>, <1 IRQ_TYPE NONE>;
nand-bus-width = <16>;
ti,nand-ecc-opt = "bch8";
ti,nand-xfer-type = "polled";
rb-gpios = <&gpmc 0 GPIO_ACTIVE_HIGH>; /* gpmc_wait0 */
gpmc,sync-clk-ps = <0>;
gpmc,cs-on-ns = <0>;
......
* MTD generic binding
* NAND chip and NAND controller generic binding
NAND controller/NAND chip representation:
The NAND controller should be represented with its own DT node, and all
NAND chips attached to this controller should be defined as children nodes
of the NAND controller. This representation should be enforced even for
simple controllers supporting only one chip.
Mandatory NAND controller properties:
- #address-cells: depends on your controller. Should at least be 1 to
encode the CS line id.
- #size-cells: depends on your controller. Put zero unless you need a
mapping between CS lines and dedicated memory regions
Optional NAND controller properties
- ranges: only needed if you need to define a mapping between CS lines and
memory regions
Optional NAND chip properties:
- nand-ecc-mode : String, operation mode of the NAND ecc mode.
Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
"soft_bch".
Supported values are: "none", "soft", "hw", "hw_syndrome",
"hw_oob_first".
Deprecated values:
"soft_bch": use "soft" and nand-ecc-algo instead
- nand-ecc-algo: string, algorithm of NAND ECC.
Supported values are: "hamming", "bch".
- 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
......@@ -19,3 +42,19 @@ errors per {size} bytes".
The interpretation of these parameters is implementation-defined, so not all
implementations must support all possible combinations. However, implementations
are encouraged to further specify the value(s) they support.
Example:
nand-controller {
#address-cells = <1>;
#size-cells = <0>;
/* controller specific properties */
nand@0 {
reg = <0>;
nand-ecc-mode = "soft_bch";
/* controller specific properties */
};
};
......@@ -97,9 +97,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
memset(&s, 0, sizeof(struct gpmc_settings));
if (gpmc_nand_data->of_node)
gpmc_read_settings_dt(gpmc_nand_data->of_node, &s);
else
gpmc_set_legacy(gpmc_nand_data, &s);
s.device_nand = true;
......@@ -121,8 +118,6 @@ int gpmc_nand_init(struct omap_nand_platform_data *gpmc_nand_data,
if (err < 0)
goto out_free_cs;
gpmc_update_nand_reg(&gpmc_nand_data->reg, gpmc_nand_data->cs);
if (!gpmc_hwecc_bch_capable(gpmc_nand_data->ecc_opt)) {
pr_err("omap2-nand: Unsupported NAND ECC scheme selected\n");
err = -EINVAL;
......
......@@ -763,14 +763,49 @@ static struct nand_bbt_descr spitz_nand_bbt = {
.pattern = scan_ff_pattern
};
static struct nand_ecclayout akita_oobinfo = {
.oobfree = { {0x08, 0x09} },
.eccbytes = 24,
.eccpos = {
0x05, 0x01, 0x02, 0x03, 0x06, 0x07, 0x15, 0x11,
0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37,
},
static int akita_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 12)
return -ERANGE;
switch (section % 3) {
case 0:
oobregion->offset = 5;
oobregion->length = 1;
break;
case 1:
oobregion->offset = 1;
oobregion->length = 3;
break;
case 2:
oobregion->offset = 6;
oobregion->length = 2;
break;
}
oobregion->offset += (section / 3) * 0x10;
return 0;
}
static int akita_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section)
return -ERANGE;
oobregion->offset = 8;
oobregion->length = 9;
return 0;
}
static const struct mtd_ooblayout_ops akita_ooblayout_ops = {
.ecc = akita_ooblayout_ecc,
.free = akita_ooblayout_free,
};
static struct sharpsl_nand_platform_data spitz_nand_pdata = {
......@@ -804,11 +839,11 @@ static void __init spitz_nand_init(void)
} else if (machine_is_akita()) {
spitz_nand_partitions[1].size = 58 * 1024 * 1024;
spitz_nand_bbt.len = 1;
spitz_nand_pdata.ecc_layout = &akita_oobinfo;
spitz_nand_pdata.ecc_layout = &akita_ooblayout_ops;
} else if (machine_is_borzoi()) {
spitz_nand_partitions[1].size = 32 * 1024 * 1024;
spitz_nand_bbt.len = 1;
spitz_nand_pdata.ecc_layout = &akita_oobinfo;
spitz_nand_pdata.ecc_layout = &akita_ooblayout_ops;
}
platform_device_register(&spitz_nand_device);
......
......@@ -157,6 +157,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)
/* 20 us command delay time */
this->chip_delay = 20;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
/* Enable the following for a flash based bad block table */
/* this->bbt_options = NAND_BBT_USE_FLASH; */
......
......@@ -148,6 +148,7 @@ struct mtd_info *__init crisv32_nand_flash_probe(void)
/* 20 us command delay time */
this->chip_delay = 20;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
/* Enable the following for a flash based bad block table */
/* this->bbt_options = NAND_BBT_USE_FLASH; */
......
......@@ -27,7 +27,7 @@ struct jz_nand_platform_data {
unsigned char banks[JZ_NAND_NUM_BANKS];
void (*ident_callback)(struct platform_device *, struct nand_chip *,
void (*ident_callback)(struct platform_device *, struct mtd_info *,
struct mtd_partition **, int *num_partitions);
};
......
......@@ -48,20 +48,6 @@
#define QI_LB60_GPIO_KEYIN8 JZ_GPIO_PORTD(26)
/* NAND */
static struct nand_ecclayout qi_lb60_ecclayout_1gb = {
.eccbytes = 36,
.eccpos = {
6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41
},
.oobfree = {
{ .offset = 2, .length = 4 },
{ .offset = 42, .length = 22 }
},
};
/* Early prototypes of the QI LB60 had only 1GB of NAND.
* In order to support these devices as well the partition and ecc layout is
......@@ -84,25 +70,6 @@ static struct mtd_partition qi_lb60_partitions_1gb[] = {
},
};
static struct nand_ecclayout qi_lb60_ecclayout_2gb = {
.eccbytes = 72,
.eccpos = {
12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83
},
.oobfree = {
{ .offset = 2, .length = 10 },
{ .offset = 84, .length = 44 },
},
};
static struct mtd_partition qi_lb60_partitions_2gb[] = {
{
.name = "NAND BOOT partition",
......@@ -121,19 +88,67 @@ static struct mtd_partition qi_lb60_partitions_2gb[] = {
},
};
static int qi_lb60_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section)
return -ERANGE;
oobregion->length = 36;
oobregion->offset = 6;
if (mtd->oobsize == 128) {
oobregion->length *= 2;
oobregion->offset *= 2;
}
return 0;
}
static int qi_lb60_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
int eccbytes = 36, eccoff = 6;
if (section > 1)
return -ERANGE;
if (mtd->oobsize == 128) {
eccbytes *= 2;
eccoff *= 2;
}
if (!section) {
oobregion->offset = 2;
oobregion->length = eccoff - 2;
} else {
oobregion->offset = eccoff + eccbytes;
oobregion->length = mtd->oobsize - oobregion->offset;
}
return 0;
}
static const struct mtd_ooblayout_ops qi_lb60_ooblayout_ops = {
.ecc = qi_lb60_ooblayout_ecc,
.free = qi_lb60_ooblayout_free,
};
static void qi_lb60_nand_ident(struct platform_device *pdev,
struct nand_chip *chip, struct mtd_partition **partitions,
struct mtd_info *mtd, struct mtd_partition **partitions,
int *num_partitions)
{
struct nand_chip *chip = mtd_to_nand(mtd);
if (chip->page_shift == 12) {
chip->ecc.layout = &qi_lb60_ecclayout_2gb;
*partitions = qi_lb60_partitions_2gb;
*num_partitions = ARRAY_SIZE(qi_lb60_partitions_2gb);
} else {
chip->ecc.layout = &qi_lb60_ecclayout_1gb;
*partitions = qi_lb60_partitions_1gb;
*num_partitions = ARRAY_SIZE(qi_lb60_partitions_1gb);
}
mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops);
}
static struct jz_nand_platform_data qi_lb60_nand_pdata = {
......
......@@ -146,7 +146,6 @@ int bcma_sflash_init(struct bcma_drv_cc *cc)
return -ENOTSUPP;
}
sflash->window = BCMA_SOC_FLASH2;
sflash->blocksize = e->blocksize;
sflash->numblocks = e->numblocks;
sflash->size = sflash->blocksize * sflash->numblocks;
......
......@@ -51,6 +51,7 @@ config TI_EMIF
config OMAP_GPMC
bool
select GPIOLIB
help
This driver is for the General Purpose Memory Controller (GPMC)
present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows
......
......@@ -59,11 +59,11 @@ int fsl_ifc_find(phys_addr_t addr_base)
{
int i = 0;
if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->gregs)
return -ENODEV;
for (i = 0; i < fsl_ifc_ctrl_dev->banks; i++) {
u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr);
u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->gregs->cspr_cs[i].cspr);
if (cspr & CSPR_V && (cspr & CSPR_BA) ==
convert_ifc_address(addr_base))
return i;
......@@ -75,7 +75,7 @@ EXPORT_SYMBOL(fsl_ifc_find);
static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
{
struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
/*
* Clear all the common status and event registers
......@@ -104,7 +104,7 @@ static int fsl_ifc_ctrl_remove(struct platform_device *dev)
irq_dispose_mapping(ctrl->nand_irq);
irq_dispose_mapping(ctrl->irq);
iounmap(ctrl->regs);
iounmap(ctrl->gregs);
dev_set_drvdata(&dev->dev, NULL);
kfree(ctrl);
......@@ -122,7 +122,7 @@ static DEFINE_SPINLOCK(nand_irq_lock);
static u32 check_nand_stat(struct fsl_ifc_ctrl *ctrl)
{
struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
unsigned long flags;
u32 stat;
......@@ -157,7 +157,7 @@ static irqreturn_t fsl_ifc_nand_irq(int irqno, void *data)
static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
{
struct fsl_ifc_ctrl *ctrl = data;
struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
u32 err_axiid, err_srcid, status, cs_err, err_addr;
irqreturn_t ret = IRQ_NONE;
......@@ -215,6 +215,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
{
int ret = 0;
int version, banks;
void __iomem *addr;
dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
......@@ -225,22 +226,13 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
/* IOMAP the entire IFC region */
fsl_ifc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
if (!fsl_ifc_ctrl_dev->regs) {
fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0);
if (!fsl_ifc_ctrl_dev->gregs) {
dev_err(&dev->dev, "failed to get memory region\n");
ret = -ENODEV;
goto err;
}
version = ifc_in32(&fsl_ifc_ctrl_dev->regs->ifc_rev) &
FSL_IFC_VERSION_MASK;
banks = (version == FSL_IFC_VERSION_1_0_0) ? 4 : 8;
dev_info(&dev->dev, "IFC version %d.%d, %d banks\n",
version >> 24, (version >> 16) & 0xf, banks);
fsl_ifc_ctrl_dev->version = version;
fsl_ifc_ctrl_dev->banks = banks;
if (of_property_read_bool(dev->dev.of_node, "little-endian")) {
fsl_ifc_ctrl_dev->little_endian = true;
dev_dbg(&dev->dev, "IFC REGISTERS are LITTLE endian\n");
......@@ -249,8 +241,9 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
dev_dbg(&dev->dev, "IFC REGISTERS are BIG endian\n");
}
version = ioread32be(&fsl_ifc_ctrl_dev->regs->ifc_rev) &
version = ifc_in32(&fsl_ifc_ctrl_dev->gregs->ifc_rev) &
FSL_IFC_VERSION_MASK;
banks = (version == FSL_IFC_VERSION_1_0_0) ? 4 : 8;
dev_info(&dev->dev, "IFC version %d.%d, %d banks\n",
version >> 24, (version >> 16) & 0xf, banks);
......@@ -258,6 +251,13 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
fsl_ifc_ctrl_dev->version = version;
fsl_ifc_ctrl_dev->banks = banks;
addr = fsl_ifc_ctrl_dev->gregs;
if (version >= FSL_IFC_VERSION_2_0_0)
addr += PGOFFSET_64K;
else
addr += PGOFFSET_4K;
fsl_ifc_ctrl_dev->rregs = addr;
/* get the Controller level irq */
fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
if (fsl_ifc_ctrl_dev->irq == 0) {
......
This diff is collapsed.
......@@ -115,6 +115,7 @@ config MTD_MAP_BANK_WIDTH_16
config MTD_MAP_BANK_WIDTH_32
bool "Support 256-bit buswidth" if MTD_CFI_GEOMETRY
select MTD_COMPLEX_MAPPINGS if HAS_IOMEM
default n
help
If you wish to support CFI devices on a physical bus which is
......
......@@ -2,6 +2,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/mtd/mtd.h>
#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
......@@ -109,8 +110,7 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
if ((from + len) > mtd->size)
return -EINVAL;
memcpy_fromio(buf, (void __iomem *)KSEG0ADDR(b47s->window + from),
len);
memcpy_fromio(buf, b47s->window + from, len);
*retlen = len;
return len;
......@@ -275,15 +275,33 @@ static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
{
struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev;
struct bcma_sflash *sflash = dev_get_platdata(dev);
struct bcm47xxsflash *b47s;
struct resource *res;
int err;
b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
b47s = devm_kzalloc(dev, sizeof(*b47s), GFP_KERNEL);
if (!b47s)
return -ENOMEM;
sflash->priv = b47s;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "invalid resource\n");
return -EINVAL;
}
if (!devm_request_mem_region(dev, res->start, resource_size(res),
res->name)) {
dev_err(dev, "can't request region for resource %pR\n", res);
return -EBUSY;
}
b47s->window = ioremap_cache(res->start, resource_size(res));
if (!b47s->window) {
dev_err(dev, "ioremap failed for resource %pR\n", res);
return -ENOMEM;
}
b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
b47s->cc_read = bcm47xxsflash_bcma_cc_read;
b47s->cc_write = bcm47xxsflash_bcma_cc_write;
......@@ -297,7 +315,6 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
break;
}
b47s->window = sflash->window;
b47s->blocksize = sflash->blocksize;
b47s->numblocks = sflash->numblocks;
b47s->size = sflash->size;
......@@ -306,6 +323,7 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
if (err) {
pr_err("Failed to register MTD device: %d\n", err);
iounmap(b47s->window);
return err;
}
......@@ -321,6 +339,7 @@ static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
struct bcm47xxsflash *b47s = sflash->priv;
mtd_device_unregister(&b47s->mtd);
iounmap(b47s->window);
return 0;
}
......
......@@ -65,7 +65,8 @@ struct bcm47xxsflash {
enum bcm47xxsflash_type type;
u32 window;
void __iomem *window;
u32 blocksize;
u16 numblocks;
u32 size;
......
......@@ -67,16 +67,40 @@ module_param(reliable_mode, uint, 0);
MODULE_PARM_DESC(reliable_mode, "Set the docg3 mode (0=normal MLC, 1=fast, "
"2=reliable) : MLC normal operations are in normal mode");
/**
* struct docg3_oobinfo - DiskOnChip G3 OOB layout
* @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)
* @oobfree: free pageinfo bytes (byte 0 until byte 6, byte 15
*/
static struct nand_ecclayout docg3_oobinfo = {
.eccbytes = 8,
.eccpos = {7, 8, 9, 10, 11, 12, 13, 14},
.oobfree = {{0, 7}, {15, 1} },
static int docg3_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section)
return -ERANGE;
/* byte 7 is Hamming ECC, byte 8-14 are BCH ECC */
oobregion->offset = 7;
oobregion->length = 8;
return 0;
}
static int docg3_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 1)
return -ERANGE;
/* free bytes: byte 0 until byte 6, byte 15 */
if (!section) {
oobregion->offset = 0;
oobregion->length = 7;
} else {
oobregion->offset = 15;
oobregion->length = 1;
}
return 0;
}
static const struct mtd_ooblayout_ops nand_ooblayout_docg3_ops = {
.ecc = docg3_ooblayout_ecc,
.free = docg3_ooblayout_free,
};
static inline u8 doc_readb(struct docg3 *docg3, u16 reg)
......@@ -1857,7 +1881,7 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
mtd->_read_oob = doc_read_oob;
mtd->_write_oob = doc_write_oob;
mtd->_block_isbad = doc_block_isbad;
mtd->ecclayout = &docg3_oobinfo;
mtd_set_ooblayout(mtd, &nand_ooblayout_docg3_ops);
mtd->oobavail = 8;
mtd->ecc_strength = DOC_ECC_BCH_T;
......
......@@ -131,6 +131,28 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
/* convert the dummy cycles to the number of bytes */
dummy /= 8;
if (spi_flash_read_supported(spi)) {
struct spi_flash_read_message msg;
int ret;
memset(&msg, 0, sizeof(msg));
msg.buf = buf;
msg.from = from;
msg.len = len;
msg.read_opcode = nor->read_opcode;
msg.addr_width = nor->addr_width;
msg.dummy_bytes = dummy;
/* TODO: Support other combinations */
msg.opcode_nbits = SPI_NBITS_SINGLE;
msg.addr_nbits = SPI_NBITS_SINGLE;
msg.data_nbits = m25p80_rx_nbits(nor);
ret = spi_flash_read(spi, &msg);
*retlen = msg.retlen;
return ret;
}
spi_message_init(&m);
memset(t, 0, (sizeof t));
......
......@@ -353,7 +353,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
* mechanism
* returns the size of the memory region found.
*/
static int fixup_pmc551(struct pci_dev *dev)
static int __init fixup_pmc551(struct pci_dev *dev)
{
#ifdef CONFIG_MTD_PMC551_BUGFIX
u32 dram_data;
......
......@@ -112,7 +112,7 @@ static void ck804xrom_cleanup(struct ck804xrom_window *window)
}
static int ck804xrom_init_one(struct pci_dev *pdev,
static int __init ck804xrom_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
......
......@@ -144,7 +144,7 @@ static void esb2rom_cleanup(struct esb2rom_window *window)
pci_dev_put(window->pdev);
}
static int esb2rom_init_one(struct pci_dev *pdev,
static int __init esb2rom_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
......
......@@ -84,7 +84,7 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
}
static int ichxrom_init_one(struct pci_dev *pdev,
static int __init ichxrom_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
......
......@@ -4,11 +4,13 @@
* uclinux.c -- generic memory mapped MTD driver for uclinux
*
* (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
*
* License: GPL
*/
/****************************************************************************/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
......@@ -117,27 +119,6 @@ static int __init uclinux_mtd_init(void)
return(0);
}
/****************************************************************************/
static void __exit uclinux_mtd_cleanup(void)
{
if (uclinux_ram_mtdinfo) {
mtd_device_unregister(uclinux_ram_mtdinfo);
map_destroy(uclinux_ram_mtdinfo);
uclinux_ram_mtdinfo = NULL;
}
if (uclinux_ram_map.virt)
uclinux_ram_map.virt = 0;
}
/****************************************************************************/
module_init(uclinux_mtd_init);
module_exit(uclinux_mtd_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
MODULE_DESCRIPTION("Generic MTD for uClinux");
device_initcall(uclinux_mtd_init);
/****************************************************************************/
......@@ -465,38 +465,111 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd,
}
/*
* Copies (and truncates, if necessary) data from the larger struct,
* nand_ecclayout, to the smaller, deprecated layout struct,
* nand_ecclayout_user. This is necessary only to support the deprecated
* API ioctl ECCGETLAYOUT while allowing all new functionality to use
* nand_ecclayout flexibly (i.e. the struct may change size in new
* releases without requiring major rewrites).
* Copies (and truncates, if necessary) OOB layout information to the
* deprecated layout struct, nand_ecclayout_user. This is necessary only to
* support the deprecated API ioctl ECCGETLAYOUT while allowing all new
* functionality to use mtd_ooblayout_ops flexibly (i.e. mtd_ooblayout_ops
* can describe any kind of OOB layout with almost zero overhead from a
* memory usage point of view).
*/
static int shrink_ecclayout(const struct nand_ecclayout *from,
static int shrink_ecclayout(struct mtd_info *mtd,
struct nand_ecclayout_user *to)
{
int i;
struct mtd_oob_region oobregion;
int i, section = 0, ret;
if (!from || !to)
if (!mtd || !to)
return -EINVAL;
memset(to, 0, sizeof(*to));
to->eccbytes = min((int)from->eccbytes, MTD_MAX_ECCPOS_ENTRIES);
for (i = 0; i < to->eccbytes; i++)
to->eccpos[i] = from->eccpos[i];
to->eccbytes = 0;
for (i = 0; i < MTD_MAX_ECCPOS_ENTRIES;) {
u32 eccpos;
ret = mtd_ooblayout_ecc(mtd, section, &oobregion);
if (ret < 0) {
if (ret != -ERANGE)
return ret;
break;
}
eccpos = oobregion.offset;
for (; i < MTD_MAX_ECCPOS_ENTRIES &&
eccpos < oobregion.offset + oobregion.length; i++) {
to->eccpos[i] = eccpos++;
to->eccbytes++;
}
}
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
if (from->oobfree[i].length == 0 &&
from->oobfree[i].offset == 0)
ret = mtd_ooblayout_free(mtd, i, &oobregion);
if (ret < 0) {
if (ret != -ERANGE)
return ret;
break;
to->oobavail += from->oobfree[i].length;
to->oobfree[i] = from->oobfree[i];
}
to->oobfree[i].offset = oobregion.offset;
to->oobfree[i].length = oobregion.length;
to->oobavail += to->oobfree[i].length;
}
return 0;
}
static int get_oobinfo(struct mtd_info *mtd, struct nand_oobinfo *to)
{
struct mtd_oob_region oobregion;
int i, section = 0, ret;
if (!mtd || !to)
return -EINVAL;
memset(to, 0, sizeof(*to));
to->eccbytes = 0;
for (i = 0; i < ARRAY_SIZE(to->eccpos);) {
u32 eccpos;
ret = mtd_ooblayout_ecc(mtd, section, &oobregion);
if (ret < 0) {
if (ret != -ERANGE)
return ret;
break;
}
if (oobregion.length + i > ARRAY_SIZE(to->eccpos))
return -EINVAL;
eccpos = oobregion.offset;
for (; eccpos < oobregion.offset + oobregion.length; i++) {
to->eccpos[i] = eccpos++;
to->eccbytes++;
}
}
for (i = 0; i < 8; i++) {
ret = mtd_ooblayout_free(mtd, i, &oobregion);
if (ret < 0) {
if (ret != -ERANGE)
return ret;
break;
}
to->oobfree[i][0] = oobregion.offset;
to->oobfree[i][1] = oobregion.length;
}
to->useecc = MTD_NANDECC_AUTOPLACE;
return 0;
}
static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
struct blkpg_ioctl_arg *arg)
{
......@@ -815,16 +888,12 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
{
struct nand_oobinfo oi;
if (!mtd->ecclayout)
if (!mtd->ooblayout)
return -EOPNOTSUPP;
if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos))
return -EINVAL;
oi.useecc = MTD_NANDECC_AUTOPLACE;
memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));
memcpy(&oi.oobfree, mtd->ecclayout->oobfree,
sizeof(oi.oobfree));
oi.eccbytes = mtd->ecclayout->eccbytes;
ret = get_oobinfo(mtd, &oi);
if (ret)
return ret;
if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))
return -EFAULT;
......@@ -913,14 +982,14 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
{
struct nand_ecclayout_user *usrlay;
if (!mtd->ecclayout)
if (!mtd->ooblayout)
return -EOPNOTSUPP;
usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
if (!usrlay)
return -ENOMEM;
shrink_ecclayout(mtd->ecclayout, usrlay);
shrink_ecclayout(mtd, usrlay);
if (copy_to_user(argp, usrlay, sizeof(*usrlay)))
ret = -EFAULT;
......
......@@ -777,7 +777,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
}
concat->mtd.ecclayout = subdev[0]->ecclayout;
mtd_set_ooblayout(&concat->mtd, subdev[0]->ooblayout);
concat->num_subdev = num_devs;
concat->mtd.name = name;
......
This diff is collapsed.
......@@ -317,6 +317,27 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
return res;
}
static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct mtd_part *part = mtd_to_part(mtd);
return mtd_ooblayout_ecc(part->master, section, oobregion);
}
static int part_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct mtd_part *part = mtd_to_part(mtd);
return mtd_ooblayout_free(part->master, section, oobregion);
}
static const struct mtd_ooblayout_ops part_ooblayout_ops = {
.ecc = part_ooblayout_ecc,
.free = part_ooblayout_free,
};
static inline void free_partition(struct mtd_part *p)
{
kfree(p->mtd.name);
......@@ -533,7 +554,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
part->name);
}
slave->mtd.ecclayout = master->ecclayout;
mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
slave->mtd.ecc_step_size = master->ecc_step_size;
slave->mtd.ecc_strength = master->ecc_strength;
slave->mtd.bitflip_threshold = master->bitflip_threshold;
......
......@@ -224,6 +224,7 @@ static int ams_delta_init(struct platform_device *pdev)
/* 25 us command delay time */
this->chip_delay = 30;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
platform_set_drvdata(pdev, io_base);
......
This diff is collapsed.
......@@ -459,6 +459,7 @@ static int au1550nd_probe(struct platform_device *pdev)
/* 30 us command delay time */
this->chip_delay = 30;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
if (pd->devwidth)
this->options |= NAND_BUSWIDTH_16;
......
......@@ -109,28 +109,33 @@ static const unsigned short bfin_nfc_pin_req[] =
0};
#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
static struct nand_ecclayout bootrom_ecclayout = {
.eccbytes = 24,
.eccpos = {
0x8 * 0, 0x8 * 0 + 1, 0x8 * 0 + 2,
0x8 * 1, 0x8 * 1 + 1, 0x8 * 1 + 2,
0x8 * 2, 0x8 * 2 + 1, 0x8 * 2 + 2,
0x8 * 3, 0x8 * 3 + 1, 0x8 * 3 + 2,
0x8 * 4, 0x8 * 4 + 1, 0x8 * 4 + 2,
0x8 * 5, 0x8 * 5 + 1, 0x8 * 5 + 2,
0x8 * 6, 0x8 * 6 + 1, 0x8 * 6 + 2,
0x8 * 7, 0x8 * 7 + 1, 0x8 * 7 + 2
},
.oobfree = {
{ 0x8 * 0 + 3, 5 },
{ 0x8 * 1 + 3, 5 },
{ 0x8 * 2 + 3, 5 },
{ 0x8 * 3 + 3, 5 },
{ 0x8 * 4 + 3, 5 },
{ 0x8 * 5 + 3, 5 },
{ 0x8 * 6 + 3, 5 },
{ 0x8 * 7 + 3, 5 },
}
static int bootrom_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 7)
return -ERANGE;
oobregion->offset = section * 8;
oobregion->length = 3;
return 0;
}
static int bootrom_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 7)
return -ERANGE;
oobregion->offset = (section * 8) + 3;
oobregion->length = 5;
return 0;
}
static const struct mtd_ooblayout_ops bootrom_ooblayout_ops = {
.ecc = bootrom_ooblayout_ecc,
.free = bootrom_ooblayout_free,
};
#endif
......@@ -800,7 +805,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
/* setup hardware ECC data struct */
if (hardware_ecc) {
#ifdef CONFIG_MTD_NAND_BF5XX_BOOTROM_ECC
chip->ecc.layout = &bootrom_ecclayout;
mtd_set_ooblayout(mtd, &bootrom_ooblayout_ops);
#endif
chip->read_buf = bf5xx_nand_dma_read_buf;
chip->write_buf = bf5xx_nand_dma_write_buf;
......@@ -812,6 +817,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
chip->ecc.write_page_raw = bf5xx_nand_write_page_raw;
} else {
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
}
/* scan hardware nand chip and setup mtd info data struct */
......
This diff is collapsed.
......@@ -459,10 +459,37 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
return max_bitflips;
}
static struct nand_ecclayout cafe_oobinfo_2048 = {
.eccbytes = 14,
.eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
.oobfree = {{14, 50}}
static int cafe_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct nand_chip *chip = mtd_to_nand(mtd);
if (section)
return -ERANGE;
oobregion->offset = 0;
oobregion->length = chip->ecc.total;
return 0;
}
static int cafe_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct nand_chip *chip = mtd_to_nand(mtd);
if (section)
return -ERANGE;
oobregion->offset = chip->ecc.total;
oobregion->length = mtd->oobsize - chip->ecc.total;
return 0;
}
static const struct mtd_ooblayout_ops cafe_ooblayout_ops = {
.ecc = cafe_ooblayout_ecc,
.free = cafe_ooblayout_free,
};
/* Ick. The BBT code really ought to be able to work this bit out
......@@ -494,12 +521,6 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_2048 = {
.pattern = cafe_mirror_pattern_2048
};
static struct nand_ecclayout cafe_oobinfo_512 = {
.eccbytes = 14,
.eccpos = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13},
.oobfree = {{14, 2}}
};
static struct nand_bbt_descr cafe_bbt_main_descr_512 = {
.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
| NAND_BBT_2BIT | NAND_BBT_VERSION,
......@@ -743,12 +764,11 @@ static int cafe_nand_probe(struct pci_dev *pdev,
cafe->ctl2 |= 1<<29; /* 2KiB page size */
/* Set up ECC according to the type of chip we found */
mtd_set_ooblayout(mtd, &cafe_ooblayout_ops);
if (mtd->writesize == 2048) {
cafe->nand.ecc.layout = &cafe_oobinfo_2048;
cafe->nand.bbt_td = &cafe_bbt_main_descr_2048;
cafe->nand.bbt_md = &cafe_bbt_mirror_descr_2048;
} else if (mtd->writesize == 512) {
cafe->nand.ecc.layout = &cafe_oobinfo_512;
cafe->nand.bbt_td = &cafe_bbt_main_descr_512;
cafe->nand.bbt_md = &cafe_bbt_mirror_descr_512;
} else {
......
......@@ -187,6 +187,7 @@ static int __init cmx270_init(void)
/* 15 us command delay time */
this->chip_delay = 20;
this->ecc.mode = NAND_ECC_SOFT;
this->ecc.algo = NAND_ECC_HAMMING;
/* read/write functions */
this->read_byte = cmx270_read_byte;
......
......@@ -34,7 +34,6 @@
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/of_mtd.h>
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/mtd-davinci-aemif.h>
......@@ -54,7 +53,6 @@
*/
struct davinci_nand_info {
struct nand_chip chip;
struct nand_ecclayout ecclayout;
struct device *dev;
struct clk *clk;
......@@ -480,63 +478,46 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
* ten ECC bytes plus the manufacturer's bad block marker byte, and
* and not overlapping the default BBT markers.
*/
static struct nand_ecclayout hwecc4_small = {
.eccbytes = 10,
.eccpos = { 0, 1, 2, 3, 4,
/* offset 5 holds the badblock marker */
6, 7,
13, 14, 15, },
.oobfree = {
{.offset = 8, .length = 5, },
{.offset = 16, },
},
};
static int hwecc4_ooblayout_small_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 2)
return -ERANGE;
if (!section) {
oobregion->offset = 0;
oobregion->length = 5;
} else if (section == 1) {
oobregion->offset = 6;
oobregion->length = 2;
} else {
oobregion->offset = 13;
oobregion->length = 3;
}
/* An ECC layout for using 4-bit ECC with large-page (2048bytes) flash,
* storing ten ECC bytes plus the manufacturer's bad block marker byte,
* and not overlapping the default BBT markers.
*/
static struct nand_ecclayout hwecc4_2048 = {
.eccbytes = 40,
.eccpos = {
/* at the end of spare sector */
24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
},
.oobfree = {
/* 2 bytes at offset 0 hold manufacturer badblock markers */
{.offset = 2, .length = 22, },
/* 5 bytes at offset 8 hold BBT markers */
/* 8 bytes at offset 16 hold JFFS2 clean markers */
},
};
return 0;
}
/*
* An ECC layout for using 4-bit ECC with large-page (4096bytes) flash,
* storing ten ECC bytes plus the manufacturer's bad block marker byte,
* and not overlapping the default BBT markers.
*/
static struct nand_ecclayout hwecc4_4096 = {
.eccbytes = 80,
.eccpos = {
/* at the end of spare sector */
48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
},
.oobfree = {
/* 2 bytes at offset 0 hold manufacturer badblock markers */
{.offset = 2, .length = 46, },
/* 5 bytes at offset 8 hold BBT markers */
/* 8 bytes at offset 16 hold JFFS2 clean markers */
},
static int hwecc4_ooblayout_small_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 1)
return -ERANGE;
if (!section) {
oobregion->offset = 8;
oobregion->length = 5;
} else {
oobregion->offset = 16;
oobregion->length = mtd->oobsize - 16;
}
return 0;
}
static const struct mtd_ooblayout_ops hwecc4_small_ooblayout_ops = {
.ecc = hwecc4_ooblayout_small_ecc,
.free = hwecc4_ooblayout_small_free,
};
#if defined(CONFIG_OF)
......@@ -577,8 +558,6 @@ static struct davinci_nand_pdata
"ti,davinci-mask-chipsel", &prop))
pdata->mask_chipsel = prop;
if (!of_property_read_string(pdev->dev.of_node,
"nand-ecc-mode", &mode) ||
!of_property_read_string(pdev->dev.of_node,
"ti,davinci-ecc-mode", &mode)) {
if (!strncmp("none", mode, 4))
pdata->ecc_mode = NAND_ECC_NONE;
......@@ -591,14 +570,11 @@ static struct davinci_nand_pdata
"ti,davinci-ecc-bits", &prop))
pdata->ecc_bits = prop;
prop = of_get_nand_bus_width(pdev->dev.of_node);
if (0 < prop || !of_property_read_u32(pdev->dev.of_node,
"ti,davinci-nand-buswidth", &prop))
if (prop == 16)
if (!of_property_read_u32(pdev->dev.of_node,
"ti,davinci-nand-buswidth", &prop) && prop == 16)
pdata->options |= NAND_BUSWIDTH_16;
if (of_property_read_bool(pdev->dev.of_node,
"nand-on-flash-bbt") ||
of_property_read_bool(pdev->dev.of_node,
"ti,davinci-nand-use-bbt"))
pdata->bbt_options = NAND_BBT_USE_FLASH;
......@@ -628,7 +604,6 @@ static int nand_davinci_probe(struct platform_device *pdev)
void __iomem *base;
int ret;
uint32_t val;
nand_ecc_modes_t ecc_mode;
struct mtd_info *mtd;
pdata = nand_davinci_get_pdata(pdev);
......@@ -712,13 +687,53 @@ static int nand_davinci_probe(struct platform_device *pdev)
info->chip.write_buf = nand_davinci_write_buf;
/* Use board-specific ECC config */
ecc_mode = pdata->ecc_mode;
info->chip.ecc.mode = pdata->ecc_mode;
ret = -EINVAL;
switch (ecc_mode) {
info->clk = devm_clk_get(&pdev->dev, "aemif");
if (IS_ERR(info->clk)) {
ret = PTR_ERR(info->clk);
dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
return ret;
}
ret = clk_prepare_enable(info->clk);
if (ret < 0) {
dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
ret);
goto err_clk_enable;
}
spin_lock_irq(&davinci_nand_lock);
/* put CSxNAND into NAND mode */
val = davinci_nand_readl(info, NANDFCR_OFFSET);
val |= BIT(info->core_chipsel);
davinci_nand_writel(info, NANDFCR_OFFSET, val);
spin_unlock_irq(&davinci_nand_lock);
/* Scan to find existence of the device(s) */
ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
if (ret < 0) {
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
goto err;
}
switch (info->chip.ecc.mode) {
case NAND_ECC_NONE:
pdata->ecc_bits = 0;
break;
case NAND_ECC_SOFT:
pdata->ecc_bits = 0;
/*
* This driver expects Hamming based ECC when ecc_mode is set
* to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to
* avoid adding an extra ->ecc_algo field to
* davinci_nand_pdata.
*/
info->chip.ecc.algo = NAND_ECC_HAMMING;
break;
case NAND_ECC_HW:
if (pdata->ecc_bits == 4) {
......@@ -754,37 +769,6 @@ static int nand_davinci_probe(struct platform_device *pdev)
default:
return -EINVAL;
}
info->chip.ecc.mode = ecc_mode;
info->clk = devm_clk_get(&pdev->dev, "aemif");
if (IS_ERR(info->clk)) {
ret = PTR_ERR(info->clk);
dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
return ret;
}
ret = clk_prepare_enable(info->clk);
if (ret < 0) {
dev_dbg(&pdev->dev, "unable to enable AEMIF clock, err %d\n",
ret);
goto err_clk_enable;
}
spin_lock_irq(&davinci_nand_lock);
/* put CSxNAND into NAND mode */
val = davinci_nand_readl(info, NANDFCR_OFFSET);
val |= BIT(info->core_chipsel);
davinci_nand_writel(info, NANDFCR_OFFSET, val);
spin_unlock_irq(&davinci_nand_lock);
/* Scan to find existence of the device(s) */
ret = nand_scan_ident(mtd, pdata->mask_chipsel ? 2 : 1, NULL);
if (ret < 0) {
dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
goto err;
}
/* Update ECC layout if needed ... for 1-bit HW ECC, the default
* is OK, but it allocates 6 bytes when only 3 are needed (for
......@@ -805,26 +789,14 @@ static int nand_davinci_probe(struct platform_device *pdev)
* table marker fits in the free bytes.
*/
if (chunks == 1) {
info->ecclayout = hwecc4_small;
info->ecclayout.oobfree[1].length = mtd->oobsize - 16;
goto syndrome_done;
}
if (chunks == 4) {
info->ecclayout = hwecc4_2048;
info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
goto syndrome_done;
}
if (chunks == 8) {
info->ecclayout = hwecc4_4096;
mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops);
} else if (chunks == 4 || chunks == 8) {
mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST;
goto syndrome_done;
}
} else {
ret = -EIO;
goto err;
syndrome_done:
info->chip.ecc.layout = &info->ecclayout;
}
}
ret = nand_scan_tail(mtd);
......@@ -850,7 +822,7 @@ static int nand_davinci_probe(struct platform_device *pdev)
err_clk_enable:
spin_lock_irq(&davinci_nand_lock);
if (ecc_mode == NAND_ECC_HW_SYNDROME)
if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME)
ecc4_busy = false;
spin_unlock_irq(&davinci_nand_lock);
return ret;
......
......@@ -1374,13 +1374,41 @@ static void denali_hw_init(struct denali_nand_info *denali)
* correction
*/
#define ECC_8BITS 14
static struct nand_ecclayout nand_8bit_oob = {
.eccbytes = 14,
};
#define ECC_15BITS 26
static struct nand_ecclayout nand_15bit_oob = {
.eccbytes = 26,
static int denali_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
struct nand_chip *chip = mtd_to_nand(mtd);
if (section)
return -ERANGE;
oobregion->offset = denali->bbtskipbytes;
oobregion->length = chip->ecc.total;
return 0;
}
static int denali_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct denali_nand_info *denali = mtd_to_denali(mtd);
struct nand_chip *chip = mtd_to_nand(mtd);
if (section)
return -ERANGE;
oobregion->offset = chip->ecc.total + denali->bbtskipbytes;
oobregion->length = mtd->oobsize - oobregion->offset;
return 0;
}
static const struct mtd_ooblayout_ops denali_ooblayout_ops = {
.ecc = denali_ooblayout_ecc,
.free = denali_ooblayout_free,
};
static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
......@@ -1561,7 +1589,6 @@ int denali_init(struct denali_nand_info *denali)
ECC_SECTOR_SIZE)))) {
/* if MLC OOB size is large enough, use 15bit ECC*/
denali->nand.ecc.strength = 15;
denali->nand.ecc.layout = &nand_15bit_oob;
denali->nand.ecc.bytes = ECC_15BITS;
iowrite32(15, denali->flash_reg + ECC_CORRECTION);
} else if (mtd->oobsize < (denali->bbtskipbytes +
......@@ -1571,20 +1598,13 @@ int denali_init(struct denali_nand_info *denali)
goto failed_req_irq;
} else {
denali->nand.ecc.strength = 8;
denali->nand.ecc.layout = &nand_8bit_oob;
denali->nand.ecc.bytes = ECC_8BITS;
iowrite32(8, denali->flash_reg + ECC_CORRECTION);
}
mtd_set_ooblayout(mtd, &denali_ooblayout_ops);
denali->nand.ecc.bytes *= denali->devnum;
denali->nand.ecc.strength *= denali->devnum;
denali->nand.ecc.layout->eccbytes *=
mtd->writesize / ECC_SECTOR_SIZE;
denali->nand.ecc.layout->oobfree[0].offset =
denali->bbtskipbytes + denali->nand.ecc.layout->eccbytes;
denali->nand.ecc.layout->oobfree[0].length =
mtd->oobsize - denali->nand.ecc.layout->eccbytes -
denali->bbtskipbytes;
/*
* Let driver know the total blocks number and how many blocks
......
......@@ -950,20 +950,50 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
//u_char mydatabuf[528];
/* The strange out-of-order .oobfree list below is a (possibly unneeded)
* attempt to retain compatibility. It used to read:
static int doc200x_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section)
return -ERANGE;
oobregion->offset = 0;
oobregion->length = 6;
return 0;
}
static int doc200x_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section > 1)
return -ERANGE;
/*
* The strange out-of-order free bytes definition is a (possibly
* unneeded) attempt to retain compatibility. It used to read:
* .oobfree = { {8, 8} }
* Since that leaves two bytes unusable, it was changed. But the following
* scheme might affect existing jffs2 installs by moving the cleanmarker:
* Since that leaves two bytes unusable, it was changed. But the
* following scheme might affect existing jffs2 installs by moving the
* cleanmarker:
* .oobfree = { {6, 10} }
* jffs2 seems to handle the above gracefully, but the current scheme seems
* safer. The only problem with it is that any code that parses oobfree must
* be able to handle out-of-order segments.
* jffs2 seems to handle the above gracefully, but the current scheme
* seems safer. The only problem with it is that any code retrieving
* free bytes position must be able to handle out-of-order segments.
*/
static struct nand_ecclayout doc200x_oobinfo = {
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 4, 5},
.oobfree = {{8, 8}, {6, 2}}
if (!section) {
oobregion->offset = 8;
oobregion->length = 8;
} else {
oobregion->offset = 6;
oobregion->length = 2;
}
return 0;
}
static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
.ecc = doc200x_ooblayout_ecc,
.free = doc200x_ooblayout_free,
};
/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
......@@ -1537,6 +1567,7 @@ static int __init doc_probe(unsigned long physadr)
nand->bbt_md = nand->bbt_td + 1;
mtd->owner = THIS_MODULE;
mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);
nand_set_controller_data(nand, doc);
nand->select_chip = doc200x_select_chip;
......@@ -1548,7 +1579,6 @@ static int __init doc_probe(unsigned long physadr)
nand->ecc.calculate = doc200x_calculate_ecc;
nand->ecc.correct = doc200x_correct_data;
nand->ecc.layout = &doc200x_oobinfo;
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
nand->ecc.size = 512;
nand->ecc.bytes = 6;
......
......@@ -222,10 +222,33 @@ struct docg4_priv {
* Bytes 8 - 14 are hw-generated ecc covering entire page + oob bytes 0 - 14.
* Byte 15 (the last) is used by the driver as a "page written" flag.
*/
static struct nand_ecclayout docg4_oobinfo = {
.eccbytes = 9,
.eccpos = {7, 8, 9, 10, 11, 12, 13, 14, 15},
.oobfree = { {.offset = 2, .length = 5} }
static int docg4_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section)
return -ERANGE;
oobregion->offset = 7;
oobregion->length = 9;
return 0;
}
static int docg4_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section)
return -ERANGE;
oobregion->offset = 2;
oobregion->length = 5;
return 0;
}
static const struct mtd_ooblayout_ops docg4_ooblayout_ops = {
.ecc = docg4_ooblayout_ecc,
.free = docg4_ooblayout_free,
};
/*
......@@ -1209,6 +1232,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
mtd->writesize = DOCG4_PAGE_SIZE;
mtd->erasesize = DOCG4_BLOCK_SIZE;
mtd->oobsize = DOCG4_OOB_SIZE;
mtd_set_ooblayout(mtd, &docg4_ooblayout_ops);
nand->chipsize = DOCG4_CHIP_SIZE;
nand->chip_shift = DOCG4_CHIP_SHIFT;
nand->bbt_erase_shift = nand->phys_erase_shift = DOCG4_ERASE_SHIFT;
......@@ -1217,7 +1241,6 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->pagemask = 0x3ffff;
nand->badblockpos = NAND_LARGE_BADBLOCK_POS;
nand->badblockbits = 8;
nand->ecc.layout = &docg4_oobinfo;
nand->ecc.mode = NAND_ECC_HW_SYNDROME;
nand->ecc.size = DOCG4_PAGE_SIZE;
nand->ecc.prepad = 8;
......
......@@ -79,32 +79,53 @@ struct fsl_elbc_fcm_ctrl {
/* These map to the positions used by the FCM hardware ECC generator */
/* Small Page FLASH with FMR[ECCM] = 0 */
static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = {
.eccbytes = 3,
.eccpos = {6, 7, 8},
.oobfree = { {0, 5}, {9, 7} },
};
static int fsl_elbc_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
/* Small Page FLASH with FMR[ECCM] = 1 */
static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = {
.eccbytes = 3,
.eccpos = {8, 9, 10},
.oobfree = { {0, 5}, {6, 2}, {11, 5} },
};
if (section >= chip->ecc.steps)
return -ERANGE;
/* Large Page FLASH with FMR[ECCM] = 0 */
static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = {
.eccbytes = 12,
.eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56},
.oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} },
};
oobregion->offset = (16 * section) + 6;
if (priv->fmr & FMR_ECCM)
oobregion->offset += 2;
oobregion->length = chip->ecc.bytes;
return 0;
}
static int fsl_elbc_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct fsl_elbc_mtd *priv = nand_get_controller_data(chip);
if (section > chip->ecc.steps)
return -ERANGE;
/* Large Page FLASH with FMR[ECCM] = 1 */
static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = {
.eccbytes = 12,
.eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
.oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} },
if (!section) {
oobregion->offset = 0;
if (mtd->writesize > 512)
oobregion->offset++;
oobregion->length = (priv->fmr & FMR_ECCM) ? 7 : 5;
} else {
oobregion->offset = (16 * section) -
((priv->fmr & FMR_ECCM) ? 5 : 7);
if (section < chip->ecc.steps)
oobregion->length = 13;
else
oobregion->length = mtd->oobsize - oobregion->offset;
}
return 0;
}
static const struct mtd_ooblayout_ops fsl_elbc_ooblayout_ops = {
.ecc = fsl_elbc_ooblayout_ecc,
.free = fsl_elbc_ooblayout_free,
};
/*
......@@ -657,8 +678,8 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
chip->ecc.bytes);
dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
chip->ecc.total);
dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
chip->ecc.layout);
dev_dbg(priv->dev, "fsl_elbc_init: mtd->ooblayout = %p\n",
mtd->ooblayout);
dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
......@@ -675,14 +696,6 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
} else if (mtd->writesize == 2048) {
priv->page_size = 1;
setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
/* adjust ecc setup if needed */
if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
BR_DECC_CHK_GEN) {
chip->ecc.size = 512;
chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
&fsl_elbc_oob_lp_eccm1 :
&fsl_elbc_oob_lp_eccm0;
}
} else {
dev_err(priv->dev,
"fsl_elbc_init: page size %d is not supported\n",
......@@ -780,15 +793,14 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
BR_DECC_CHK_GEN) {
chip->ecc.mode = NAND_ECC_HW;
/* put in small page settings and adjust later if needed */
chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
&fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0;
mtd_set_ooblayout(mtd, &fsl_elbc_ooblayout_ops);
chip->ecc.size = 512;
chip->ecc.bytes = 3;
chip->ecc.strength = 1;
} else {
/* otherwise fall back to default software ECC */
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
}
return 0;
......
This diff is collapsed.
......@@ -170,6 +170,7 @@ static int fun_chip_init(struct fsl_upm_nand *fun,
fun->chip.read_buf = fun_read_buf;
fun->chip.write_buf = fun_write_buf;
fun->chip.ecc.mode = NAND_ECC_SOFT;
fun->chip.ecc.algo = NAND_ECC_HAMMING;
if (fun->mchip_count > 1)
fun->chip.select_chip = fun_select_chip;
......
This diff is collapsed.
......@@ -273,6 +273,7 @@ static int gpio_nand_probe(struct platform_device *pdev)
nand_set_flash_node(chip, pdev->dev.of_node);
chip->IO_ADDR_W = chip->IO_ADDR_R;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
chip->options = gpiomtd->plat.options;
chip->chip_delay = gpiomtd->plat.chip_delay;
chip->cmd_ctrl = gpio_nand_cmd_ctrl;
......
This diff is collapsed.
......@@ -19,7 +19,6 @@
* GNU General Public License for more details.
*/
#include <linux/of.h>
#include <linux/of_mtd.h>
#include <linux/mtd/mtd.h>
#include <linux/sizes.h>
#include <linux/clk.h>
......@@ -631,8 +630,28 @@ static void hisi_nfc_host_init(struct hinfc_host *host)
hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN);
}
static struct nand_ecclayout nand_ecc_2K_16bits = {
.oobfree = { {2, 6} },
static int hisi_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
/* FIXME: add ECC bytes position */
return -ENOTSUPP;
}
static int hisi_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
if (section)
return -ERANGE;
oobregion->offset = 2;
oobregion->length = 6;
return 0;
}
static const struct mtd_ooblayout_ops hisi_ooblayout_ops = {
.ecc = hisi_ooblayout_ecc,
.free = hisi_ooblayout_free,
};
static int hisi_nfc_ecc_probe(struct hinfc_host *host)
......@@ -642,10 +661,9 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
struct device *dev = host->dev;
struct nand_chip *chip = &host->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct device_node *np = host->dev->of_node;
size = of_get_nand_ecc_step_size(np);
strength = of_get_nand_ecc_strength(np);
size = chip->ecc.size;
strength = chip->ecc.strength;
if (size != 1024) {
dev_err(dev, "error ecc size: %d\n", size);
return -EINVAL;
......@@ -668,7 +686,7 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
case 16:
ecc_bits = 6;
if (mtd->writesize == 2048)
chip->ecc.layout = &nand_ecc_2K_16bits;
mtd_set_ooblayout(mtd, &hisi_ooblayout_ops);
/* TODO: add more page size support */
break;
......@@ -695,7 +713,7 @@ static int hisi_nfc_ecc_probe(struct hinfc_host *host)
static int hisi_nfc_probe(struct platform_device *pdev)
{
int ret = 0, irq, buswidth, flag, max_chips = HINFC504_MAX_CHIP;
int ret = 0, irq, flag, max_chips = HINFC504_MAX_CHIP;
struct device *dev = &pdev->dev;
struct hinfc_host *host;
struct nand_chip *chip;
......@@ -747,12 +765,6 @@ static int hisi_nfc_probe(struct platform_device *pdev)
chip->read_buf = hisi_nfc_read_buf;
chip->chip_delay = HINFC504_CHIP_DELAY;
chip->ecc.mode = of_get_nand_ecc_mode(np);
buswidth = of_get_nand_bus_width(np);
if (buswidth == 16)
chip->options |= NAND_BUSWIDTH_16;
hisi_nfc_host_init(host);
ret = devm_request_irq(dev, irq, hinfc_irq_handle, 0x0, "nandc", host);
......
......@@ -221,7 +221,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat,
struct jz_nand *nand = mtd_to_jz_nand(mtd);
int i, error_count, index;
uint32_t reg, status, error;
uint32_t t;
unsigned int timeout = 1000;
for (i = 0; i < 9; ++i)
......@@ -476,7 +475,7 @@ static int jz_nand_probe(struct platform_device *pdev)
}
if (pdata && pdata->ident_callback) {
pdata->ident_callback(pdev, chip, &pdata->partitions,
pdata->ident_callback(pdev, mtd, &pdata->partitions,
&pdata->num_partitions);
}
......
......@@ -287,7 +287,6 @@ static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
bch = platform_get_drvdata(pdev);
clk_prepare_enable(bch->clk);
bch->dev = &pdev->dev;
return bch;
}
......
......@@ -17,7 +17,6 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/gpio/consumer.h>
#include <linux/of_mtd.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
......@@ -56,8 +55,6 @@ struct jz4780_nand_chip {
struct nand_chip chip;
struct list_head chip_list;
struct nand_ecclayout ecclayout;
struct gpio_desc *busy_gpio;
struct gpio_desc *wp_gpio;
unsigned int reading: 1;
......@@ -165,8 +162,7 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
struct nand_chip *chip = &nand->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct jz4780_nand_controller *nfc = to_jz4780_nand_controller(chip->controller);
struct nand_ecclayout *layout = &nand->ecclayout;
u32 start, i;
int eccbytes;
chip->ecc.bytes = fls((1 + 8) * chip->ecc.size) *
(chip->ecc.strength / 8);
......@@ -183,7 +179,6 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
chip->ecc.correct = jz4780_nand_ecc_correct;
/* fall through */
case NAND_ECC_SOFT:
case NAND_ECC_SOFT_BCH:
dev_info(dev, "using %s (strength %d, size %d, bytes %d)\n",
(nfc->bch) ? "hardware BCH" : "software ECC",
chip->ecc.strength, chip->ecc.size, chip->ecc.bytes);
......@@ -201,23 +196,17 @@ static int jz4780_nand_init_ecc(struct jz4780_nand_chip *nand, struct device *de
return 0;
/* Generate ECC layout. ECC codes are right aligned in the OOB area. */
layout->eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
eccbytes = mtd->writesize / chip->ecc.size * chip->ecc.bytes;
if (layout->eccbytes > mtd->oobsize - 2) {
if (eccbytes > mtd->oobsize - 2) {
dev_err(dev,
"invalid ECC config: required %d ECC bytes, but only %d are available",
layout->eccbytes, mtd->oobsize - 2);
eccbytes, mtd->oobsize - 2);
return -EINVAL;
}
start = mtd->oobsize - layout->eccbytes;
for (i = 0; i < layout->eccbytes; i++)
layout->eccpos[i] = start + i;
layout->oobfree[0].offset = 2;
layout->oobfree[0].length = mtd->oobsize - layout->eccbytes - 2;
mtd->ooblayout = &nand_ooblayout_lp_ops;
chip->ecc.layout = layout;
return 0;
}
......
......@@ -35,7 +35,6 @@
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_mtd.h>
#include <linux/of_gpio.h>
#include <linux/mtd/lpc32xx_mlc.h>
#include <linux/io.h>
......@@ -139,22 +138,37 @@ struct lpc32xx_nand_cfg_mlc {
unsigned num_parts;
};
static struct nand_ecclayout lpc32xx_nand_oob = {
.eccbytes = 40,
.eccpos = { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
.oobfree = {
{ .offset = 0,
.length = 6, },
{ .offset = 16,
.length = 6, },
{ .offset = 32,
.length = 6, },
{ .offset = 48,
.length = 6, },
},
static int lpc32xx_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
if (section >= nand_chip->ecc.steps)
return -ERANGE;
oobregion->offset = ((section + 1) * 16) - nand_chip->ecc.bytes;
oobregion->length = nand_chip->ecc.bytes;
return 0;
}
static int lpc32xx_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobregion)
{
struct nand_chip *nand_chip = mtd_to_nand(mtd);
if (section >= nand_chip->ecc.steps)
return -ERANGE;
oobregion->offset = 16 * section;
oobregion->length = 16 - nand_chip->ecc.bytes;
return 0;
}
static const struct mtd_ooblayout_ops lpc32xx_ooblayout_ops = {
.ecc = lpc32xx_ooblayout_ecc,
.free = lpc32xx_ooblayout_free,
};
static struct nand_bbt_descr lpc32xx_nand_bbt = {
......@@ -713,6 +727,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
nand_chip->ecc.write_oob = lpc32xx_write_oob;
nand_chip->ecc.read_oob = lpc32xx_read_oob;
nand_chip->ecc.strength = 4;
nand_chip->ecc.bytes = 10;
nand_chip->waitfunc = lpc32xx_waitfunc;
nand_chip->options = NAND_NO_SUBPAGE_WRITE;
......@@ -751,7 +766,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
nand_chip->ecc.mode = NAND_ECC_HW;
nand_chip->ecc.size = 512;
nand_chip->ecc.layout = &lpc32xx_nand_oob;
mtd_set_ooblayout(mtd, &lpc32xx_ooblayout_ops);
host->mlcsubpages = mtd->writesize / 512;
/* initially clear interrupt status */
......
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.
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.
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.
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.
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