Commit d6666be6 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MTD updates from Brian Norris:
 "Summary:
   - Add device tree support for DoC3

   - SPI NOR:
        Refactoring, for better layering between spi-nor.c and its
        driver users (e.g., m25p80.c)

        New flash device support

        Support 6-byte ID strings

   - NAND:
        New NAND driver for Allwinner SoC's (sunxi)

        GPMI NAND: add support for raw (no ECC) access, for testing
        purposes

        Add ATO manufacturer ID

        A few odd driver fixes

   - MTD tests:
        Allow testers to compensate for OOB bitflips in oobtest

        Fix a torturetest regression

   - nandsim: Support longer ID byte strings

  And more"

* tag 'for-linus-20141215' of git://git.infradead.org/linux-mtd: (63 commits)
  mtd: tests: abort torturetest on erase errors
  mtd: physmap_of: fix potential NULL dereference
  mtd: spi-nor: allow NULL as chip name and try to auto detect it
  mtd: nand: gpmi: add raw oob access functions
  mtd: nand: gpmi: add proper raw access support
  mtd: nand: gpmi: add gpmi_copy_bits function
  mtd: spi-nor: factor out write_enable() for erase commands
  mtd: spi-nor: add support for s25fl128s
  mtd: spi-nor: remove the jedec_id/ext_id
  mtd: spi-nor: add id/id_len for flash_info{}
  mtd: nand: correct the comment of function nand_block_isreserved()
  jffs2: Drop bogus if in comment
  mtd: atmel_nand: replace memcpy32_toio/memcpy32_fromio with memcpy
  mtd: cafe_nand: drop duplicate .write_page implementation
  mtd: m25p80: Add support for serial flash Spansion S25FL132K
  MTD: m25p80: fix inconsistency in m25p_ids compared to spi_nor_ids
  mtd: spi-nor: improve wait-till-ready timeout loop
  mtd: delete unnecessary checks before two function calls
  mtd: nand: omap: Fix NAND enumeration on 3430 LDP
  mtd: nand: add ATO manufacturer info
  ...
parents 0ea90b9e 68f29815
...@@ -5,7 +5,9 @@ Required properties: ...@@ -5,7 +5,9 @@ Required properties:
- 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
PMECC, PMECC Error Location controller and ROM which has lookup tables. PMECC and PMECC Error Location controller.
The PMECC lookup table address and size in ROM is optional. If not
specified, driver will build it in runtime.
- atmel,nand-addr-offset : offset for the address latch. - atmel,nand-addr-offset : offset for the address latch.
- atmel,nand-cmd-offset : offset for the command latch. - atmel,nand-cmd-offset : offset for the command latch.
- #address-cells, #size-cells : Must be present if the device has sub-nodes - #address-cells, #size-cells : Must be present if the device has sub-nodes
...@@ -27,7 +29,7 @@ Optional properties: ...@@ -27,7 +29,7 @@ Optional properties:
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
for different sector size. First one is for sector size 512, the next is for for different sector size. First one is for sector size 512, the next is for
sector size 1024. 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 - Nand Flash Controller(NFC) is a slave driver under Atmel nand flash
......
M-Systems and Sandisk DiskOnChip devices
M-System DiskOnChip G3
======================
The Sandisk (formerly M-Systems) docg3 is a nand device of 64M to 256MB.
Required properties:
- compatible: should be "m-systems,diskonchip-g3"
- reg: register base and size
Example:
docg3: flash@0 {
compatible = "m-systems,diskonchip-g3";
reg = <0x0 0x2000>;
};
...@@ -11,8 +11,8 @@ Required properties: ...@@ -11,8 +11,8 @@ Required properties:
are made in native endianness. are made in native endianness.
- #address-cells, #size-cells : Must be present if the device has sub-nodes - #address-cells, #size-cells : Must be present if the device has sub-nodes
representing partitions. representing partitions.
- gpios : specifies the gpio pins to control the NAND device. nwp is an - gpios : Specifies the GPIO pins to control the NAND device. The order of
optional gpio and may be set to 0 if not present. GPIO references is: RDY, nCE, ALE, CLE, and an optional nWP.
Optional properties: Optional properties:
- bank-width : Width (in bytes) of the device. If not present, the width - bank-width : Width (in bytes) of the device. If not present, the width
...@@ -35,11 +35,11 @@ gpio-nand@1,0 { ...@@ -35,11 +35,11 @@ gpio-nand@1,0 {
reg = <1 0x0000 0x2>; reg = <1 0x0000 0x2>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
gpios = <&banka 1 0 /* rdy */ gpios = <&banka 1 0>, /* RDY */
&banka 2 0 /* nce */ <&banka 2 0>, /* nCE */
&banka 3 0 /* ale */ <&banka 3 0>, /* ALE */
&banka 4 0 /* cle */ <&banka 4 0>, /* CLE */
0 /* nwp */>; <0>; /* nWP */
partition@0 { partition@0 {
... ...
......
Allwinner NAND Flash Controller (NFC)
Required properties:
- compatible : "allwinner,sun4i-a10-nand".
- reg : shall contain registers location and length for data and reg.
- interrupts : shall define the nand controller interrupt.
- #address-cells: shall be set to 1. Encode the nand CS.
- #size-cells : shall be set to 0.
- clocks : shall reference nand controller clocks.
- clock-names : nand controller internal clock names. Shall contain :
* "ahb" : AHB gating clock
* "mod" : nand controller clock
Optional children nodes:
Children nodes represent the available nand chips.
Optional properties:
- allwinner,rb : shall contain the native Ready/Busy ids.
or
- rb-gpios : shall contain the gpios used as R/B pins.
- nand-ecc-mode : one of the supported ECC modes ("hw", "hw_syndrome", "soft",
"soft_bch" or "none")
see Documentation/devicetree/mtd/nand.txt for generic bindings.
Examples:
nfc: nand@01c03000 {
compatible = "allwinner,sun4i-a10-nand";
reg = <0x01c03000 0x1000>;
interrupts = <0 37 1>;
clocks = <&ahb_gates 13>, <&nand_clk>;
clock-names = "ahb", "mod";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
status = "okay";
nand@0 {
reg = <0>;
allwinner,rb = <0>;
nand-ecc-mode = "soft_bch";
};
};
...@@ -61,7 +61,7 @@ int fsl_ifc_find(phys_addr_t addr_base) ...@@ -61,7 +61,7 @@ int fsl_ifc_find(phys_addr_t addr_base)
if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs) if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs)
return -ENODEV; return -ENODEV;
for (i = 0; i < ARRAY_SIZE(fsl_ifc_ctrl_dev->regs->cspr_cs); i++) { for (i = 0; i < fsl_ifc_ctrl_dev->banks; i++) {
u32 cspr = in_be32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr); u32 cspr = in_be32(&fsl_ifc_ctrl_dev->regs->cspr_cs[i].cspr);
if (cspr & CSPR_V && (cspr & CSPR_BA) == if (cspr & CSPR_V && (cspr & CSPR_BA) ==
convert_ifc_address(addr_base)) convert_ifc_address(addr_base))
...@@ -213,7 +213,7 @@ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data) ...@@ -213,7 +213,7 @@ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
static int fsl_ifc_ctrl_probe(struct platform_device *dev) static int fsl_ifc_ctrl_probe(struct platform_device *dev)
{ {
int ret = 0; int ret = 0;
int version, banks;
dev_info(&dev->dev, "Freescale Integrated Flash Controller\n"); dev_info(&dev->dev, "Freescale Integrated Flash Controller\n");
...@@ -231,6 +231,15 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev) ...@@ -231,6 +231,15 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
goto err; goto err;
} }
version = ioread32be(&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;
/* 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 == NO_IRQ) {
......
...@@ -133,7 +133,7 @@ config MTD_OF_PARTS ...@@ -133,7 +133,7 @@ config MTD_OF_PARTS
help help
This provides a partition parsing function which derives This provides a partition parsing function which derives
the partition map from the children of the flash node, the partition map from the children of the flash node,
as described in Documentation/devicetree/booting-without-of.txt. as described in Documentation/devicetree/bindings/mtd/partition.txt.
config MTD_AR7_PARTS config MTD_AR7_PARTS
tristate "TI AR7 partitioning support" tristate "TI AR7 partitioning support"
......
...@@ -15,8 +15,12 @@ ...@@ -15,8 +15,12 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
/* 10 parts were found on sflash on Netgear WNDR4500 */ /*
#define BCM47XXPART_MAX_PARTS 12 * NAND flash on Netgear R6250 was verified to contain 15 partitions.
* This will result in allocating too big array for some old devices, but the
* memory will be freed soon anyway (see mtd_device_parse_register).
*/
#define BCM47XXPART_MAX_PARTS 20
/* /*
* Amount of bytes we read when analyzing each block of flash memory. * Amount of bytes we read when analyzing each block of flash memory.
...@@ -168,18 +172,26 @@ static int bcm47xxpart_parse(struct mtd_info *master, ...@@ -168,18 +172,26 @@ static int bcm47xxpart_parse(struct mtd_info *master,
i++; i++;
} }
bcm47xxpart_add_part(&parts[curr_part++], "linux", if (trx->offset[i]) {
offset + trx->offset[i], 0); bcm47xxpart_add_part(&parts[curr_part++],
i++; "linux",
offset + trx->offset[i],
0);
i++;
}
/* /*
* Pure rootfs size is known and can be calculated as: * Pure rootfs size is known and can be calculated as:
* trx->length - trx->offset[i]. We don't fill it as * trx->length - trx->offset[i]. We don't fill it as
* we want to have jffs2 (overlay) in the same mtd. * we want to have jffs2 (overlay) in the same mtd.
*/ */
bcm47xxpart_add_part(&parts[curr_part++], "rootfs", if (trx->offset[i]) {
offset + trx->offset[i], 0); bcm47xxpart_add_part(&parts[curr_part++],
i++; "rootfs",
offset + trx->offset[i],
0);
i++;
}
last_trx_part = curr_part - 1; last_trx_part = curr_part - 1;
......
...@@ -2654,8 +2654,7 @@ static void cfi_intelext_destroy(struct mtd_info *mtd) ...@@ -2654,8 +2654,7 @@ static void cfi_intelext_destroy(struct mtd_info *mtd)
kfree(cfi); kfree(cfi);
for (i = 0; i < mtd->numeraseregions; i++) { for (i = 0; i < mtd->numeraseregions; i++) {
region = &mtd->eraseregions[i]; region = &mtd->eraseregions[i];
if (region->lockmap) kfree(region->lockmap);
kfree(region->lockmap);
} }
kfree(mtd->eraseregions); kfree(mtd->eraseregions);
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -1655,22 +1656,21 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p) ...@@ -1655,22 +1656,21 @@ static int dbg_flashctrl_show(struct seq_file *s, void *p)
{ {
struct docg3 *docg3 = (struct docg3 *)s->private; struct docg3 *docg3 = (struct docg3 *)s->private;
int pos = 0;
u8 fctrl; u8 fctrl;
mutex_lock(&docg3->cascade->lock); mutex_lock(&docg3->cascade->lock);
fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL);
mutex_unlock(&docg3->cascade->lock); mutex_unlock(&docg3->cascade->lock);
pos += seq_printf(s, seq_printf(s, "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n",
"FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", fctrl,
fctrl, fctrl & DOC_CTRL_VIOLATION ? "protocol violation" : "-",
fctrl & DOC_CTRL_VIOLATION ? "protocol violation" : "-", fctrl & DOC_CTRL_CE ? "active" : "inactive",
fctrl & DOC_CTRL_CE ? "active" : "inactive", fctrl & DOC_CTRL_PROTECTION_ERROR ? "protection error" : "-",
fctrl & DOC_CTRL_PROTECTION_ERROR ? "protection error" : "-", fctrl & DOC_CTRL_SEQUENCE_ERROR ? "sequence error" : "-",
fctrl & DOC_CTRL_SEQUENCE_ERROR ? "sequence error" : "-", fctrl & DOC_CTRL_FLASHREADY ? "ready" : "not ready");
fctrl & DOC_CTRL_FLASHREADY ? "ready" : "not ready");
return pos; return 0;
} }
DEBUGFS_RO_ATTR(flashcontrol, dbg_flashctrl_show); DEBUGFS_RO_ATTR(flashcontrol, dbg_flashctrl_show);
...@@ -1678,58 +1678,56 @@ static int dbg_asicmode_show(struct seq_file *s, void *p) ...@@ -1678,58 +1678,56 @@ static int dbg_asicmode_show(struct seq_file *s, void *p)
{ {
struct docg3 *docg3 = (struct docg3 *)s->private; struct docg3 *docg3 = (struct docg3 *)s->private;
int pos = 0, pctrl, mode; int pctrl, mode;
mutex_lock(&docg3->cascade->lock); mutex_lock(&docg3->cascade->lock);
pctrl = doc_register_readb(docg3, DOC_ASICMODE); pctrl = doc_register_readb(docg3, DOC_ASICMODE);
mode = pctrl & 0x03; mode = pctrl & 0x03;
mutex_unlock(&docg3->cascade->lock); mutex_unlock(&docg3->cascade->lock);
pos += seq_printf(s, seq_printf(s,
"%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (",
pctrl, pctrl,
pctrl & DOC_ASICMODE_RAM_WE ? 1 : 0, pctrl & DOC_ASICMODE_RAM_WE ? 1 : 0,
pctrl & DOC_ASICMODE_RSTIN_RESET ? 1 : 0, pctrl & DOC_ASICMODE_RSTIN_RESET ? 1 : 0,
pctrl & DOC_ASICMODE_BDETCT_RESET ? 1 : 0, pctrl & DOC_ASICMODE_BDETCT_RESET ? 1 : 0,
pctrl & DOC_ASICMODE_MDWREN ? 1 : 0, pctrl & DOC_ASICMODE_MDWREN ? 1 : 0,
pctrl & DOC_ASICMODE_POWERDOWN ? 1 : 0, pctrl & DOC_ASICMODE_POWERDOWN ? 1 : 0,
mode >> 1, mode & 0x1); mode >> 1, mode & 0x1);
switch (mode) { switch (mode) {
case DOC_ASICMODE_RESET: case DOC_ASICMODE_RESET:
pos += seq_puts(s, "reset"); seq_puts(s, "reset");
break; break;
case DOC_ASICMODE_NORMAL: case DOC_ASICMODE_NORMAL:
pos += seq_puts(s, "normal"); seq_puts(s, "normal");
break; break;
case DOC_ASICMODE_POWERDOWN: case DOC_ASICMODE_POWERDOWN:
pos += seq_puts(s, "powerdown"); seq_puts(s, "powerdown");
break; break;
} }
pos += seq_puts(s, ")\n"); seq_puts(s, ")\n");
return pos; return 0;
} }
DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show); DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show);
static int dbg_device_id_show(struct seq_file *s, void *p) static int dbg_device_id_show(struct seq_file *s, void *p)
{ {
struct docg3 *docg3 = (struct docg3 *)s->private; struct docg3 *docg3 = (struct docg3 *)s->private;
int pos = 0;
int id; int id;
mutex_lock(&docg3->cascade->lock); mutex_lock(&docg3->cascade->lock);
id = doc_register_readb(docg3, DOC_DEVICESELECT); id = doc_register_readb(docg3, DOC_DEVICESELECT);
mutex_unlock(&docg3->cascade->lock); mutex_unlock(&docg3->cascade->lock);
pos += seq_printf(s, "DeviceId = %d\n", id); seq_printf(s, "DeviceId = %d\n", id);
return pos; return 0;
} }
DEBUGFS_RO_ATTR(device_id, dbg_device_id_show); DEBUGFS_RO_ATTR(device_id, dbg_device_id_show);
static int dbg_protection_show(struct seq_file *s, void *p) static int dbg_protection_show(struct seq_file *s, void *p)
{ {
struct docg3 *docg3 = (struct docg3 *)s->private; struct docg3 *docg3 = (struct docg3 *)s->private;
int pos = 0;
int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high; int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high;
mutex_lock(&docg3->cascade->lock); mutex_lock(&docg3->cascade->lock);
...@@ -1742,45 +1740,40 @@ static int dbg_protection_show(struct seq_file *s, void *p) ...@@ -1742,45 +1740,40 @@ static int dbg_protection_show(struct seq_file *s, void *p)
dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH); dps1_high = doc_register_readw(docg3, DOC_DPS1_ADDRHIGH);
mutex_unlock(&docg3->cascade->lock); mutex_unlock(&docg3->cascade->lock);
pos += seq_printf(s, "Protection = 0x%02x (", seq_printf(s, "Protection = 0x%02x (", protect);
protect);
if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK) if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK)
pos += seq_puts(s, "FOUNDRY_OTP_LOCK,"); seq_puts(s, "FOUNDRY_OTP_LOCK,");
if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK) if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK)
pos += seq_puts(s, "CUSTOMER_OTP_LOCK,"); seq_puts(s, "CUSTOMER_OTP_LOCK,");
if (protect & DOC_PROTECT_LOCK_INPUT) if (protect & DOC_PROTECT_LOCK_INPUT)
pos += seq_puts(s, "LOCK_INPUT,"); seq_puts(s, "LOCK_INPUT,");
if (protect & DOC_PROTECT_STICKY_LOCK) if (protect & DOC_PROTECT_STICKY_LOCK)
pos += seq_puts(s, "STICKY_LOCK,"); seq_puts(s, "STICKY_LOCK,");
if (protect & DOC_PROTECT_PROTECTION_ENABLED) if (protect & DOC_PROTECT_PROTECTION_ENABLED)
pos += seq_puts(s, "PROTECTION ON,"); seq_puts(s, "PROTECTION ON,");
if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK) if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK)
pos += seq_puts(s, "IPL_DOWNLOAD_LOCK,"); seq_puts(s, "IPL_DOWNLOAD_LOCK,");
if (protect & DOC_PROTECT_PROTECTION_ERROR) if (protect & DOC_PROTECT_PROTECTION_ERROR)
pos += seq_puts(s, "PROTECT_ERR,"); seq_puts(s, "PROTECT_ERR,");
else else
pos += seq_puts(s, "NO_PROTECT_ERR"); seq_puts(s, "NO_PROTECT_ERR");
pos += seq_puts(s, ")\n"); seq_puts(s, ")\n");
pos += seq_printf(s, "DPS0 = 0x%02x : " seq_printf(s, "DPS0 = 0x%02x : Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n",
"Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " dps0, dps0_low, dps0_high,
"WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", !!(dps0 & DOC_DPS_OTP_PROTECTED),
dps0, dps0_low, dps0_high, !!(dps0 & DOC_DPS_READ_PROTECTED),
!!(dps0 & DOC_DPS_OTP_PROTECTED), !!(dps0 & DOC_DPS_WRITE_PROTECTED),
!!(dps0 & DOC_DPS_READ_PROTECTED), !!(dps0 & DOC_DPS_HW_LOCK_ENABLED),
!!(dps0 & DOC_DPS_WRITE_PROTECTED), !!(dps0 & DOC_DPS_KEY_OK));
!!(dps0 & DOC_DPS_HW_LOCK_ENABLED), seq_printf(s, "DPS1 = 0x%02x : Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n",
!!(dps0 & DOC_DPS_KEY_OK)); dps1, dps1_low, dps1_high,
pos += seq_printf(s, "DPS1 = 0x%02x : " !!(dps1 & DOC_DPS_OTP_PROTECTED),
"Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " !!(dps1 & DOC_DPS_READ_PROTECTED),
"WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", !!(dps1 & DOC_DPS_WRITE_PROTECTED),
dps1, dps1_low, dps1_high, !!(dps1 & DOC_DPS_HW_LOCK_ENABLED),
!!(dps1 & DOC_DPS_OTP_PROTECTED), !!(dps1 & DOC_DPS_KEY_OK));
!!(dps1 & DOC_DPS_READ_PROTECTED), return 0;
!!(dps1 & DOC_DPS_WRITE_PROTECTED),
!!(dps1 & DOC_DPS_HW_LOCK_ENABLED),
!!(dps1 & DOC_DPS_KEY_OK));
return pos;
} }
DEBUGFS_RO_ATTR(protection, dbg_protection_show); DEBUGFS_RO_ATTR(protection, dbg_protection_show);
...@@ -2126,9 +2119,18 @@ static int __exit docg3_release(struct platform_device *pdev) ...@@ -2126,9 +2119,18 @@ static int __exit docg3_release(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_OF
static struct of_device_id docg3_dt_ids[] = {
{ .compatible = "m-systems,diskonchip-g3" },
{}
};
MODULE_DEVICE_TABLE(of, docg3_dt_ids);
#endif
static struct platform_driver g3_driver = { static struct platform_driver g3_driver = {
.driver = { .driver = {
.name = "docg3", .name = "docg3",
.of_match_table = of_match_ptr(docg3_dt_ids),
}, },
.suspend = docg3_suspend, .suspend = docg3_suspend,
.resume = docg3_resume, .resume = docg3_resume,
......
...@@ -128,13 +128,10 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, ...@@ -128,13 +128,10 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
struct spi_device *spi = flash->spi; struct spi_device *spi = flash->spi;
struct spi_transfer t[2]; struct spi_transfer t[2];
struct spi_message m; struct spi_message m;
int dummy = nor->read_dummy; unsigned int dummy = nor->read_dummy;
int ret;
/* Wait till previous write/erase is done. */ /* convert the dummy cycles to the number of bytes */
ret = nor->wait_till_ready(nor); dummy /= 8;
if (ret)
return ret;
spi_message_init(&m); spi_message_init(&m);
memset(t, 0, (sizeof t)); memset(t, 0, (sizeof t));
...@@ -160,21 +157,10 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len, ...@@ -160,21 +157,10 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
static int m25p80_erase(struct spi_nor *nor, loff_t offset) static int m25p80_erase(struct spi_nor *nor, loff_t offset)
{ {
struct m25p *flash = nor->priv; struct m25p *flash = nor->priv;
int ret;
dev_dbg(nor->dev, "%dKiB at 0x%08x\n", dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
flash->mtd.erasesize / 1024, (u32)offset); flash->mtd.erasesize / 1024, (u32)offset);
/* Wait until finished previous write command. */
ret = nor->wait_till_ready(nor);
if (ret)
return ret;
/* Send write enable, then erase commands. */
ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
if (ret)
return ret;
/* Set up command buffer. */ /* Set up command buffer. */
flash->command[0] = nor->erase_opcode; flash->command[0] = nor->erase_opcode;
m25p_addr2cmd(nor, offset, flash->command); m25p_addr2cmd(nor, offset, flash->command);
...@@ -260,7 +246,6 @@ static int m25p_remove(struct spi_device *spi) ...@@ -260,7 +246,6 @@ static int m25p_remove(struct spi_device *spi)
return mtd_device_unregister(&flash->mtd); return mtd_device_unregister(&flash->mtd);
} }
/* /*
* XXX This needs to be kept in sync with spi_nor_ids. We can't share * XXX This needs to be kept in sync with spi_nor_ids. We can't share
* it with spi-nor, because if this is built as a module then modpost * it with spi-nor, because if this is built as a module then modpost
...@@ -287,7 +272,7 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -287,7 +272,7 @@ static const struct spi_device_id m25p_ids[] = {
{"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"}, {"s25fl512s"}, {"s70fl01gs"}, {"s25sl12800"}, {"s25sl12801"},
{"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"}, {"s25fl129p0"}, {"s25fl129p1"}, {"s25sl004a"}, {"s25sl008a"},
{"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"}, {"s25sl016a"}, {"s25sl032a"}, {"s25sl064a"}, {"s25fl008k"},
{"s25fl016k"}, {"s25fl064k"}, {"s25fl016k"}, {"s25fl064k"}, {"s25fl132k"},
{"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"}, {"sst25vf040b"},{"sst25vf080b"},{"sst25vf016b"},{"sst25vf032b"},
{"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"}, {"sst25vf064c"},{"sst25wf512"}, {"sst25wf010"}, {"sst25wf020"},
{"sst25wf040"}, {"sst25wf040"},
...@@ -300,17 +285,16 @@ static const struct spi_device_id m25p_ids[] = { ...@@ -300,17 +285,16 @@ static const struct spi_device_id m25p_ids[] = {
{"m45pe10"}, {"m45pe80"}, {"m45pe16"}, {"m45pe10"}, {"m45pe80"}, {"m45pe16"},
{"m25pe20"}, {"m25pe80"}, {"m25pe16"}, {"m25pe20"}, {"m25pe80"}, {"m25pe16"},
{"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"}, {"m25px16"}, {"m25px32"}, {"m25px32-s0"}, {"m25px32-s1"},
{"m25px64"}, {"m25px64"}, {"m25px80"},
{"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"}, {"w25x10"}, {"w25x20"}, {"w25x40"}, {"w25x80"},
{"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"}, {"w25x16"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"},
{"w25x64"}, {"w25q64"}, {"w25q128"}, {"w25q80"}, {"w25x64"}, {"w25q64"}, {"w25q80"}, {"w25q80bl"},
{"w25q80bl"}, {"w25q128"}, {"w25q256"}, {"cat25c11"}, {"w25q128"}, {"w25q256"}, {"cat25c11"},
{"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"},
{ }, { },
}; };
MODULE_DEVICE_TABLE(spi, m25p_ids); MODULE_DEVICE_TABLE(spi, m25p_ids);
static struct spi_driver m25p80_driver = { static struct spi_driver m25p80_driver = {
.driver = { .driver = {
.name = "m25p80", .name = "m25p80",
......
...@@ -149,7 +149,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -149,7 +149,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
{ {
struct dataflash *priv = mtd->priv; struct dataflash *priv = mtd->priv;
struct spi_device *spi = priv->spi; struct spi_device *spi = priv->spi;
struct spi_transfer x = { .tx_dma = 0, }; struct spi_transfer x = { };
struct spi_message msg; struct spi_message msg;
unsigned blocksize = priv->page_size << 3; unsigned blocksize = priv->page_size << 3;
uint8_t *command; uint8_t *command;
...@@ -235,7 +235,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, ...@@ -235,7 +235,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf) size_t *retlen, u_char *buf)
{ {
struct dataflash *priv = mtd->priv; struct dataflash *priv = mtd->priv;
struct spi_transfer x[2] = { { .tx_dma = 0, }, }; struct spi_transfer x[2] = { };
struct spi_message msg; struct spi_message msg;
unsigned int addr; unsigned int addr;
uint8_t *command; uint8_t *command;
...@@ -301,7 +301,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -301,7 +301,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
{ {
struct dataflash *priv = mtd->priv; struct dataflash *priv = mtd->priv;
struct spi_device *spi = priv->spi; struct spi_device *spi = priv->spi;
struct spi_transfer x[2] = { { .tx_dma = 0, }, }; struct spi_transfer x[2] = { };
struct spi_message msg; struct spi_message msg;
unsigned int pageaddr, addr, offset, writelen; unsigned int pageaddr, addr, offset, writelen;
size_t remaining = len; size_t remaining = len;
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/io.h> #include <linux/io.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
......
...@@ -812,8 +812,7 @@ static int __init init_pmc551(void) ...@@ -812,8 +812,7 @@ static int __init init_pmc551(void)
} }
/* Exited early, reference left over */ /* Exited early, reference left over */
if (PCI_Device) pci_dev_put(PCI_Device);
pci_dev_put(PCI_Device);
if (!pmc551list) { if (!pmc551list) {
printk(KERN_NOTICE "pmc551: not detected\n"); printk(KERN_NOTICE "pmc551: not detected\n");
......
...@@ -518,7 +518,7 @@ void INFTL_dumpVUchains(struct INFTLrecord *s) ...@@ -518,7 +518,7 @@ void INFTL_dumpVUchains(struct INFTLrecord *s)
pr_debug("INFTL Virtual Unit Chains:\n"); pr_debug("INFTL Virtual Unit Chains:\n");
for (logical = 0; logical < s->nb_blocks; logical++) { for (logical = 0; logical < s->nb_blocks; logical++) {
block = s->VUtable[logical]; block = s->VUtable[logical];
if (block > s->nb_blocks) if (block >= s->nb_blocks)
continue; continue;
pr_debug(" LOGICAL %d --> %d ", logical, block); pr_debug(" LOGICAL %d --> %d ", logical, block);
for (i = 0; i < s->nb_blocks; i++) { for (i = 0; i < s->nb_blocks; i++) {
......
...@@ -126,7 +126,6 @@ static const char * const part_probe_types[] = { ...@@ -126,7 +126,6 @@ static const char * const part_probe_types[] = {
static int bfin_flash_probe(struct platform_device *pdev) static int bfin_flash_probe(struct platform_device *pdev)
{ {
int ret;
struct physmap_flash_data *pdata = dev_get_platdata(&pdev->dev); struct physmap_flash_data *pdata = dev_get_platdata(&pdev->dev);
struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1); struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1);
......
...@@ -47,14 +47,12 @@ static int of_flash_remove(struct platform_device *dev) ...@@ -47,14 +47,12 @@ static int of_flash_remove(struct platform_device *dev)
return 0; return 0;
dev_set_drvdata(&dev->dev, NULL); dev_set_drvdata(&dev->dev, NULL);
if (info->cmtd != info->list[0].mtd) { if (info->cmtd) {
mtd_device_unregister(info->cmtd); mtd_device_unregister(info->cmtd);
mtd_concat_destroy(info->cmtd); if (info->cmtd != info->list[0].mtd)
mtd_concat_destroy(info->cmtd);
} }
if (info->cmtd)
mtd_device_unregister(info->cmtd);
for (i = 0; i < info->list_size; i++) { for (i = 0; i < info->list_size; i++) {
if (info->list[i].mtd) if (info->list[i].mtd)
map_destroy(info->list[i].mtd); map_destroy(info->list[i].mtd);
......
...@@ -75,10 +75,12 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR ...@@ -75,10 +75,12 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
boards, the scratch register is at 0xFF108018. boards, the scratch register is at 0xFF108018.
config MTD_NAND_GPIO config MTD_NAND_GPIO
tristate "GPIO NAND Flash driver" tristate "GPIO assisted NAND Flash driver"
depends on GPIOLIB depends on GPIOLIB
help help
This enables a GPIO based NAND flash driver. This enables a NAND flash driver where control signals are
connected to GPIO pins, and commands and data are communicated
via a memory mapped interface.
config MTD_NAND_AMS_DELTA config MTD_NAND_AMS_DELTA
tristate "NAND Flash device on Amstrad E3" tristate "NAND Flash device on Amstrad E3"
...@@ -516,4 +518,10 @@ config MTD_NAND_XWAY ...@@ -516,4 +518,10 @@ config MTD_NAND_XWAY
Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
to the External Bus Unit (EBU). to the External Bus Unit (EBU).
config MTD_NAND_SUNXI
tristate "Support for NAND on Allwinner SoCs"
depends on ARCH_SUNXI
help
Enables support for NAND Flash chips on Allwinner SoCs.
endif # MTD_NAND endif # MTD_NAND
...@@ -50,5 +50,6 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o ...@@ -50,5 +50,6 @@ obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o
obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/ obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o nand-objs := nand_base.o nand_bbt.o nand_timings.o
...@@ -92,7 +92,7 @@ static struct nand_ecclayout atmel_oobinfo_small = { ...@@ -92,7 +92,7 @@ static struct nand_ecclayout atmel_oobinfo_small = {
struct atmel_nfc { struct atmel_nfc {
void __iomem *base_cmd_regs; void __iomem *base_cmd_regs;
void __iomem *hsmc_regs; void __iomem *hsmc_regs;
void __iomem *sram_bank0; void *sram_bank0;
dma_addr_t sram_bank0_phys; dma_addr_t sram_bank0_phys;
bool use_nfc_sram; bool use_nfc_sram;
bool write_by_sram; bool write_by_sram;
...@@ -105,7 +105,7 @@ struct atmel_nfc { ...@@ -105,7 +105,7 @@ struct atmel_nfc {
struct completion comp_xfer_done; struct completion comp_xfer_done;
/* Point to the sram bank which include readed data via NFC */ /* Point to the sram bank which include readed data via NFC */
void __iomem *data_in_sram; void *data_in_sram;
bool will_write_sram; bool will_write_sram;
}; };
static struct atmel_nfc nand_nfc; static struct atmel_nfc nand_nfc;
...@@ -127,6 +127,7 @@ struct atmel_nand_host { ...@@ -127,6 +127,7 @@ struct atmel_nand_host {
bool has_pmecc; bool has_pmecc;
u8 pmecc_corr_cap; u8 pmecc_corr_cap;
u16 pmecc_sector_size; u16 pmecc_sector_size;
bool has_no_lookup_table;
u32 pmecc_lookup_table_offset; u32 pmecc_lookup_table_offset;
u32 pmecc_lookup_table_offset_512; u32 pmecc_lookup_table_offset_512;
u32 pmecc_lookup_table_offset_1024; u32 pmecc_lookup_table_offset_1024;
...@@ -256,26 +257,6 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd) ...@@ -256,26 +257,6 @@ static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
return res; return res;
} }
static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size)
{
int i;
u32 *t = trg;
const __iomem u32 *s = src;
for (i = 0; i < (size >> 2); i++)
*t++ = readl_relaxed(s++);
}
static void memcpy32_toio(void __iomem *trg, const void *src, int size)
{
int i;
u32 __iomem *t = trg;
const u32 *s = src;
for (i = 0; i < (size >> 2); i++)
writel_relaxed(*s++, t++);
}
/* /*
* Minimal-overhead PIO for data access. * Minimal-overhead PIO for data access.
*/ */
...@@ -285,7 +266,7 @@ static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) ...@@ -285,7 +266,7 @@ static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
struct atmel_nand_host *host = nand_chip->priv; struct atmel_nand_host *host = nand_chip->priv;
if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) { if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
memcpy32_fromio(buf, host->nfc->data_in_sram, len); memcpy(buf, host->nfc->data_in_sram, len);
host->nfc->data_in_sram += len; host->nfc->data_in_sram += len;
} else { } else {
__raw_readsb(nand_chip->IO_ADDR_R, buf, len); __raw_readsb(nand_chip->IO_ADDR_R, buf, len);
...@@ -298,7 +279,7 @@ static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) ...@@ -298,7 +279,7 @@ static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
struct atmel_nand_host *host = nand_chip->priv; struct atmel_nand_host *host = nand_chip->priv;
if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) { if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
memcpy32_fromio(buf, host->nfc->data_in_sram, len); memcpy(buf, host->nfc->data_in_sram, len);
host->nfc->data_in_sram += len; host->nfc->data_in_sram += len;
} else { } else {
__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
...@@ -1112,12 +1093,66 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host, ...@@ -1112,12 +1093,66 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
return 0; return 0;
} }
static inline int deg(unsigned int poly)
{
/* polynomial degree is the most-significant bit index */
return fls(poly) - 1;
}
static int build_gf_tables(int mm, unsigned int poly,
int16_t *index_of, int16_t *alpha_to)
{
unsigned int i, x = 1;
const unsigned int k = 1 << deg(poly);
unsigned int nn = (1 << mm) - 1;
/* primitive polynomial must be of degree m */
if (k != (1u << mm))
return -EINVAL;
for (i = 0; i < nn; i++) {
alpha_to[i] = x;
index_of[x] = i;
if (i && (x == 1))
/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */
return -EINVAL;
x <<= 1;
if (x & k)
x ^= poly;
}
alpha_to[nn] = 1;
index_of[0] = 0;
return 0;
}
static uint16_t *create_lookup_table(struct device *dev, int sector_size)
{
int degree = (sector_size == 512) ?
PMECC_GF_DIMENSION_13 :
PMECC_GF_DIMENSION_14;
unsigned int poly = (sector_size == 512) ?
PMECC_GF_13_PRIMITIVE_POLY :
PMECC_GF_14_PRIMITIVE_POLY;
int table_size = (sector_size == 512) ?
PMECC_LOOKUP_TABLE_SIZE_512 :
PMECC_LOOKUP_TABLE_SIZE_1024;
int16_t *addr = devm_kzalloc(dev, 2 * table_size * sizeof(uint16_t),
GFP_KERNEL);
if (addr && build_gf_tables(degree, poly, addr, addr + table_size))
return NULL;
return addr;
}
static int atmel_pmecc_nand_init_params(struct platform_device *pdev, static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
struct atmel_nand_host *host) struct atmel_nand_host *host)
{ {
struct mtd_info *mtd = &host->mtd; struct mtd_info *mtd = &host->mtd;
struct nand_chip *nand_chip = &host->nand_chip; struct nand_chip *nand_chip = &host->nand_chip;
struct resource *regs, *regs_pmerr, *regs_rom; struct resource *regs, *regs_pmerr, *regs_rom;
uint16_t *galois_table;
int cap, sector_size, err_no; int cap, sector_size, err_no;
err_no = pmecc_choose_ecc(host, &cap, &sector_size); err_no = pmecc_choose_ecc(host, &cap, &sector_size);
...@@ -1163,8 +1198,24 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, ...@@ -1163,8 +1198,24 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
if (IS_ERR(host->pmecc_rom_base)) { if (IS_ERR(host->pmecc_rom_base)) {
err_no = PTR_ERR(host->pmecc_rom_base); if (!host->has_no_lookup_table)
goto err; /* Don't display the information again */
dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n");
host->has_no_lookup_table = true;
}
if (host->has_no_lookup_table) {
/* Build the look-up table in runtime */
galois_table = create_lookup_table(host->dev, sector_size);
if (!galois_table) {
dev_err(host->dev, "Failed to build a lookup table in runtime!\n");
err_no = -EINVAL;
goto err;
}
host->pmecc_rom_base = (void __iomem *)galois_table;
host->pmecc_lookup_table_offset = 0;
} }
nand_chip->ecc.size = sector_size; nand_chip->ecc.size = sector_size;
...@@ -1501,8 +1552,10 @@ static int atmel_of_init_port(struct atmel_nand_host *host, ...@@ -1501,8 +1552,10 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset", if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset",
offset, 2) != 0) { offset, 2) != 0) {
dev_err(host->dev, "Cannot get PMECC lookup table offset\n"); dev_err(host->dev, "Cannot get PMECC lookup table offset, will build a lookup table in runtime.\n");
return -EINVAL; host->has_no_lookup_table = true;
/* Will build a lookup table and initialize the offset later */
return 0;
} }
if (!offset[0] && !offset[1]) { if (!offset[0] && !offset[1]) {
dev_err(host->dev, "Invalid PMECC lookup table offset\n"); dev_err(host->dev, "Invalid PMECC lookup table offset\n");
...@@ -1899,7 +1952,7 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1899,7 +1952,7 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
int cfg, len; int cfg, len;
int status = 0; int status = 0;
struct atmel_nand_host *host = chip->priv; struct atmel_nand_host *host = chip->priv;
void __iomem *sram = host->nfc->sram_bank0 + nfc_get_sram_off(host); void *sram = host->nfc->sram_bank0 + nfc_get_sram_off(host);
/* Subpage write is not supported */ /* Subpage write is not supported */
if (offset || (data_len < mtd->writesize)) if (offset || (data_len < mtd->writesize))
...@@ -1910,14 +1963,14 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1910,14 +1963,14 @@ static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
if (use_dma) { if (use_dma) {
if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0) if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0)
/* Fall back to use cpu copy */ /* Fall back to use cpu copy */
memcpy32_toio(sram, buf, len); memcpy(sram, buf, len);
} else { } else {
memcpy32_toio(sram, buf, len); memcpy(sram, buf, len);
} }
cfg = nfc_readl(host->nfc->hsmc_regs, CFG); cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
if (unlikely(raw) && oob_required) { if (unlikely(raw) && oob_required) {
memcpy32_toio(sram + len, chip->oob_poi, mtd->oobsize); memcpy(sram + len, chip->oob_poi, mtd->oobsize);
len += mtd->oobsize; len += mtd->oobsize;
nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE); nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
} else { } else {
...@@ -2260,7 +2313,8 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev) ...@@ -2260,7 +2313,8 @@ static int atmel_nand_nfc_probe(struct platform_device *pdev)
nfc_sram = platform_get_resource(pdev, IORESOURCE_MEM, 2); nfc_sram = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (nfc_sram) { if (nfc_sram) {
nfc->sram_bank0 = devm_ioremap_resource(&pdev->dev, nfc_sram); nfc->sram_bank0 = (void * __force)
devm_ioremap_resource(&pdev->dev, nfc_sram);
if (IS_ERR(nfc->sram_bank0)) { if (IS_ERR(nfc->sram_bank0)) {
dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n", dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
PTR_ERR(nfc->sram_bank0)); PTR_ERR(nfc->sram_bank0));
......
...@@ -142,6 +142,10 @@ ...@@ -142,6 +142,10 @@
#define PMECC_GF_DIMENSION_13 13 #define PMECC_GF_DIMENSION_13 13
#define PMECC_GF_DIMENSION_14 14 #define PMECC_GF_DIMENSION_14 14
/* Primitive Polynomial used by PMECC */
#define PMECC_GF_13_PRIMITIVE_POLY 0x201b
#define PMECC_GF_14_PRIMITIVE_POLY 0x4443
#define PMECC_LOOKUP_TABLE_SIZE_512 0x2000 #define PMECC_LOOKUP_TABLE_SIZE_512 0x2000
#define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000 #define PMECC_LOOKUP_TABLE_SIZE_1024 0x4000
......
...@@ -529,50 +529,6 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd, ...@@ -529,50 +529,6 @@ static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
return 0; return 0;
} }
static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw)
{
int status;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
if (unlikely(raw))
status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
else
status = chip->ecc.write_page(mtd, chip, buf, oob_required);
if (status < 0)
return status;
/*
* Cached progamming disabled for now, Not sure if its worth the
* trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
*/
cached = 0;
if (!cached || !(chip->options & NAND_CACHEPRG)) {
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
/*
* See if operation failed and additional status checks are
* available
*/
if ((status & NAND_STATUS_FAIL) && (chip->errstat))
status = chip->errstat(mtd, chip, FL_WRITING, status,
page);
if (status & NAND_STATUS_FAIL)
return -EIO;
} else {
chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
}
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, int getchip)
{ {
return 0; return 0;
...@@ -800,7 +756,6 @@ static int cafe_nand_probe(struct pci_dev *pdev, ...@@ -800,7 +756,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
cafe->nand.ecc.hwctl = (void *)cafe_nand_bug; cafe->nand.ecc.hwctl = (void *)cafe_nand_bug;
cafe->nand.ecc.calculate = (void *)cafe_nand_bug; cafe->nand.ecc.calculate = (void *)cafe_nand_bug;
cafe->nand.ecc.correct = (void *)cafe_nand_bug; cafe->nand.ecc.correct = (void *)cafe_nand_bug;
cafe->nand.write_page = cafe_nand_write_page;
cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel; cafe->nand.ecc.write_page = cafe_nand_write_page_lowlevel;
cafe->nand.ecc.write_oob = cafe_nand_write_oob; cafe->nand.ecc.write_oob = cafe_nand_write_oob;
cafe->nand.ecc.read_page = cafe_nand_read_page; cafe->nand.ecc.read_page = cafe_nand_read_page;
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
#include <linux/mtd/nand_ecc.h> #include <linux/mtd/nand_ecc.h>
#include <linux/fsl_ifc.h> #include <linux/fsl_ifc.h>
#define FSL_IFC_V1_1_0 0x01010000
#define ERR_BYTE 0xFF /* Value returned for read #define ERR_BYTE 0xFF /* Value returned for read
bytes when read failed */ bytes when read failed */
#define IFC_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait #define IFC_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait
...@@ -877,7 +876,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) ...@@ -877,7 +876,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
struct fsl_ifc_regs __iomem *ifc = ctrl->regs; struct fsl_ifc_regs __iomem *ifc = ctrl->regs;
struct nand_chip *chip = &priv->chip; struct nand_chip *chip = &priv->chip;
struct nand_ecclayout *layout; struct nand_ecclayout *layout;
u32 csor, ver; u32 csor;
/* Fill in fsl_ifc_mtd structure */ /* Fill in fsl_ifc_mtd structure */
priv->mtd.priv = chip; priv->mtd.priv = chip;
...@@ -984,8 +983,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) ...@@ -984,8 +983,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.mode = NAND_ECC_SOFT;
} }
ver = ioread32be(&ifc->ifc_rev); if (ctrl->version == FSL_IFC_VERSION_1_1_0)
if (ver == FSL_IFC_V1_1_0)
fsl_ifc_sram_init(priv); fsl_ifc_sram_init(priv);
return 0; return 0;
...@@ -1045,12 +1043,12 @@ static int fsl_ifc_nand_probe(struct platform_device *dev) ...@@ -1045,12 +1043,12 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
} }
/* find which chip select it is connected to */ /* find which chip select it is connected to */
for (bank = 0; bank < FSL_IFC_BANK_COUNT; bank++) { for (bank = 0; bank < fsl_ifc_ctrl_dev->banks; bank++) {
if (match_bank(ifc, bank, res.start)) if (match_bank(ifc, bank, res.start))
break; break;
} }
if (bank >= FSL_IFC_BANK_COUNT) { if (bank >= fsl_ifc_ctrl_dev->banks) {
dev_err(&dev->dev, "%s: address did not match any chip selects\n", dev_err(&dev->dev, "%s: address did not match any chip selects\n",
__func__); __func__);
return -ENODEV; return -ENODEV;
......
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
* *
* © 2004 Simtec Electronics * © 2004 Simtec Electronics
* *
* Device driver for NAND connected via GPIO * Device driver for NAND flash that uses a memory mapped interface to
* read/write the NAND commands and data, and GPIO pins for control signals
* (the DT binding refers to this as "GPIO assisted NAND flash")
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
......
...@@ -1353,3 +1353,156 @@ int gpmi_read_page(struct gpmi_nand_data *this, ...@@ -1353,3 +1353,156 @@ int gpmi_read_page(struct gpmi_nand_data *this,
set_dma_type(this, DMA_FOR_READ_ECC_PAGE); set_dma_type(this, DMA_FOR_READ_ECC_PAGE);
return start_dma_with_bch_irq(this, desc); return start_dma_with_bch_irq(this, desc);
} }
/**
* gpmi_copy_bits - copy bits from one memory region to another
* @dst: destination buffer
* @dst_bit_off: bit offset we're starting to write at
* @src: source buffer
* @src_bit_off: bit offset we're starting to read from
* @nbits: number of bits to copy
*
* This functions copies bits from one memory region to another, and is used by
* the GPMI driver to copy ECC sections which are not guaranteed to be byte
* aligned.
*
* src and dst should not overlap.
*
*/
void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
const u8 *src, size_t src_bit_off,
size_t nbits)
{
size_t i;
size_t nbytes;
u32 src_buffer = 0;
size_t bits_in_src_buffer = 0;
if (!nbits)
return;
/*
* Move src and dst pointers to the closest byte pointer and store bit
* offsets within a byte.
*/
src += src_bit_off / 8;
src_bit_off %= 8;
dst += dst_bit_off / 8;
dst_bit_off %= 8;
/*
* Initialize the src_buffer value with bits available in the first
* byte of data so that we end up with a byte aligned src pointer.
*/
if (src_bit_off) {
src_buffer = src[0] >> src_bit_off;
if (nbits >= (8 - src_bit_off)) {
bits_in_src_buffer += 8 - src_bit_off;
} else {
src_buffer &= GENMASK(nbits - 1, 0);
bits_in_src_buffer += nbits;
}
nbits -= bits_in_src_buffer;
src++;
}
/* Calculate the number of bytes that can be copied from src to dst. */
nbytes = nbits / 8;
/* Try to align dst to a byte boundary. */
if (dst_bit_off) {
if (bits_in_src_buffer < (8 - dst_bit_off) && nbytes) {
src_buffer |= src[0] << bits_in_src_buffer;
bits_in_src_buffer += 8;
src++;
nbytes--;
}
if (bits_in_src_buffer >= (8 - dst_bit_off)) {
dst[0] &= GENMASK(dst_bit_off - 1, 0);
dst[0] |= src_buffer << dst_bit_off;
src_buffer >>= (8 - dst_bit_off);
bits_in_src_buffer -= (8 - dst_bit_off);
dst_bit_off = 0;
dst++;
if (bits_in_src_buffer > 7) {
bits_in_src_buffer -= 8;
dst[0] = src_buffer;
dst++;
src_buffer >>= 8;
}
}
}
if (!bits_in_src_buffer && !dst_bit_off) {
/*
* Both src and dst pointers are byte aligned, thus we can
* just use the optimized memcpy function.
*/
if (nbytes)
memcpy(dst, src, nbytes);
} else {
/*
* src buffer is not byte aligned, hence we have to copy each
* src byte to the src_buffer variable before extracting a byte
* to store in dst.
*/
for (i = 0; i < nbytes; i++) {
src_buffer |= src[i] << bits_in_src_buffer;
dst[i] = src_buffer;
src_buffer >>= 8;
}
}
/* Update dst and src pointers */
dst += nbytes;
src += nbytes;
/*
* nbits is the number of remaining bits. It should not exceed 8 as
* we've already copied as much bytes as possible.
*/
nbits %= 8;
/*
* If there's no more bits to copy to the destination and src buffer
* was already byte aligned, then we're done.
*/
if (!nbits && !bits_in_src_buffer)
return;
/* Copy the remaining bits to src_buffer */
if (nbits)
src_buffer |= (*src & GENMASK(nbits - 1, 0)) <<
bits_in_src_buffer;
bits_in_src_buffer += nbits;
/*
* In case there were not enough bits to get a byte aligned dst buffer
* prepare the src_buffer variable to match the dst organization (shift
* src_buffer by dst_bit_off and retrieve the least significant bits
* from dst).
*/
if (dst_bit_off)
src_buffer = (src_buffer << dst_bit_off) |
(*dst & GENMASK(dst_bit_off - 1, 0));
bits_in_src_buffer += dst_bit_off;
/*
* Keep most significant bits from dst if we end up with an unaligned
* number of bits.
*/
nbytes = bits_in_src_buffer / 8;
if (bits_in_src_buffer % 8) {
src_buffer |= (dst[nbytes] &
GENMASK(7, bits_in_src_buffer % 8)) <<
(nbytes * 8);
nbytes++;
}
/* Copy the remaining bytes to dst */
for (i = 0; i < nbytes; i++) {
dst[i] = src_buffer;
src_buffer >>= 8;
}
}
...@@ -791,6 +791,7 @@ static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) ...@@ -791,6 +791,7 @@ static void gpmi_free_dma_buffer(struct gpmi_nand_data *this)
this->page_buffer_phys); this->page_buffer_phys);
kfree(this->cmd_buffer); kfree(this->cmd_buffer);
kfree(this->data_buffer_dma); kfree(this->data_buffer_dma);
kfree(this->raw_buffer);
this->cmd_buffer = NULL; this->cmd_buffer = NULL;
this->data_buffer_dma = NULL; this->data_buffer_dma = NULL;
...@@ -837,6 +838,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) ...@@ -837,6 +838,9 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
if (!this->page_buffer_virt) if (!this->page_buffer_virt)
goto error_alloc; goto error_alloc;
this->raw_buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
if (!this->raw_buffer)
goto error_alloc;
/* Slice up the page buffer. */ /* Slice up the page buffer. */
this->payload_virt = this->page_buffer_virt; this->payload_virt = this->page_buffer_virt;
...@@ -1347,6 +1351,199 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) ...@@ -1347,6 +1351,199 @@ gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page)
return status & NAND_STATUS_FAIL ? -EIO : 0; return status & NAND_STATUS_FAIL ? -EIO : 0;
} }
/*
* This function reads a NAND page without involving the ECC engine (no HW
* ECC correction).
* The tricky part in the GPMI/BCH controller is that it stores ECC bits
* inline (interleaved with payload DATA), and do not align data chunk on
* byte boundaries.
* We thus need to take care moving the payload data and ECC bits stored in the
* page into the provided buffers, which is why we're using gpmi_copy_bits.
*
* See set_geometry_by_ecc_info inline comments to have a full description
* of the layout used by the GPMI controller.
*/
static int gpmi_ecc_read_page_raw(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
struct gpmi_nand_data *this = chip->priv;
struct bch_geometry *nfc_geo = &this->bch_geometry;
int eccsize = nfc_geo->ecc_chunk_size;
int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
u8 *tmp_buf = this->raw_buffer;
size_t src_bit_off;
size_t oob_bit_off;
size_t oob_byte_off;
uint8_t *oob = chip->oob_poi;
int step;
chip->read_buf(mtd, tmp_buf,
mtd->writesize + mtd->oobsize);
/*
* If required, swap the bad block marker and the data stored in the
* metadata section, so that we don't wrongly consider a block as bad.
*
* See the layout description for a detailed explanation on why this
* is needed.
*/
if (this->swap_block_mark) {
u8 swap = tmp_buf[0];
tmp_buf[0] = tmp_buf[mtd->writesize];
tmp_buf[mtd->writesize] = swap;
}
/*
* Copy the metadata section into the oob buffer (this section is
* guaranteed to be aligned on a byte boundary).
*/
if (oob_required)
memcpy(oob, tmp_buf, nfc_geo->metadata_size);
oob_bit_off = nfc_geo->metadata_size * 8;
src_bit_off = oob_bit_off;
/* Extract interleaved payload data and ECC bits */
for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
if (buf)
gpmi_copy_bits(buf, step * eccsize * 8,
tmp_buf, src_bit_off,
eccsize * 8);
src_bit_off += eccsize * 8;
/* Align last ECC block to align a byte boundary */
if (step == nfc_geo->ecc_chunk_count - 1 &&
(oob_bit_off + eccbits) % 8)
eccbits += 8 - ((oob_bit_off + eccbits) % 8);
if (oob_required)
gpmi_copy_bits(oob, oob_bit_off,
tmp_buf, src_bit_off,
eccbits);
src_bit_off += eccbits;
oob_bit_off += eccbits;
}
if (oob_required) {
oob_byte_off = oob_bit_off / 8;
if (oob_byte_off < mtd->oobsize)
memcpy(oob + oob_byte_off,
tmp_buf + mtd->writesize + oob_byte_off,
mtd->oobsize - oob_byte_off);
}
return 0;
}
/*
* This function writes a NAND page without involving the ECC engine (no HW
* ECC generation).
* The tricky part in the GPMI/BCH controller is that it stores ECC bits
* inline (interleaved with payload DATA), and do not align data chunk on
* byte boundaries.
* We thus need to take care moving the OOB area at the right place in the
* final page, which is why we're using gpmi_copy_bits.
*
* See set_geometry_by_ecc_info inline comments to have a full description
* of the layout used by the GPMI controller.
*/
static int gpmi_ecc_write_page_raw(struct mtd_info *mtd,
struct nand_chip *chip,
const uint8_t *buf,
int oob_required)
{
struct gpmi_nand_data *this = chip->priv;
struct bch_geometry *nfc_geo = &this->bch_geometry;
int eccsize = nfc_geo->ecc_chunk_size;
int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
u8 *tmp_buf = this->raw_buffer;
uint8_t *oob = chip->oob_poi;
size_t dst_bit_off;
size_t oob_bit_off;
size_t oob_byte_off;
int step;
/*
* Initialize all bits to 1 in case we don't have a buffer for the
* payload or oob data in order to leave unspecified bits of data
* to their initial state.
*/
if (!buf || !oob_required)
memset(tmp_buf, 0xff, mtd->writesize + mtd->oobsize);
/*
* First copy the metadata section (stored in oob buffer) at the
* beginning of the page, as imposed by the GPMI layout.
*/
memcpy(tmp_buf, oob, nfc_geo->metadata_size);
oob_bit_off = nfc_geo->metadata_size * 8;
dst_bit_off = oob_bit_off;
/* Interleave payload data and ECC bits */
for (step = 0; step < nfc_geo->ecc_chunk_count; step++) {
if (buf)
gpmi_copy_bits(tmp_buf, dst_bit_off,
buf, step * eccsize * 8, eccsize * 8);
dst_bit_off += eccsize * 8;
/* Align last ECC block to align a byte boundary */
if (step == nfc_geo->ecc_chunk_count - 1 &&
(oob_bit_off + eccbits) % 8)
eccbits += 8 - ((oob_bit_off + eccbits) % 8);
if (oob_required)
gpmi_copy_bits(tmp_buf, dst_bit_off,
oob, oob_bit_off, eccbits);
dst_bit_off += eccbits;
oob_bit_off += eccbits;
}
oob_byte_off = oob_bit_off / 8;
if (oob_required && oob_byte_off < mtd->oobsize)
memcpy(tmp_buf + mtd->writesize + oob_byte_off,
oob + oob_byte_off, mtd->oobsize - oob_byte_off);
/*
* If required, swap the bad block marker and the first byte of the
* metadata section, so that we don't modify the bad block marker.
*
* See the layout description for a detailed explanation on why this
* is needed.
*/
if (this->swap_block_mark) {
u8 swap = tmp_buf[0];
tmp_buf[0] = tmp_buf[mtd->writesize];
tmp_buf[mtd->writesize] = swap;
}
chip->write_buf(mtd, tmp_buf, mtd->writesize + mtd->oobsize);
return 0;
}
static int gpmi_ecc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
return gpmi_ecc_read_page_raw(mtd, chip, NULL, 1, page);
}
static int gpmi_ecc_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page);
return gpmi_ecc_write_page_raw(mtd, chip, NULL, 1);
}
static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
{ {
struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd->priv;
...@@ -1664,6 +1861,10 @@ static int gpmi_init_last(struct gpmi_nand_data *this) ...@@ -1664,6 +1861,10 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
ecc->write_page = gpmi_ecc_write_page; ecc->write_page = gpmi_ecc_write_page;
ecc->read_oob = gpmi_ecc_read_oob; ecc->read_oob = gpmi_ecc_read_oob;
ecc->write_oob = gpmi_ecc_write_oob; ecc->write_oob = gpmi_ecc_write_oob;
ecc->read_page_raw = gpmi_ecc_read_page_raw;
ecc->write_page_raw = gpmi_ecc_write_page_raw;
ecc->read_oob_raw = gpmi_ecc_read_oob_raw;
ecc->write_oob_raw = gpmi_ecc_write_oob_raw;
ecc->mode = NAND_ECC_HW; ecc->mode = NAND_ECC_HW;
ecc->size = bch_geo->ecc_chunk_size; ecc->size = bch_geo->ecc_chunk_size;
ecc->strength = bch_geo->ecc_strength; ecc->strength = bch_geo->ecc_strength;
......
...@@ -189,6 +189,8 @@ struct gpmi_nand_data { ...@@ -189,6 +189,8 @@ struct gpmi_nand_data {
void *auxiliary_virt; void *auxiliary_virt;
dma_addr_t auxiliary_phys; dma_addr_t auxiliary_phys;
void *raw_buffer;
/* DMA channels */ /* DMA channels */
#define DMA_CHANS 8 #define DMA_CHANS 8
struct dma_chan *dma_chans[DMA_CHANS]; struct dma_chan *dma_chans[DMA_CHANS];
...@@ -290,6 +292,10 @@ extern int gpmi_send_page(struct gpmi_nand_data *, ...@@ -290,6 +292,10 @@ extern int gpmi_send_page(struct gpmi_nand_data *,
extern int gpmi_read_page(struct gpmi_nand_data *, extern int gpmi_read_page(struct gpmi_nand_data *,
dma_addr_t payload, dma_addr_t auxiliary); dma_addr_t payload, dma_addr_t auxiliary);
void gpmi_copy_bits(u8 *dst, size_t dst_bit_off,
const u8 *src, size_t src_bit_off,
size_t nbits);
/* BCH : Status Block Completion Codes */ /* BCH : Status Block Completion Codes */
#define STATUS_GOOD 0x00 #define STATUS_GOOD 0x00
#define STATUS_ERASED 0xff #define STATUS_ERASED 0xff
......
...@@ -280,14 +280,10 @@ static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size) ...@@ -280,14 +280,10 @@ static void memcpy32_fromio(void *trg, const void __iomem *src, size_t size)
*t++ = __raw_readl(s++); *t++ = __raw_readl(s++);
} }
static void memcpy32_toio(void __iomem *trg, const void *src, int size) static inline void memcpy32_toio(void __iomem *trg, const void *src, int size)
{ {
int i; /* __iowrite32_copy use 32bit size values so divide by 4 */
u32 __iomem *t = trg; __iowrite32_copy(trg, src, size / 4);
const u32 *s = src;
for (i = 0; i < (size >> 2); i++)
__raw_writel(*s++, t++);
} }
static int check_int_v3(struct mxc_nand_host *host) static int check_int_v3(struct mxc_nand_host *host)
......
...@@ -485,11 +485,11 @@ static int nand_check_wp(struct mtd_info *mtd) ...@@ -485,11 +485,11 @@ static int nand_check_wp(struct mtd_info *mtd)
} }
/** /**
* nand_block_checkbad - [GENERIC] Check if a block is marked bad * nand_block_isreserved - [GENERIC] Check if a block is marked reserved.
* @mtd: MTD device structure * @mtd: MTD device structure
* @ofs: offset from device start * @ofs: offset from device start
* *
* Check if the block is mark as reserved. * Check if the block is marked as reserved.
*/ */
static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs) static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs)
{ {
...@@ -720,7 +720,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, ...@@ -720,7 +720,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
/* /*
* Program and erase have their own busy handlers status, sequential * Program and erase have their own busy handlers status, sequential
* in, and deplete1 need no delay. * in and status need no delay.
*/ */
switch (command) { switch (command) {
...@@ -3765,9 +3765,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, ...@@ -3765,9 +3765,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
type->name); type->name);
pr_info("%dMiB, %s, page size: %d, OOB size: %d\n", pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
mtd->writesize, mtd->oobsize); mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
return type; return type;
} }
...@@ -4035,7 +4035,7 @@ int nand_scan_tail(struct mtd_info *mtd) ...@@ -4035,7 +4035,7 @@ int nand_scan_tail(struct mtd_info *mtd)
*/ */
if (!ecc->size && (mtd->oobsize >= 64)) { if (!ecc->size && (mtd->oobsize >= 64)) {
ecc->size = 512; ecc->size = 512;
ecc->bytes = 7; ecc->bytes = DIV_ROUND_UP(13 * ecc->strength, 8);
} }
ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes, ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
&ecc->layout); &ecc->layout);
......
...@@ -178,6 +178,7 @@ struct nand_manufacturers nand_manuf_ids[] = { ...@@ -178,6 +178,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_EON, "Eon"}, {NAND_MFR_EON, "Eon"},
{NAND_MFR_SANDISK, "SanDisk"}, {NAND_MFR_SANDISK, "SanDisk"},
{NAND_MFR_INTEL, "Intel"}, {NAND_MFR_INTEL, "Intel"},
{NAND_MFR_ATO, "ATO"},
{0x0, "Unknown"} {0x0, "Unknown"}
}; };
......
...@@ -87,10 +87,6 @@ ...@@ -87,10 +87,6 @@
#define CONFIG_NANDSIM_MAX_PARTS 32 #define CONFIG_NANDSIM_MAX_PARTS 32
#endif #endif
static uint first_id_byte = CONFIG_NANDSIM_FIRST_ID_BYTE;
static uint second_id_byte = CONFIG_NANDSIM_SECOND_ID_BYTE;
static uint third_id_byte = CONFIG_NANDSIM_THIRD_ID_BYTE;
static uint fourth_id_byte = CONFIG_NANDSIM_FOURTH_ID_BYTE;
static uint access_delay = CONFIG_NANDSIM_ACCESS_DELAY; static uint access_delay = CONFIG_NANDSIM_ACCESS_DELAY;
static uint programm_delay = CONFIG_NANDSIM_PROGRAMM_DELAY; static uint programm_delay = CONFIG_NANDSIM_PROGRAMM_DELAY;
static uint erase_delay = CONFIG_NANDSIM_ERASE_DELAY; static uint erase_delay = CONFIG_NANDSIM_ERASE_DELAY;
...@@ -111,11 +107,19 @@ static unsigned int overridesize = 0; ...@@ -111,11 +107,19 @@ static unsigned int overridesize = 0;
static char *cache_file = NULL; static char *cache_file = NULL;
static unsigned int bbt; static unsigned int bbt;
static unsigned int bch; static unsigned int bch;
static u_char id_bytes[8] = {
[0] = CONFIG_NANDSIM_FIRST_ID_BYTE,
[1] = CONFIG_NANDSIM_SECOND_ID_BYTE,
[2] = CONFIG_NANDSIM_THIRD_ID_BYTE,
[3] = CONFIG_NANDSIM_FOURTH_ID_BYTE,
[4 ... 7] = 0xFF,
};
module_param(first_id_byte, uint, 0400); module_param_array(id_bytes, byte, NULL, 0400);
module_param(second_id_byte, uint, 0400); module_param_named(first_id_byte, id_bytes[0], byte, 0400);
module_param(third_id_byte, uint, 0400); module_param_named(second_id_byte, id_bytes[1], byte, 0400);
module_param(fourth_id_byte, uint, 0400); module_param_named(third_id_byte, id_bytes[2], byte, 0400);
module_param_named(fourth_id_byte, id_bytes[3], byte, 0400);
module_param(access_delay, uint, 0400); module_param(access_delay, uint, 0400);
module_param(programm_delay, uint, 0400); module_param(programm_delay, uint, 0400);
module_param(erase_delay, uint, 0400); module_param(erase_delay, uint, 0400);
...@@ -136,10 +140,11 @@ module_param(cache_file, charp, 0400); ...@@ -136,10 +140,11 @@ module_param(cache_file, charp, 0400);
module_param(bbt, uint, 0400); module_param(bbt, uint, 0400);
module_param(bch, uint, 0400); module_param(bch, uint, 0400);
MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); MODULE_PARM_DESC(id_bytes, "The ID bytes returned by NAND Flash 'read ID' command");
MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID) (obsolete)");
MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID) (obsolete)");
MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command (obsolete)");
MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command (obsolete)");
MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)"); MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)");
MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)");
...@@ -304,7 +309,7 @@ struct nandsim { ...@@ -304,7 +309,7 @@ struct nandsim {
unsigned int nbparts; unsigned int nbparts;
uint busw; /* flash chip bus width (8 or 16) */ uint busw; /* flash chip bus width (8 or 16) */
u_char ids[4]; /* chip's ID bytes */ u_char ids[8]; /* chip's ID bytes */
uint32_t options; /* chip's characteristic bits */ uint32_t options; /* chip's characteristic bits */
uint32_t state; /* current chip state */ uint32_t state; /* current chip state */
uint32_t nxstate; /* next expected state */ uint32_t nxstate; /* next expected state */
...@@ -2279,17 +2284,18 @@ static int __init ns_init_module(void) ...@@ -2279,17 +2284,18 @@ static int __init ns_init_module(void)
* Perform minimum nandsim structure initialization to handle * Perform minimum nandsim structure initialization to handle
* the initial ID read command correctly * the initial ID read command correctly
*/ */
if (third_id_byte != 0xFF || fourth_id_byte != 0xFF) if (id_bytes[6] != 0xFF || id_bytes[7] != 0xFF)
nand->geom.idbytes = 8;
else if (id_bytes[4] != 0xFF || id_bytes[5] != 0xFF)
nand->geom.idbytes = 6;
else if (id_bytes[2] != 0xFF || id_bytes[3] != 0xFF)
nand->geom.idbytes = 4; nand->geom.idbytes = 4;
else else
nand->geom.idbytes = 2; nand->geom.idbytes = 2;
nand->regs.status = NS_STATUS_OK(nand); nand->regs.status = NS_STATUS_OK(nand);
nand->nxstate = STATE_UNKNOWN; nand->nxstate = STATE_UNKNOWN;
nand->options |= OPT_PAGE512; /* temporary value */ nand->options |= OPT_PAGE512; /* temporary value */
nand->ids[0] = first_id_byte; memcpy(nand->ids, id_bytes, sizeof(nand->ids));
nand->ids[1] = second_id_byte;
nand->ids[2] = third_id_byte;
nand->ids[3] = fourth_id_byte;
if (bus_width == 16) { if (bus_width == 16) {
nand->busw = 16; nand->busw = 16;
chip->options |= NAND_BUSWIDTH_16; chip->options |= NAND_BUSWIDTH_16;
......
...@@ -144,11 +144,13 @@ static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, ...@@ -144,11 +144,13 @@ static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc,
0xac, 0x6b, 0xff, 0x99, 0x7b}; 0xac, 0x6b, 0xff, 0x99, 0x7b};
static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10};
/* oob info generated runtime depending on ecc algorithm and layout selected */ /* Shared among all NAND instances to synchronize access to the ECC Engine */
static struct nand_ecclayout omap_oobinfo; static struct nand_hw_control omap_gpmc_controller = {
.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
};
struct omap_nand_info { struct omap_nand_info {
struct nand_hw_control controller;
struct omap_nand_platform_data *pdata; struct omap_nand_platform_data *pdata;
struct mtd_info mtd; struct mtd_info mtd;
struct nand_chip nand; struct nand_chip nand;
...@@ -168,6 +170,8 @@ struct omap_nand_info { ...@@ -168,6 +170,8 @@ struct omap_nand_info {
u_char *buf; u_char *buf;
int buf_len; int buf_len;
struct gpmc_nand_regs reg; struct gpmc_nand_regs reg;
/* generated at runtime depending on ECC algorithm and layout selected */
struct nand_ecclayout oobinfo;
/* fields specific for BCHx_HW ECC scheme */ /* fields specific for BCHx_HW ECC scheme */
struct device *elm_dev; struct device *elm_dev;
struct device_node *of_node; struct device_node *of_node;
...@@ -1686,9 +1690,6 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1686,9 +1690,6 @@ static int omap_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
spin_lock_init(&info->controller.lock);
init_waitqueue_head(&info->controller.wq);
info->pdev = pdev; info->pdev = pdev;
info->gpmc_cs = pdata->cs; info->gpmc_cs = pdata->cs;
info->reg = pdata->reg; info->reg = pdata->reg;
...@@ -1708,7 +1709,7 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1708,7 +1709,7 @@ static int omap_nand_probe(struct platform_device *pdev)
info->phys_base = res->start; info->phys_base = res->start;
nand_chip->controller = &info->controller; nand_chip->controller = &omap_gpmc_controller;
nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R; nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R;
nand_chip->cmd_ctrl = omap_hwcontrol; nand_chip->cmd_ctrl = omap_hwcontrol;
...@@ -1741,13 +1742,6 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1741,13 +1742,6 @@ static int omap_nand_probe(struct platform_device *pdev)
goto return_error; goto return_error;
} }
/* check for small page devices */
if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) {
dev_err(&info->pdev->dev, "small page devices are not supported\n");
err = -EINVAL;
goto return_error;
}
/* re-populate low-level callbacks based on xfer modes */ /* re-populate low-level callbacks based on xfer modes */
switch (pdata->xfer_type) { switch (pdata->xfer_type) {
case NAND_OMAP_PREFETCH_POLLED: case NAND_OMAP_PREFETCH_POLLED:
...@@ -1840,7 +1834,7 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -1840,7 +1834,7 @@ static int omap_nand_probe(struct platform_device *pdev)
} }
/* populate MTD interface based on ECC scheme */ /* populate MTD interface based on ECC scheme */
ecclayout = &omap_oobinfo; ecclayout = &info->oobinfo;
switch (info->ecc_opt) { switch (info->ecc_opt) {
case OMAP_ECC_HAM1_CODE_SW: case OMAP_ECC_HAM1_CODE_SW:
nand_chip->ecc.mode = NAND_ECC_SOFT; nand_chip->ecc.mode = NAND_ECC_SOFT;
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <asm/io.h> #include <linux/io.h>
#include <asm/sizes.h> #include <asm/sizes.h>
#include <linux/platform_data/mtd-orion_nand.h> #include <linux/platform_data/mtd-orion_nand.h>
...@@ -85,33 +85,24 @@ static int __init orion_nand_probe(struct platform_device *pdev) ...@@ -85,33 +85,24 @@ static int __init orion_nand_probe(struct platform_device *pdev)
int ret = 0; int ret = 0;
u32 val = 0; u32 val = 0;
nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL); nc = devm_kzalloc(&pdev->dev,
if (!nc) { sizeof(struct nand_chip) + sizeof(struct mtd_info),
ret = -ENOMEM; GFP_KERNEL);
goto no_res; if (!nc)
} return -ENOMEM;
mtd = (struct mtd_info *)(nc + 1); mtd = (struct mtd_info *)(nc + 1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { io_base = devm_ioremap_resource(&pdev->dev, res);
ret = -ENODEV;
goto no_res;
}
io_base = ioremap(res->start, resource_size(res)); if (IS_ERR(io_base))
if (!io_base) { return PTR_ERR(io_base);
dev_err(&pdev->dev, "ioremap failed\n");
ret = -EIO;
goto no_res;
}
if (pdev->dev.of_node) { if (pdev->dev.of_node) {
board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data), board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
GFP_KERNEL); GFP_KERNEL);
if (!board) { if (!board)
ret = -ENOMEM; return -ENOMEM;
goto no_res;
}
if (!of_property_read_u32(pdev->dev.of_node, "cle", &val)) if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
board->cle = (u8)val; board->cle = (u8)val;
else else
...@@ -185,9 +176,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) ...@@ -185,9 +176,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)
clk_disable_unprepare(clk); clk_disable_unprepare(clk);
clk_put(clk); clk_put(clk);
} }
iounmap(io_base);
no_res:
kfree(nc);
return ret; return ret;
} }
...@@ -195,15 +183,10 @@ static int __init orion_nand_probe(struct platform_device *pdev) ...@@ -195,15 +183,10 @@ static int __init orion_nand_probe(struct platform_device *pdev)
static int orion_nand_remove(struct platform_device *pdev) static int orion_nand_remove(struct platform_device *pdev)
{ {
struct mtd_info *mtd = platform_get_drvdata(pdev); struct mtd_info *mtd = platform_get_drvdata(pdev);
struct nand_chip *nc = mtd->priv;
struct clk *clk; struct clk *clk;
nand_release(mtd); nand_release(mtd);
iounmap(nc->IO_ADDR_W);
kfree(nc);
clk = clk_get(&pdev->dev, NULL); clk = clk_get(&pdev->dev, NULL);
if (!IS_ERR(clk)) { if (!IS_ERR(clk)) {
clk_disable_unprepare(clk); clk_disable_unprepare(clk);
......
This diff is collapsed.
...@@ -719,16 +719,10 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from, ...@@ -719,16 +719,10 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
{ {
struct fsl_qspi *q = nor->priv; struct fsl_qspi *q = nor->priv;
u8 cmd = nor->read_opcode; u8 cmd = nor->read_opcode;
int ret;
dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n", dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n",
cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len); cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len);
/* Wait until the previous command is finished. */
ret = nor->wait_till_ready(nor);
if (ret)
return ret;
/* Read out the data directly from the AHB buffer.*/ /* Read out the data directly from the AHB buffer.*/
memcpy(buf, q->ahb_base + q->chip_base_addr + from, len); memcpy(buf, q->ahb_base + q->chip_base_addr + from, len);
...@@ -744,16 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs) ...@@ -744,16 +738,6 @@ static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)
dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n", dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n",
nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs); nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs);
/* Wait until finished previous write command. */
ret = nor->wait_till_ready(nor);
if (ret)
return ret;
/* Send write enable, then erase commands. */
ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0, 0);
if (ret)
return ret;
ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0); ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0);
if (ret) if (ret)
return ret; return ret;
...@@ -849,9 +833,8 @@ static int fsl_qspi_probe(struct platform_device *pdev) ...@@ -849,9 +833,8 @@ static int fsl_qspi_probe(struct platform_device *pdev)
ret = clk_prepare_enable(q->clk); ret = clk_prepare_enable(q->clk);
if (ret) { if (ret) {
clk_disable_unprepare(q->clk_en);
dev_err(dev, "can not enable the qspi clock\n"); dev_err(dev, "can not enable the qspi clock\n");
goto map_failed; goto clk_failed;
} }
/* find the irq */ /* find the irq */
...@@ -905,7 +888,8 @@ static int fsl_qspi_probe(struct platform_device *pdev) ...@@ -905,7 +888,8 @@ static int fsl_qspi_probe(struct platform_device *pdev)
nor->prepare = fsl_qspi_prep; nor->prepare = fsl_qspi_prep;
nor->unprepare = fsl_qspi_unprep; nor->unprepare = fsl_qspi_unprep;
if (of_modalias_node(np, modalias, sizeof(modalias)) < 0) ret = of_modalias_node(np, modalias, sizeof(modalias));
if (ret < 0)
goto map_failed; goto map_failed;
ret = of_property_read_u32(np, "spi-max-frequency", ret = of_property_read_u32(np, "spi-max-frequency",
...@@ -964,6 +948,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) ...@@ -964,6 +948,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
irq_failed: irq_failed:
clk_disable_unprepare(q->clk); clk_disable_unprepare(q->clk);
clk_failed:
clk_disable_unprepare(q->clk_en); clk_disable_unprepare(q->clk_en);
map_failed: map_failed:
dev_err(dev, "Freescale QuadSPI probe failed\n"); dev_err(dev, "Freescale QuadSPI probe failed\n");
......
This diff is collapsed.
...@@ -34,8 +34,11 @@ ...@@ -34,8 +34,11 @@
#include "mtd_test.h" #include "mtd_test.h"
static int dev = -EINVAL; static int dev = -EINVAL;
static int bitflip_limit;
module_param(dev, int, S_IRUGO); module_param(dev, int, S_IRUGO);
MODULE_PARM_DESC(dev, "MTD device number to use"); MODULE_PARM_DESC(dev, "MTD device number to use");
module_param(bitflip_limit, int, S_IRUGO);
MODULE_PARM_DESC(bitflip_limit, "Max. allowed bitflips per page");
static struct mtd_info *mtd; static struct mtd_info *mtd;
static unsigned char *readbuf; static unsigned char *readbuf;
...@@ -115,12 +118,36 @@ static int write_whole_device(void) ...@@ -115,12 +118,36 @@ static int write_whole_device(void)
return 0; return 0;
} }
/*
* Display the address, offset and data bytes at comparison failure.
* Return number of bitflips encountered.
*/
static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t count)
{
const unsigned char *su1, *su2;
int res;
size_t i = 0;
size_t bitflips = 0;
for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) {
res = *su1 ^ *su2;
if (res) {
pr_info("error @addr[0x%lx:0x%zx] 0x%x -> 0x%x diff 0x%x\n",
(unsigned long)addr, i, *su1, *su2, res);
bitflips += hweight8(res);
}
}
return bitflips;
}
static int verify_eraseblock(int ebnum) static int verify_eraseblock(int ebnum)
{ {
int i; int i;
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 bitflips;
prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
...@@ -139,8 +166,11 @@ static int verify_eraseblock(int ebnum) ...@@ -139,8 +166,11 @@ static int verify_eraseblock(int ebnum)
errcnt += 1; errcnt += 1;
return err ? err : -1; return err ? err : -1;
} }
if (memcmp(readbuf, writebuf + (use_len_max * i) + use_offset,
use_len)) { bitflips = memcmpshow(addr, readbuf,
writebuf + (use_len_max * i) + use_offset,
use_len);
if (bitflips > bitflip_limit) {
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;
...@@ -148,7 +178,10 @@ static int verify_eraseblock(int ebnum) ...@@ -148,7 +178,10 @@ static int verify_eraseblock(int ebnum)
pr_err("error: too many errors\n"); pr_err("error: too many errors\n");
return -1; return -1;
} }
} else if (bitflips) {
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->ecclayout->oobavail) {
int k; int k;
...@@ -167,9 +200,10 @@ static int verify_eraseblock(int ebnum) ...@@ -167,9 +200,10 @@ static int verify_eraseblock(int ebnum)
errcnt += 1; errcnt += 1;
return err ? err : -1; return err ? err : -1;
} }
if (memcmp(readbuf + use_offset, bitflips = memcmpshow(addr, readbuf + use_offset,
writebuf + (use_len_max * i) + use_offset, writebuf + (use_len_max * i) + use_offset,
use_len)) { use_len);
if (bitflips > bitflip_limit) {
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;
...@@ -177,7 +211,10 @@ static int verify_eraseblock(int ebnum) ...@@ -177,7 +211,10 @@ static int verify_eraseblock(int ebnum)
pr_err("error: too many errors\n"); pr_err("error: too many errors\n");
return -1; return -1;
} }
} else if (bitflips) {
pr_info("ignoring error as within bitflip_limit\n");
} }
for (k = 0; k < use_offset; ++k) for (k = 0; k < use_offset; ++k)
if (readbuf[k] != 0xff) { if (readbuf[k] != 0xff) {
pr_err("error: verify 0xff " pr_err("error: verify 0xff "
...@@ -216,6 +253,9 @@ static int verify_eraseblock_in_one_go(int ebnum) ...@@ -216,6 +253,9 @@ static int verify_eraseblock_in_one_go(int ebnum)
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->ecclayout->oobavail * pgcnt;
size_t oobavail = mtd->ecclayout->oobavail;
size_t bitflips;
int i;
prandom_bytes_state(&rnd_state, writebuf, len); prandom_bytes_state(&rnd_state, writebuf, len);
ops.mode = MTD_OPS_AUTO_OOB; ops.mode = MTD_OPS_AUTO_OOB;
...@@ -226,6 +266,8 @@ static int verify_eraseblock_in_one_go(int ebnum) ...@@ -226,6 +266,8 @@ static int verify_eraseblock_in_one_go(int ebnum)
ops.ooboffs = 0; ops.ooboffs = 0;
ops.datbuf = NULL; ops.datbuf = NULL;
ops.oobbuf = readbuf; ops.oobbuf = readbuf;
/* read entire block's OOB at one go */
err = mtd_read_oob(mtd, addr, &ops); err = mtd_read_oob(mtd, addr, &ops);
if (err || ops.oobretlen != len) { if (err || ops.oobretlen != len) {
pr_err("error: readoob failed at %#llx\n", pr_err("error: readoob failed at %#llx\n",
...@@ -233,13 +275,21 @@ static int verify_eraseblock_in_one_go(int ebnum) ...@@ -233,13 +275,21 @@ static int verify_eraseblock_in_one_go(int ebnum)
errcnt += 1; errcnt += 1;
return err ? err : -1; return err ? err : -1;
} }
if (memcmp(readbuf, writebuf, len)) {
pr_err("error: verify failed at %#llx\n", /* verify one page OOB at a time for bitflip per page limit check */
(long long)addr); for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
errcnt += 1; bitflips = memcmpshow(addr, readbuf + (i * oobavail),
if (errcnt > 1000) { writebuf + (i * oobavail), oobavail);
pr_err("error: too many errors\n"); if (bitflips > bitflip_limit) {
return -1; pr_err("error: verify failed at %#llx\n",
(long long)addr);
errcnt += 1;
if (errcnt > 1000) {
pr_err("error: too many errors\n");
return -1;
}
} else if (bitflips) {
pr_info("ignoring error as within bitflip_limit\n");
} }
} }
...@@ -610,7 +660,8 @@ static int __init mtd_oobtest_init(void) ...@@ -610,7 +660,8 @@ static int __init mtd_oobtest_init(void)
err = mtd_read_oob(mtd, addr, &ops); err = mtd_read_oob(mtd, addr, &ops);
if (err) if (err)
goto out; goto out;
if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) { if (memcmpshow(addr, readbuf, writebuf,
mtd->ecclayout->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;
......
...@@ -264,7 +264,9 @@ static int __init tort_init(void) ...@@ -264,7 +264,9 @@ static int __init tort_init(void)
int i; int i;
void *patt; void *patt;
mtdtest_erase_good_eraseblocks(mtd, bad_ebs, eb, ebcnt); err = mtdtest_erase_good_eraseblocks(mtd, bad_ebs, eb, ebcnt);
if (err)
goto out;
/* Check if the eraseblocks contain only 0xFF bytes */ /* Check if the eraseblocks contain only 0xFF bytes */
if (check) { if (check) {
......
...@@ -224,7 +224,7 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, ...@@ -224,7 +224,7 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw)); dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw));
/* If a node has zero dsize, we only have to keep if it if it might be the /* If a node has zero dsize, we only have to keep it if it might be the
node with highest version -- i.e. the one which will end up as f->metadata. node with highest version -- i.e. the one which will end up as f->metadata.
Note that such nodes won't be REF_UNCHECKED since there are no data to Note that such nodes won't be REF_UNCHECKED since there are no data to
check anyway. */ check anyway. */
......
...@@ -844,6 +844,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock ...@@ -844,6 +844,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
/* Write out summary information - called from jffs2_do_reserve_space */ /* Write out summary information - called from jffs2_do_reserve_space */
int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
__must_hold(&c->erase_completion_block)
{ {
int datasize, infosize, padsize; int datasize, infosize, padsize;
struct jffs2_eraseblock *jeb; struct jffs2_eraseblock *jeb;
......
...@@ -29,7 +29,16 @@ ...@@ -29,7 +29,16 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#define FSL_IFC_BANK_COUNT 4 /*
* The actual number of banks implemented depends on the IFC version
* - IFC version 1.0 implements 4 banks.
* - IFC version 1.1 onward implements 8 banks.
*/
#define FSL_IFC_BANK_COUNT 8
#define FSL_IFC_VERSION_MASK 0x0F0F0000
#define FSL_IFC_VERSION_1_0_0 0x01000000
#define FSL_IFC_VERSION_1_1_0 0x01010000
/* /*
* CSPR - Chip Select Property Register * CSPR - Chip Select Property Register
...@@ -776,23 +785,23 @@ struct fsl_ifc_regs { ...@@ -776,23 +785,23 @@ struct fsl_ifc_regs {
__be32 cspr; __be32 cspr;
u32 res2; u32 res2;
} cspr_cs[FSL_IFC_BANK_COUNT]; } cspr_cs[FSL_IFC_BANK_COUNT];
u32 res3[0x19]; u32 res3[0xd];
struct { struct {
__be32 amask; __be32 amask;
u32 res4[0x2]; u32 res4[0x2];
} amask_cs[FSL_IFC_BANK_COUNT]; } amask_cs[FSL_IFC_BANK_COUNT];
u32 res5[0x18]; u32 res5[0xc];
struct { struct {
__be32 csor; __be32 csor;
__be32 csor_ext; __be32 csor_ext;
u32 res6; u32 res6;
} csor_cs[FSL_IFC_BANK_COUNT]; } csor_cs[FSL_IFC_BANK_COUNT];
u32 res7[0x18]; u32 res7[0xc];
struct { struct {
__be32 ftim[4]; __be32 ftim[4];
u32 res8[0x8]; u32 res8[0x8];
} ftim_cs[FSL_IFC_BANK_COUNT]; } ftim_cs[FSL_IFC_BANK_COUNT];
u32 res9[0x60]; u32 res9[0x30];
__be32 rb_stat; __be32 rb_stat;
u32 res10[0x2]; u32 res10[0x2];
__be32 ifc_gcr; __be32 ifc_gcr;
...@@ -827,6 +836,8 @@ struct fsl_ifc_ctrl { ...@@ -827,6 +836,8 @@ struct fsl_ifc_ctrl {
int nand_irq; int nand_irq;
spinlock_t lock; spinlock_t lock;
void *nand; void *nand;
int version;
int banks;
u32 nand_stat; u32 nand_stat;
wait_queue_head_t nand_wait; wait_queue_head_t nand_wait;
......
...@@ -455,8 +455,21 @@ struct nand_hw_control { ...@@ -455,8 +455,21 @@ struct nand_hw_control {
* be provided if an hardware ECC is available * be provided if an hardware ECC is available
* @calculate: function for ECC calculation or readback from ECC hardware * @calculate: function for ECC calculation or readback from ECC hardware
* @correct: function for ECC correction, matching to ECC generator (sw/hw) * @correct: function for ECC correction, matching to ECC generator (sw/hw)
* @read_page_raw: function to read a raw page without ECC * @read_page_raw: function to read a raw page without ECC. This function
* @write_page_raw: function to write a raw page without ECC * should hide the specific layout used by the ECC
* controller and always return contiguous in-band and
* out-of-band data even if they're not stored
* contiguously on the NAND chip (e.g.
* NAND_ECC_HW_SYNDROME interleaves in-band and
* out-of-band data).
* @write_page_raw: function to write a raw page without ECC. This function
* should hide the specific layout used by the ECC
* controller and consider the passed data as contiguous
* in-band and out-of-band data. ECC controller is
* responsible for doing the appropriate transformations
* to adapt to its specific layout (e.g.
* NAND_ECC_HW_SYNDROME interleaves in-band and
* out-of-band data).
* @read_page: function to read a page according to the ECC generator * @read_page: function to read a page according to the ECC generator
* requirements; returns maximum number of bitflips corrected in * requirements; returns maximum number of bitflips corrected in
* any single ECC step, 0 if bitflips uncorrectable, -EIO hw error * any single ECC step, 0 if bitflips uncorrectable, -EIO hw error
...@@ -723,6 +736,7 @@ struct nand_chip { ...@@ -723,6 +736,7 @@ struct nand_chip {
#define NAND_MFR_EON 0x92 #define NAND_MFR_EON 0x92
#define NAND_MFR_SANDISK 0x45 #define NAND_MFR_SANDISK 0x45
#define NAND_MFR_INTEL 0x89 #define NAND_MFR_INTEL 0x89
#define NAND_MFR_ATO 0x9b
/* The maximum expected count of bytes in the NAND ID sequence */ /* The maximum expected count of bytes in the NAND ID sequence */
#define NAND_MAX_ID_LEN 8 #define NAND_MAX_ID_LEN 8
......
...@@ -116,6 +116,10 @@ enum spi_nor_ops { ...@@ -116,6 +116,10 @@ enum spi_nor_ops {
SPI_NOR_OPS_UNLOCK, SPI_NOR_OPS_UNLOCK,
}; };
enum spi_nor_option_flags {
SNOR_F_USE_FSR = BIT(0),
};
/** /**
* struct spi_nor - Structure for defining a the SPI NOR layer * struct spi_nor - Structure for defining a the SPI NOR layer
* @mtd: point to a mtd_info structure * @mtd: point to a mtd_info structure
...@@ -129,6 +133,7 @@ enum spi_nor_ops { ...@@ -129,6 +133,7 @@ enum spi_nor_ops {
* @program_opcode: the program opcode * @program_opcode: the program opcode
* @flash_read: the mode of the read * @flash_read: the mode of the read
* @sst_write_second: used by the SST write operation * @sst_write_second: used by the SST write operation
* @flags: flag options for the current SPI-NOR (SNOR_F_*)
* @cfg: used by the read_xfer/write_xfer * @cfg: used by the read_xfer/write_xfer
* @cmd_buf: used by the write_reg * @cmd_buf: used by the write_reg
* @prepare: [OPTIONAL] do some preparations for the * @prepare: [OPTIONAL] do some preparations for the
...@@ -139,9 +144,6 @@ enum spi_nor_ops { ...@@ -139,9 +144,6 @@ enum spi_nor_ops {
* @write_xfer: [OPTIONAL] the writefundamental primitive * @write_xfer: [OPTIONAL] the writefundamental primitive
* @read_reg: [DRIVER-SPECIFIC] read out the register * @read_reg: [DRIVER-SPECIFIC] read out the register
* @write_reg: [DRIVER-SPECIFIC] write data to the register * @write_reg: [DRIVER-SPECIFIC] write data to the register
* @read_id: [REPLACEABLE] read out the ID data, and find
* the proper spi_device_id
* @wait_till_ready: [REPLACEABLE] wait till the NOR becomes ready
* @read: [DRIVER-SPECIFIC] read data from the SPI NOR * @read: [DRIVER-SPECIFIC] read data from the SPI NOR
* @write: [DRIVER-SPECIFIC] write data to the SPI NOR * @write: [DRIVER-SPECIFIC] write data to the SPI NOR
* @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
...@@ -160,6 +162,7 @@ struct spi_nor { ...@@ -160,6 +162,7 @@ struct spi_nor {
u8 program_opcode; u8 program_opcode;
enum read_mode flash_read; enum read_mode flash_read;
bool sst_write_second; bool sst_write_second;
u32 flags;
struct spi_nor_xfer_cfg cfg; struct spi_nor_xfer_cfg cfg;
u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
...@@ -172,8 +175,6 @@ struct spi_nor { ...@@ -172,8 +175,6 @@ struct spi_nor {
int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len); int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len, int (*write_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
int write_enable); int write_enable);
const struct spi_device_id *(*read_id)(struct spi_nor *nor);
int (*wait_till_ready)(struct spi_nor *nor);
int (*read)(struct spi_nor *nor, loff_t from, int (*read)(struct spi_nor *nor, loff_t from,
size_t len, size_t *retlen, u_char *read_buf); size_t len, size_t *retlen, u_char *read_buf);
......
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