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).
   - Checking the return code of nand_reset() and nand_readid_op().
   - Removing ->legacy.erase and single_erase().
   - Simplifying the locking.
   - Several implicit fall through annotations.
 
   Raw NAND controllers drivers changes:
   - Fixing various possible object reference leaks (MTK, JZ4780, Atmel).
   - ST:
     * Adding support for STM32 FMC2 NAND flash controller.
   - Meson:
     * Adding support for Amlogic NAND flash controller.
   - Denali:
     * Several cleanup patches.
   - Sunxi:
     * Several cleanup patches.
   - FSMC:
     * Disabling NAND on remove().
     * Resetting NAND timings on resume().
 
   SPI-NAND drivers changes:
   - Toshiba:
     * Adding support for all Toshiba products.
   - Macronix:
     * Fixing ECC status read.
   - Gigadevice:
     * Adding support for GD5F1GQ4UExxG.
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJcc6fZAAoJEGXtNgF+CLcAuJAQAMKmhbWs9j8+A/hLNkfiZv1g
 Yg1e4rs9AMCJcBAprw1nO6U8EJyAgNxY/WafR1Kqz8tvUAw8LjJxvhPQzyhfBKq5
 w/eR6C1sod7Ay6oNkpI7r2dM0spyLJUwP13FMthoMSM1heupe/HE6s8QXCS71WXW
 vi0C6LKDlokdo2VtArB8orA4x2794/+Mn2JHOhIqZcoLl8W6B3k/kckrv0MXd0po
 bCivqVx5jdQC0+khl+yT4CJvB10DQmmLRZ8Itd4GUP1mHoCEO+De8NDqjoddzKM2
 VCMI8dr5h/YjBsspLSPBfH1qnT+OxJnAnWRf+XCBraYG4bJP9xdmnhV6zDz9T0dS
 sxj62IRTrW41u+Izv8+Rus5EPuKsCATnfKTReQRwc3zDkyYYVzdi8XYvHknxkJ1Z
 0+wKjRGf4K/ETcenSXr8Tqx0IRz5PzXyTZdWyyk/cJKLhmYIJQQs0lwa+9PHJK45
 FIt9vFTJYOAFdrecnCNbhymeSHLAtDNdG8x9XzjgjF6R3aftVBGLjCNuwN7ECfyq
 LMJpqycWih5wiihaL5QXnvMnRHvHaolle2Rlvl5BR+y+LMBc4luw9TFtJ3Jwq/qy
 hHjFlugCCtQVk3TYRFNLhiidml6hDoUEL01JofgjnYZcBfmGfkNnPz1RrcoMW9QT
 J4ZQKXj0T01OVna/zme+
 =wIHY
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2019-03-04 18:59:37 -08:00
commit 811c16a2a2
41 changed files with 4536 additions and 675 deletions

View File

@ -0,0 +1,60 @@
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;
};
};

View File

@ -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

View File

@ -1,4 +1,4 @@
* 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:
"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

View File

@ -0,0 +1,61 @@
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>;
};
};

View File

@ -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/
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/

View File

@ -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,

View File

@ -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);

View File

@ -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)
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)
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);
} }

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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,
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,
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,
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,
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,
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,
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,
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)
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);
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); return ret;
*retlen = ops.retlen;
} else {
return -ENOTSUPP;
}
if (unlikely(ret_code < 0))
return ret_code;
if (mtd->ecc_strength == 0)
return 0; /* device lacks ecc */
return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
} }
EXPORT_SYMBOL_GPL(mtd_read); 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);

View File

@ -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

View File

@ -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

View File

@ -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 };

View File

@ -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,
} }
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,
} }
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,
} }
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,
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,
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)
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)
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)
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)

View File

@ -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 */

View File

@ -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)
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)

View File

@ -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)
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)
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)
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;

View File

@ -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;

View File

@ -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");

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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;

View File

@ -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)
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) { mutex_lock(&chip->controller->lock);
if (chip->controller->active->state == FL_PM_SUSPENDED) {
chip->state = FL_PM_SUSPENDED; return 0;
spin_unlock(lock);
return 0;
}
}
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(wq, &wait);
spin_unlock(lock);
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,
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,
* 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)
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,
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,
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,
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,
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)
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,
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,
(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)
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)
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)
*/ */
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)
{ {
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)
*/ */
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,
/* 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,
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)
} }
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)
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)
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)
} }
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;

View File

@ -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,
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

View File

@ -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 = {
}; };
/* 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)
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;

View File

@ -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))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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)
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)
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)
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);

View File

@ -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,
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[] = {
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)

View File

@ -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)
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,

View File

@ -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,
/* 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,
} }
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_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)),
/* 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_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)),
}; };
static int toshiba_spinand_detect(struct spinand_device *spinand) static int toshiba_spinand_detect(struct spinand_device *spinand)

View File

@ -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
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)

View File

@ -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

View File

@ -44,6 +44,12 @@
/* Quirks */ /* Quirks */
#define CQSPI_NEEDS_WR_DELAY BIT(0) #define CQSPI_NEEDS_WR_DELAY BIT(0)
/* Capabilities mask */
#define CQSPI_BASE_HWCAPS_MASK \
(SNOR_HWCAPS_READ | SNOR_HWCAPS_READ_FAST | \
SNOR_HWCAPS_READ_1_1_2 | SNOR_HWCAPS_READ_1_1_4 | \
SNOR_HWCAPS_PP)
struct cqspi_st; struct cqspi_st;
struct cqspi_flash_pdata { struct cqspi_flash_pdata {
@ -93,6 +99,11 @@ struct cqspi_st {
struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT]; struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
}; };
struct cqspi_driver_platdata {
u32 hwcaps_mask;
u8 quirks;
};
/* Operation timeout value */ /* Operation timeout value */
#define CQSPI_TIMEOUT_MS 500 #define CQSPI_TIMEOUT_MS 500
#define CQSPI_READ_TIMEOUT_MS 10 #define CQSPI_READ_TIMEOUT_MS 10
@ -101,6 +112,7 @@ struct cqspi_st {
#define CQSPI_INST_TYPE_SINGLE 0 #define CQSPI_INST_TYPE_SINGLE 0
#define CQSPI_INST_TYPE_DUAL 1 #define CQSPI_INST_TYPE_DUAL 1
#define CQSPI_INST_TYPE_QUAD 2 #define CQSPI_INST_TYPE_QUAD 2
#define CQSPI_INST_TYPE_OCTAL 3
#define CQSPI_DUMMY_CLKS_PER_BYTE 8 #define CQSPI_DUMMY_CLKS_PER_BYTE 8
#define CQSPI_DUMMY_BYTES_MAX 4 #define CQSPI_DUMMY_BYTES_MAX 4
@ -418,9 +430,10 @@ static int cqspi_command_write(struct spi_nor *nor, const u8 opcode,
void __iomem *reg_base = cqspi->iobase; void __iomem *reg_base = cqspi->iobase;
unsigned int reg; unsigned int reg;
unsigned int data; unsigned int data;
u32 write_len;
int ret; int ret;
if (n_tx > 4 || (n_tx && !txbuf)) { if (n_tx > CQSPI_STIG_DATA_LEN_MAX || (n_tx && !txbuf)) {
dev_err(nor->dev, dev_err(nor->dev,
"Invalid input argument, cmdlen %d txbuf 0x%p\n", "Invalid input argument, cmdlen %d txbuf 0x%p\n",
n_tx, txbuf); n_tx, txbuf);
@ -433,10 +446,18 @@ static int cqspi_command_write(struct spi_nor *nor, const u8 opcode,
reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK) reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK)
<< CQSPI_REG_CMDCTRL_WR_BYTES_LSB; << CQSPI_REG_CMDCTRL_WR_BYTES_LSB;
data = 0; data = 0;
memcpy(&data, txbuf, n_tx); write_len = (n_tx > 4) ? 4 : n_tx;
memcpy(&data, txbuf, write_len);
txbuf += write_len;
writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER); writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER);
}
if (n_tx > 4) {
data = 0;
write_len = n_tx - 4;
memcpy(&data, txbuf, write_len);
writel(data, reg_base + CQSPI_REG_CMDWRITEDATAUPPER);
}
}
ret = cqspi_exec_flash_cmd(cqspi, reg); ret = cqspi_exec_flash_cmd(cqspi, reg);
return ret; return ret;
} }
@ -911,6 +932,9 @@ static int cqspi_set_protocol(struct spi_nor *nor, const int read)
case SNOR_PROTO_1_1_4: case SNOR_PROTO_1_1_4:
f_pdata->data_width = CQSPI_INST_TYPE_QUAD; f_pdata->data_width = CQSPI_INST_TYPE_QUAD;
break; break;
case SNOR_PROTO_1_1_8:
f_pdata->data_width = CQSPI_INST_TYPE_OCTAL;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -1213,21 +1237,23 @@ static void cqspi_request_mmap_dma(struct cqspi_st *cqspi)
static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np) static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np)
{ {
const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
SNOR_HWCAPS_READ_1_1_2 |
SNOR_HWCAPS_READ_1_1_4 |
SNOR_HWCAPS_PP,
};
struct platform_device *pdev = cqspi->pdev; struct platform_device *pdev = cqspi->pdev;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct cqspi_driver_platdata *ddata;
struct spi_nor_hwcaps hwcaps;
struct cqspi_flash_pdata *f_pdata; struct cqspi_flash_pdata *f_pdata;
struct spi_nor *nor; struct spi_nor *nor;
struct mtd_info *mtd; struct mtd_info *mtd;
unsigned int cs; unsigned int cs;
int i, ret; int i, ret;
ddata = of_device_get_match_data(dev);
if (!ddata) {
dev_err(dev, "Couldn't find driver data\n");
return -EINVAL;
}
hwcaps.mask = ddata->hwcaps_mask;
/* Get flash device data */ /* Get flash device data */
for_each_available_child_of_node(dev->of_node, np) { for_each_available_child_of_node(dev->of_node, np) {
ret = of_property_read_u32(np, "reg", &cs); ret = of_property_read_u32(np, "reg", &cs);
@ -1310,7 +1336,7 @@ static int cqspi_probe(struct platform_device *pdev)
struct cqspi_st *cqspi; struct cqspi_st *cqspi;
struct resource *res; struct resource *res;
struct resource *res_ahb; struct resource *res_ahb;
unsigned long data; const struct cqspi_driver_platdata *ddata;
int ret; int ret;
int irq; int irq;
@ -1377,8 +1403,8 @@ static int cqspi_probe(struct platform_device *pdev)
} }
cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk); cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
data = (unsigned long)of_device_get_match_data(dev); ddata = of_device_get_match_data(dev);
if (data & CQSPI_NEEDS_WR_DELAY) if (ddata && (ddata->quirks & CQSPI_NEEDS_WR_DELAY))
cqspi->wr_delay = 5 * DIV_ROUND_UP(NSEC_PER_SEC, cqspi->wr_delay = 5 * DIV_ROUND_UP(NSEC_PER_SEC,
cqspi->master_ref_clk_hz); cqspi->master_ref_clk_hz);
@ -1460,14 +1486,32 @@ static const struct dev_pm_ops cqspi__dev_pm_ops = {
#define CQSPI_DEV_PM_OPS NULL #define CQSPI_DEV_PM_OPS NULL
#endif #endif
static const struct cqspi_driver_platdata cdns_qspi = {
.hwcaps_mask = CQSPI_BASE_HWCAPS_MASK,
};
static const struct cqspi_driver_platdata k2g_qspi = {
.hwcaps_mask = CQSPI_BASE_HWCAPS_MASK,
.quirks = CQSPI_NEEDS_WR_DELAY,
};
static const struct cqspi_driver_platdata am654_ospi = {
.hwcaps_mask = CQSPI_BASE_HWCAPS_MASK | SNOR_HWCAPS_READ_1_1_8,
.quirks = CQSPI_NEEDS_WR_DELAY,
};
static const struct of_device_id cqspi_dt_ids[] = { static const struct of_device_id cqspi_dt_ids[] = {
{ {
.compatible = "cdns,qspi-nor", .compatible = "cdns,qspi-nor",
.data = (void *)0, .data = &cdns_qspi,
}, },
{ {
.compatible = "ti,k2g-qspi", .compatible = "ti,k2g-qspi",
.data = (void *)CQSPI_NEEDS_WR_DELAY, .data = &k2g_qspi,
},
{
.compatible = "ti,am654-ospi",
.data = &am654_ospi,
}, },
{ /* end of table */ } { /* end of table */ }
}; };

View File

@ -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,
}; };

View File

@ -68,7 +68,7 @@ enum spi_nor_read_command_index {
SNOR_CMD_READ_4_4_4, SNOR_CMD_READ_4_4_4,
SNOR_CMD_READ_1_4_4_DTR, SNOR_CMD_READ_1_4_4_DTR,
/* Octo SPI */ /* Octal SPI */
SNOR_CMD_READ_1_1_8, SNOR_CMD_READ_1_1_8,
SNOR_CMD_READ_1_8_8, SNOR_CMD_READ_1_8_8,
SNOR_CMD_READ_8_8_8, SNOR_CMD_READ_8_8_8,
@ -85,7 +85,7 @@ enum spi_nor_pp_command_index {
SNOR_CMD_PP_1_4_4, SNOR_CMD_PP_1_4_4,
SNOR_CMD_PP_4_4_4, SNOR_CMD_PP_4_4_4,
/* Octo SPI */ /* Octal SPI */
SNOR_CMD_PP_1_1_8, SNOR_CMD_PP_1_1_8,
SNOR_CMD_PP_1_8_8, SNOR_CMD_PP_1_8_8,
SNOR_CMD_PP_8_8_8, SNOR_CMD_PP_8_8_8,
@ -278,6 +278,7 @@ struct flash_info {
#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ #define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
#define USE_CLSR BIT(14) /* use CLSR command */ #define USE_CLSR BIT(14) /* use CLSR command */
#define SPI_NOR_OCTAL_READ BIT(15) /* Flash supports Octal Read */
/* Part specific fixup hooks. */ /* Part specific fixup hooks. */
const struct spi_nor_fixups *fixups; const struct spi_nor_fixups *fixups;
@ -398,6 +399,8 @@ static u8 spi_nor_convert_3to4_read(u8 opcode)
{ SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B }, { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B },
{ SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B }, { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B },
{ SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B }, { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B },
{ SPINOR_OP_READ_1_1_8, SPINOR_OP_READ_1_1_8_4B },
{ SPINOR_OP_READ_1_8_8, SPINOR_OP_READ_1_8_8_4B },
{ SPINOR_OP_READ_1_1_1_DTR, SPINOR_OP_READ_1_1_1_DTR_4B }, { SPINOR_OP_READ_1_1_1_DTR, SPINOR_OP_READ_1_1_1_DTR_4B },
{ SPINOR_OP_READ_1_2_2_DTR, SPINOR_OP_READ_1_2_2_DTR_4B }, { SPINOR_OP_READ_1_2_2_DTR, SPINOR_OP_READ_1_2_2_DTR_4B },
@ -414,6 +417,8 @@ static u8 spi_nor_convert_3to4_program(u8 opcode)
{ SPINOR_OP_PP, SPINOR_OP_PP_4B }, { SPINOR_OP_PP, SPINOR_OP_PP_4B },
{ SPINOR_OP_PP_1_1_4, SPINOR_OP_PP_1_1_4_4B }, { SPINOR_OP_PP_1_1_4, SPINOR_OP_PP_1_1_4_4B },
{ SPINOR_OP_PP_1_4_4, SPINOR_OP_PP_1_4_4_4B }, { SPINOR_OP_PP_1_4_4, SPINOR_OP_PP_1_4_4_4B },
{ SPINOR_OP_PP_1_1_8, SPINOR_OP_PP_1_1_8_4B },
{ SPINOR_OP_PP_1_8_8, SPINOR_OP_PP_1_8_8_4B },
}; };
return spi_nor_convert_opcode(opcode, spi_nor_3to4_program, return spi_nor_convert_opcode(opcode, spi_nor_3to4_program,
@ -1740,7 +1745,11 @@ static const struct flash_info spi_nor_ids[] = {
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) },
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
{ "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16,
SECT_4K | SPI_NOR_DUAL_READ) },
{ "en25qh32", INFO(0x1c7016, 0, 64 * 1024, 64, 0) }, { "en25qh32", INFO(0x1c7016, 0, 64 * 1024, 64, 0) },
{ "en25qh64", INFO(0x1c7017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ) },
{ "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) },
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
{ "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, SECT_4K) }, { "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, SECT_4K) },
@ -1836,6 +1845,8 @@ static const struct flash_info spi_nor_ids[] = {
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) }, { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) },
{ "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8, SECT_4K) }, { "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8, SECT_4K) },
{ "mx25u8035", INFO(0xc22534, 0, 64 * 1024, 16, SECT_4K) }, { "mx25u8035", INFO(0xc22534, 0, 64 * 1024, 16, SECT_4K) },
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
@ -1847,6 +1858,8 @@ static const struct flash_info spi_nor_ids[] = {
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
.fixups = &mx25l25635_fixups }, .fixups = &mx25l25635_fixups },
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
{ "mx25v8035f", INFO(0xc22314, 0, 64 * 1024, 16,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, { "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
@ -1872,7 +1885,8 @@ static const struct flash_info spi_nor_ids[] = {
/* Micron */ /* Micron */
{ {
"mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512, "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512,
SECT_4K | USE_FSR | SPI_NOR_4B_OPCODES) SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ |
SPI_NOR_4B_OPCODES)
}, },
/* PMC */ /* PMC */
@ -1885,13 +1899,17 @@ static const struct flash_info spi_nor_ids[] = {
*/ */
{ "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "s25fl128s0", INFO6(0x012018, 0x4d0080, 256 * 1024, 64,
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ "s25fl128s1", INFO6(0x012018, 0x4d0180, 64 * 1024, 256,
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, USE_CLSR) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, USE_CLSR) },
{ "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s25fl512s", INFO6(0x010220, 0x4d0080, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
{ "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) }, { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
{ "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) },
@ -3591,6 +3609,13 @@ static int spi_nor_init_params(struct spi_nor *nor,
SNOR_PROTO_1_1_4); SNOR_PROTO_1_1_4);
} }
if (info->flags & SPI_NOR_OCTAL_READ) {
params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_1_1_8],
0, 8, SPINOR_OP_READ_1_1_8,
SNOR_PROTO_1_1_8);
}
/* Page Program settings. */ /* Page Program settings. */
params->hwcaps.mask |= SNOR_HWCAPS_PP; params->hwcaps.mask |= SNOR_HWCAPS_PP;
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP], spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],

View File

@ -16,13 +16,12 @@
#ifndef __LINUX_MTD_RAWNAND_H #ifndef __LINUX_MTD_RAWNAND_H
#define __LINUX_MTD_RAWNAND_H #define __LINUX_MTD_RAWNAND_H
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/flashchip.h> #include <linux/mtd/flashchip.h>
#include <linux/mtd/bbm.h> #include <linux/mtd/bbm.h>
#include <linux/mtd/jedec.h> #include <linux/mtd/jedec.h>
#include <linux/mtd/onfi.h> #include <linux/mtd/onfi.h>
#include <linux/mutex.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/types.h> #include <linux/types.h>
@ -897,25 +896,17 @@ struct nand_controller_ops {
/** /**
* struct nand_controller - Structure used to describe a NAND controller * struct nand_controller - Structure used to describe a NAND controller
* *
* @lock: protection lock * @lock: lock used to serialize accesses to the NAND controller
* @active: the mtd device which holds the controller currently
* @wq: wait queue to sleep on if a NAND operation is in
* progress used instead of the per chip wait queue
* when a hw controller is available.
* @ops: NAND controller operations. * @ops: NAND controller operations.
*/ */
struct nand_controller { struct nand_controller {
spinlock_t lock; struct mutex lock;
struct nand_chip *active;
wait_queue_head_t wq;
const struct nand_controller_ops *ops; const struct nand_controller_ops *ops;
}; };
static inline void nand_controller_init(struct nand_controller *nfc) static inline void nand_controller_init(struct nand_controller *nfc)
{ {
nfc->active = NULL; mutex_init(&nfc->lock);
spin_lock_init(&nfc->lock);
init_waitqueue_head(&nfc->wq);
} }
/** /**
@ -936,7 +927,6 @@ static inline void nand_controller_init(struct nand_controller *nfc)
* @waitfunc: hardware specific function for wait on ready. * @waitfunc: hardware specific function for wait on ready.
* @block_bad: check if a block is bad, using OOB markers * @block_bad: check if a block is bad, using OOB markers
* @block_markbad: mark a block bad * @block_markbad: mark a block bad
* @erase: erase function
* @set_features: set the NAND chip features * @set_features: set the NAND chip features
* @get_features: get the NAND chip features * @get_features: get the NAND chip features
* @chip_delay: chip dependent delay for transferring data from array to read * @chip_delay: chip dependent delay for transferring data from array to read
@ -962,7 +952,6 @@ struct nand_legacy {
int (*waitfunc)(struct nand_chip *chip); int (*waitfunc)(struct nand_chip *chip);
int (*block_bad)(struct nand_chip *chip, loff_t ofs); int (*block_bad)(struct nand_chip *chip, loff_t ofs);
int (*block_markbad)(struct nand_chip *chip, loff_t ofs); int (*block_markbad)(struct nand_chip *chip, loff_t ofs);
int (*erase)(struct nand_chip *chip, int page);
int (*set_features)(struct nand_chip *chip, int feature_addr, int (*set_features)(struct nand_chip *chip, int feature_addr,
u8 *subfeature_para); u8 *subfeature_para);
int (*get_features)(struct nand_chip *chip, int feature_addr, int (*get_features)(struct nand_chip *chip, int feature_addr,
@ -983,7 +972,6 @@ struct nand_legacy {
* setting the read-retry mode. Mostly needed for MLC NAND. * setting the read-retry mode. Mostly needed for MLC NAND.
* @ecc: [BOARDSPECIFIC] ECC control structure * @ecc: [BOARDSPECIFIC] ECC control structure
* @buf_align: minimum buffer alignment required by a platform * @buf_align: minimum buffer alignment required by a platform
* @state: [INTERN] the current state of the NAND device
* @oob_poi: "poison value buffer," used for laying out OOB data * @oob_poi: "poison value buffer," used for laying out OOB data
* before writing * before writing
* @page_shift: [INTERN] number of address bits in a page (column * @page_shift: [INTERN] number of address bits in a page (column
@ -1034,6 +1022,9 @@ struct nand_legacy {
* cur_cs < numchips. NAND Controller drivers should not * cur_cs < numchips. NAND Controller drivers should not
* modify this value, but they're allowed to read it. * modify this value, but they're allowed to read it.
* @read_retries: [INTERN] the number of read retry modes supported * @read_retries: [INTERN] the number of read retry modes supported
* @lock: lock protecting the suspended field. Also used to
* serialize accesses to the NAND device.
* @suspended: set to 1 when the device is suspended, 0 when it's not.
* @bbt: [INTERN] bad block table pointer * @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash * @bbt_td: [REPLACEABLE] bad block table descriptor for flash
* lookup. * lookup.
@ -1088,7 +1079,8 @@ struct nand_chip {
int read_retries; int read_retries;
flstate_t state; struct mutex lock;
unsigned int suspended : 1;
uint8_t *oob_poi; uint8_t *oob_poi;
struct nand_controller *controller; struct nand_controller *controller;

View File

@ -46,9 +46,13 @@
#define SPINOR_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */ #define SPINOR_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */
#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */ #define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */
#define SPINOR_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */ #define SPINOR_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */
#define SPINOR_OP_READ_1_1_8 0x8b /* Read data bytes (Octal Output SPI) */
#define SPINOR_OP_READ_1_8_8 0xcb /* Read data bytes (Octal I/O SPI) */
#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */ #define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */
#define SPINOR_OP_PP_1_1_4 0x32 /* Quad page program */ #define SPINOR_OP_PP_1_1_4 0x32 /* Quad page program */
#define SPINOR_OP_PP_1_4_4 0x38 /* Quad page program */ #define SPINOR_OP_PP_1_4_4 0x38 /* Quad page program */
#define SPINOR_OP_PP_1_1_8 0x82 /* Octal page program */
#define SPINOR_OP_PP_1_8_8 0xc2 /* Octal page program */
#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */ #define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */
#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ #define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
#define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */ #define SPINOR_OP_BE_32K 0x52 /* Erase 32KiB block */
@ -69,9 +73,13 @@
#define SPINOR_OP_READ_1_2_2_4B 0xbc /* Read data bytes (Dual I/O SPI) */ #define SPINOR_OP_READ_1_2_2_4B 0xbc /* Read data bytes (Dual I/O SPI) */
#define SPINOR_OP_READ_1_1_4_4B 0x6c /* Read data bytes (Quad Output SPI) */ #define SPINOR_OP_READ_1_1_4_4B 0x6c /* Read data bytes (Quad Output SPI) */
#define SPINOR_OP_READ_1_4_4_4B 0xec /* Read data bytes (Quad I/O SPI) */ #define SPINOR_OP_READ_1_4_4_4B 0xec /* Read data bytes (Quad I/O SPI) */
#define SPINOR_OP_READ_1_1_8_4B 0x7c /* Read data bytes (Octal Output SPI) */
#define SPINOR_OP_READ_1_8_8_4B 0xcc /* Read data bytes (Octal I/O SPI) */
#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */ #define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */
#define SPINOR_OP_PP_1_1_4_4B 0x34 /* Quad page program */ #define SPINOR_OP_PP_1_1_4_4B 0x34 /* Quad page program */
#define SPINOR_OP_PP_1_4_4_4B 0x3e /* Quad page program */ #define SPINOR_OP_PP_1_4_4_4B 0x3e /* Quad page program */
#define SPINOR_OP_PP_1_1_8_4B 0x84 /* Octal page program */
#define SPINOR_OP_PP_1_8_8_4B 0x8e /* Octal page program */
#define SPINOR_OP_BE_4K_4B 0x21 /* Erase 4KiB block */ #define SPINOR_OP_BE_4K_4B 0x21 /* Erase 4KiB block */
#define SPINOR_OP_BE_32K_4B 0x5c /* Erase 32KiB block */ #define SPINOR_OP_BE_32K_4B 0x5c /* Erase 32KiB block */
#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */ #define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */
@ -458,7 +466,7 @@ struct spi_nor_hwcaps {
/* /*
*(Fast) Read capabilities. *(Fast) Read capabilities.
* MUST be ordered by priority: the higher bit position, the higher priority. * MUST be ordered by priority: the higher bit position, the higher priority.
* As a matter of performances, it is relevant to use Octo SPI protocols first, * As a matter of performances, it is relevant to use Octal SPI protocols first,
* then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly * then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
* (Slow) Read. * (Slow) Read.
*/ */
@ -479,7 +487,7 @@ struct spi_nor_hwcaps {
#define SNOR_HWCAPS_READ_4_4_4 BIT(9) #define SNOR_HWCAPS_READ_4_4_4 BIT(9)
#define SNOR_HWCAPS_READ_1_4_4_DTR BIT(10) #define SNOR_HWCAPS_READ_1_4_4_DTR BIT(10)
#define SNOR_HWCPAS_READ_OCTO GENMASK(14, 11) #define SNOR_HWCAPS_READ_OCTAL GENMASK(14, 11)
#define SNOR_HWCAPS_READ_1_1_8 BIT(11) #define SNOR_HWCAPS_READ_1_1_8 BIT(11)
#define SNOR_HWCAPS_READ_1_8_8 BIT(12) #define SNOR_HWCAPS_READ_1_8_8 BIT(12)
#define SNOR_HWCAPS_READ_8_8_8 BIT(13) #define SNOR_HWCAPS_READ_8_8_8 BIT(13)
@ -488,7 +496,7 @@ struct spi_nor_hwcaps {
/* /*
* Page Program capabilities. * Page Program capabilities.
* MUST be ordered by priority: the higher bit position, the higher priority. * MUST be ordered by priority: the higher bit position, the higher priority.
* Like (Fast) Read capabilities, Octo/Quad SPI protocols are preferred to the * Like (Fast) Read capabilities, Octal/Quad SPI protocols are preferred to the
* legacy SPI 1-1-1 protocol. * legacy SPI 1-1-1 protocol.
* Note that Dual Page Programs are not supported because there is no existing * Note that Dual Page Programs are not supported because there is no existing
* JEDEC/SFDP standard to define them. Also at this moment no SPI flash memory * JEDEC/SFDP standard to define them. Also at this moment no SPI flash memory
@ -502,7 +510,7 @@ struct spi_nor_hwcaps {
#define SNOR_HWCAPS_PP_1_4_4 BIT(18) #define SNOR_HWCAPS_PP_1_4_4 BIT(18)
#define SNOR_HWCAPS_PP_4_4_4 BIT(19) #define SNOR_HWCAPS_PP_4_4_4 BIT(19)
#define SNOR_HWCAPS_PP_OCTO GENMASK(22, 20) #define SNOR_HWCAPS_PP_OCTAL GENMASK(22, 20)
#define SNOR_HWCAPS_PP_1_1_8 BIT(20) #define SNOR_HWCAPS_PP_1_1_8 BIT(20)
#define SNOR_HWCAPS_PP_1_8_8 BIT(21) #define SNOR_HWCAPS_PP_1_8_8 BIT(21)
#define SNOR_HWCAPS_PP_8_8_8 BIT(22) #define SNOR_HWCAPS_PP_8_8_8 BIT(22)