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:
commit
811c16a2a2
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -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/
|
||||||
|
|
|
@ -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
|
||||||
* 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)
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
#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)
|
||||||
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,
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -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/
|
||||||
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,
|
||||||
{
|
{
|
||||||
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 @@
|
||||||
#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)
|
||||||
|
|
|
@ -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)
|
||||||
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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
@ -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)
|
||||||
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);
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */ }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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(¶ms->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(¶ms->page_programs[SNOR_CMD_PP],
|
spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP],
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue