Commit c01d85c2 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mtd/for-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux

Pull MTD updates from Miquel Raynal:
 "MTD core changes:

   - mtdchar: Prevent unbounded allocation in MEMWRITE ioctl

   - gen_probe: Use bitmap_zalloc() when applicable

   - Introduce an expert mode for forensics and debugging purposes

   - Clear out unregistered devices a bit more

   - Provide unique name for nvmem device

   - Remove unused header file <linux/mtd/latch-addr-flash.h>

   - Fixed breaking list in __mtd_del_partition.

  MTD device changes:

   - Warn about failure to unregister mtd device in sst25l, mchp48l640,
     mchp23k256, and dataflash drivers.

  Raw NAND core changes:

   - Export nand_read_page_hwecc_oob_first()

  GPMC memory controller for OMAP2 NAND controller changes:

   - Add support for AM64 SoC and allow build on K3 platforms

   - Use a compatible match table when checking for NAND controller

   - Use platform_get_irq() to get the interrupt

  Raw NAND controller changes:

   - OMAP2 NAND controller:
      - Document the missing 'rb-gpios' DT property
      - Drop unused variable
      - Fix force_8bit flag behaviour for DMA mode
      - Move to exec_op interface
      - Use platform_get_irq() to get the interrupt

   - Renesas:
      - Add new NAND controller driver with its bindings and MAINTAINERS entry

   - Onenand:
      - Remove redundant variable ooblen

   - MPC5121:
      - Remove unused variable in ads5121_select_chip()

   - GPMI:
      - Add ERR007117 protection for nfc_apply_timings
      - Remove explicit default gpmi clock setting for i.MX6
      - Use platform_get_irq_byname() to get the interrupt
      - Remove unneeded variable

   - Ingenic:
      - JZ4740 needs 'oob_first' read page function

   - Davinci:
      - Rewrite function description
      - Avoid duplicated page read
      - Don't calculate ECC when reading page

  SPI NOR core changes:

   - Add Pratyush as SPI NOR co-maintainer.

   - Flash parameters initialization was done in a spaghetti way. Clean
     flash parameters initialization.

   - Rework the flash_info flags and clarify where one should be used.

   - Initialize all flash parameters based on JESD216 SFDP where
     possible. Flash parameters and settings that are SFDP discoverable
     should not be duplicated via flash_info flags at flash declaration.

   - Remove debugfs entries that duplicate sysfs entries.

  SPI NOR manufacturer driver changes:

   - Use late_init() hook in various drivers to make it clear that those
     flash parameters are either not declared in the JESD216 SFDP
     standard, or the SFDP tables which define those flash parameters
     are not defined by the flash.

   - Fix mtd size for s3an flashes.

   - Write 2 bytes when disabling Octal DTR mode: 1 byte long
     transactions are not allowed in 8D-8D-8D mode.

  Hyperbus changes:

   - Couple of fixes in Renesas hyperbus rpc-if driver to avoid crash on
     module remove and for missing check for error value in probe"

* tag 'mtd/for-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (71 commits)
  mtd: spi-nor: Remove debugfs entries that duplicate sysfs entries
  mtd: spi-nor: micron-st: write 2 bytes when disabling Octal DTR mode
  mtd: spi-nor: spansion: write 2 bytes when disabling Octal DTR mode
  mtd: spi-nor: core: use 2 data bytes for template ops
  mtd: spi-nor: Constify part specific fixup hooks
  mtd: spi-nor: core: Remove reference to spi-nor.c
  mtd: rawnand: gpmi: Use platform_get_irq_byname() to get the interrupt
  mtd: rawnand: omap_elm: Use platform_get_irq() to get the interrupt
  mtd: rawnand: omap2: Select GPMC device driver for ARCH_K3
  memory: omap-gpmc: Use a compatible match table when checking for NAND controller
  memory: omap-gpmc: Add support for GPMC on AM64 SoC
  dt-bindings: memory-controllers: ti,gpmc: Add compatible for AM64
  memory: omap-gpmc: Use platform_get_irq() to get the interrupt
  MAINTAINERS: Add an entry for Renesas NAND controller
  mtd: rawnand: renesas: Add new NAND controller driver
  dt-bindings: mtd: renesas: Describe Renesas R-Car Gen3 & RZ/N1 NAND controller
  mtd: rawnand: gpmi: remove unneeded variable
  mtd: rawnand: omap2: drop unused variable
  mtd: rawnand: omap2: fix force_8bit flag behaviour for DMA mode
  mtd: rawnand: omap2: Add compatible for AM64 SoC
  ...
parents 34770887 9ce47e43
...@@ -23,13 +23,20 @@ properties: ...@@ -23,13 +23,20 @@ properties:
items: items:
- enum: - enum:
- ti,am3352-gpmc - ti,am3352-gpmc
- ti,am64-gpmc
- ti,omap2420-gpmc - ti,omap2420-gpmc
- ti,omap2430-gpmc - ti,omap2430-gpmc
- ti,omap3430-gpmc - ti,omap3430-gpmc
- ti,omap4430-gpmc - ti,omap4430-gpmc
reg: reg:
maxItems: 1 minItems: 1
maxItems: 2
reg-names:
items:
- const: cfg
- const: data
interrupts: interrupts:
maxItems: 1 maxItems: 1
...@@ -44,6 +51,9 @@ properties: ...@@ -44,6 +51,9 @@ properties:
items: items:
- const: fck - const: fck
power-domains:
maxItems: 1
dmas: dmas:
items: items:
- description: DMA channel for GPMC NAND prefetch - description: DMA channel for GPMC NAND prefetch
...@@ -133,6 +143,17 @@ required: ...@@ -133,6 +143,17 @@ required:
- "#address-cells" - "#address-cells"
- "#size-cells" - "#size-cells"
allOf:
- if:
properties:
compatible:
contains:
const: ti,am64-gpmc
then:
required:
- reg-names
- power-domains
additionalProperties: false additionalProperties: false
examples: examples:
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mtd/renesas-nandc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas R-Car Gen3 & RZ/N1x NAND flash controller device tree bindings
maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com>
allOf:
- $ref: "nand-controller.yaml"
properties:
compatible:
oneOf:
- items:
- enum:
- renesas,r9a06g032-nandc
- const: renesas,rzn1-nandc
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: APB host controller clock
- description: External NAND bus clock
clock-names:
items:
- const: hclk
- const: eclk
required:
- compatible
- reg
- clocks
- clock-names
- interrupts
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/r9a06g032-sysctrl.h>
nand-controller@40102000 {
compatible = "renesas,r9a06g032-nandc", "renesas,rzn1-nandc";
reg = <0x40102000 0x2000>;
interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&sysctrl R9A06G032_HCLK_NAND>, <&sysctrl R9A06G032_CLK_NAND>;
clock-names = "hclk", "eclk";
#address-cells = <1>;
#size-cells = <0>;
};
...@@ -16,7 +16,10 @@ description: ...@@ -16,7 +16,10 @@ description:
properties: properties:
compatible: compatible:
const: ti,omap2-nand items:
- enum:
- ti,am64-nand
- ti,omap2-nand
reg: reg:
maxItems: 1 maxItems: 1
...@@ -53,6 +56,11 @@ properties: ...@@ -53,6 +56,11 @@ properties:
enum: [8, 16] enum: [8, 16]
default: 8 default: 8
rb-gpios:
description:
GPIO connection to R/B signal from NAND chip
maxItems: 1
patternProperties: patternProperties:
"@[0-9a-f]+$": "@[0-9a-f]+$":
$ref: "/schemas/mtd/partitions/partition.yaml" $ref: "/schemas/mtd/partitions/partition.yaml"
......
...@@ -16416,6 +16416,14 @@ S: Supported ...@@ -16416,6 +16416,14 @@ S: Supported
F: Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml F: Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
F: drivers/iio/adc/rzg2l_adc.c F: drivers/iio/adc/rzg2l_adc.c
RENESAS R-CAR GEN3 & RZ/N1 NAND CONTROLLER DRIVER
M: Miquel Raynal <miquel.raynal@bootlin.com>
L: linux-mtd@lists.infradead.org
L: linux-renesas-soc@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/mtd/renesas-nandc.yaml
F: drivers/mtd/nand/raw/renesas-nand-controller.c
RESET CONTROLLER FRAMEWORK RESET CONTROLLER FRAMEWORK
M: Philipp Zabel <p.zabel@pengutronix.de> M: Philipp Zabel <p.zabel@pengutronix.de>
S: Maintained S: Maintained
...@@ -18084,8 +18092,8 @@ F: drivers/pinctrl/spear/ ...@@ -18084,8 +18092,8 @@ F: drivers/pinctrl/spear/
SPI NOR SUBSYSTEM SPI NOR SUBSYSTEM
M: Tudor Ambarus <tudor.ambarus@microchip.com> M: Tudor Ambarus <tudor.ambarus@microchip.com>
M: Pratyush Yadav <p.yadav@ti.com>
R: Michael Walle <michael@walle.cc> R: Michael Walle <michael@walle.cc>
R: Pratyush Yadav <p.yadav@ti.com>
L: linux-mtd@lists.infradead.org L: linux-mtd@lists.infradead.org
S: Maintained S: Maintained
W: http://www.linux-mtd.infradead.org/ W: http://www.linux-mtd.infradead.org/
......
...@@ -237,6 +237,7 @@ struct gpmc_device { ...@@ -237,6 +237,7 @@ struct gpmc_device {
struct omap3_gpmc_regs context; struct omap3_gpmc_regs context;
int nirqs; int nirqs;
unsigned int is_suspended:1; unsigned int is_suspended:1;
struct resource *data;
}; };
static struct irq_domain *gpmc_irq_domain; static struct irq_domain *gpmc_irq_domain;
...@@ -1456,12 +1457,18 @@ static void gpmc_mem_exit(void) ...@@ -1456,12 +1457,18 @@ static void gpmc_mem_exit(void)
} }
} }
static void gpmc_mem_init(void) static void gpmc_mem_init(struct gpmc_device *gpmc)
{ {
int cs; int cs;
gpmc_mem_root.start = GPMC_MEM_START; if (!gpmc->data) {
gpmc_mem_root.end = GPMC_MEM_END; /* All legacy devices have same data IO window */
gpmc_mem_root.start = GPMC_MEM_START;
gpmc_mem_root.end = GPMC_MEM_END;
} else {
gpmc_mem_root.start = gpmc->data->start;
gpmc_mem_root.end = gpmc->data->end;
}
/* Reserve all regions that has been set up by bootloader */ /* Reserve all regions that has been set up by bootloader */
for (cs = 0; cs < gpmc_cs_num; cs++) { for (cs = 0; cs < gpmc_cs_num; cs++) {
...@@ -1888,6 +1895,7 @@ static const struct of_device_id gpmc_dt_ids[] = { ...@@ -1888,6 +1895,7 @@ static const struct of_device_id gpmc_dt_ids[] = {
{ .compatible = "ti,omap3430-gpmc" }, /* omap3430 & omap3630 */ { .compatible = "ti,omap3430-gpmc" }, /* omap3430 & omap3630 */
{ .compatible = "ti,omap4430-gpmc" }, /* omap4430 & omap4460 & omap543x */ { .compatible = "ti,omap4430-gpmc" }, /* omap4430 & omap4460 & omap543x */
{ .compatible = "ti,am3352-gpmc" }, /* am335x devices */ { .compatible = "ti,am3352-gpmc" }, /* am335x devices */
{ .compatible = "ti,am64-gpmc" },
{ } { }
}; };
...@@ -2175,7 +2183,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, ...@@ -2175,7 +2183,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
} }
} }
if (of_device_is_compatible(child, "ti,omap2-nand")) { if (of_match_node(omap_nand_ids, child)) {
/* NAND specific setup */ /* NAND specific setup */
val = 8; val = 8;
of_property_read_u32(child, "nand-bus-width", &val); of_property_read_u32(child, "nand-bus-width", &val);
...@@ -2502,21 +2510,29 @@ static int gpmc_probe(struct platform_device *pdev) ...@@ -2502,21 +2510,29 @@ static int gpmc_probe(struct platform_device *pdev)
gpmc->dev = &pdev->dev; gpmc->dev = &pdev->dev;
platform_set_drvdata(pdev, gpmc); platform_set_drvdata(pdev, gpmc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
if (!res)
return -ENOENT;
gpmc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(gpmc_base))
return PTR_ERR(gpmc_base);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) { if (!res) {
dev_err(&pdev->dev, "Failed to get resource: irq\n"); /* legacy DT */
return -ENOENT; gpmc_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(gpmc_base))
return PTR_ERR(gpmc_base);
} else {
gpmc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(gpmc_base))
return PTR_ERR(gpmc_base);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "data");
if (!res) {
dev_err(&pdev->dev, "couldn't get data reg resource\n");
return -ENOENT;
}
gpmc->data = res;
} }
gpmc->irq = res->start; gpmc->irq = platform_get_irq(pdev, 0);
if (gpmc->irq < 0)
return gpmc->irq;
gpmc_l3_clk = devm_clk_get(&pdev->dev, "fck"); gpmc_l3_clk = devm_clk_get(&pdev->dev, "fck");
if (IS_ERR(gpmc_l3_clk)) { if (IS_ERR(gpmc_l3_clk)) {
...@@ -2562,7 +2578,7 @@ static int gpmc_probe(struct platform_device *pdev) ...@@ -2562,7 +2578,7 @@ static int gpmc_probe(struct platform_device *pdev)
dev_info(gpmc->dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l), dev_info(gpmc->dev, "GPMC revision %d.%d\n", GPMC_REVISION_MAJOR(l),
GPMC_REVISION_MINOR(l)); GPMC_REVISION_MINOR(l));
gpmc_mem_init(); gpmc_mem_init(gpmc);
rc = gpmc_gpio_init(gpmc); rc = gpmc_gpio_init(gpmc);
if (rc) if (rc)
goto gpio_init_failed; goto gpio_init_failed;
......
...@@ -61,8 +61,8 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi ...@@ -61,8 +61,8 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
struct cfi_private cfi; struct cfi_private cfi;
struct cfi_private *retcfi; struct cfi_private *retcfi;
unsigned long *chip_map; unsigned long *chip_map;
int i, j, mapsize;
int max_chips; int max_chips;
int i, j;
memset(&cfi, 0, sizeof(cfi)); memset(&cfi, 0, sizeof(cfi));
...@@ -111,8 +111,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi ...@@ -111,8 +111,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
max_chips = 1; max_chips = 1;
} }
mapsize = sizeof(long) * DIV_ROUND_UP(max_chips, BITS_PER_LONG); chip_map = bitmap_zalloc(max_chips, GFP_KERNEL);
chip_map = kzalloc(mapsize, GFP_KERNEL);
if (!chip_map) { if (!chip_map) {
kfree(cfi.cfiq); kfree(cfi.cfiq);
return NULL; return NULL;
...@@ -139,7 +138,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi ...@@ -139,7 +138,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
if (!retcfi) { if (!retcfi) {
kfree(cfi.cfiq); kfree(cfi.cfiq);
kfree(chip_map); bitmap_free(chip_map);
return NULL; return NULL;
} }
...@@ -157,7 +156,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi ...@@ -157,7 +156,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
} }
} }
kfree(chip_map); bitmap_free(chip_map);
return retcfi; return retcfi;
} }
......
...@@ -213,7 +213,9 @@ static int mchp23k256_remove(struct spi_device *spi) ...@@ -213,7 +213,9 @@ static int mchp23k256_remove(struct spi_device *spi)
{ {
struct mchp23k256_flash *flash = spi_get_drvdata(spi); struct mchp23k256_flash *flash = spi_get_drvdata(spi);
return mtd_device_unregister(&flash->mtd); WARN_ON(mtd_device_unregister(&flash->mtd));
return 0;
} }
static const struct of_device_id mchp23k256_of_table[] = { static const struct of_device_id mchp23k256_of_table[] = {
......
...@@ -345,7 +345,9 @@ static int mchp48l640_remove(struct spi_device *spi) ...@@ -345,7 +345,9 @@ static int mchp48l640_remove(struct spi_device *spi)
{ {
struct mchp48l640_flash *flash = spi_get_drvdata(spi); struct mchp48l640_flash *flash = spi_get_drvdata(spi);
return mtd_device_unregister(&flash->mtd); WARN_ON(mtd_device_unregister(&flash->mtd));
return 0;
} }
static const struct of_device_id mchp48l640_of_table[] = { static const struct of_device_id mchp48l640_of_table[] = {
......
...@@ -919,14 +919,14 @@ static int dataflash_probe(struct spi_device *spi) ...@@ -919,14 +919,14 @@ static int dataflash_probe(struct spi_device *spi)
static int dataflash_remove(struct spi_device *spi) static int dataflash_remove(struct spi_device *spi)
{ {
struct dataflash *flash = spi_get_drvdata(spi); struct dataflash *flash = spi_get_drvdata(spi);
int status;
dev_dbg(&spi->dev, "remove\n"); dev_dbg(&spi->dev, "remove\n");
status = mtd_device_unregister(&flash->mtd); WARN_ON(mtd_device_unregister(&flash->mtd));
if (status == 0)
kfree(flash); kfree(flash);
return status;
return 0;
} }
static struct spi_driver dataflash_driver = { static struct spi_driver dataflash_driver = {
......
...@@ -402,7 +402,9 @@ static int sst25l_remove(struct spi_device *spi) ...@@ -402,7 +402,9 @@ static int sst25l_remove(struct spi_device *spi)
{ {
struct sst25l_flash *flash = spi_get_drvdata(spi); struct sst25l_flash *flash = spi_get_drvdata(spi);
return mtd_device_unregister(&flash->mtd); WARN_ON(mtd_device_unregister(&flash->mtd));
return 0;
} }
static struct spi_driver sst25l_driver = { static struct spi_driver sst25l_driver = {
......
...@@ -124,7 +124,9 @@ static int rpcif_hb_probe(struct platform_device *pdev) ...@@ -124,7 +124,9 @@ static int rpcif_hb_probe(struct platform_device *pdev)
if (!hyperbus) if (!hyperbus)
return -ENOMEM; return -ENOMEM;
rpcif_sw_init(&hyperbus->rpc, pdev->dev.parent); error = rpcif_sw_init(&hyperbus->rpc, pdev->dev.parent);
if (error)
return error;
platform_set_drvdata(pdev, hyperbus); platform_set_drvdata(pdev, hyperbus);
...@@ -152,9 +154,9 @@ static int rpcif_hb_remove(struct platform_device *pdev) ...@@ -152,9 +154,9 @@ static int rpcif_hb_remove(struct platform_device *pdev)
{ {
struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev); struct rpcif_hyperbus *hyperbus = platform_get_drvdata(pdev);
int error = hyperbus_unregister_device(&hyperbus->hbdev); int error = hyperbus_unregister_device(&hyperbus->hbdev);
struct rpcif *rpc = dev_get_drvdata(pdev->dev.parent);
rpcif_disable_rpm(rpc); rpcif_disable_rpm(&hyperbus->rpc);
return error; return error;
} }
......
...@@ -573,14 +573,32 @@ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd, ...@@ -573,14 +573,32 @@ static int mtdchar_blkpg_ioctl(struct mtd_info *mtd,
} }
} }
static void adjust_oob_length(struct mtd_info *mtd, uint64_t start,
struct mtd_oob_ops *ops)
{
uint32_t start_page, end_page;
u32 oob_per_page;
if (ops->len == 0 || ops->ooblen == 0)
return;
start_page = mtd_div_by_ws(start, mtd);
end_page = mtd_div_by_ws(start + ops->len - 1, mtd);
oob_per_page = mtd_oobavail(mtd, ops);
ops->ooblen = min_t(size_t, ops->ooblen,
(end_page - start_page + 1) * oob_per_page);
}
static int mtdchar_write_ioctl(struct mtd_info *mtd, static int mtdchar_write_ioctl(struct mtd_info *mtd,
struct mtd_write_req __user *argp) struct mtd_write_req __user *argp)
{ {
struct mtd_info *master = mtd_get_master(mtd); struct mtd_info *master = mtd_get_master(mtd);
struct mtd_write_req req; struct mtd_write_req req;
struct mtd_oob_ops ops = {};
const void __user *usr_data, *usr_oob; const void __user *usr_data, *usr_oob;
int ret; uint8_t *datbuf = NULL, *oobbuf = NULL;
size_t datbuf_len, oobbuf_len;
int ret = 0;
if (copy_from_user(&req, argp, sizeof(req))) if (copy_from_user(&req, argp, sizeof(req)))
return -EFAULT; return -EFAULT;
...@@ -590,33 +608,79 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd, ...@@ -590,33 +608,79 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd,
if (!master->_write_oob) if (!master->_write_oob)
return -EOPNOTSUPP; return -EOPNOTSUPP;
ops.mode = req.mode;
ops.len = (size_t)req.len; if (!usr_data)
ops.ooblen = (size_t)req.ooblen; req.len = 0;
ops.ooboffs = 0;
if (!usr_oob)
if (usr_data) { req.ooblen = 0;
ops.datbuf = memdup_user(usr_data, ops.len);
if (IS_ERR(ops.datbuf)) if (req.start + req.len > mtd->size)
return PTR_ERR(ops.datbuf); return -EINVAL;
} else {
ops.datbuf = NULL; datbuf_len = min_t(size_t, req.len, mtd->erasesize);
if (datbuf_len > 0) {
datbuf = kmalloc(datbuf_len, GFP_KERNEL);
if (!datbuf)
return -ENOMEM;
} }
if (usr_oob) { oobbuf_len = min_t(size_t, req.ooblen, mtd->erasesize);
ops.oobbuf = memdup_user(usr_oob, ops.ooblen); if (oobbuf_len > 0) {
if (IS_ERR(ops.oobbuf)) { oobbuf = kmalloc(oobbuf_len, GFP_KERNEL);
kfree(ops.datbuf); if (!oobbuf) {
return PTR_ERR(ops.oobbuf); kfree(datbuf);
return -ENOMEM;
} }
} else {
ops.oobbuf = NULL;
} }
ret = mtd_write_oob(mtd, (loff_t)req.start, &ops); while (req.len > 0 || (!usr_data && req.ooblen > 0)) {
struct mtd_oob_ops ops = {
.mode = req.mode,
.len = min_t(size_t, req.len, datbuf_len),
.ooblen = min_t(size_t, req.ooblen, oobbuf_len),
.datbuf = datbuf,
.oobbuf = oobbuf,
};
kfree(ops.datbuf); /*
kfree(ops.oobbuf); * Shorten non-page-aligned, eraseblock-sized writes so that
* the write ends on an eraseblock boundary. This is necessary
* for adjust_oob_length() to properly handle non-page-aligned
* writes.
*/
if (ops.len == mtd->erasesize)
ops.len -= mtd_mod_by_ws(req.start + ops.len, mtd);
/*
* For writes which are not OOB-only, adjust the amount of OOB
* data written according to the number of data pages written.
* This is necessary to prevent OOB data from being skipped
* over in data+OOB writes requiring multiple mtd_write_oob()
* calls to be completed.
*/
adjust_oob_length(mtd, req.start, &ops);
if (copy_from_user(datbuf, usr_data, ops.len) ||
copy_from_user(oobbuf, usr_oob, ops.ooblen)) {
ret = -EFAULT;
break;
}
ret = mtd_write_oob(mtd, req.start, &ops);
if (ret)
break;
req.start += ops.retlen;
req.len -= ops.retlen;
usr_data += ops.retlen;
req.ooblen -= ops.oobretlen;
usr_oob += ops.oobretlen;
}
kfree(datbuf);
kfree(oobbuf);
return ret; return ret;
} }
......
...@@ -747,6 +747,9 @@ int del_mtd_device(struct mtd_info *mtd) ...@@ -747,6 +747,9 @@ int del_mtd_device(struct mtd_info *mtd)
device_unregister(&mtd->dev); device_unregister(&mtd->dev);
/* Clear dev so mtd can be safely re-registered later if desired */
memset(&mtd->dev, 0, sizeof(mtd->dev));
idr_remove(&mtd_idr, mtd->index); idr_remove(&mtd_idr, mtd->index);
of_node_put(mtd_get_of_node(mtd)); of_node_put(mtd_get_of_node(mtd));
...@@ -825,8 +828,7 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd, ...@@ -825,8 +828,7 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd,
/* OTP nvmem will be registered on the physical device */ /* OTP nvmem will be registered on the physical device */
config.dev = mtd->dev.parent; config.dev = mtd->dev.parent;
/* just reuse the compatible as name */ config.name = kasprintf(GFP_KERNEL, "%s-%s", dev_name(&mtd->dev), compatible);
config.name = compatible;
config.id = NVMEM_DEVID_NONE; config.id = NVMEM_DEVID_NONE;
config.owner = THIS_MODULE; config.owner = THIS_MODULE;
config.type = NVMEM_TYPE_OTP; config.type = NVMEM_TYPE_OTP;
...@@ -842,6 +844,7 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd, ...@@ -842,6 +844,7 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd,
nvmem = NULL; nvmem = NULL;
of_node_put(np); of_node_put(np);
kfree(config.name);
return nvmem; return nvmem;
} }
...@@ -1018,8 +1021,10 @@ int mtd_device_unregister(struct mtd_info *master) ...@@ -1018,8 +1021,10 @@ int mtd_device_unregister(struct mtd_info *master)
{ {
int err; int err;
if (master->_reboot) if (master->_reboot) {
unregister_reboot_notifier(&master->reboot_notifier); unregister_reboot_notifier(&master->reboot_notifier);
memset(&master->reboot_notifier, 0, sizeof(master->reboot_notifier));
}
if (master->otp_user_nvmem) if (master->otp_user_nvmem)
nvmem_unregister(master->otp_user_nvmem); nvmem_unregister(master->otp_user_nvmem);
...@@ -2365,6 +2370,14 @@ static struct backing_dev_info * __init mtd_bdi_init(const char *name) ...@@ -2365,6 +2370,14 @@ static struct backing_dev_info * __init mtd_bdi_init(const char *name)
return ret ? ERR_PTR(ret) : bdi; return ret ? ERR_PTR(ret) : bdi;
} }
char *mtd_expert_analysis_warning =
"Bad block checks have been entirely disabled.\n"
"This is only reserved for post-mortem forensics and debug purposes.\n"
"Never enable this mode if you do not know what you are doing!\n";
EXPORT_SYMBOL_GPL(mtd_expert_analysis_warning);
bool mtd_expert_analysis_mode;
EXPORT_SYMBOL_GPL(mtd_expert_analysis_mode);
static struct proc_dir_entry *proc_mtd; static struct proc_dir_entry *proc_mtd;
static int __init init_mtd(void) static int __init init_mtd(void)
...@@ -2388,6 +2401,8 @@ static int __init init_mtd(void) ...@@ -2388,6 +2401,8 @@ static int __init init_mtd(void)
goto out_procfs; goto out_procfs;
dfs_dir_mtd = debugfs_create_dir("mtd", NULL); dfs_dir_mtd = debugfs_create_dir("mtd", NULL);
debugfs_create_bool("expert_analysis_mode", 0600, dfs_dir_mtd,
&mtd_expert_analysis_mode);
return 0; return 0;
......
...@@ -312,7 +312,7 @@ static int __mtd_del_partition(struct mtd_info *mtd) ...@@ -312,7 +312,7 @@ static int __mtd_del_partition(struct mtd_info *mtd)
if (err) if (err)
return err; return err;
list_del(&child->part.node); list_del(&mtd->part.node);
free_partition(mtd); free_partition(mtd);
return 0; return 0;
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
*/ */
bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos) bool nanddev_isbad(struct nand_device *nand, const struct nand_pos *pos)
{ {
if (WARN_ONCE(mtd_expert_analysis_mode, mtd_expert_analysis_warning))
return false;
if (nanddev_bbt_is_initialized(nand)) { if (nanddev_bbt_is_initialized(nand)) {
unsigned int entry; unsigned int entry;
int status; int status;
......
...@@ -60,7 +60,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr ...@@ -60,7 +60,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
int i, j, numblocks, len, scanlen; int i, j, numblocks, len, scanlen;
int startblock; int startblock;
loff_t from; loff_t from;
size_t readlen, ooblen; size_t readlen;
struct mtd_oob_ops ops; struct mtd_oob_ops ops;
int rgn; int rgn;
...@@ -69,7 +69,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr ...@@ -69,7 +69,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
len = 2; len = 2;
/* We need only read few bytes from the OOB area */ /* We need only read few bytes from the OOB area */
scanlen = ooblen = 0; scanlen = 0;
readlen = bd->len; readlen = bd->len;
/* chip == -1 case only */ /* chip == -1 case only */
......
...@@ -40,8 +40,9 @@ config MTD_NAND_AMS_DELTA ...@@ -40,8 +40,9 @@ config MTD_NAND_AMS_DELTA
config MTD_NAND_OMAP2 config MTD_NAND_OMAP2
tristate "OMAP2, OMAP3, OMAP4 and Keystone NAND controller" tristate "OMAP2, OMAP3, OMAP4 and Keystone NAND controller"
depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
depends on HAS_IOMEM depends on HAS_IOMEM
select OMAP_GPMC if ARCH_K3
help help
Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4 Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
and Keystone platforms. and Keystone platforms.
...@@ -461,6 +462,13 @@ config MTD_NAND_PL35X ...@@ -461,6 +462,13 @@ config MTD_NAND_PL35X
Enables support for PrimeCell SMC PL351 and PL353 NAND Enables support for PrimeCell SMC PL351 and PL353 NAND
controller found on Zynq7000. controller found on Zynq7000.
config MTD_NAND_RENESAS
tristate "Renesas R-Car Gen3 & RZ/N1 NAND controller"
depends on ARCH_RENESAS || COMPILE_TEST
help
Enables support for the NAND controller found on Renesas R-Car
Gen3 and RZ/N1 SoC families.
comment "Misc" comment "Misc"
config MTD_SM_COMMON config MTD_SM_COMMON
......
...@@ -58,6 +58,7 @@ obj-$(CONFIG_MTD_NAND_ARASAN) += arasan-nand-controller.o ...@@ -58,6 +58,7 @@ obj-$(CONFIG_MTD_NAND_ARASAN) += arasan-nand-controller.o
obj-$(CONFIG_MTD_NAND_INTEL_LGM) += intel-nand-controller.o obj-$(CONFIG_MTD_NAND_INTEL_LGM) += intel-nand-controller.o
obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o obj-$(CONFIG_MTD_NAND_ROCKCHIP) += rockchip-nand-controller.o
obj-$(CONFIG_MTD_NAND_PL35X) += pl35x-nand-controller.o obj-$(CONFIG_MTD_NAND_PL35X) += pl35x-nand-controller.o
obj-$(CONFIG_MTD_NAND_RENESAS) += renesas-nand-controller.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
......
...@@ -371,77 +371,6 @@ static int nand_davinci_correct_4bit(struct nand_chip *chip, u_char *data, ...@@ -371,77 +371,6 @@ static int nand_davinci_correct_4bit(struct nand_chip *chip, u_char *data,
return corrected; return corrected;
} }
/**
* nand_read_page_hwecc_oob_first - hw ecc, read oob first
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Hardware ECC for large page chips, require OOB to be read first. For this
* ECC mode, the write_page method is re-used from ECC_HW. These methods
* read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with
* multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from
* the data area, by overwriting the NAND manufacturer bad block markings.
*/
static int nand_davinci_read_page_hwecc_oob_first(struct nand_chip *chip,
uint8_t *buf,
int oob_required, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
uint8_t *ecc_code = chip->ecc.code_buf;
uint8_t *ecc_calc = chip->ecc.calc_buf;
unsigned int max_bitflips = 0;
/* Read the OOB area first */
ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
if (ret)
return ret;
ret = nand_read_page_op(chip, page, 0, NULL, 0);
if (ret)
return ret;
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total);
if (ret)
return ret;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
chip->ecc.hwctl(chip, NAND_ECC_READ);
ret = nand_read_data_op(chip, p, eccsize, false, false);
if (ret)
return ret;
chip->ecc.calculate(chip, p, &ecc_calc[i]);
stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL);
if (stat == -EBADMSG &&
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
/* check for empty pages with bitflips */
stat = nand_check_erased_ecc_chunk(p, eccsize,
&ecc_code[i],
eccbytes, NULL, 0,
chip->ecc.strength);
}
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return max_bitflips;
}
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
/* An ECC layout for using 4-bit ECC with small-page flash, storing /* An ECC layout for using 4-bit ECC with small-page flash, storing
...@@ -651,7 +580,7 @@ static int davinci_nand_attach_chip(struct nand_chip *chip) ...@@ -651,7 +580,7 @@ static int davinci_nand_attach_chip(struct nand_chip *chip)
} else if (chunks == 4 || chunks == 8) { } else if (chunks == 4 || chunks == 8) {
mtd_set_ooblayout(mtd, mtd_set_ooblayout(mtd,
nand_get_large_page_ooblayout()); nand_get_large_page_ooblayout());
chip->ecc.read_page = nand_davinci_read_page_hwecc_oob_first; chip->ecc.read_page = nand_read_page_hwecc_oob_first;
} else { } else {
return -EIO; return -EIO;
} }
......
...@@ -713,14 +713,32 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this, ...@@ -713,14 +713,32 @@ static void gpmi_nfc_compute_timings(struct gpmi_nand_data *this,
(use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0); (use_half_period ? BM_GPMI_CTRL1_HALF_PERIOD : 0);
} }
static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) static int gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
{ {
struct gpmi_nfc_hardware_timing *hw = &this->hw; struct gpmi_nfc_hardware_timing *hw = &this->hw;
struct resources *r = &this->resources; struct resources *r = &this->resources;
void __iomem *gpmi_regs = r->gpmi_regs; void __iomem *gpmi_regs = r->gpmi_regs;
unsigned int dll_wait_time_us; unsigned int dll_wait_time_us;
int ret;
/* Clock dividers do NOT guarantee a clean clock signal on its output
* during the change of the divide factor on i.MX6Q/UL/SX. On i.MX7/8,
* all clock dividers provide these guarantee.
*/
if (GPMI_IS_MX6Q(this) || GPMI_IS_MX6SX(this))
clk_disable_unprepare(r->clock[0]);
clk_set_rate(r->clock[0], hw->clk_rate); ret = clk_set_rate(r->clock[0], hw->clk_rate);
if (ret) {
dev_err(this->dev, "cannot set clock rate to %lu Hz: %d\n", hw->clk_rate, ret);
return ret;
}
if (GPMI_IS_MX6Q(this) || GPMI_IS_MX6SX(this)) {
ret = clk_prepare_enable(r->clock[0]);
if (ret)
return ret;
}
writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0); writel(hw->timing0, gpmi_regs + HW_GPMI_TIMING0);
writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1); writel(hw->timing1, gpmi_regs + HW_GPMI_TIMING1);
...@@ -739,6 +757,8 @@ static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this) ...@@ -739,6 +757,8 @@ static void gpmi_nfc_apply_timings(struct gpmi_nand_data *this)
/* Wait for the DLL to settle. */ /* Wait for the DLL to settle. */
udelay(dll_wait_time_us); udelay(dll_wait_time_us);
return 0;
} }
static int gpmi_setup_interface(struct nand_chip *chip, int chipnr, static int gpmi_setup_interface(struct nand_chip *chip, int chipnr,
...@@ -971,16 +991,13 @@ static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) ...@@ -971,16 +991,13 @@ static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
{ {
struct platform_device *pdev = this->pdev; struct platform_device *pdev = this->pdev;
const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME; const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME;
struct resource *r;
int err; int err;
r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); err = platform_get_irq_byname(pdev, res_name);
if (!r) { if (err < 0)
dev_err(this->dev, "Can't get resource for %s\n", res_name); return err;
return -ENODEV;
}
err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this); err = devm_request_irq(this->dev, err, irq_h, 0, res_name, this);
if (err) if (err)
dev_err(this->dev, "error requesting BCH IRQ\n"); dev_err(this->dev, "error requesting BCH IRQ\n");
...@@ -1032,15 +1049,6 @@ static int gpmi_get_clks(struct gpmi_nand_data *this) ...@@ -1032,15 +1049,6 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
r->clock[i] = clk; r->clock[i] = clk;
} }
if (GPMI_IS_MX6(this))
/*
* Set the default value for the gpmi clock.
*
* If you want to use the ONFI nand which is in the
* Synchronous Mode, you should change the clock as you need.
*/
clk_set_rate(r->clock[0], 22000000);
return 0; return 0;
err_clock: err_clock:
...@@ -1425,7 +1433,6 @@ static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf, ...@@ -1425,7 +1433,6 @@ static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf,
struct mtd_info *mtd = nand_to_mtd(chip); struct mtd_info *mtd = nand_to_mtd(chip);
struct gpmi_nand_data *this = nand_get_controller_data(chip); struct gpmi_nand_data *this = nand_get_controller_data(chip);
struct bch_geometry *nfc_geo = &this->bch_geometry; struct bch_geometry *nfc_geo = &this->bch_geometry;
int ret;
dev_dbg(this->dev, "ecc write page.\n"); dev_dbg(this->dev, "ecc write page.\n");
...@@ -1445,9 +1452,7 @@ static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf, ...@@ -1445,9 +1452,7 @@ static int gpmi_ecc_write_page(struct nand_chip *chip, const uint8_t *buf,
this->auxiliary_virt); this->auxiliary_virt);
} }
ret = nand_prog_page_op(chip, page, 0, buf, nfc_geo->page_size); return nand_prog_page_op(chip, page, 0, buf, nfc_geo->page_size);
return ret;
} }
/* /*
...@@ -2278,7 +2283,9 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip, ...@@ -2278,7 +2283,9 @@ static int gpmi_nfc_exec_op(struct nand_chip *chip,
*/ */
if (this->hw.must_apply_timings) { if (this->hw.must_apply_timings) {
this->hw.must_apply_timings = false; this->hw.must_apply_timings = false;
gpmi_nfc_apply_timings(this); ret = gpmi_nfc_apply_timings(this);
if (ret)
return ret;
} }
dev_dbg(this->dev, "%s: %d instructions\n", __func__, op->ninstrs); dev_dbg(this->dev, "%s: %d instructions\n", __func__, op->ninstrs);
......
...@@ -32,6 +32,7 @@ struct jz_soc_info { ...@@ -32,6 +32,7 @@ struct jz_soc_info {
unsigned long addr_offset; unsigned long addr_offset;
unsigned long cmd_offset; unsigned long cmd_offset;
const struct mtd_ooblayout_ops *oob_layout; const struct mtd_ooblayout_ops *oob_layout;
bool oob_first;
}; };
struct ingenic_nand_cs { struct ingenic_nand_cs {
...@@ -240,6 +241,9 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) ...@@ -240,6 +241,9 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip)
if (chip->bbt_options & NAND_BBT_USE_FLASH) if (chip->bbt_options & NAND_BBT_USE_FLASH)
chip->bbt_options |= NAND_BBT_NO_OOB; chip->bbt_options |= NAND_BBT_NO_OOB;
if (nfc->soc_info->oob_first)
chip->ecc.read_page = nand_read_page_hwecc_oob_first;
/* For legacy reasons we use a different layout on the qi,lb60 board. */ /* For legacy reasons we use a different layout on the qi,lb60 board. */
if (of_machine_is_compatible("qi,lb60")) if (of_machine_is_compatible("qi,lb60"))
mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops); mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops);
...@@ -534,6 +538,7 @@ static const struct jz_soc_info jz4740_soc_info = { ...@@ -534,6 +538,7 @@ static const struct jz_soc_info jz4740_soc_info = {
.data_offset = 0x00000000, .data_offset = 0x00000000,
.cmd_offset = 0x00008000, .cmd_offset = 0x00008000,
.addr_offset = 0x00010000, .addr_offset = 0x00010000,
.oob_first = true,
}; };
static const struct jz_soc_info jz4725b_soc_info = { static const struct jz_soc_info jz4725b_soc_info = {
......
...@@ -291,7 +291,6 @@ static int ads5121_chipselect_init(struct mtd_info *mtd) ...@@ -291,7 +291,6 @@ static int ads5121_chipselect_init(struct mtd_info *mtd)
/* Control chips select signal on ADS5121 board */ /* Control chips select signal on ADS5121 board */
static void ads5121_select_chip(struct nand_chip *nand, int chip) static void ads5121_select_chip(struct nand_chip *nand, int chip)
{ {
struct mtd_info *mtd = nand_to_mtd(nand);
struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand); struct mpc5121_nfc_prv *prv = nand_get_controller_data(nand);
u8 v; u8 v;
......
...@@ -321,6 +321,9 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) ...@@ -321,6 +321,9 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
if (nand_region_is_secured(chip, ofs, mtd->erasesize)) if (nand_region_is_secured(chip, ofs, mtd->erasesize))
return -EIO; return -EIO;
if (WARN_ONCE(mtd_expert_analysis_mode, mtd_expert_analysis_warning))
return 0;
if (chip->legacy.block_bad) if (chip->legacy.block_bad)
return chip->legacy.block_bad(chip, ofs); return chip->legacy.block_bad(chip, ofs);
...@@ -3160,6 +3163,73 @@ static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, ...@@ -3160,6 +3163,73 @@ static int nand_read_page_hwecc(struct nand_chip *chip, uint8_t *buf,
return max_bitflips; return max_bitflips;
} }
/**
* nand_read_page_hwecc_oob_first - Hardware ECC page read with ECC
* data read from OOB area
* @chip: nand chip info structure
* @buf: buffer to store read data
* @oob_required: caller requires OOB data read to chip->oob_poi
* @page: page number to read
*
* Hardware ECC for large page chips, which requires the ECC data to be
* extracted from the OOB before the actual data is read.
*/
int nand_read_page_hwecc_oob_first(struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int i, eccsize = chip->ecc.size, ret;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
uint8_t *ecc_code = chip->ecc.code_buf;
unsigned int max_bitflips = 0;
/* Read the OOB area first */
ret = nand_read_oob_op(chip, page, 0, chip->oob_poi, mtd->oobsize);
if (ret)
return ret;
/* Move read cursor to start of page */
ret = nand_change_read_column_op(chip, 0, NULL, 0, false);
if (ret)
return ret;
ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
chip->ecc.total);
if (ret)
return ret;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
chip->ecc.hwctl(chip, NAND_ECC_READ);
ret = nand_read_data_op(chip, p, eccsize, false, false);
if (ret)
return ret;
stat = chip->ecc.correct(chip, p, &ecc_code[i], NULL);
if (stat == -EBADMSG &&
(chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
/* check for empty pages with bitflips */
stat = nand_check_erased_ecc_chunk(p, eccsize,
&ecc_code[i],
eccbytes, NULL, 0,
chip->ecc.strength);
}
if (stat < 0) {
mtd->ecc_stats.failed++;
} else {
mtd->ecc_stats.corrected += stat;
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
return max_bitflips;
}
EXPORT_SYMBOL_GPL(nand_read_page_hwecc_oob_first);
/** /**
* nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read
* @chip: nand chip info structure * @chip: nand chip info structure
......
...@@ -1455,6 +1455,9 @@ int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt) ...@@ -1455,6 +1455,9 @@ int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt)
pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
(unsigned int)offs, block, res); (unsigned int)offs, block, res);
if (WARN_ONCE(mtd_expert_analysis_mode, mtd_expert_analysis_warning))
return 0;
switch (res) { switch (res) {
case BBT_BLOCK_GOOD: case BBT_BLOCK_GOOD:
return 0; return 0;
......
This diff is collapsed.
...@@ -384,8 +384,8 @@ static irqreturn_t elm_isr(int this_irq, void *dev_id) ...@@ -384,8 +384,8 @@ static irqreturn_t elm_isr(int this_irq, void *dev_id)
static int elm_probe(struct platform_device *pdev) static int elm_probe(struct platform_device *pdev)
{ {
int ret = 0; int ret = 0;
struct resource *irq;
struct elm_info *info; struct elm_info *info;
int irq;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
...@@ -393,20 +393,18 @@ static int elm_probe(struct platform_device *pdev) ...@@ -393,20 +393,18 @@ static int elm_probe(struct platform_device *pdev)
info->dev = &pdev->dev; info->dev = &pdev->dev;
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq = platform_get_irq(pdev, 0);
if (!irq) { if (irq < 0)
dev_err(&pdev->dev, "no irq resource defined\n"); return irq;
return -ENODEV;
}
info->elm_base = devm_platform_ioremap_resource(pdev, 0); info->elm_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(info->elm_base)) if (IS_ERR(info->elm_base))
return PTR_ERR(info->elm_base); return PTR_ERR(info->elm_base);
ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0, ret = devm_request_irq(&pdev->dev, irq, elm_isr, 0,
pdev->name, info); pdev->name, info);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failure requesting %pr\n", irq); dev_err(&pdev->dev, "failure requesting %d\n", irq);
return ret; return ret;
} }
......
This diff is collapsed.
...@@ -48,13 +48,13 @@ static const struct spi_nor_locking_ops atmel_at25fs_locking_ops = { ...@@ -48,13 +48,13 @@ static const struct spi_nor_locking_ops atmel_at25fs_locking_ops = {
.is_locked = atmel_at25fs_is_locked, .is_locked = atmel_at25fs_is_locked,
}; };
static void atmel_at25fs_default_init(struct spi_nor *nor) static void atmel_at25fs_late_init(struct spi_nor *nor)
{ {
nor->params->locking_ops = &atmel_at25fs_locking_ops; nor->params->locking_ops = &atmel_at25fs_locking_ops;
} }
static const struct spi_nor_fixups atmel_at25fs_fixups = { static const struct spi_nor_fixups atmel_at25fs_fixups = {
.default_init = atmel_at25fs_default_init, .late_init = atmel_at25fs_late_init,
}; };
/** /**
...@@ -146,50 +146,59 @@ static const struct spi_nor_locking_ops atmel_global_protection_ops = { ...@@ -146,50 +146,59 @@ static const struct spi_nor_locking_ops atmel_global_protection_ops = {
.is_locked = atmel_is_global_protected, .is_locked = atmel_is_global_protected,
}; };
static void atmel_global_protection_default_init(struct spi_nor *nor) static void atmel_global_protection_late_init(struct spi_nor *nor)
{ {
nor->params->locking_ops = &atmel_global_protection_ops; nor->params->locking_ops = &atmel_global_protection_ops;
} }
static const struct spi_nor_fixups atmel_global_protection_fixups = { static const struct spi_nor_fixups atmel_global_protection_fixups = {
.default_init = atmel_global_protection_default_init, .late_init = atmel_global_protection_late_init,
}; };
static const struct flash_info atmel_parts[] = { static const struct flash_info atmel_parts[] = {
/* Atmel -- some are (confusingly) marketed as "DataFlash" */ /* Atmel -- some are (confusingly) marketed as "DataFlash" */
{ "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K | SPI_NOR_HAS_LOCK) { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4)
FLAGS(SPI_NOR_HAS_LOCK)
NO_SFDP_FLAGS(SECT_4K)
.fixups = &atmel_at25fs_fixups }, .fixups = &atmel_at25fs_fixups },
{ "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_HAS_LOCK) { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8)
FLAGS(SPI_NOR_HAS_LOCK)
NO_SFDP_FLAGS(SECT_4K)
.fixups = &atmel_at25fs_fixups }, .fixups = &atmel_at25fs_fixups },
{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8)
{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) NO_SFDP_FLAGS(SECT_4K)
.fixups = &atmel_global_protection_fixups }, .fixups = &atmel_global_protection_fixups },
{ "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64, { "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64)
SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
.fixups = &atmel_global_protection_fixups }, NO_SFDP_FLAGS(SECT_4K)
{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, .fixups = &atmel_global_protection_fixups },
SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64)
.fixups = &atmel_global_protection_fixups }, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
{ "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, NO_SFDP_FLAGS(SECT_4K)
SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) .fixups = &atmel_global_protection_fixups },
.fixups = &atmel_global_protection_fixups }, { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
{ "at25sl321", INFO(0x1f4216, 0, 64 * 1024, 64, NO_SFDP_FLAGS(SECT_4K)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, .fixups = &atmel_global_protection_fixups },
{ "at25sl321", INFO(0x1f4216, 0, 64 * 1024, 64)
{ "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8)
SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) NO_SFDP_FLAGS(SECT_4K) },
.fixups = &atmel_global_protection_fixups }, { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16)
{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) NO_SFDP_FLAGS(SECT_4K)
.fixups = &atmel_global_protection_fixups }, .fixups = &atmel_global_protection_fixups },
{ "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32)
SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
.fixups = &atmel_global_protection_fixups }, NO_SFDP_FLAGS(SECT_4K)
.fixups = &atmel_global_protection_fixups },
{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) }, { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
NO_SFDP_FLAGS(SECT_4K)
.fixups = &atmel_global_protection_fixups },
{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16)
NO_SFDP_FLAGS(SECT_4K) },
}; };
const struct spi_nor_manufacturer spi_nor_atmel = { const struct spi_nor_manufacturer spi_nor_atmel = {
......
...@@ -10,16 +10,11 @@ ...@@ -10,16 +10,11 @@
static const struct flash_info catalyst_parts[] = { static const struct flash_info catalyst_parts[] = {
/* Catalyst / On Semiconductor -- non-JEDEC */ /* Catalyst / On Semiconductor -- non-JEDEC */
{ "cat25c11", CAT25_INFO(16, 8, 16, 1, { "cat25c11", CAT25_INFO(16, 8, 16, 1) },
SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "cat25c03", CAT25_INFO(32, 8, 16, 2) },
{ "cat25c03", CAT25_INFO(32, 8, 16, 2, { "cat25c09", CAT25_INFO(128, 8, 32, 2) },
SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "cat25c17", CAT25_INFO(256, 8, 32, 2) },
{ "cat25c09", CAT25_INFO(128, 8, 32, 2, { "cat25128", CAT25_INFO(2048, 8, 64, 2) },
SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "cat25c17", CAT25_INFO(256, 8, 32, 2,
SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "cat25128", CAT25_INFO(2048, 8, 64, 2,
SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
}; };
const struct spi_nor_manufacturer spi_nor_catalyst = { const struct spi_nor_manufacturer spi_nor_catalyst = {
......
This diff is collapsed.
This diff is collapsed.
...@@ -10,21 +10,24 @@ ...@@ -10,21 +10,24 @@
static const struct flash_info eon_parts[] = { static const struct flash_info eon_parts[] = {
/* EON -- en25xxx */ /* EON -- en25xxx */
{ "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64)
{ "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, NO_SFDP_FLAGS(SECT_4K) },
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64) },
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64) },
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128) },
{ "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16, { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128)
SECT_4K | SPI_NOR_DUAL_READ) }, NO_SFDP_FLAGS(SECT_4K) },
{ "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32, { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16)
SECT_4K | SPI_NOR_DUAL_READ) }, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
{ "en25qh32", INFO(0x1c7016, 0, 64 * 1024, 64, 0) }, { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32)
{ "en25qh64", INFO(0x1c7017, 0, 64 * 1024, 128, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
SECT_4K | SPI_NOR_DUAL_READ) }, { "en25qh32", INFO(0x1c7016, 0, 64 * 1024, 64) },
{ "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, { "en25qh64", INFO(0x1c7017, 0, 64 * 1024, 128)
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
{ "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, SECT_4K) }, { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256) },
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512) },
{ "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128)
NO_SFDP_FLAGS(SECT_4K) },
}; };
const struct spi_nor_manufacturer spi_nor_eon = { const struct spi_nor_manufacturer spi_nor_eon = {
......
...@@ -10,12 +10,15 @@ ...@@ -10,12 +10,15 @@
static const struct flash_info esmt_parts[] = { static const struct flash_info esmt_parts[] = {
/* ESMT */ /* ESMT */
{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64)
SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
{ "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, NO_SFDP_FLAGS(SECT_4K) },
SECT_4K | SPI_NOR_HAS_LOCK) }, { "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64)
{ "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, FLAGS(SPI_NOR_HAS_LOCK)
SECT_4K | SPI_NOR_HAS_LOCK) }, NO_SFDP_FLAGS(SECT_4K) },
{ "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128)
FLAGS(SPI_NOR_HAS_LOCK)
NO_SFDP_FLAGS(SECT_4K) },
}; };
const struct spi_nor_manufacturer spi_nor_esmt = { const struct spi_nor_manufacturer spi_nor_esmt = {
......
...@@ -10,14 +10,10 @@ ...@@ -10,14 +10,10 @@
static const struct flash_info everspin_parts[] = { static const struct flash_info everspin_parts[] = {
/* Everspin */ /* Everspin */
{ "mr25h128", CAT25_INFO(16 * 1024, 1, 256, 2, { "mr25h128", CAT25_INFO(16 * 1024, 1, 256, 2) },
SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "mr25h256", CAT25_INFO(32 * 1024, 1, 256, 2) },
{ "mr25h256", CAT25_INFO(32 * 1024, 1, 256, 2, { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3) },
SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "mr25h40", CAT25_INFO(512 * 1024, 1, 256, 3) },
{ "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3,
SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
{ "mr25h40", CAT25_INFO(512 * 1024, 1, 256, 3,
SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
}; };
const struct spi_nor_manufacturer spi_nor_everspin = { const struct spi_nor_manufacturer spi_nor_everspin = {
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
static const struct flash_info fujitsu_parts[] = { static const struct flash_info fujitsu_parts[] = {
/* Fujitsu */ /* Fujitsu */
{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) }, { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1)
FLAGS(SPI_NOR_NO_ERASE) },
}; };
const struct spi_nor_manufacturer spi_nor_fujitsu = { const struct spi_nor_manufacturer spi_nor_fujitsu = {
......
...@@ -19,36 +19,43 @@ static void gd25q256_default_init(struct spi_nor *nor) ...@@ -19,36 +19,43 @@ static void gd25q256_default_init(struct spi_nor *nor)
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
} }
static struct spi_nor_fixups gd25q256_fixups = { static const struct spi_nor_fixups gd25q256_fixups = {
.default_init = gd25q256_default_init, .default_init = gd25q256_default_init,
}; };
static const struct flash_info gigadevice_parts[] = { static const struct flash_info gigadevice_parts[] = {
{ "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32, { "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
{ "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64)
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
{ "gd25lq32", INFO(0xc86016, 0, 64 * 1024, 64, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_QUAD_READ) },
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, { "gd25lq32", INFO(0xc86016, 0, 64 * 1024, 64)
{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, SPI_NOR_QUAD_READ) },
{ "gd25lq64c", INFO(0xc86017, 0, 64 * 1024, 128, { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
{ "gd25lq128d", INFO(0xc86018, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | { "gd25lq64c", INFO(0xc86017, 0, 64 * 1024, 128)
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
{ "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_QUAD_READ) },
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, { "gd25lq128d", INFO(0xc86018, 0, 64 * 1024, 256)
{ "gd25q256", INFO(0xc84019, 0, 64 * 1024, 512, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_QUAD_READ) },
SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6) { "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) },
{ "gd25q256", INFO(0xc84019, 0, 64 * 1024, 512)
PARSE_SFDP
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6)
FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
.fixups = &gd25q256_fixups }, .fixups = &gd25q256_fixups },
}; };
......
...@@ -10,12 +10,12 @@ ...@@ -10,12 +10,12 @@
static const struct flash_info intel_parts[] = { static const struct flash_info intel_parts[] = {
/* Intel/Numonyx -- xxxs33b */ /* Intel/Numonyx -- xxxs33b */
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, { "160s33b", INFO(0x898911, 0, 64 * 1024, 32)
SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
{ "320s33b", INFO(0x898912, 0, 64 * 1024, 64, { "320s33b", INFO(0x898912, 0, 64 * 1024, 64)
SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
{ "640s33b", INFO(0x898913, 0, 64 * 1024, 128, { "640s33b", INFO(0x898913, 0, 64 * 1024, 128)
SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) },
}; };
const struct spi_nor_manufacturer spi_nor_intel = { const struct spi_nor_manufacturer spi_nor_intel = {
......
...@@ -25,44 +25,48 @@ is25lp256_post_bfpt_fixups(struct spi_nor *nor, ...@@ -25,44 +25,48 @@ is25lp256_post_bfpt_fixups(struct spi_nor *nor,
return 0; return 0;
} }
static struct spi_nor_fixups is25lp256_fixups = { static const struct spi_nor_fixups is25lp256_fixups = {
.post_bfpt = is25lp256_post_bfpt_fixups, .post_bfpt = is25lp256_post_bfpt_fixups,
}; };
static const struct flash_info issi_parts[] = { static const struct flash_info issi_parts[] = {
/* ISSI */ /* ISSI */
{ "is25cd512", INFO(0x7f9d20, 0, 32 * 1024, 2, SECT_4K) }, { "is25cd512", INFO(0x7f9d20, 0, 32 * 1024, 2)
{ "is25lq040b", INFO(0x9d4013, 0, 64 * 1024, 8, NO_SFDP_FLAGS(SECT_4K) },
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25lq040b", INFO(0x9d4013, 0, 64 * 1024, 8)
{ "is25lp016d", INFO(0x9d6015, 0, 64 * 1024, 32, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25lp016d", INFO(0x9d6015, 0, 64 * 1024, 32)
{ "is25lp080d", INFO(0x9d6014, 0, 64 * 1024, 16, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "is25lp080d", INFO(0x9d6014, 0, 64 * 1024, 16)
{ "is25lp032", INFO(0x9d6016, 0, 64 * 1024, 64, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp032", INFO(0x9d6016, 0, 64 * 1024, 64)
{ "is25lp064", INFO(0x9d6017, 0, 64 * 1024, 128, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp064", INFO(0x9d6017, 0, 64 * 1024, 128)
{ "is25lp128", INFO(0x9d6018, 0, 64 * 1024, 256, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
SECT_4K | SPI_NOR_DUAL_READ) }, { "is25lp128", INFO(0x9d6018, 0, 64 * 1024, 256)
{ "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | { "is25lp256", INFO(0x9d6019, 0, 64 * 1024, 512)
SPI_NOR_4B_OPCODES) PARSE_SFDP
FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
.fixups = &is25lp256_fixups }, .fixups = &is25lp256_fixups },
{ "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64, { "is25wp032", INFO(0x9d7016, 0, 64 * 1024, 64)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128, { "is25wp064", INFO(0x9d7017, 0, 64 * 1024, 128)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp128", INFO(0x9d7018, 0, 64 * 1024, 256, { "is25wp128", INFO(0x9d7018, 0, 64 * 1024, 256)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 512, { "is25wp256", INFO(0x9d7019, 0, 64 * 1024, 512)
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
SPI_NOR_4B_OPCODES) FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
.fixups = &is25lp256_fixups }, .fixups = &is25lp256_fixups },
/* PMC */ /* PMC */
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, { "pm25lv512", INFO(0, 0, 32 * 1024, 2)
{ "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) }, NO_SFDP_FLAGS(SECT_4K_PMC) },
{ "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) }, { "pm25lv010", INFO(0, 0, 32 * 1024, 4)
NO_SFDP_FLAGS(SECT_4K_PMC) },
{ "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64)
NO_SFDP_FLAGS(SECT_4K) },
}; };
static void issi_default_init(struct spi_nor *nor) static void issi_default_init(struct spi_nor *nor)
......
...@@ -28,65 +28,78 @@ mx25l25635_post_bfpt_fixups(struct spi_nor *nor, ...@@ -28,65 +28,78 @@ mx25l25635_post_bfpt_fixups(struct spi_nor *nor,
return 0; return 0;
} }
static struct spi_nor_fixups mx25l25635_fixups = { static const struct spi_nor_fixups mx25l25635_fixups = {
.post_bfpt = mx25l25635_post_bfpt_fixups, .post_bfpt = mx25l25635_post_bfpt_fixups,
}; };
static const struct flash_info macronix_parts[] = { static const struct flash_info macronix_parts[] = {
/* Macronix */ /* Macronix */
{ "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1, SECT_4K) }, { "mx25l512e", INFO(0xc22010, 0, 64 * 1024, 1)
{ "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4, SECT_4K) }, NO_SFDP_FLAGS(SECT_4K) },
{ "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8, SECT_4K) }, { "mx25l2005a", INFO(0xc22012, 0, 64 * 1024, 4)
{ "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16, 0) }, NO_SFDP_FLAGS(SECT_4K) },
{ "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, { "mx25l4005a", INFO(0xc22013, 0, 64 * 1024, 8)
{ "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) }, NO_SFDP_FLAGS(SECT_4K) },
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, { "mx25l8005", INFO(0xc22014, 0, 64 * 1024, 16) },
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32)
{ "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) }, NO_SFDP_FLAGS(SECT_4K) },
{ "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64, { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64)
SECT_4K | SPI_NOR_DUAL_READ | NO_SFDP_FLAGS(SECT_4K) },
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64)
NO_SFDP_FLAGS(SECT_4K) },
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128)
NO_SFDP_FLAGS(SECT_4K) },
{ "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4)
NO_SFDP_FLAGS(SECT_4K) },
{ "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) }, SPI_NOR_QUAD_READ) },
{ "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8, SECT_4K) }, { "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8)
{ "mx25u8035", INFO(0xc22534, 0, 64 * 1024, 16, SECT_4K) }, NO_SFDP_FLAGS(SECT_4K) },
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, { "mx25u8035", INFO(0xc22534, 0, 64 * 1024, 16)
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, SECT_4K | NO_SFDP_FLAGS(SECT_4K) },
SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP) }, { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128)
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, NO_SFDP_FLAGS(SECT_4K) },
{ "mx25r1635f", INFO(0xc22815, 0, 64 * 1024, 32, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256)
SECT_4K | SPI_NOR_DUAL_READ | FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP)
NO_SFDP_FLAGS(SECT_4K) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256) },
{ "mx25r1635f", INFO(0xc22815, 0, 64 * 1024, 32)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) }, SPI_NOR_QUAD_READ) },
{ "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64, { "mx25r3235f", INFO(0xc22816, 0, 64 * 1024, 64)
SECT_4K | SPI_NOR_DUAL_READ | NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) }, SPI_NOR_QUAD_READ) },
{ "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256, { "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256)
SECT_4K | SPI_NOR_DUAL_READ | NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) }, SPI_NOR_QUAD_READ) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512)
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
.fixups = &mx25l25635_fixups }, .fixups = &mx25l25635_fixups },
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512)
SECT_4K | SPI_NOR_4B_OPCODES) }, NO_SFDP_FLAGS(SECT_4K)
{ "mx25u51245g", INFO(0xc2253a, 0, 64 * 1024, 1024, FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
SECT_4K | SPI_NOR_DUAL_READ | { "mx25u51245g", INFO(0xc2253a, 0, 64 * 1024, 1024)
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
{ "mx25v8035f", INFO(0xc22314, 0, 64 * 1024, 16, FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
SECT_4K | SPI_NOR_DUAL_READ | { "mx25v8035f", INFO(0xc22314, 0, 64 * 1024, 16)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) }, SPI_NOR_QUAD_READ) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512) },
{ "mx66l51235f", INFO(0xc2201a, 0, 64 * 1024, 1024, { "mx66l51235f", INFO(0xc2201a, 0, 64 * 1024, 1024)
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
SPI_NOR_4B_OPCODES) }, FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
{ "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024, { "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024)
SECT_4K | SPI_NOR_DUAL_READ | NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
{ "mx66l1g45g", INFO(0xc2201b, 0, 64 * 1024, 2048, { "mx66l1g45g", INFO(0xc2201b, 0, 64 * 1024, 2048)
SECT_4K | SPI_NOR_DUAL_READ | NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) }, SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048)
SPI_NOR_QUAD_READ) }, NO_SFDP_FLAGS(SPI_NOR_QUAD_READ) },
{ "mx66u2g45g", INFO(0xc2253c, 0, 64 * 1024, 4096, { "mx66u2g45g", INFO(0xc2253c, 0, 64 * 1024, 4096)
SECT_4K | SPI_NOR_DUAL_READ | NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
}; };
static void macronix_default_init(struct spi_nor *nor) static void macronix_default_init(struct spi_nor *nor)
......
This diff is collapsed.
...@@ -480,7 +480,7 @@ static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len) ...@@ -480,7 +480,7 @@ static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len)
return ret; return ret;
} }
void spi_nor_otp_init(struct spi_nor *nor) void spi_nor_set_mtd_otp_ops(struct spi_nor *nor)
{ {
struct mtd_info *mtd = &nor->mtd; struct mtd_info *mtd = &nor->mtd;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -414,7 +414,7 @@ void spi_nor_try_unlock_all(struct spi_nor *nor) ...@@ -414,7 +414,7 @@ void spi_nor_try_unlock_all(struct spi_nor *nor)
dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n"); dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n");
} }
void spi_nor_register_locking_ops(struct spi_nor *nor) void spi_nor_set_mtd_locking_ops(struct spi_nor *nor)
{ {
struct mtd_info *mtd = &nor->mtd; struct mtd_info *mtd = &nor->mtd;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -711,4 +711,7 @@ static inline int mtd_is_bitflip_or_eccerr(int err) { ...@@ -711,4 +711,7 @@ static inline int mtd_is_bitflip_or_eccerr(int err) {
unsigned mtd_mmap_capabilities(struct mtd_info *mtd); unsigned mtd_mmap_capabilities(struct mtd_info *mtd);
extern char *mtd_expert_analysis_warning;
extern bool mtd_expert_analysis_mode;
#endif /* __MTD_MTD_H__ */ #endif /* __MTD_MTD_H__ */
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment