Commit 811c16a2 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MTD updates from Boris Brezillon:
 "Core MTD changes:
   - Use struct_size() where appropriate
   - mtd_{read,write}() as wrappers around mtd_{read,write}_oob()
   - Fix misuse of PTR_ERR() in docg3
   - Coding style improvements in mtdcore.c

  SPI NOR changes:
    Core changes:
     - Add support of octal mode I/O transfer
     - Add a bunch of SPI NOR entries to the flash_info table

    SPI NOR controller driver changes:
     - cadence-quadspi:
        * Add support for Octal SPI controller
        * write upto 8-bytes data in STIG mode
     - mtk-quadspi:
        * rename config to a common one
        * add SNOR_HWCAPS_READ to spi_nor_hwcaps mask
     - Add Tudor as SPI-NOR co-maintainer

  NAND changes:
    NAND core changes:
     - Fourth batch of fixes/cleanup to the raw NAND core impacting
       various controller drivers (Sunxi, Marvell, MTK, TMIO, OMAP2).
     - Check the return code of nand_reset() and nand_readid_op().
     - Remove ->legacy.erase and single_erase().
     - Simplify the locking.
     - Several implicit fall through annotations.

    Raw NAND controllers drivers changes:
     - Fix various possible object reference leaks (MTK, JZ4780, Atmel)
     - ST:
        * Add support for STM32 FMC2 NAND flash controller
     - Meson:
        * Add support for Amlogic NAND flash controller
     - Denali:
        * Several cleanup patches
     - Sunxi:
        * Several cleanup patches
     - FSMC:
        * Disable NAND on remove()
        * Reset NAND timings on resume()

    SPI-NAND drivers changes:
     - Toshiba:
        * Add support for all Toshiba products.
     - Macronix:
        * Fix ECC status read.
     - Gigadevice:
        * Add support for GD5F1GQ4UExxG"

* tag 'mtd/for-5.1' of git://git.infradead.org/linux-mtd: (64 commits)
  mtd: spi-nor: Fix wrong abbreviation HWCPAS
  mtd: spi-nor: cadence-quadspi: fix spelling mistake: "Couldnt't" -> "Couldn't"
  mtd: spi-nor: Add support for en25qh64
  mtd: spi-nor: Add support for MX25V8035F
  mtd: spi-nor: Add support for EN25Q80A
  mtd: spi-nor: cadence-quadspi: Add support for Octal SPI controller
  dt-bindings: cadence-quadspi: Add new compatible for AM654 SoC
  mtd: spi-nor: split s25fl128s into s25fl128s0 and s25fl128s1
  mtd: spi-nor: cadence-quadspi: write upto 8-bytes data in STIG mode
  mtd: spi-nor: Add support for mx25u3235f
  mtd: rawnand: denali_dt: remove single anonymous clock support
  mtd: rawnand: mtk: fix possible object reference leak
  mtd: rawnand: jz4780: fix possible object reference leak
  mtd: rawnand: atmel: fix possible object reference leak
  mtd: rawnand: fsmc: Disable NAND on remove()
  mtd: rawnand: fsmc: Reset NAND timings on resume()
  mtd: spinand: Add support for GigaDevice GD5F1GQ4UExxG
  mtd: rawnand: denali: remove unused dma_addr field from denali_nand_info
  mtd: rawnand: denali: remove unused function argument 'raw'
  mtd: rawnand: denali: remove unneeded denali_reset_irq() call
  ...
parents a83b0423 9220d7be
Amlogic NAND Flash Controller (NFC) for GXBB/GXL/AXG family SoCs
This file documents the properties in addition to those available in
the MTD NAND bindings.
Required properties:
- compatible : contains one of:
- "amlogic,meson-gxl-nfc"
- "amlogic,meson-axg-nfc"
- clocks :
A list of phandle + clock-specifier pairs for the clocks listed
in clock-names.
- clock-names: Should contain the following:
"core" - NFC module gate clock
"device" - device clock from eMMC sub clock controller
"rx" - rx clock phase
"tx" - tx clock phase
- amlogic,mmc-syscon : Required for NAND clocks, it's shared with SD/eMMC
controller port C
Optional children nodes:
Children nodes represent the available nand chips.
Other properties:
see Documentation/devicetree/bindings/mtd/nand.txt for generic bindings.
Example demonstrate on AXG SoC:
sd_emmc_c_clkc: mmc@7000 {
compatible = "amlogic,meson-axg-mmc-clkc", "syscon";
reg = <0x0 0x7000 0x0 0x800>;
};
nand-controller@7800 {
compatible = "amlogic,meson-axg-nfc";
reg = <0x0 0x7800 0x0 0x100>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>;
clocks = <&clkc CLKID_SD_EMMC_C>,
<&sd_emmc_c_clkc CLKID_MMC_DIV>,
<&sd_emmc_c_clkc CLKID_MMC_PHASE_RX>,
<&sd_emmc_c_clkc CLKID_MMC_PHASE_TX>;
clock-names = "core", "device", "rx", "tx";
amlogic,mmc-syscon = <&sd_emmc_c_clkc>;
pinctrl-names = "default";
pinctrl-0 = <&nand_pins>;
nand@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-on-flash-bbt;
};
};
...@@ -4,6 +4,7 @@ Required properties: ...@@ -4,6 +4,7 @@ Required properties:
- compatible : should be one of the following: - compatible : should be one of the following:
Generic default - "cdns,qspi-nor". Generic default - "cdns,qspi-nor".
For TI 66AK2G SoC - "ti,k2g-qspi", "cdns,qspi-nor". For TI 66AK2G SoC - "ti,k2g-qspi", "cdns,qspi-nor".
For TI AM654 SoC - "ti,am654-ospi", "cdns,qspi-nor".
- reg : Contains two entries, each of which is a tuple consisting of a - reg : Contains two entries, each of which is a tuple consisting of a
physical address and length. The first entry is the address and physical address and length. The first entry is the address and
length of the controller register set. The second entry is the length of the controller register set. The second entry is the
......
* Serial NOR flash controller for MTK MT81xx (and similar) * Serial NOR flash controller for MediaTek SoCs
Required properties: Required properties:
- compatible: For mt8173, compatible should be "mediatek,mt8173-nor", - compatible: For mt8173, compatible should be "mediatek,mt8173-nor",
...@@ -10,6 +10,7 @@ Required properties: ...@@ -10,6 +10,7 @@ Required properties:
"mediatek,mt2712-nor", "mediatek,mt8173-nor" "mediatek,mt2712-nor", "mediatek,mt8173-nor"
"mediatek,mt7622-nor", "mediatek,mt8173-nor" "mediatek,mt7622-nor", "mediatek,mt8173-nor"
"mediatek,mt7623-nor", "mediatek,mt8173-nor" "mediatek,mt7623-nor", "mediatek,mt8173-nor"
"mediatek,mt7629-nor", "mediatek,mt8173-nor"
"mediatek,mt8173-nor" "mediatek,mt8173-nor"
- reg: physical base address and length of the controller's register - reg: physical base address and length of the controller's register
- clocks: the phandle of the clocks needed by the nor controller - clocks: the phandle of the clocks needed by the nor controller
......
STMicroelectronics Flexible Memory Controller 2 (FMC2)
NAND Interface
Required properties:
- compatible: Should be one of:
* st,stm32mp15-fmc2
- reg: NAND flash controller memory areas.
First region contains the register location.
Regions 2 to 4 respectively contain the data, command,
and address space for CS0.
Regions 5 to 7 contain the same areas for CS1.
- interrupts: The interrupt number
- pinctrl-0: Standard Pinctrl phandle (see: pinctrl/pinctrl-bindings.txt)
- clocks: The clock needed by the NAND flash controller
Optional properties:
- resets: Reference to a reset controller asserting the FMC controller
- dmas: DMA specifiers (see: dma/stm32-mdma.txt)
- dma-names: Must be "tx", "rx" and "ecc"
* NAND device bindings:
Required properties:
- reg: describes the CS lines assigned to the NAND device.
Optional properties:
- nand-on-flash-bbt: see nand.txt
- nand-ecc-strength: see nand.txt
- nand-ecc-step-size: see nand.txt
The following ECC strength and step size are currently supported:
- nand-ecc-strength = <1>, nand-ecc-step-size = <512> (Hamming)
- nand-ecc-strength = <4>, nand-ecc-step-size = <512> (BCH4)
- nand-ecc-strength = <8>, nand-ecc-step-size = <512> (BCH8) (default)
Example:
fmc: nand-controller@58002000 {
compatible = "st,stm32mp15-fmc2";
reg = <0x58002000 0x1000>,
<0x80000000 0x1000>,
<0x88010000 0x1000>,
<0x88020000 0x1000>,
<0x81000000 0x1000>,
<0x89010000 0x1000>,
<0x89020000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc FMC_K>;
resets = <&rcc FMC_R>;
pinctrl-names = "default";
pinctrl-0 = <&fmc_pins_a>;
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
reg = <0>;
nand-on-flash-bbt;
#address-cells = <1>;
#size-cells = <1>;
};
};
...@@ -9866,6 +9866,13 @@ F: drivers/media/platform/meson/ao-cec.c ...@@ -9866,6 +9866,13 @@ F: drivers/media/platform/meson/ao-cec.c
F: Documentation/devicetree/bindings/media/meson-ao-cec.txt F: Documentation/devicetree/bindings/media/meson-ao-cec.txt
T: git git://linuxtv.org/media_tree.git T: git git://linuxtv.org/media_tree.git
MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS
M: Liang Yang <liang.yang@amlogic.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/raw/meson_*
F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt
MICROBLAZE ARCHITECTURE MICROBLAZE ARCHITECTURE
M: Michal Simek <monstr@monstr.eu> M: Michal Simek <monstr@monstr.eu>
W: http://www.monstr.eu/fdt/ W: http://www.monstr.eu/fdt/
...@@ -14339,6 +14346,7 @@ F: arch/arm/mach-spear/ ...@@ -14339,6 +14346,7 @@ F: arch/arm/mach-spear/
SPI NOR SUBSYSTEM SPI NOR SUBSYSTEM
M: Marek Vasut <marek.vasut@gmail.com> M: Marek Vasut <marek.vasut@gmail.com>
M: Tudor Ambarus <tudor.ambarus@microchip.com>
L: linux-mtd@lists.infradead.org L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/ W: http://www.linux-mtd.infradead.org/
Q: http://patchwork.ozlabs.org/project/linux-mtd/list/ Q: http://patchwork.ozlabs.org/project/linux-mtd/list/
......
...@@ -756,7 +756,8 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, ...@@ -756,7 +756,8 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
} }
numvirtchips = cfi->numchips * numparts; numvirtchips = cfi->numchips * numparts;
newcfi = kmalloc(sizeof(struct cfi_private) + numvirtchips * sizeof(struct flchip), GFP_KERNEL); newcfi = kmalloc(struct_size(newcfi, chips, numvirtchips),
GFP_KERNEL);
if (!newcfi) if (!newcfi)
return -ENOMEM; return -ENOMEM;
shared = kmalloc_array(cfi->numchips, shared = kmalloc_array(cfi->numchips,
......
...@@ -135,7 +135,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi ...@@ -135,7 +135,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
* our caller, and copy the appropriate data into them. * our caller, and copy the appropriate data into them.
*/ */
retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL); retcfi = kmalloc(struct_size(retcfi, chips, cfi.numchips), GFP_KERNEL);
if (!retcfi) { if (!retcfi) {
kfree(cfi.cfiq); kfree(cfi.cfiq);
......
...@@ -1767,8 +1767,8 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) ...@@ -1767,8 +1767,8 @@ static int __init doc_set_driver_info(int chip_id, struct mtd_info *mtd)
switch (chip_id) { switch (chip_id) {
case DOC_CHIPID_G3: case DOC_CHIPID_G3:
mtd->name = kasprintf(GFP_KERNEL, "docg3.%d", mtd->name = devm_kasprintf(docg3->dev, GFP_KERNEL, "docg3.%d",
docg3->device_id); docg3->device_id);
if (!mtd->name) if (!mtd->name)
return -ENOMEM; return -ENOMEM;
docg3->max_block = 2047; docg3->max_block = 2047;
...@@ -1872,7 +1872,7 @@ doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev) ...@@ -1872,7 +1872,7 @@ doc_probe_device(struct docg3_cascade *cascade, int floor, struct device *dev)
nomem2: nomem2:
kfree(docg3); kfree(docg3);
nomem1: nomem1:
return ERR_PTR(ret); return ret ? ERR_PTR(ret) : NULL;
} }
/** /**
...@@ -1886,7 +1886,6 @@ static void doc_release_device(struct mtd_info *mtd) ...@@ -1886,7 +1886,6 @@ static void doc_release_device(struct mtd_info *mtd)
mtd_device_unregister(mtd); mtd_device_unregister(mtd);
kfree(docg3->bbt); kfree(docg3->bbt);
kfree(docg3); kfree(docg3);
kfree(mtd->name);
kfree(mtd); kfree(mtd);
} }
......
...@@ -195,7 +195,14 @@ static int m25p_probe(struct spi_mem *spimem) ...@@ -195,7 +195,14 @@ static int m25p_probe(struct spi_mem *spimem)
spi_mem_set_drvdata(spimem, flash); spi_mem_set_drvdata(spimem, flash);
flash->spimem = spimem; flash->spimem = spimem;
if (spi->mode & SPI_RX_QUAD) { if (spi->mode & SPI_RX_OCTAL) {
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
if (spi->mode & SPI_TX_OCTAL)
hwcaps.mask |= (SNOR_HWCAPS_READ_1_8_8 |
SNOR_HWCAPS_PP_1_1_8 |
SNOR_HWCAPS_PP_1_8_8);
} else if (spi->mode & SPI_RX_QUAD) {
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
if (spi->mode & SPI_TX_QUAD) if (spi->mode & SPI_TX_QUAD)
......
...@@ -24,14 +24,12 @@ static unsigned long writebuf_size = 64; ...@@ -24,14 +24,12 @@ static unsigned long writebuf_size = 64;
#define MTDRAM_TOTAL_SIZE (total_size * 1024) #define MTDRAM_TOTAL_SIZE (total_size * 1024)
#define MTDRAM_ERASE_SIZE (erase_size * 1024) #define MTDRAM_ERASE_SIZE (erase_size * 1024)
#ifdef MODULE
module_param(total_size, ulong, 0); module_param(total_size, ulong, 0);
MODULE_PARM_DESC(total_size, "Total device size in KiB"); MODULE_PARM_DESC(total_size, "Total device size in KiB");
module_param(erase_size, ulong, 0); module_param(erase_size, ulong, 0);
MODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
module_param(writebuf_size, ulong, 0); module_param(writebuf_size, ulong, 0);
MODULE_PARM_DESC(writebuf_size, "Device write buf size in Bytes (Default: 64)"); MODULE_PARM_DESC(writebuf_size, "Device write buf size in Bytes (Default: 64)");
#endif
// We could store these in the mtd structure, but we only support 1 device.. // We could store these in the mtd structure, but we only support 1 device..
static struct mtd_info *mtd_info; static struct mtd_info *mtd_info;
......
...@@ -181,8 +181,8 @@ static struct lpddr_private *lpddr_probe_chip(struct map_info *map) ...@@ -181,8 +181,8 @@ static struct lpddr_private *lpddr_probe_chip(struct map_info *map)
lpddr.numchips = 1; lpddr.numchips = 1;
numvirtchips = lpddr.numchips * lpddr.qinfo->HWPartsNum; numvirtchips = lpddr.numchips * lpddr.qinfo->HWPartsNum;
retlpddr = kzalloc(sizeof(struct lpddr_private) + retlpddr = kzalloc(struct_size(retlpddr, chips, numvirtchips),
numvirtchips * sizeof(struct flchip), GFP_KERNEL); GFP_KERNEL);
if (!retlpddr) if (!retlpddr)
return NULL; return NULL;
......
...@@ -155,7 +155,6 @@ static ssize_t mtd_flags_show(struct device *dev, ...@@ -155,7 +155,6 @@ static ssize_t mtd_flags_show(struct device *dev,
struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_info *mtd = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)mtd->flags); return snprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)mtd->flags);
} }
static DEVICE_ATTR(flags, S_IRUGO, mtd_flags_show, NULL); static DEVICE_ATTR(flags, S_IRUGO, mtd_flags_show, NULL);
...@@ -166,7 +165,6 @@ static ssize_t mtd_size_show(struct device *dev, ...@@ -166,7 +165,6 @@ static ssize_t mtd_size_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%llu\n", return snprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)mtd->size); (unsigned long long)mtd->size);
} }
static DEVICE_ATTR(size, S_IRUGO, mtd_size_show, NULL); static DEVICE_ATTR(size, S_IRUGO, mtd_size_show, NULL);
...@@ -176,7 +174,6 @@ static ssize_t mtd_erasesize_show(struct device *dev, ...@@ -176,7 +174,6 @@ static ssize_t mtd_erasesize_show(struct device *dev,
struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_info *mtd = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->erasesize); return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->erasesize);
} }
static DEVICE_ATTR(erasesize, S_IRUGO, mtd_erasesize_show, NULL); static DEVICE_ATTR(erasesize, S_IRUGO, mtd_erasesize_show, NULL);
...@@ -186,7 +183,6 @@ static ssize_t mtd_writesize_show(struct device *dev, ...@@ -186,7 +183,6 @@ static ssize_t mtd_writesize_show(struct device *dev,
struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_info *mtd = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->writesize); return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->writesize);
} }
static DEVICE_ATTR(writesize, S_IRUGO, mtd_writesize_show, NULL); static DEVICE_ATTR(writesize, S_IRUGO, mtd_writesize_show, NULL);
...@@ -197,7 +193,6 @@ static ssize_t mtd_subpagesize_show(struct device *dev, ...@@ -197,7 +193,6 @@ static ssize_t mtd_subpagesize_show(struct device *dev,
unsigned int subpagesize = mtd->writesize >> mtd->subpage_sft; unsigned int subpagesize = mtd->writesize >> mtd->subpage_sft;
return snprintf(buf, PAGE_SIZE, "%u\n", subpagesize); return snprintf(buf, PAGE_SIZE, "%u\n", subpagesize);
} }
static DEVICE_ATTR(subpagesize, S_IRUGO, mtd_subpagesize_show, NULL); static DEVICE_ATTR(subpagesize, S_IRUGO, mtd_subpagesize_show, NULL);
...@@ -207,7 +202,6 @@ static ssize_t mtd_oobsize_show(struct device *dev, ...@@ -207,7 +202,6 @@ static ssize_t mtd_oobsize_show(struct device *dev,
struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_info *mtd = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->oobsize); return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->oobsize);
} }
static DEVICE_ATTR(oobsize, S_IRUGO, mtd_oobsize_show, NULL); static DEVICE_ATTR(oobsize, S_IRUGO, mtd_oobsize_show, NULL);
...@@ -226,7 +220,6 @@ static ssize_t mtd_numeraseregions_show(struct device *dev, ...@@ -226,7 +220,6 @@ static ssize_t mtd_numeraseregions_show(struct device *dev,
struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_info *mtd = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%u\n", mtd->numeraseregions); return snprintf(buf, PAGE_SIZE, "%u\n", mtd->numeraseregions);
} }
static DEVICE_ATTR(numeraseregions, S_IRUGO, mtd_numeraseregions_show, static DEVICE_ATTR(numeraseregions, S_IRUGO, mtd_numeraseregions_show,
NULL); NULL);
...@@ -237,7 +230,6 @@ static ssize_t mtd_name_show(struct device *dev, ...@@ -237,7 +230,6 @@ static ssize_t mtd_name_show(struct device *dev,
struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_info *mtd = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", mtd->name); return snprintf(buf, PAGE_SIZE, "%s\n", mtd->name);
} }
static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL); static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL);
...@@ -560,6 +552,14 @@ int add_mtd_device(struct mtd_info *mtd) ...@@ -560,6 +552,14 @@ int add_mtd_device(struct mtd_info *mtd)
BUG_ON(mtd->writesize == 0); BUG_ON(mtd->writesize == 0);
/*
* MTD drivers should implement ->_{write,read}() or
* ->_{write,read}_oob(), but not both.
*/
if (WARN_ON((mtd->_write && mtd->_write_oob) ||
(mtd->_read && mtd->_read_oob)))
return -EINVAL;
if (WARN_ON((!mtd->erasesize || !mtd->_erase) && if (WARN_ON((!mtd->erasesize || !mtd->_erase) &&
!(mtd->flags & MTD_NO_ERASE))) !(mtd->flags & MTD_NO_ERASE)))
return -EINVAL; return -EINVAL;
...@@ -1090,67 +1090,32 @@ EXPORT_SYMBOL_GPL(mtd_get_unmapped_area); ...@@ -1090,67 +1090,32 @@ EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
u_char *buf) u_char *buf)
{ {
int ret_code; struct mtd_oob_ops ops = {
*retlen = 0; .len = len,
if (from < 0 || from >= mtd->size || len > mtd->size - from) .datbuf = buf,
return -EINVAL; };
if (!len) int ret;
return 0;
ledtrig_mtd_activity(); ret = mtd_read_oob(mtd, from, &ops);
/* *retlen = ops.retlen;
* In the absence of an error, drivers return a non-negative integer
* representing the maximum number of bitflips that were corrected on
* any one ecc region (if applicable; zero otherwise).
*/
if (mtd->_read) {
ret_code = mtd->_read(mtd, from, len, retlen, buf);
} else if (mtd->_read_oob) {
struct mtd_oob_ops ops = {
.len = len,
.datbuf = buf,
};
ret_code = mtd->_read_oob(mtd, from, &ops);
*retlen = ops.retlen;
} else {
return -ENOTSUPP;
}
if (unlikely(ret_code < 0)) return ret;
return ret_code;
if (mtd->ecc_strength == 0)
return 0; /* device lacks ecc */
return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
} }
EXPORT_SYMBOL_GPL(mtd_read); EXPORT_SYMBOL_GPL(mtd_read);
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
const u_char *buf) const u_char *buf)
{ {
*retlen = 0; struct mtd_oob_ops ops = {
if (to < 0 || to >= mtd->size || len > mtd->size - to) .len = len,
return -EINVAL; .datbuf = (u8 *)buf,
if ((!mtd->_write && !mtd->_write_oob) || };
!(mtd->flags & MTD_WRITEABLE)) int ret;
return -EROFS;
if (!len)
return 0;
ledtrig_mtd_activity();
if (!mtd->_write) { ret = mtd_write_oob(mtd, to, &ops);
struct mtd_oob_ops ops = { *retlen = ops.retlen;
.len = len,
.datbuf = (u8 *)buf,
};
int ret;
ret = mtd->_write_oob(mtd, to, &ops); return ret;
*retlen = ops.retlen;
return ret;
}
return mtd->_write(mtd, to, len, retlen, buf);
} }
EXPORT_SYMBOL_GPL(mtd_write); EXPORT_SYMBOL_GPL(mtd_write);
......
...@@ -541,4 +541,21 @@ config MTD_NAND_TEGRA ...@@ -541,4 +541,21 @@ config MTD_NAND_TEGRA
is supported. Extra OOB bytes when using HW ECC are currently is supported. Extra OOB bytes when using HW ECC are currently
not supported. not supported.
config MTD_NAND_STM32_FMC2
tristate "Support for NAND controller on STM32MP SoCs"
depends on MACH_STM32MP157 || COMPILE_TEST
help
Enables support for NAND Flash chips on SoCs containing the FMC2
NAND controller. This controller is found on STM32MP SoCs.
The controller supports a maximum 8k page size and supports
a maximum 8-bit correction error per sector of 512 bytes.
config MTD_NAND_MESON
tristate "Support for NAND controller on Amlogic's Meson SoCs"
depends on ARCH_MESON || COMPILE_TEST
select MFD_SYSCON
help
Enables support for NAND controller on Amlogic's Meson SoCs.
This controller is found on Meson SoCs.
endif # MTD_NAND endif # MTD_NAND
...@@ -56,6 +56,8 @@ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ ...@@ -56,6 +56,8 @@ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o
obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o
nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_onfi.o nand-objs += nand_onfi.o
......
...@@ -876,23 +876,32 @@ static struct atmel_pmecc *atmel_pmecc_get_by_node(struct device *userdev, ...@@ -876,23 +876,32 @@ static struct atmel_pmecc *atmel_pmecc_get_by_node(struct device *userdev,
{ {
struct platform_device *pdev; struct platform_device *pdev;
struct atmel_pmecc *pmecc, **ptr; struct atmel_pmecc *pmecc, **ptr;
int ret;
pdev = of_find_device_by_node(np); pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev)) if (!pdev)
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
pmecc = platform_get_drvdata(pdev);
if (!pmecc) {
ret = -EPROBE_DEFER;
goto err_put_device;
}
ptr = devres_alloc(devm_atmel_pmecc_put, sizeof(*ptr), GFP_KERNEL); ptr = devres_alloc(devm_atmel_pmecc_put, sizeof(*ptr), GFP_KERNEL);
if (!ptr) if (!ptr) {
return ERR_PTR(-ENOMEM); ret = -ENOMEM;
goto err_put_device;
get_device(&pdev->dev); }
pmecc = platform_get_drvdata(pdev);
*ptr = pmecc; *ptr = pmecc;
devres_add(userdev, ptr); devres_add(userdev, ptr);
return pmecc; return pmecc;
err_put_device:
put_device(&pdev->dev);
return ERR_PTR(ret);
} }
static const int atmel_pmecc_strengths[] = { 2, 4, 8, 12, 24, 32 }; static const int atmel_pmecc_strengths[] = { 2, 4, 8, 12, 24, 32 };
......
...@@ -37,9 +37,6 @@ ...@@ -37,9 +37,6 @@
#define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) /* address cycle */ #define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) /* address cycle */
#define DENALI_MAP11_DATA ((DENALI_MAP11) | 2) /* data cycle */ #define DENALI_MAP11_DATA ((DENALI_MAP11) | 2) /* data cycle */
/* MAP10 commands */
#define DENALI_ERASE 0x01
#define DENALI_BANK(denali) ((denali)->active_bank << 24) #define DENALI_BANK(denali) ((denali)->active_bank << 24)
#define DENALI_INVALID_BANK -1 #define DENALI_INVALID_BANK -1
...@@ -476,7 +473,7 @@ static void denali_setup_dma32(struct denali_nand_info *denali, ...@@ -476,7 +473,7 @@ static void denali_setup_dma32(struct denali_nand_info *denali,
} }
static int denali_pio_read(struct denali_nand_info *denali, void *buf, static int denali_pio_read(struct denali_nand_info *denali, void *buf,
size_t size, int page, int raw) size_t size, int page)
{ {
u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
uint32_t *buf32 = (uint32_t *)buf; uint32_t *buf32 = (uint32_t *)buf;
...@@ -504,7 +501,7 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf, ...@@ -504,7 +501,7 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf,
} }
static int denali_pio_write(struct denali_nand_info *denali, static int denali_pio_write(struct denali_nand_info *denali,
const void *buf, size_t size, int page, int raw) const void *buf, size_t size, int page)
{ {
u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page; u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
const uint32_t *buf32 = (uint32_t *)buf; const uint32_t *buf32 = (uint32_t *)buf;
...@@ -525,16 +522,16 @@ static int denali_pio_write(struct denali_nand_info *denali, ...@@ -525,16 +522,16 @@ static int denali_pio_write(struct denali_nand_info *denali,
} }
static int denali_pio_xfer(struct denali_nand_info *denali, void *buf, static int denali_pio_xfer(struct denali_nand_info *denali, void *buf,
size_t size, int page, int raw, int write) size_t size, int page, int write)
{ {
if (write) if (write)
return denali_pio_write(denali, buf, size, page, raw); return denali_pio_write(denali, buf, size, page);
else else
return denali_pio_read(denali, buf, size, page, raw); return denali_pio_read(denali, buf, size, page);
} }
static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
size_t size, int page, int raw, int write) size_t size, int page, int write)
{ {
dma_addr_t dma_addr; dma_addr_t dma_addr;
uint32_t irq_mask, irq_status, ecc_err_mask; uint32_t irq_mask, irq_status, ecc_err_mask;
...@@ -544,7 +541,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf, ...@@ -544,7 +541,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
dma_addr = dma_map_single(denali->dev, buf, size, dir); dma_addr = dma_map_single(denali->dev, buf, size, dir);
if (dma_mapping_error(denali->dev, dma_addr)) { if (dma_mapping_error(denali->dev, dma_addr)) {
dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n"); dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n");
return denali_pio_xfer(denali, buf, size, page, raw, write); return denali_pio_xfer(denali, buf, size, page, write);
} }
if (write) { if (write) {
...@@ -598,9 +595,9 @@ static int denali_data_xfer(struct denali_nand_info *denali, void *buf, ...@@ -598,9 +595,9 @@ static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
denali->reg + TRANSFER_SPARE_REG); denali->reg + TRANSFER_SPARE_REG);
if (denali->dma_avail) if (denali->dma_avail)
return denali_dma_xfer(denali, buf, size, page, raw, write); return denali_dma_xfer(denali, buf, size, page, write);
else else
return denali_pio_xfer(denali, buf, size, page, raw, write); return denali_pio_xfer(denali, buf, size, page, write);
} }
static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip, static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
...@@ -754,9 +751,6 @@ static int denali_read_oob(struct nand_chip *chip, int page) ...@@ -754,9 +751,6 @@ static int denali_read_oob(struct nand_chip *chip, int page)
static int denali_write_oob(struct nand_chip *chip, int page) static int denali_write_oob(struct nand_chip *chip, int page)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
denali_reset_irq(denali);
denali_oob_xfer(mtd, chip, page, 1); denali_oob_xfer(mtd, chip, page, 1);
...@@ -903,23 +897,6 @@ static int denali_waitfunc(struct nand_chip *chip) ...@@ -903,23 +897,6 @@ static int denali_waitfunc(struct nand_chip *chip)
return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL; return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
} }
static int denali_erase(struct nand_chip *chip, int page)
{
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
uint32_t irq_status;
denali_reset_irq(denali);
denali->host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page,
DENALI_ERASE);
/* wait for erase to complete or failure to occur */
irq_status = denali_wait_for_irq(denali,
INTR__ERASE_COMP | INTR__ERASE_FAIL);
return irq_status & INTR__ERASE_COMP ? 0 : -EIO;
}
static int denali_setup_data_interface(struct nand_chip *chip, int chipnr, static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf) const struct nand_data_interface *conf)
{ {
...@@ -1244,7 +1221,6 @@ static int denali_attach_chip(struct nand_chip *chip) ...@@ -1244,7 +1221,6 @@ static int denali_attach_chip(struct nand_chip *chip)
chip->ecc.write_page_raw = denali_write_page_raw; chip->ecc.write_page_raw = denali_write_page_raw;
chip->ecc.read_oob = denali_read_oob; chip->ecc.read_oob = denali_read_oob;
chip->ecc.write_oob = denali_write_oob; chip->ecc.write_oob = denali_write_oob;
chip->legacy.erase = denali_erase;
ret = denali_multidev_fixup(denali); ret = denali_multidev_fixup(denali);
if (ret) if (ret)
......
...@@ -304,7 +304,6 @@ struct denali_nand_info { ...@@ -304,7 +304,6 @@ struct denali_nand_info {
u32 irq_status; /* interrupts that have happened */ u32 irq_status; /* interrupts that have happened */
int irq; int irq;
void *buf; /* for syndrome layout conversion */ void *buf; /* for syndrome layout conversion */
dma_addr_t dma_addr;
int dma_avail; /* can support DMA? */ int dma_avail; /* can support DMA? */
int devs_per_cs; /* devices connected in parallel */ int devs_per_cs; /* devices connected in parallel */
int oob_skip_bytes; /* number of bytes reserved for BBM */ int oob_skip_bytes; /* number of bytes reserved for BBM */
......
...@@ -109,25 +109,17 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -109,25 +109,17 @@ static int denali_dt_probe(struct platform_device *pdev)
if (IS_ERR(denali->host)) if (IS_ERR(denali->host))
return PTR_ERR(denali->host); return PTR_ERR(denali->host);
/*
* A single anonymous clock is supported for the backward compatibility.
* New platforms should support all the named clocks.
*/
dt->clk = devm_clk_get(dev, "nand"); dt->clk = devm_clk_get(dev, "nand");
if (IS_ERR(dt->clk)) if (IS_ERR(dt->clk))
dt->clk = devm_clk_get(dev, NULL);
if (IS_ERR(dt->clk)) {
dev_err(dev, "no clk available\n");
return PTR_ERR(dt->clk); return PTR_ERR(dt->clk);
}
dt->clk_x = devm_clk_get(dev, "nand_x"); dt->clk_x = devm_clk_get(dev, "nand_x");
if (IS_ERR(dt->clk_x)) if (IS_ERR(dt->clk_x))
dt->clk_x = NULL; return PTR_ERR(dt->clk_x);
dt->clk_ecc = devm_clk_get(dev, "ecc"); dt->clk_ecc = devm_clk_get(dev, "ecc");
if (IS_ERR(dt->clk_ecc)) if (IS_ERR(dt->clk_ecc))
dt->clk_ecc = NULL; return PTR_ERR(dt->clk_ecc);
ret = clk_prepare_enable(dt->clk); ret = clk_prepare_enable(dt->clk);
if (ret) if (ret)
...@@ -141,19 +133,8 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -141,19 +133,8 @@ static int denali_dt_probe(struct platform_device *pdev)
if (ret) if (ret)
goto out_disable_clk_x; goto out_disable_clk_x;
if (dt->clk_x) { denali->clk_rate = clk_get_rate(dt->clk);
denali->clk_rate = clk_get_rate(dt->clk); denali->clk_x_rate = clk_get_rate(dt->clk_x);
denali->clk_x_rate = clk_get_rate(dt->clk_x);
} else {
/*
* Hardcode the clock rates for the backward compatibility.
* This works for both SOCFPGA and UniPhier.
*/
dev_notice(dev,
"necessary clock is missing. default clock rates are used.\n");
denali->clk_rate = 50000000;
denali->clk_x_rate = 200000000;
}
ret = denali_init(denali); ret = denali_init(denali);
if (ret) if (ret)
......
...@@ -965,6 +965,19 @@ static const struct nand_controller_ops fsmc_nand_controller_ops = { ...@@ -965,6 +965,19 @@ static const struct nand_controller_ops fsmc_nand_controller_ops = {
.setup_data_interface = fsmc_setup_data_interface, .setup_data_interface = fsmc_setup_data_interface,
}; };
/**
* fsmc_nand_disable() - Disables the NAND bank
* @host: The instance to disable
*/
static void fsmc_nand_disable(struct fsmc_nand_data *host)
{
u32 val;
val = readl(host->regs_va + FSMC_PC);
val &= ~FSMC_ENABLE;
writel(val, host->regs_va + FSMC_PC);
}
/* /*
* fsmc_nand_probe - Probe function * fsmc_nand_probe - Probe function
* @pdev: platform device structure * @pdev: platform device structure
...@@ -1120,6 +1133,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -1120,6 +1133,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (host->mode == USE_DMA_ACCESS) if (host->mode == USE_DMA_ACCESS)
dma_release_channel(host->read_dma_chan); dma_release_channel(host->read_dma_chan);
disable_clk: disable_clk:
fsmc_nand_disable(host);
clk_disable_unprepare(host->clk); clk_disable_unprepare(host->clk);
return ret; return ret;
...@@ -1134,6 +1148,7 @@ static int fsmc_nand_remove(struct platform_device *pdev) ...@@ -1134,6 +1148,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
if (host) { if (host) {
nand_release(&host->nand); nand_release(&host->nand);
fsmc_nand_disable(host);
if (host->mode == USE_DMA_ACCESS) { if (host->mode == USE_DMA_ACCESS) {
dma_release_channel(host->write_dma_chan); dma_release_channel(host->write_dma_chan);
...@@ -1164,6 +1179,7 @@ static int fsmc_nand_resume(struct device *dev) ...@@ -1164,6 +1179,7 @@ static int fsmc_nand_resume(struct device *dev)
clk_prepare_enable(host->clk); clk_prepare_enable(host->clk);
if (host->dev_timings) if (host->dev_timings)
fsmc_nand_setup(host, host->dev_timings); fsmc_nand_setup(host, host->dev_timings);
nand_reset(&host->nand, 0);
} }
return 0; return 0;
......
...@@ -281,12 +281,15 @@ static struct jz4780_bch *jz4780_bch_get(struct device_node *np) ...@@ -281,12 +281,15 @@ static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
struct jz4780_bch *bch; struct jz4780_bch *bch;
pdev = of_find_device_by_node(np); pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev)) if (!pdev)
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
get_device(&pdev->dev);
bch = platform_get_drvdata(pdev); bch = platform_get_drvdata(pdev);
if (!bch) {
put_device(&pdev->dev);
return ERR_PTR(-EPROBE_DEFER);
}
clk_prepare_enable(bch->clk); clk_prepare_enable(bch->clk);
return bch; return bch;
......
...@@ -2550,9 +2550,8 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, ...@@ -2550,9 +2550,8 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
} }
/* Alloc the nand chip structure */ /* Alloc the nand chip structure */
marvell_nand = devm_kzalloc(dev, sizeof(*marvell_nand) + marvell_nand = devm_kzalloc(dev,
(nsels * struct_size(marvell_nand, sels, nsels),
sizeof(struct marvell_nand_chip_sel)),
GFP_KERNEL); GFP_KERNEL);
if (!marvell_nand) { if (!marvell_nand) {
dev_err(dev, "could not allocate chip structure\n"); dev_err(dev, "could not allocate chip structure\n");
......
This diff is collapsed.
...@@ -267,11 +267,15 @@ static struct mtk_ecc *mtk_ecc_get(struct device_node *np) ...@@ -267,11 +267,15 @@ static struct mtk_ecc *mtk_ecc_get(struct device_node *np)
struct mtk_ecc *ecc; struct mtk_ecc *ecc;
pdev = of_find_device_by_node(np); pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev)) if (!pdev)
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
get_device(&pdev->dev);
ecc = platform_get_drvdata(pdev); ecc = platform_get_drvdata(pdev);
if (!ecc) {
put_device(&pdev->dev);
return ERR_PTR(-EPROBE_DEFER);
}
clk_prepare_enable(ecc->clk); clk_prepare_enable(ecc->clk);
mtk_ecc_hw_init(ecc); mtk_ecc_hw_init(ecc);
......
...@@ -1451,8 +1451,7 @@ static int mtk_nfc_probe(struct platform_device *pdev) ...@@ -1451,8 +1451,7 @@ static int mtk_nfc_probe(struct platform_device *pdev)
if (!nfc) if (!nfc)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&nfc->controller.lock); nand_controller_init(&nfc->controller);
init_waitqueue_head(&nfc->controller.wq);
INIT_LIST_HEAD(&nfc->chips); INIT_LIST_HEAD(&nfc->chips);
nfc->controller.ops = &mtk_nfc_controller_ops; nfc->controller.ops = &mtk_nfc_controller_ops;
......
...@@ -278,11 +278,8 @@ EXPORT_SYMBOL_GPL(nand_deselect_target); ...@@ -278,11 +278,8 @@ EXPORT_SYMBOL_GPL(nand_deselect_target);
static void nand_release_device(struct nand_chip *chip) static void nand_release_device(struct nand_chip *chip)
{ {
/* Release the controller and the chip */ /* Release the controller and the chip */
spin_lock(&chip->controller->lock); mutex_unlock(&chip->controller->lock);
chip->controller->active = NULL; mutex_unlock(&chip->lock);
chip->state = FL_READY;
wake_up(&chip->controller->wq);
spin_unlock(&chip->controller->lock);
} }
/** /**
...@@ -330,58 +327,24 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) ...@@ -330,58 +327,24 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
return nand_block_bad(chip, ofs); return nand_block_bad(chip, ofs);
} }
/**
* panic_nand_get_device - [GENERIC] Get chip for selected access
* @chip: the nand chip descriptor
* @new_state: the state which is requested
*
* Used when in panic, no locks are taken.
*/
static void panic_nand_get_device(struct nand_chip *chip, int new_state)
{
/* Hardware controller shared among independent devices */
chip->controller->active = chip;
chip->state = new_state;
}
/** /**
* nand_get_device - [GENERIC] Get chip for selected access * nand_get_device - [GENERIC] Get chip for selected access
* @chip: NAND chip structure * @chip: NAND chip structure
* @new_state: the state which is requested
* *
* Get the device and lock it for exclusive access * Lock the device and its controller for exclusive access
*
* Return: -EBUSY if the chip has been suspended, 0 otherwise
*/ */
static int static int nand_get_device(struct nand_chip *chip)
nand_get_device(struct nand_chip *chip, int new_state)
{ {
spinlock_t *lock = &chip->controller->lock; mutex_lock(&chip->lock);
wait_queue_head_t *wq = &chip->controller->wq; if (chip->suspended) {
DECLARE_WAITQUEUE(wait, current); mutex_unlock(&chip->lock);
retry: return -EBUSY;
spin_lock(lock);
/* Hardware controller shared among independent devices */
if (!chip->controller->active)
chip->controller->active = chip;
if (chip->controller->active == chip && chip->state == FL_READY) {
chip->state = new_state;
spin_unlock(lock);
return 0;
}
if (new_state == FL_PM_SUSPENDED) {
if (chip->controller->active->state == FL_PM_SUSPENDED) {
chip->state = FL_PM_SUSPENDED;
spin_unlock(lock);
return 0;
}
} }
set_current_state(TASK_UNINTERRUPTIBLE); mutex_lock(&chip->controller->lock);
add_wait_queue(wq, &wait);
spin_unlock(lock); return 0;
schedule();
remove_wait_queue(wq, &wait);
goto retry;
} }
/** /**
...@@ -458,7 +421,7 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to, ...@@ -458,7 +421,7 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to,
struct mtd_oob_ops *ops) struct mtd_oob_ops *ops)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
int chipnr, page, status, len; int chipnr, page, status, len, ret;
pr_debug("%s: to = 0x%08x, len = %i\n", pr_debug("%s: to = 0x%08x, len = %i\n",
__func__, (unsigned int)to, (int)ops->ooblen); __func__, (unsigned int)to, (int)ops->ooblen);
...@@ -480,7 +443,9 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to, ...@@ -480,7 +443,9 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to,
* if we don't do this. I have no clue why, but I seem to have 'fixed' * if we don't do this. I have no clue why, but I seem to have 'fixed'
* it in the doc2000 driver in August 1999. dwmw2. * it in the doc2000 driver in August 1999. dwmw2.
*/ */
nand_reset(chip, chipnr); ret = nand_reset(chip, chipnr);
if (ret)
return ret;
nand_select_target(chip, chipnr); nand_select_target(chip, chipnr);
...@@ -603,7 +568,10 @@ static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs) ...@@ -603,7 +568,10 @@ static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs)
nand_erase_nand(chip, &einfo, 0); nand_erase_nand(chip, &einfo, 0);
/* Write bad block marker to OOB */ /* Write bad block marker to OOB */
nand_get_device(chip, FL_WRITING); ret = nand_get_device(chip);
if (ret)
return ret;
ret = nand_markbad_bbm(chip, ofs); ret = nand_markbad_bbm(chip, ofs);
nand_release_device(chip); nand_release_device(chip);
} }
...@@ -3581,7 +3549,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -3581,7 +3549,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
ops->mode != MTD_OPS_RAW) ops->mode != MTD_OPS_RAW)
return -ENOTSUPP; return -ENOTSUPP;
nand_get_device(chip, FL_READING); ret = nand_get_device(chip);
if (ret)
return ret;
if (!ops->datbuf) if (!ops->datbuf)
ret = nand_do_read_oob(chip, from, ops); ret = nand_do_read_oob(chip, from, ops);
...@@ -4100,9 +4070,6 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, ...@@ -4100,9 +4070,6 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
struct mtd_oob_ops ops; struct mtd_oob_ops ops;
int ret; int ret;
/* Grab the device */
panic_nand_get_device(chip, FL_WRITING);
nand_select_target(chip, chipnr); nand_select_target(chip, chipnr);
/* Wait for the device to get ready */ /* Wait for the device to get ready */
...@@ -4133,7 +4100,9 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, ...@@ -4133,7 +4100,9 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
ops->retlen = 0; ops->retlen = 0;
nand_get_device(chip, FL_WRITING); ret = nand_get_device(chip);
if (ret)
return ret;
switch (ops->mode) { switch (ops->mode) {
case MTD_OPS_PLACE_OOB: case MTD_OPS_PLACE_OOB:
...@@ -4155,23 +4124,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, ...@@ -4155,23 +4124,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
return ret; return ret;
} }
/**
* single_erase - [GENERIC] NAND standard block erase command function
* @chip: NAND chip object
* @page: the page address of the block which will be erased
*
* Standard erase command for NAND chips. Returns NAND status.
*/
static int single_erase(struct nand_chip *chip, int page)
{
unsigned int eraseblock;
/* Send commands to erase a block */
eraseblock = page >> (chip->phys_erase_shift - chip->page_shift);
return nand_erase_op(chip, eraseblock);
}
/** /**
* nand_erase - [MTD Interface] erase block(s) * nand_erase - [MTD Interface] erase block(s)
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -4195,7 +4147,7 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -4195,7 +4147,7 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
int allowbbt) int allowbbt)
{ {
int page, status, pages_per_block, ret, chipnr; int page, pages_per_block, ret, chipnr;
loff_t len; loff_t len;
pr_debug("%s: start = 0x%012llx, len = %llu\n", pr_debug("%s: start = 0x%012llx, len = %llu\n",
...@@ -4206,7 +4158,9 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, ...@@ -4206,7 +4158,9 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
return -EINVAL; return -EINVAL;
/* Grab the lock and see if the device is available */ /* Grab the lock and see if the device is available */
nand_get_device(chip, FL_ERASING); ret = nand_get_device(chip);
if (ret)
return ret;
/* Shift to get first page */ /* Shift to get first page */
page = (int)(instr->addr >> chip->page_shift); page = (int)(instr->addr >> chip->page_shift);
...@@ -4247,17 +4201,11 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, ...@@ -4247,17 +4201,11 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
(page + pages_per_block)) (page + pages_per_block))
chip->pagebuf = -1; chip->pagebuf = -1;
if (chip->legacy.erase) ret = nand_erase_op(chip, (page & chip->pagemask) >>
status = chip->legacy.erase(chip, (chip->phys_erase_shift - chip->page_shift));
page & chip->pagemask); if (ret) {
else
status = single_erase(chip, page & chip->pagemask);
/* See if block erase succeeded */
if (status) {
pr_debug("%s: failed erase, page 0x%08x\n", pr_debug("%s: failed erase, page 0x%08x\n",
__func__, page); __func__, page);
ret = -EIO;
instr->fail_addr = instr->fail_addr =
((loff_t)page << chip->page_shift); ((loff_t)page << chip->page_shift);
goto erase_exit; goto erase_exit;
...@@ -4299,7 +4247,7 @@ static void nand_sync(struct mtd_info *mtd) ...@@ -4299,7 +4247,7 @@ static void nand_sync(struct mtd_info *mtd)
pr_debug("%s: called\n", __func__); pr_debug("%s: called\n", __func__);
/* Grab the lock and see if the device is available */ /* Grab the lock and see if the device is available */
nand_get_device(chip, FL_SYNCING); WARN_ON(nand_get_device(chip));
/* Release it and go back */ /* Release it and go back */
nand_release_device(chip); nand_release_device(chip);
} }
...@@ -4316,7 +4264,10 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) ...@@ -4316,7 +4264,10 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
int ret; int ret;
/* Select the NAND device */ /* Select the NAND device */
nand_get_device(chip, FL_READING); ret = nand_get_device(chip);
if (ret)
return ret;
nand_select_target(chip, chipnr); nand_select_target(chip, chipnr);
ret = nand_block_checkbad(chip, offs, 0); ret = nand_block_checkbad(chip, offs, 0);
...@@ -4389,7 +4340,13 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) ...@@ -4389,7 +4340,13 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len)
*/ */
static int nand_suspend(struct mtd_info *mtd) static int nand_suspend(struct mtd_info *mtd)
{ {
return nand_get_device(mtd_to_nand(mtd), FL_PM_SUSPENDED); struct nand_chip *chip = mtd_to_nand(mtd);
mutex_lock(&chip->lock);
chip->suspended = 1;
mutex_unlock(&chip->lock);
return 0;
} }
/** /**
...@@ -4400,11 +4357,13 @@ static void nand_resume(struct mtd_info *mtd) ...@@ -4400,11 +4357,13 @@ static void nand_resume(struct mtd_info *mtd)
{ {
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
if (chip->state == FL_PM_SUSPENDED) mutex_lock(&chip->lock);
nand_release_device(chip); if (chip->suspended)
chip->suspended = 0;
else else
pr_err("%s called for a chip which is not in suspended state\n", pr_err("%s called for a chip which is not in suspended state\n",
__func__); __func__);
mutex_unlock(&chip->lock);
} }
/** /**
...@@ -4414,7 +4373,7 @@ static void nand_resume(struct mtd_info *mtd) ...@@ -4414,7 +4373,7 @@ static void nand_resume(struct mtd_info *mtd)
*/ */
static void nand_shutdown(struct mtd_info *mtd) static void nand_shutdown(struct mtd_info *mtd)
{ {
nand_get_device(mtd_to_nand(mtd), FL_PM_SUSPENDED); nand_suspend(mtd);
} }
/* Set default functions */ /* Set default functions */
...@@ -5019,6 +4978,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, ...@@ -5019,6 +4978,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
/* Assume all dies are deselected when we enter nand_scan_ident(). */ /* Assume all dies are deselected when we enter nand_scan_ident(). */
chip->cur_cs = -1; chip->cur_cs = -1;
mutex_init(&chip->lock);
/* Enforce the right timings for reset/detection */ /* Enforce the right timings for reset/detection */
onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0); onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
...@@ -5061,11 +5022,15 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, ...@@ -5061,11 +5022,15 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
u8 id[2]; u8 id[2];
/* See comment in nand_get_flash_type for reset */ /* See comment in nand_get_flash_type for reset */
nand_reset(chip, i); ret = nand_reset(chip, i);
if (ret)
break;
nand_select_target(chip, i); nand_select_target(chip, i);
/* Send the command for reading device ID */ /* Send the command for reading device ID */
nand_readid_op(chip, 0, id, sizeof(id)); ret = nand_readid_op(chip, 0, id, sizeof(id));
if (ret)
break;
/* Read manufacturer and device IDs */ /* Read manufacturer and device IDs */
if (nand_maf_id != id[0] || nand_dev_id != id[1]) { if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
nand_deselect_target(chip); nand_deselect_target(chip);
...@@ -5556,6 +5521,7 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5556,6 +5521,7 @@ static int nand_scan_tail(struct nand_chip *chip)
} }
if (!ecc->read_page) if (!ecc->read_page)
ecc->read_page = nand_read_page_hwecc_oob_first; ecc->read_page = nand_read_page_hwecc_oob_first;
/* fall through */
case NAND_ECC_HW: case NAND_ECC_HW:
/* Use standard hwecc read page function? */ /* Use standard hwecc read page function? */
...@@ -5575,6 +5541,7 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5575,6 +5541,7 @@ static int nand_scan_tail(struct nand_chip *chip)
ecc->read_subpage = nand_read_subpage; ecc->read_subpage = nand_read_subpage;
if (!ecc->write_subpage && ecc->hwctl && ecc->calculate) if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
ecc->write_subpage = nand_write_subpage_hwecc; ecc->write_subpage = nand_write_subpage_hwecc;
/* fall through */
case NAND_ECC_HW_SYNDROME: case NAND_ECC_HW_SYNDROME:
if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) && if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
...@@ -5612,6 +5579,7 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5612,6 +5579,7 @@ static int nand_scan_tail(struct nand_chip *chip)
ecc->size, mtd->writesize); ecc->size, mtd->writesize);
ecc->mode = NAND_ECC_SOFT; ecc->mode = NAND_ECC_SOFT;
ecc->algo = NAND_ECC_HAMMING; ecc->algo = NAND_ECC_HAMMING;
/* fall through */
case NAND_ECC_SOFT: case NAND_ECC_SOFT:
ret = nand_set_ecc_soft_ops(chip); ret = nand_set_ecc_soft_ops(chip);
...@@ -5718,9 +5686,6 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5718,9 +5686,6 @@ static int nand_scan_tail(struct nand_chip *chip)
} }
chip->subpagesize = mtd->writesize >> mtd->subpage_sft; chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
/* Initialize state */
chip->state = FL_READY;
/* Invalidate the pagebuffer reference */ /* Invalidate the pagebuffer reference */
chip->pagebuf = -1; chip->pagebuf = -1;
......
...@@ -331,6 +331,7 @@ static void nand_command(struct nand_chip *chip, unsigned int command, ...@@ -331,6 +331,7 @@ static void nand_command(struct nand_chip *chip, unsigned int command,
*/ */
if (column == -1 && page_addr == -1) if (column == -1 && page_addr == -1)
return; return;
/* fall through */
default: default:
/* /*
...@@ -483,7 +484,7 @@ static void nand_command_lp(struct nand_chip *chip, unsigned int command, ...@@ -483,7 +484,7 @@ static void nand_command_lp(struct nand_chip *chip, unsigned int command,
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE); NAND_NCE | NAND_CTRL_CHANGE);
/* This applies to read commands */ /* fall through - This applies to read commands */
default: default:
/* /*
* If we don't have access to the busy pin, we apply the given * If we don't have access to the busy pin, we apply the given
......
...@@ -994,12 +994,9 @@ static int omap_wait(struct nand_chip *this) ...@@ -994,12 +994,9 @@ static int omap_wait(struct nand_chip *this)
{ {
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this)); struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this));
unsigned long timeo = jiffies; unsigned long timeo = jiffies;
int status, state = this->state; int status;
if (state == FL_ERASING) timeo += msecs_to_jiffies(400);
timeo += msecs_to_jiffies(400);
else
timeo += msecs_to_jiffies(20);
writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command); writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
while (time_before(jiffies, timeo)) { while (time_before(jiffies, timeo)) {
...@@ -2173,11 +2170,8 @@ static const struct nand_controller_ops omap_nand_controller_ops = { ...@@ -2173,11 +2170,8 @@ static const struct nand_controller_ops omap_nand_controller_ops = {
}; };
/* Shared among all NAND instances to synchronize access to the ECC Engine */ /* Shared among all NAND instances to synchronize access to the ECC Engine */
static struct nand_controller omap_gpmc_controller = { static struct nand_controller omap_gpmc_controller;
.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock), static bool omap_gpmc_controller_initialized;
.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
.ops = &omap_nand_controller_ops,
};
static int omap_nand_probe(struct platform_device *pdev) static int omap_nand_probe(struct platform_device *pdev)
{ {
...@@ -2227,6 +2221,12 @@ static int omap_nand_probe(struct platform_device *pdev) ...@@ -2227,6 +2221,12 @@ static int omap_nand_probe(struct platform_device *pdev)
info->phys_base = res->start; info->phys_base = res->start;
if (!omap_gpmc_controller_initialized) {
omap_gpmc_controller.ops = &omap_nand_controller_ops;
nand_controller_init(&omap_gpmc_controller);
omap_gpmc_controller_initialized = true;
}
nand_chip->controller = &omap_gpmc_controller; nand_chip->controller = &omap_gpmc_controller;
nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R; nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R;
......
...@@ -369,8 +369,7 @@ static int r852_wait(struct nand_chip *chip) ...@@ -369,8 +369,7 @@ static int r852_wait(struct nand_chip *chip)
unsigned long timeout; unsigned long timeout;
u8 status; u8 status;
timeout = jiffies + (chip->state == FL_ERASING ? timeout = jiffies + msecs_to_jiffies(400);
msecs_to_jiffies(400) : msecs_to_jiffies(20));
while (time_before(jiffies, timeout)) while (time_before(jiffies, timeout))
if (chip->legacy.dev_ready(chip)) if (chip->legacy.dev_ready(chip))
......
This diff is collapsed.
This diff is collapsed.
...@@ -104,6 +104,7 @@ ...@@ -104,6 +104,7 @@
struct tmio_nand { struct tmio_nand {
struct nand_chip chip; struct nand_chip chip;
struct completion comp;
struct platform_device *dev; struct platform_device *dev;
...@@ -168,15 +169,11 @@ static int tmio_nand_dev_ready(struct nand_chip *chip) ...@@ -168,15 +169,11 @@ static int tmio_nand_dev_ready(struct nand_chip *chip)
static irqreturn_t tmio_irq(int irq, void *__tmio) static irqreturn_t tmio_irq(int irq, void *__tmio)
{ {
struct tmio_nand *tmio = __tmio; struct tmio_nand *tmio = __tmio;
struct nand_chip *nand_chip = &tmio->chip;
/* disable RDYREQ interrupt */ /* disable RDYREQ interrupt */
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
complete(&tmio->comp);
if (unlikely(!waitqueue_active(&nand_chip->controller->wq)))
dev_warn(&tmio->dev->dev, "spurious interrupt\n");
wake_up(&nand_chip->controller->wq);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -193,18 +190,18 @@ static int tmio_nand_wait(struct nand_chip *nand_chip) ...@@ -193,18 +190,18 @@ static int tmio_nand_wait(struct nand_chip *nand_chip)
u8 status; u8 status;
/* enable RDYREQ interrupt */ /* enable RDYREQ interrupt */
tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
reinit_completion(&tmio->comp);
tmio_iowrite8(0x81, tmio->fcr + FCR_IMR); tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
timeout = wait_event_timeout(nand_chip->controller->wq, timeout = 400;
tmio_nand_dev_ready(nand_chip), timeout = wait_for_completion_timeout(&tmio->comp,
msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20)); msecs_to_jiffies(timeout));
if (unlikely(!tmio_nand_dev_ready(nand_chip))) { if (unlikely(!tmio_nand_dev_ready(nand_chip))) {
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n", dev_warn(&tmio->dev->dev, "still busy after 400 ms\n");
nand_chip->state == FL_ERASING ? "erase" : "program",
nand_chip->state == FL_ERASING ? 400 : 20);
} else if (unlikely(!timeout)) { } else if (unlikely(!timeout)) {
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
...@@ -378,6 +375,8 @@ static int tmio_probe(struct platform_device *dev) ...@@ -378,6 +375,8 @@ static int tmio_probe(struct platform_device *dev)
if (!tmio) if (!tmio)
return -ENOMEM; return -ENOMEM;
init_completion(&tmio->comp);
tmio->dev = dev; tmio->dev = dev;
platform_set_drvdata(dev, tmio); platform_set_drvdata(dev, tmio);
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4) #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4) #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
#define GD5FXGQ4UEXXG_REG_STATUS2 0xf0
static SPINAND_OP_VARIANTS(read_cache_variants, static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
...@@ -81,11 +83,83 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand, ...@@ -81,11 +83,83 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
return -EINVAL; return -EINVAL;
} }
static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
region->offset = 64;
region->length = 64;
return 0;
}
static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
/* Reserve 1 bytes for the BBM. */
region->offset = 1;
region->length = 63;
return 0;
}
static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
u8 status2;
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4UEXXG_REG_STATUS2,
&status2);
int ret;
switch (status & STATUS_ECC_MASK) {
case STATUS_ECC_NO_BITFLIPS:
return 0;
case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
/*
* Read status2 register to determine a more fine grained
* bit error status
*/
ret = spi_mem_exec_op(spinand->spimem, &op);
if (ret)
return ret;
/*
* 4 ... 7 bits are flipped (1..4 can't be detected, so
* report the maximum of 4 in this case
*/
/* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
return ((status & STATUS_ECC_MASK) >> 2) |
((status2 & STATUS_ECC_MASK) >> 4);
case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
return 8;
case STATUS_ECC_UNCOR_ERROR:
return -EBADMSG;
default:
break;
}
return -EINVAL;
}
static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = { static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
.ecc = gd5fxgq4xa_ooblayout_ecc, .ecc = gd5fxgq4xa_ooblayout_ecc,
.free = gd5fxgq4xa_ooblayout_free, .free = gd5fxgq4xa_ooblayout_free,
}; };
static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
.ecc = gd5fxgq4uexxg_ooblayout_ecc,
.free = gd5fxgq4uexxg_ooblayout_free,
};
static const struct spinand_info gigadevice_spinand_table[] = { static const struct spinand_info gigadevice_spinand_table[] = {
SPINAND_INFO("GD5F1GQ4xA", 0xF1, SPINAND_INFO("GD5F1GQ4xA", 0xF1,
NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
...@@ -114,6 +188,15 @@ static const struct spinand_info gigadevice_spinand_table[] = { ...@@ -114,6 +188,15 @@ static const struct spinand_info gigadevice_spinand_table[] = {
0, 0,
SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
gd5fxgq4xa_ecc_get_status)), gd5fxgq4xa_ecc_get_status)),
SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&gd5fxgq4uexxg_ooblayout,
gd5fxgq4uexxg_ecc_get_status)),
}; };
static int gigadevice_spinand_detect(struct spinand_device *spinand) static int gigadevice_spinand_detect(struct spinand_device *spinand)
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/mtd/spinand.h> #include <linux/mtd/spinand.h>
#define SPINAND_MFR_MACRONIX 0xC2 #define SPINAND_MFR_MACRONIX 0xC2
#define MACRONIX_ECCSR_MASK 0x0F
static SPINAND_OP_VARIANTS(read_cache_variants, static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
...@@ -55,7 +56,12 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr) ...@@ -55,7 +56,12 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
SPI_MEM_OP_DUMMY(1, 1), SPI_MEM_OP_DUMMY(1, 1),
SPI_MEM_OP_DATA_IN(1, eccsr, 1)); SPI_MEM_OP_DATA_IN(1, eccsr, 1));
return spi_mem_exec_op(spinand->spimem, &op); int ret = spi_mem_exec_op(spinand->spimem, &op);
if (ret)
return ret;
*eccsr &= MACRONIX_ECCSR_MASK;
return 0;
} }
static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand, static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
......
...@@ -25,19 +25,19 @@ static SPINAND_OP_VARIANTS(write_cache_variants, ...@@ -25,19 +25,19 @@ static SPINAND_OP_VARIANTS(write_cache_variants,
static SPINAND_OP_VARIANTS(update_cache_variants, static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD(false, 0, NULL, 0)); SPINAND_PROG_LOAD(false, 0, NULL, 0));
static int tc58cvg2s0h_ooblayout_ecc(struct mtd_info *mtd, int section, static int tc58cxgxsx_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region) struct mtd_oob_region *region)
{ {
if (section > 7) if (section > 0)
return -ERANGE; return -ERANGE;
region->offset = 128 + 16 * section; region->offset = mtd->oobsize / 2;
region->length = 16; region->length = mtd->oobsize / 2;
return 0; return 0;
} }
static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section, static int tc58cxgxsx_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region) struct mtd_oob_region *region)
{ {
if (section > 0) if (section > 0)
...@@ -45,17 +45,17 @@ static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section, ...@@ -45,17 +45,17 @@ static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
/* 2 bytes reserved for BBM */ /* 2 bytes reserved for BBM */
region->offset = 2; region->offset = 2;
region->length = 126; region->length = (mtd->oobsize / 2) - 2;
return 0; return 0;
} }
static const struct mtd_ooblayout_ops tc58cvg2s0h_ooblayout = { static const struct mtd_ooblayout_ops tc58cxgxsx_ooblayout = {
.ecc = tc58cvg2s0h_ooblayout_ecc, .ecc = tc58cxgxsx_ooblayout_ecc,
.free = tc58cvg2s0h_ooblayout_free, .free = tc58cxgxsx_ooblayout_free,
}; };
static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand, static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand,
u8 status) u8 status)
{ {
struct nand_device *nand = spinand_to_nand(spinand); struct nand_device *nand = spinand_to_nand(spinand);
...@@ -94,15 +94,66 @@ static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand, ...@@ -94,15 +94,66 @@ static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
} }
static const struct spinand_info toshiba_spinand_table[] = { static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_INFO("TC58CVG2S0H", 0xCD, /* 3.3V 1Gb */
SPINAND_INFO("TC58CVG0S3", 0xC2,
NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
/* 3.3V 2Gb */
SPINAND_INFO("TC58CVG1S3", 0xCB,
NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
/* 3.3V 4Gb */
SPINAND_INFO("TC58CVG2S0", 0xCD,
NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
/* 1.8V 1Gb */
SPINAND_INFO("TC58CYG0S3", 0xB2,
NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
/* 1.8V 2Gb */
SPINAND_INFO("TC58CYG1S3", 0xBB,
NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
/* 1.8V 4Gb */
SPINAND_INFO("TC58CYG2S0", 0xBD,
NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1), NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
NAND_ECCREQ(8, 512), NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
SPINAND_HAS_QE_BIT, 0,
SPINAND_ECCINFO(&tc58cvg2s0h_ooblayout, SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cvg2s0h_ecc_get_status)), tc58cxgxsx_ecc_get_status)),
}; };
static int toshiba_spinand_detect(struct spinand_device *spinand) static int toshiba_spinand_detect(struct spinand_device *spinand)
......
...@@ -7,14 +7,6 @@ menuconfig MTD_SPI_NOR ...@@ -7,14 +7,6 @@ menuconfig MTD_SPI_NOR
if MTD_SPI_NOR if MTD_SPI_NOR
config MTD_MT81xx_NOR
tristate "Mediatek MT81xx SPI NOR flash controller"
depends on HAS_IOMEM
help
This enables access to SPI NOR flash, using MT81xx SPI NOR flash
controller. This controller does not support generic SPI BUS, it only
supports SPI NOR Flash.
config MTD_SPI_NOR_USE_4K_SECTORS config MTD_SPI_NOR_USE_4K_SECTORS
bool "Use small 4096 B erase sectors" bool "Use small 4096 B erase sectors"
default y default y
...@@ -66,6 +58,14 @@ config SPI_HISI_SFC ...@@ -66,6 +58,14 @@ config SPI_HISI_SFC
help help
This enables support for hisilicon SPI-NOR flash controller. This enables support for hisilicon SPI-NOR flash controller.
config SPI_MTK_QUADSPI
tristate "MediaTek Quad SPI controller"
depends on HAS_IOMEM
help
This enables support for the Quad SPI controller in master mode.
This controller does not support generic SPI. It only supports
SPI NOR.
config SPI_NXP_SPIFI config SPI_NXP_SPIFI
tristate "NXP SPI Flash Interface (SPIFI)" tristate "NXP SPI Flash Interface (SPIFI)"
depends on OF && (ARCH_LPC18XX || COMPILE_TEST) depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
......
...@@ -4,7 +4,7 @@ obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o ...@@ -4,7 +4,7 @@ obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o
obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o
obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o
obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o obj-$(CONFIG_SPI_MTK_QUADSPI) += mtk-quadspi.o
obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o
obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o
......
This diff is collapsed.
...@@ -431,7 +431,8 @@ static int mtk_nor_init(struct mtk_nor *mtk_nor, ...@@ -431,7 +431,8 @@ static int mtk_nor_init(struct mtk_nor *mtk_nor,
struct device_node *flash_node) struct device_node *flash_node)
{ {
const struct spi_nor_hwcaps hwcaps = { const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ_FAST | .mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_READ_1_1_2 | SNOR_HWCAPS_READ_1_1_2 |
SNOR_HWCAPS_PP, SNOR_HWCAPS_PP,
}; };
......
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