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

Pull mtd updates from Miquel Raynal:
 "Core MTD changes:
   - dt-bindings: Drop unneeded quotes
   - mtdblock: Tolerate corrected bit-flips
   - Use of_property_read_bool() for boolean properties
   - Avoid magic values
   - Avoid printing error messages on probe deferrals
   - Prepare mtd_otp_nvmem_add() to handle -EPROBE_DEFER
   - Fix error path for nvmem provider
   - Fix nvmem error reporting
   - Provide unique name for nvmem device

  MTD device changes:
   - lpddr_cmds: Remove unused words variable
   - bcm63xxpart: Remove MODULE_LICENSE in non-modules

  SPI NOR core changes:
   - Introduce Read While Write support for flashes featuring several
     banks
   - Set the 4-Byte Address Mode method based on SFDP data
   - Allow post_sfdp hook to return errors
   - Parse SCCR MC table and introduce support for multi-chip devices

  SPI NOR manufacturer drivers changes:
   - macronix: Add support for mx25uw51245g with RWW
   - spansion:
      - Determine current address mode at runtime as it can be changed
        in a non-volatile way and differ from factory defaults or from
        what SFDP advertises.
      - Enable JFFS2 write buffer mode for few ECC'd NOR flashes:
        S25FS256T, s25hx and s28hx
      - Add support for s25hl02gt and s25hs02gt

  Raw NAND core changes:
   - Convert to platform remove callback returning void
   - Fix spelling mistake waifunc() -> waitfunc()

  Raw NAND controller driver changes:
   - imx: Remove unused is_imx51_nfc and imx53_nfc functions
   - omap2: Drop obsolete dependency on COMPILE_TEST
   - orion: Use devm_platform_ioremap_resource()
   - qcom:
      - Use of_property_present() for testing DT property presence
      - Use devm_platform_get_and_ioremap_resource()
   - stm32_fmc2: Depends on ARCH_STM32 instead of MACH_STM32MP157
   - tmio: Remove reference to config MTD_NAND_TMIO in the parsers

  Raw NAND manufacturer driver changes:
   - hynix: Fix up bit 0 of sdr_timing_mode

  SPI-NAND changes:
   - Add support for ESMT F50x1G41LB"

* tag 'mtd/for-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (55 commits)
  mtd: nand: Convert to platform remove callback returning void
  mtd: onenand: omap2: Drop obsolete dependency on COMPILE_TEST
  mtd: spi-nor: spansion: Add support for s25hl02gt and s25hs02gt
  mtd: spi-nor: spansion: Add a new ->ready() hook for multi-chip device
  mtd: spi-nor: spansion: Rework cypress_nor_quad_enable_volatile() for multi-chip device support
  mtd: spi-nor: spansion: Rework cypress_nor_get_page_size() for multi-chip device support
  mtd: spi-nor: sfdp: Add support for SCCR map for multi-chip device
  mtd: spi-nor: Extract volatile register offset from SCCR map
  mtd: spi-nor: Allow post_sfdp hook to return errors
  mtd: spi-nor: spansion: Rename method to cypress_nor_get_page_size
  mtd: spi-nor: spansion: Enable JFFS2 write buffer for S25FS256T
  mtd: spi-nor: spansion: Enable JFFS2 write buffer for Infineon s25hx SEMPER flash
  mtd: spi-nor: spansion: Enable JFFS2 write buffer for Infineon s28hx SEMPER flash
  mtd: spi-nor: spansion: Determine current address mode
  mtd: spi-nor: core: Introduce spi_nor_set_4byte_addr_mode()
  mtd: spi-nor: core: Update flash's current address mode when changing address mode
  mtd: spi-nor: Stop exporting spi_nor_restore()
  mtd: spi-nor: Set the 4-Byte Address Mode method based on SFDP data
  mtd: spi-nor: core: Make spi_nor_set_4byte_addr_mode_brwr public
  mtd: spi-nor: core: Update name and description of spi_nor_set_4byte_addr_mode
  ...
This commit is contained in:
Linus Torvalds
2023-04-25 17:23:42 -07:00
100 changed files with 1413 additions and 447 deletions

View File

@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allwinner A10 NAND Controller title: Allwinner A10 NAND Controller
allOf: allOf:
- $ref: "nand-controller.yaml" - $ref: nand-controller.yaml
maintainers: maintainers:
- Chen-Yu Tsai <wens@csie.org> - Chen-Yu Tsai <wens@csie.org>

View File

@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Arasan NAND Flash Controller with ONFI 3.1 support title: Arasan NAND Flash Controller with ONFI 3.1 support
allOf: allOf:
- $ref: "nand-controller.yaml" - $ref: nand-controller.yaml
maintainers: maintainers:
- Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com> - Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>

View File

@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: PL353 NAND Controller title: PL353 NAND Controller
allOf: allOf:
- $ref: "nand-controller.yaml" - $ref: nand-controller.yaml
maintainers: maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com> - Miquel Raynal <miquel.raynal@bootlin.com>

View File

@ -93,7 +93,7 @@ required:
unevaluatedProperties: false unevaluatedProperties: false
allOf: allOf:
- $ref: "nand-controller.yaml" - $ref: nand-controller.yaml
- if: - if:
properties: properties:

View File

@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel LGM SoC NAND Controller title: Intel LGM SoC NAND Controller
allOf: allOf:
- $ref: "nand-controller.yaml" - $ref: nand-controller.yaml
maintainers: maintainers:
- Ramuthevar Vadivel Murugan <vadivel.muruganx.ramuthevar@linux.intel.com> - Ramuthevar Vadivel Murugan <vadivel.muruganx.ramuthevar@linux.intel.com>

View File

@ -10,7 +10,7 @@ maintainers:
- Rob Herring <robh@kernel.org> - Rob Herring <robh@kernel.org>
allOf: allOf:
- $ref: "mtd.yaml#" - $ref: mtd.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml# - $ref: /schemas/spi/spi-peripheral-props.yaml#
properties: properties:

View File

@ -14,7 +14,7 @@ description: |
file systems on embedded devices. file systems on embedded devices.
allOf: allOf:
- $ref: "mtd.yaml#" - $ref: mtd.yaml#
- $ref: /schemas/memory-controllers/mc-peripheral-props.yaml# - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml#
properties: properties:

View File

@ -10,7 +10,7 @@ maintainers:
- Uwe Kleine-König <u.kleine-koenig@pengutronix.de> - Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
allOf: allOf:
- $ref: "nand-controller.yaml" - $ref: nand-controller.yaml
properties: properties:
compatible: compatible:

View File

@ -10,7 +10,7 @@ maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com> - Miquel Raynal <miquel.raynal@bootlin.com>
allOf: allOf:
- $ref: "mtd.yaml#" - $ref: mtd.yaml#
description: | description: |
This file covers the generic description of a NAND chip. It implies that the This file covers the generic description of a NAND chip. It implies that the

View File

@ -51,7 +51,7 @@ properties:
patternProperties: patternProperties:
"^nand@[a-f0-9]$": "^nand@[a-f0-9]$":
$ref: "nand-chip.yaml#" $ref: nand-chip.yaml#
properties: properties:
reg: reg:

View File

@ -31,7 +31,7 @@ properties:
patternProperties: patternProperties:
"^partition@[0-9a-f]+$": "^partition@[0-9a-f]+$":
$ref: "partition.yaml#" $ref: partition.yaml#
properties: properties:
compatible: compatible:
const: brcm,bcm4908-firmware const: brcm,bcm4908-firmware

View File

@ -32,7 +32,7 @@ properties:
patternProperties: patternProperties:
"^partition@[0-9a-f]+$": "^partition@[0-9a-f]+$":
$ref: "partition.yaml#" $ref: partition.yaml#
properties: properties:
compatible: compatible:
items: items:

View File

@ -46,7 +46,7 @@ patternProperties:
- 512 - 512
allOf: allOf:
- $ref: "nand-controller.yaml#" - $ref: nand-controller.yaml#
- if: - if:
properties: properties:

View File

@ -10,7 +10,7 @@ maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com> - Miquel Raynal <miquel.raynal@bootlin.com>
allOf: allOf:
- $ref: "nand-controller.yaml" - $ref: nand-controller.yaml
properties: properties:
compatible: compatible:

View File

@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rockchip SoCs NAND FLASH Controller (NFC) title: Rockchip SoCs NAND FLASH Controller (NFC)
allOf: allOf:
- $ref: "nand-controller.yaml#" - $ref: nand-controller.yaml#
maintainers: maintainers:
- Heiko Stuebner <heiko@sntech.de> - Heiko Stuebner <heiko@sntech.de>

View File

@ -10,7 +10,7 @@ maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com> - Miquel Raynal <miquel.raynal@bootlin.com>
allOf: allOf:
- $ref: "nand-chip.yaml#" - $ref: nand-chip.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml# - $ref: /schemas/spi/spi-peripheral-props.yaml#
properties: properties:

View File

@ -45,7 +45,7 @@ patternProperties:
enum: [1, 4, 8] enum: [1, 4, 8]
allOf: allOf:
- $ref: "nand-controller.yaml#" - $ref: nand-controller.yaml#
- if: - if:
properties: properties:

View File

@ -63,10 +63,10 @@ properties:
patternProperties: patternProperties:
"@[0-9a-f]+$": "@[0-9a-f]+$":
$ref: "/schemas/mtd/partitions/partition.yaml" $ref: /schemas/mtd/partitions/partition.yaml
allOf: allOf:
- $ref: "/schemas/memory-controllers/ti,gpmc-child.yaml" - $ref: /schemas/memory-controllers/ti,gpmc-child.yaml
required: required:
- compatible - compatible

View File

@ -36,10 +36,10 @@ properties:
patternProperties: patternProperties:
"@[0-9a-f]+$": "@[0-9a-f]+$":
$ref: "/schemas/mtd/partitions/partition.yaml" $ref: /schemas/mtd/partitions/partition.yaml
allOf: allOf:
- $ref: "/schemas/memory-controllers/ti,gpmc-child.yaml" - $ref: /schemas/memory-controllers/ti,gpmc-child.yaml
required: required:
- compatible - compatible

View File

@ -63,6 +63,3 @@ The main API is spi_nor_scan(). Before you call the hook, a driver should
initialize the necessary fields for spi_nor{}. Please see initialize the necessary fields for spi_nor{}. Please see
drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to spi-fsl-qspi.c drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to spi-fsl-qspi.c
when you want to write a new driver for a SPI NOR controller. when you want to write a new driver for a SPI NOR controller.
Another API is spi_nor_restore(), this is used to restore the status of SPI
flash chip such as addressing mode. Call it whenever detach the driver from
device or reboot the system.

View File

@ -820,8 +820,8 @@ static int spear_smi_probe_config_dt(struct platform_device *pdev,
pdata->board_flash_info->mem_base = be32_to_cpup(&addr[0]); pdata->board_flash_info->mem_base = be32_to_cpup(&addr[0]);
pdata->board_flash_info->size = be32_to_cpup(&addr[1]); pdata->board_flash_info->size = be32_to_cpup(&addr[1]);
if (of_get_property(pp, "st,smi-fast-mode", NULL)) pdata->board_flash_info->fast_mode =
pdata->board_flash_info->fast_mode = 1; of_property_read_bool(pp, "st,smi-fast-mode");
i++; i++;
} }

View File

@ -406,7 +406,7 @@ static int do_write_buffer(struct map_info *map, struct flchip *chip,
{ {
struct lpddr_private *lpddr = map->fldrv_priv; struct lpddr_private *lpddr = map->fldrv_priv;
map_word datum; map_word datum;
int ret, wbufsize, word_gap, words; int ret, wbufsize, word_gap;
const struct kvec *vec; const struct kvec *vec;
unsigned long vec_seek; unsigned long vec_seek;
unsigned long prog_buf_ofs; unsigned long prog_buf_ofs;
@ -421,10 +421,7 @@ static int do_write_buffer(struct map_info *map, struct flchip *chip,
} }
/* Figure out the number of words to write */ /* Figure out the number of words to write */
word_gap = (-adr & (map_bankwidth(map)-1)); word_gap = (-adr & (map_bankwidth(map)-1));
words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map); if (word_gap) {
if (!word_gap) {
words--;
} else {
word_gap = map_bankwidth(map) - word_gap; word_gap = map_bankwidth(map) - word_gap;
adr -= word_gap; adr -= word_gap;
datum = map_word_ff(map); datum = map_word_ff(map);

View File

@ -112,7 +112,7 @@ static int uflash_probe(struct platform_device *op)
/* Flashprom must have the "user" property in order to /* Flashprom must have the "user" property in order to
* be used by this driver. * be used by this driver.
*/ */
if (!of_find_property(dp, "user", NULL)) if (!of_property_read_bool(dp, "user"))
return -ENODEV; return -ENODEV;
return uflash_devinit(op, dp); return uflash_devinit(op, dp);

View File

@ -16,8 +16,10 @@ static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
unsigned long block, char *buf) unsigned long block, char *buf)
{ {
size_t retlen; size_t retlen;
int err;
if (mtd_read(dev->mtd, (block * 512), 512, &retlen, buf)) err = mtd_read(dev->mtd, (block * 512), 512, &retlen, buf);
if (err && !mtd_is_bitflip(err))
return 1; return 1;
return 0; return 0;
} }

View File

@ -519,7 +519,7 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
struct device_node *node = mtd_get_of_node(mtd); struct device_node *node = mtd_get_of_node(mtd);
struct nvmem_config config = {}; struct nvmem_config config = {};
config.id = -1; config.id = NVMEM_DEVID_NONE;
config.dev = &mtd->dev; config.dev = &mtd->dev;
config.name = dev_name(&mtd->dev); config.name = dev_name(&mtd->dev);
config.owner = THIS_MODULE; config.owner = THIS_MODULE;
@ -536,12 +536,11 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
mtd->nvmem = nvmem_register(&config); mtd->nvmem = nvmem_register(&config);
if (IS_ERR(mtd->nvmem)) { if (IS_ERR(mtd->nvmem)) {
/* Just ignore if there is no NVMEM support in the kernel */ /* Just ignore if there is no NVMEM support in the kernel */
if (PTR_ERR(mtd->nvmem) == -EOPNOTSUPP) { if (PTR_ERR(mtd->nvmem) == -EOPNOTSUPP)
mtd->nvmem = NULL; mtd->nvmem = NULL;
} else { else
dev_err(&mtd->dev, "Failed to register NVMEM device\n"); return dev_err_probe(&mtd->dev, PTR_ERR(mtd->nvmem),
return PTR_ERR(mtd->nvmem); "Failed to register NVMEM device\n");
}
} }
return 0; return 0;
@ -739,7 +738,7 @@ int add_mtd_device(struct mtd_info *mtd)
mutex_unlock(&mtd_table_mutex); mutex_unlock(&mtd_table_mutex);
if (of_find_property(mtd_get_of_node(mtd), "linux,rootfs", NULL)) { if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) {
if (IS_BUILTIN(CONFIG_MTD)) { if (IS_BUILTIN(CONFIG_MTD)) {
pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name); pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name);
ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
@ -888,8 +887,8 @@ 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;
config.name = kasprintf(GFP_KERNEL, "%s-%s", dev_name(&mtd->dev), compatible); config.name = compatible;
config.id = NVMEM_DEVID_NONE; config.id = NVMEM_DEVID_AUTO;
config.owner = THIS_MODULE; config.owner = THIS_MODULE;
config.type = NVMEM_TYPE_OTP; config.type = NVMEM_TYPE_OTP;
config.root_only = true; config.root_only = true;
@ -905,7 +904,6 @@ 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;
} }
@ -940,6 +938,7 @@ static int mtd_nvmem_fact_otp_reg_read(void *priv, unsigned int offset,
static int mtd_otp_nvmem_add(struct mtd_info *mtd) static int mtd_otp_nvmem_add(struct mtd_info *mtd)
{ {
struct device *dev = mtd->dev.parent;
struct nvmem_device *nvmem; struct nvmem_device *nvmem;
ssize_t size; ssize_t size;
int err; int err;
@ -953,8 +952,8 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd)
nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size, nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size,
mtd_nvmem_user_otp_reg_read); mtd_nvmem_user_otp_reg_read);
if (IS_ERR(nvmem)) { if (IS_ERR(nvmem)) {
dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n"); err = PTR_ERR(nvmem);
return PTR_ERR(nvmem); goto err;
} }
mtd->otp_user_nvmem = nvmem; mtd->otp_user_nvmem = nvmem;
} }
@ -971,7 +970,6 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd)
nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size, nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size,
mtd_nvmem_fact_otp_reg_read); mtd_nvmem_fact_otp_reg_read);
if (IS_ERR(nvmem)) { if (IS_ERR(nvmem)) {
dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n");
err = PTR_ERR(nvmem); err = PTR_ERR(nvmem);
goto err; goto err;
} }
@ -983,7 +981,7 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd)
err: err:
nvmem_unregister(mtd->otp_user_nvmem); nvmem_unregister(mtd->otp_user_nvmem);
return err; return dev_err_probe(dev, err, "Failed to register OTP NVMEM device\n");
} }
/** /**
@ -1023,10 +1021,14 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
mtd_set_dev_defaults(mtd); mtd_set_dev_defaults(mtd);
ret = mtd_otp_nvmem_add(mtd);
if (ret)
goto out;
if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
ret = add_mtd_device(mtd); ret = add_mtd_device(mtd);
if (ret) if (ret)
return ret; goto out;
} }
/* Prefer parsed partitions over driver-provided fallback */ /* Prefer parsed partitions over driver-provided fallback */
@ -1061,9 +1063,12 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
register_reboot_notifier(&mtd->reboot_notifier); register_reboot_notifier(&mtd->reboot_notifier);
} }
ret = mtd_otp_nvmem_add(mtd);
out: out:
if (ret) {
nvmem_unregister(mtd->otp_user_nvmem);
nvmem_unregister(mtd->otp_factory_nvmem);
}
if (ret && device_is_registered(&mtd->dev)) if (ret && device_is_registered(&mtd->dev))
del_mtd_device(mtd); del_mtd_device(mtd);

View File

@ -848,13 +848,11 @@ static int mxic_ecc_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int mxic_ecc_remove(struct platform_device *pdev) static void mxic_ecc_remove(struct platform_device *pdev)
{ {
struct mxic_ecc_engine *mxic = platform_get_drvdata(pdev); struct mxic_ecc_engine *mxic = platform_get_drvdata(pdev);
nand_ecc_unregister_on_host_hw_engine(&mxic->external_engine); nand_ecc_unregister_on_host_hw_engine(&mxic->external_engine);
return 0;
} }
static const struct of_device_id mxic_ecc_of_ids[] = { static const struct of_device_id mxic_ecc_of_ids[] = {
@ -871,7 +869,7 @@ static struct platform_driver mxic_ecc_driver = {
.of_match_table = mxic_ecc_of_ids, .of_match_table = mxic_ecc_of_ids,
}, },
.probe = mxic_ecc_probe, .probe = mxic_ecc_probe,
.remove = mxic_ecc_remove, .remove_new = mxic_ecc_remove,
}; };
module_platform_driver(mxic_ecc_driver); module_platform_driver(mxic_ecc_driver);

View File

@ -25,7 +25,7 @@ config MTD_ONENAND_GENERIC
config MTD_ONENAND_OMAP2 config MTD_ONENAND_OMAP2
tristate "OneNAND on OMAP2/OMAP3 support" tristate "OneNAND on OMAP2/OMAP3 support"
depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && ARM) depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && ARM)
depends on OF || COMPILE_TEST depends on OF
depends on OMAP_GPMC depends on OMAP_GPMC
help help
Support for a OneNAND flash device connected to an OMAP2/OMAP3 SoC Support for a OneNAND flash device connected to an OMAP2/OMAP3 SoC

View File

@ -85,7 +85,7 @@ out_free_info:
return err; return err;
} }
static int generic_onenand_remove(struct platform_device *pdev) static void generic_onenand_remove(struct platform_device *pdev)
{ {
struct onenand_info *info = platform_get_drvdata(pdev); struct onenand_info *info = platform_get_drvdata(pdev);
struct resource *res = pdev->resource; struct resource *res = pdev->resource;
@ -97,8 +97,6 @@ static int generic_onenand_remove(struct platform_device *pdev)
iounmap(info->onenand.base); iounmap(info->onenand.base);
kfree(info); kfree(info);
} }
return 0;
} }
static struct platform_driver generic_onenand_driver = { static struct platform_driver generic_onenand_driver = {
@ -106,7 +104,7 @@ static struct platform_driver generic_onenand_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
}, },
.probe = generic_onenand_probe, .probe = generic_onenand_probe,
.remove = generic_onenand_remove, .remove_new = generic_onenand_remove,
}; };
module_platform_driver(generic_onenand_driver); module_platform_driver(generic_onenand_driver);

View File

@ -581,7 +581,7 @@ err_release_dma:
return r; return r;
} }
static int omap2_onenand_remove(struct platform_device *pdev) static void omap2_onenand_remove(struct platform_device *pdev)
{ {
struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); struct omap2_onenand *c = dev_get_drvdata(&pdev->dev);
@ -589,8 +589,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
if (c->dma_chan) if (c->dma_chan)
dma_release_channel(c->dma_chan); dma_release_channel(c->dma_chan);
omap2_onenand_shutdown(pdev); omap2_onenand_shutdown(pdev);
return 0;
} }
static const struct of_device_id omap2_onenand_id_table[] = { static const struct of_device_id omap2_onenand_id_table[] = {
@ -601,7 +599,7 @@ MODULE_DEVICE_TABLE(of, omap2_onenand_id_table);
static struct platform_driver omap2_onenand_driver = { static struct platform_driver omap2_onenand_driver = {
.probe = omap2_onenand_probe, .probe = omap2_onenand_probe,
.remove = omap2_onenand_remove, .remove_new = omap2_onenand_remove,
.shutdown = omap2_onenand_shutdown, .shutdown = omap2_onenand_shutdown,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,

View File

@ -943,13 +943,11 @@ static int s3c_onenand_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int s3c_onenand_remove(struct platform_device *pdev) static void s3c_onenand_remove(struct platform_device *pdev)
{ {
struct mtd_info *mtd = platform_get_drvdata(pdev); struct mtd_info *mtd = platform_get_drvdata(pdev);
onenand_release(mtd); onenand_release(mtd);
return 0;
} }
static int s3c_pm_ops_suspend(struct device *dev) static int s3c_pm_ops_suspend(struct device *dev)
@ -996,7 +994,7 @@ static struct platform_driver s3c_onenand_driver = {
}, },
.id_table = s3c_onenand_driver_ids, .id_table = s3c_onenand_driver_ids,
.probe = s3c_onenand_probe, .probe = s3c_onenand_probe,
.remove = s3c_onenand_remove, .remove_new = s3c_onenand_remove,
}; };
module_platform_driver(s3c_onenand_driver); module_platform_driver(s3c_onenand_driver);

View File

@ -373,7 +373,7 @@ config MTD_NAND_TEGRA
config MTD_NAND_STM32_FMC2 config MTD_NAND_STM32_FMC2
tristate "Support for NAND controller on STM32MP SoCs" tristate "Support for NAND controller on STM32MP SoCs"
depends on MACH_STM32MP157 || COMPILE_TEST depends on ARCH_STM32 || COMPILE_TEST
select MFD_SYSCON select MFD_SYSCON
help help
Enables support for NAND Flash chips on SoCs containing the FMC2 Enables support for NAND Flash chips on SoCs containing the FMC2

View File

@ -397,7 +397,7 @@ err_nand_cleanup:
/* /*
* Clean up routine * Clean up routine
*/ */
static int gpio_nand_remove(struct platform_device *pdev) static void gpio_nand_remove(struct platform_device *pdev)
{ {
struct gpio_nand *priv = platform_get_drvdata(pdev); struct gpio_nand *priv = platform_get_drvdata(pdev);
struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip); struct mtd_info *mtd = nand_to_mtd(&priv->nand_chip);
@ -410,8 +410,6 @@ static int gpio_nand_remove(struct platform_device *pdev)
ret = mtd_device_unregister(mtd); ret = mtd_device_unregister(mtd);
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(mtd_to_nand(mtd)); nand_cleanup(mtd_to_nand(mtd));
return 0;
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
@ -434,7 +432,7 @@ MODULE_DEVICE_TABLE(platform, gpio_nand_plat_id_table);
static struct platform_driver gpio_nand_driver = { static struct platform_driver gpio_nand_driver = {
.probe = gpio_nand_probe, .probe = gpio_nand_probe,
.remove = gpio_nand_remove, .remove_new = gpio_nand_remove,
.id_table = gpio_nand_plat_id_table, .id_table = gpio_nand_plat_id_table,
.driver = { .driver = {
.name = "ams-delta-nand", .name = "ams-delta-nand",

View File

@ -1496,7 +1496,7 @@ disable_controller_clk:
return ret; return ret;
} }
static int anfc_remove(struct platform_device *pdev) static void anfc_remove(struct platform_device *pdev)
{ {
struct arasan_nfc *nfc = platform_get_drvdata(pdev); struct arasan_nfc *nfc = platform_get_drvdata(pdev);
@ -1504,8 +1504,6 @@ static int anfc_remove(struct platform_device *pdev)
clk_disable_unprepare(nfc->bus_clk); clk_disable_unprepare(nfc->bus_clk);
clk_disable_unprepare(nfc->controller_clk); clk_disable_unprepare(nfc->controller_clk);
return 0;
} }
static const struct of_device_id anfc_ids[] = { static const struct of_device_id anfc_ids[] = {
@ -1525,7 +1523,7 @@ static struct platform_driver anfc_driver = {
.of_match_table = anfc_ids, .of_match_table = anfc_ids,
}, },
.probe = anfc_probe, .probe = anfc_probe,
.remove = anfc_remove, .remove_new = anfc_remove,
}; };
module_platform_driver(anfc_driver); module_platform_driver(anfc_driver);

View File

@ -2626,13 +2626,11 @@ static int atmel_nand_controller_probe(struct platform_device *pdev)
return caps->ops->probe(pdev, caps); return caps->ops->probe(pdev, caps);
} }
static int atmel_nand_controller_remove(struct platform_device *pdev) static void atmel_nand_controller_remove(struct platform_device *pdev)
{ {
struct atmel_nand_controller *nc = platform_get_drvdata(pdev); struct atmel_nand_controller *nc = platform_get_drvdata(pdev);
WARN_ON(nc->caps->ops->remove(nc)); WARN_ON(nc->caps->ops->remove(nc));
return 0;
} }
static __maybe_unused int atmel_nand_controller_resume(struct device *dev) static __maybe_unused int atmel_nand_controller_resume(struct device *dev)
@ -2663,7 +2661,7 @@ static struct platform_driver atmel_nand_controller_driver = {
.pm = &atmel_nand_controller_pm_ops, .pm = &atmel_nand_controller_pm_ops,
}, },
.probe = atmel_nand_controller_probe, .probe = atmel_nand_controller_probe,
.remove = atmel_nand_controller_remove, .remove_new = atmel_nand_controller_remove,
}; };
module_platform_driver(atmel_nand_controller_driver); module_platform_driver(atmel_nand_controller_driver);

View File

@ -337,7 +337,7 @@ out1:
return ret; return ret;
} }
static int au1550nd_remove(struct platform_device *pdev) static void au1550nd_remove(struct platform_device *pdev)
{ {
struct au1550nd_ctx *ctx = platform_get_drvdata(pdev); struct au1550nd_ctx *ctx = platform_get_drvdata(pdev);
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -350,7 +350,6 @@ static int au1550nd_remove(struct platform_device *pdev)
iounmap(ctx->base); iounmap(ctx->base);
release_mem_region(r->start, 0x1000); release_mem_region(r->start, 0x1000);
kfree(ctx); kfree(ctx);
return 0;
} }
static struct platform_driver au1550nd_driver = { static struct platform_driver au1550nd_driver = {
@ -358,7 +357,7 @@ static struct platform_driver au1550nd_driver = {
.name = "au1550-nand", .name = "au1550-nand",
}, },
.probe = au1550nd_probe, .probe = au1550nd_probe,
.remove = au1550nd_remove, .remove_new = au1550nd_remove,
}; };
module_platform_driver(au1550nd_driver); module_platform_driver(au1550nd_driver);

View File

@ -57,7 +57,7 @@ static int bcm47xxnflash_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int bcm47xxnflash_remove(struct platform_device *pdev) static void bcm47xxnflash_remove(struct platform_device *pdev)
{ {
struct bcm47xxnflash *nflash = platform_get_drvdata(pdev); struct bcm47xxnflash *nflash = platform_get_drvdata(pdev);
struct nand_chip *chip = &nflash->nand_chip; struct nand_chip *chip = &nflash->nand_chip;
@ -66,13 +66,11 @@ static int bcm47xxnflash_remove(struct platform_device *pdev)
ret = mtd_device_unregister(nand_to_mtd(chip)); ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(chip); nand_cleanup(chip);
return 0;
} }
static struct platform_driver bcm47xxnflash_driver = { static struct platform_driver bcm47xxnflash_driver = {
.probe = bcm47xxnflash_probe, .probe = bcm47xxnflash_probe,
.remove = bcm47xxnflash_remove, .remove_new = bcm47xxnflash_remove,
.driver = { .driver = {
.name = "bcma_nflash", .name = "bcma_nflash",
}, },

View File

@ -3055,18 +3055,16 @@ static int cadence_nand_dt_probe(struct platform_device *ofdev)
return 0; return 0;
} }
static int cadence_nand_dt_remove(struct platform_device *ofdev) static void cadence_nand_dt_remove(struct platform_device *ofdev)
{ {
struct cadence_nand_dt *dt = platform_get_drvdata(ofdev); struct cadence_nand_dt *dt = platform_get_drvdata(ofdev);
cadence_nand_remove(&dt->cdns_ctrl); cadence_nand_remove(&dt->cdns_ctrl);
return 0;
} }
static struct platform_driver cadence_nand_dt_driver = { static struct platform_driver cadence_nand_dt_driver = {
.probe = cadence_nand_dt_probe, .probe = cadence_nand_dt_probe,
.remove = cadence_nand_dt_remove, .remove_new = cadence_nand_dt_remove,
.driver = { .driver = {
.name = "cadence-nand-controller", .name = "cadence-nand-controller",
.of_match_table = cadence_nand_dt_ids, .of_match_table = cadence_nand_dt_ids,

View File

@ -821,7 +821,7 @@ err_cleanup_nand:
return ret; return ret;
} }
static int nand_davinci_remove(struct platform_device *pdev) static void nand_davinci_remove(struct platform_device *pdev)
{ {
struct davinci_nand_info *info = platform_get_drvdata(pdev); struct davinci_nand_info *info = platform_get_drvdata(pdev);
struct nand_chip *chip = &info->chip; struct nand_chip *chip = &info->chip;
@ -835,13 +835,11 @@ static int nand_davinci_remove(struct platform_device *pdev)
ret = mtd_device_unregister(nand_to_mtd(chip)); ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(chip); nand_cleanup(chip);
return 0;
} }
static struct platform_driver nand_davinci_driver = { static struct platform_driver nand_davinci_driver = {
.probe = nand_davinci_probe, .probe = nand_davinci_probe,
.remove = nand_davinci_remove, .remove_new = nand_davinci_remove,
.driver = { .driver = {
.name = "davinci_nand", .name = "davinci_nand",
.of_match_table = of_match_ptr(davinci_nand_of_match), .of_match_table = of_match_ptr(davinci_nand_of_match),

View File

@ -233,7 +233,7 @@ out_disable_clk:
return ret; return ret;
} }
static int denali_dt_remove(struct platform_device *pdev) static void denali_dt_remove(struct platform_device *pdev)
{ {
struct denali_dt *dt = platform_get_drvdata(pdev); struct denali_dt *dt = platform_get_drvdata(pdev);
@ -243,13 +243,11 @@ static int denali_dt_remove(struct platform_device *pdev)
clk_disable_unprepare(dt->clk_ecc); clk_disable_unprepare(dt->clk_ecc);
clk_disable_unprepare(dt->clk_x); clk_disable_unprepare(dt->clk_x);
clk_disable_unprepare(dt->clk); clk_disable_unprepare(dt->clk);
return 0;
} }
static struct platform_driver denali_dt_driver = { static struct platform_driver denali_dt_driver = {
.probe = denali_dt_probe, .probe = denali_dt_probe,
.remove = denali_dt_remove, .remove_new = denali_dt_remove,
.driver = { .driver = {
.name = "denali-nand-dt", .name = "denali-nand-dt",
.of_match_table = denali_nand_dt_ids, .of_match_table = denali_nand_dt_ids,

View File

@ -963,7 +963,7 @@ err:
return ret; return ret;
} }
static int fsl_elbc_nand_remove(struct platform_device *pdev) static void fsl_elbc_nand_remove(struct platform_device *pdev)
{ {
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand; struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev); struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
@ -984,8 +984,6 @@ static int fsl_elbc_nand_remove(struct platform_device *pdev)
} }
mutex_unlock(&fsl_elbc_nand_mutex); mutex_unlock(&fsl_elbc_nand_mutex);
return 0;
} }
static const struct of_device_id fsl_elbc_nand_match[] = { static const struct of_device_id fsl_elbc_nand_match[] = {
@ -1000,7 +998,7 @@ static struct platform_driver fsl_elbc_nand_driver = {
.of_match_table = fsl_elbc_nand_match, .of_match_table = fsl_elbc_nand_match,
}, },
.probe = fsl_elbc_nand_probe, .probe = fsl_elbc_nand_probe,
.remove = fsl_elbc_nand_remove, .remove_new = fsl_elbc_nand_remove,
}; };
module_platform_driver(fsl_elbc_nand_driver); module_platform_driver(fsl_elbc_nand_driver);

View File

@ -1094,7 +1094,7 @@ err:
return ret; return ret;
} }
static int fsl_ifc_nand_remove(struct platform_device *dev) static void fsl_ifc_nand_remove(struct platform_device *dev)
{ {
struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev); struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev);
struct nand_chip *chip = &priv->chip; struct nand_chip *chip = &priv->chip;
@ -1113,8 +1113,6 @@ static int fsl_ifc_nand_remove(struct platform_device *dev)
kfree(ifc_nand_ctrl); kfree(ifc_nand_ctrl);
} }
mutex_unlock(&fsl_ifc_nand_mutex); mutex_unlock(&fsl_ifc_nand_mutex);
return 0;
} }
static const struct of_device_id fsl_ifc_nand_match[] = { static const struct of_device_id fsl_ifc_nand_match[] = {
@ -1131,7 +1129,7 @@ static struct platform_driver fsl_ifc_nand_driver = {
.of_match_table = fsl_ifc_nand_match, .of_match_table = fsl_ifc_nand_match,
}, },
.probe = fsl_ifc_nand_probe, .probe = fsl_ifc_nand_probe,
.remove = fsl_ifc_nand_remove, .remove_new = fsl_ifc_nand_remove,
}; };
module_platform_driver(fsl_ifc_nand_driver); module_platform_driver(fsl_ifc_nand_driver);

View File

@ -235,7 +235,7 @@ static int fun_probe(struct platform_device *ofdev)
return 0; return 0;
} }
static int fun_remove(struct platform_device *ofdev) static void fun_remove(struct platform_device *ofdev)
{ {
struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
struct nand_chip *chip = &fun->chip; struct nand_chip *chip = &fun->chip;
@ -245,8 +245,6 @@ static int fun_remove(struct platform_device *ofdev)
ret = mtd_device_unregister(mtd); ret = mtd_device_unregister(mtd);
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(chip); nand_cleanup(chip);
return 0;
} }
static const struct of_device_id of_fun_match[] = { static const struct of_device_id of_fun_match[] = {
@ -261,7 +259,7 @@ static struct platform_driver of_fun_driver = {
.of_match_table = of_fun_match, .of_match_table = of_fun_match,
}, },
.probe = fun_probe, .probe = fun_probe,
.remove = fun_remove, .remove_new = fun_remove,
}; };
module_platform_driver(of_fun_driver); module_platform_driver(of_fun_driver);

View File

@ -880,7 +880,7 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
} }
} }
if (of_get_property(np, "nand-skip-bbtscan", NULL)) if (of_property_read_bool(np, "nand-skip-bbtscan"))
nand->options |= NAND_SKIP_BBTSCAN; nand->options |= NAND_SKIP_BBTSCAN;
host->dev_timings = devm_kzalloc(&pdev->dev, host->dev_timings = devm_kzalloc(&pdev->dev,
@ -1165,7 +1165,7 @@ disable_clk:
/* /*
* Clean up routine * Clean up routine
*/ */
static int fsmc_nand_remove(struct platform_device *pdev) static void fsmc_nand_remove(struct platform_device *pdev)
{ {
struct fsmc_nand_data *host = platform_get_drvdata(pdev); struct fsmc_nand_data *host = platform_get_drvdata(pdev);
@ -1184,8 +1184,6 @@ static int fsmc_nand_remove(struct platform_device *pdev)
} }
clk_disable_unprepare(host->clk); clk_disable_unprepare(host->clk);
} }
return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
@ -1224,7 +1222,7 @@ static const struct of_device_id fsmc_nand_id_table[] = {
MODULE_DEVICE_TABLE(of, fsmc_nand_id_table); MODULE_DEVICE_TABLE(of, fsmc_nand_id_table);
static struct platform_driver fsmc_nand_driver = { static struct platform_driver fsmc_nand_driver = {
.remove = fsmc_nand_remove, .remove_new = fsmc_nand_remove,
.driver = { .driver = {
.name = "fsmc-nand", .name = "fsmc-nand",
.of_match_table = fsmc_nand_id_table, .of_match_table = fsmc_nand_id_table,

View File

@ -265,7 +265,7 @@ gpio_nand_get_io_sync(struct platform_device *pdev)
return platform_get_resource(pdev, IORESOURCE_MEM, 1); return platform_get_resource(pdev, IORESOURCE_MEM, 1);
} }
static int gpio_nand_remove(struct platform_device *pdev) static void gpio_nand_remove(struct platform_device *pdev)
{ {
struct gpiomtd *gpiomtd = platform_get_drvdata(pdev); struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
struct nand_chip *chip = &gpiomtd->nand_chip; struct nand_chip *chip = &gpiomtd->nand_chip;
@ -280,8 +280,6 @@ static int gpio_nand_remove(struct platform_device *pdev)
gpiod_set_value(gpiomtd->nwp, 0); gpiod_set_value(gpiomtd->nwp, 0);
if (gpiomtd->nce && !IS_ERR(gpiomtd->nce)) if (gpiomtd->nce && !IS_ERR(gpiomtd->nce))
gpiod_set_value(gpiomtd->nce, 0); gpiod_set_value(gpiomtd->nce, 0);
return 0;
} }
static int gpio_nand_probe(struct platform_device *pdev) static int gpio_nand_probe(struct platform_device *pdev)
@ -394,7 +392,7 @@ out_ce:
static struct platform_driver gpio_nand_driver = { static struct platform_driver gpio_nand_driver = {
.probe = gpio_nand_probe, .probe = gpio_nand_probe,
.remove = gpio_nand_remove, .remove_new = gpio_nand_remove,
.driver = { .driver = {
.name = "gpio-nand", .name = "gpio-nand",
.of_match_table = of_match_ptr(gpio_nand_id_table), .of_match_table = of_match_ptr(gpio_nand_id_table),

View File

@ -2777,7 +2777,7 @@ exit_acquire_resources:
return ret; return ret;
} }
static int gpmi_nand_remove(struct platform_device *pdev) static void gpmi_nand_remove(struct platform_device *pdev)
{ {
struct gpmi_nand_data *this = platform_get_drvdata(pdev); struct gpmi_nand_data *this = platform_get_drvdata(pdev);
struct nand_chip *chip = &this->nand; struct nand_chip *chip = &this->nand;
@ -2791,7 +2791,6 @@ static int gpmi_nand_remove(struct platform_device *pdev)
nand_cleanup(chip); nand_cleanup(chip);
gpmi_free_dma_buffer(this); gpmi_free_dma_buffer(this);
release_resources(this); release_resources(this);
return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
@ -2860,7 +2859,7 @@ static struct platform_driver gpmi_nand_driver = {
.of_match_table = gpmi_nand_id_table, .of_match_table = gpmi_nand_id_table,
}, },
.probe = gpmi_nand_probe, .probe = gpmi_nand_probe,
.remove = gpmi_nand_remove, .remove_new = gpmi_nand_remove,
}; };
module_platform_driver(gpmi_nand_driver); module_platform_driver(gpmi_nand_driver);

View File

@ -798,7 +798,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int hisi_nfc_remove(struct platform_device *pdev) static void hisi_nfc_remove(struct platform_device *pdev)
{ {
struct hinfc_host *host = platform_get_drvdata(pdev); struct hinfc_host *host = platform_get_drvdata(pdev);
struct nand_chip *chip = &host->chip; struct nand_chip *chip = &host->chip;
@ -807,8 +807,6 @@ static int hisi_nfc_remove(struct platform_device *pdev)
ret = mtd_device_unregister(nand_to_mtd(chip)); ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(chip); nand_cleanup(chip);
return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
@ -860,7 +858,7 @@ static struct platform_driver hisi_nfc_driver = {
.pm = &hisi_nfc_pm_ops, .pm = &hisi_nfc_pm_ops,
}, },
.probe = hisi_nfc_probe, .probe = hisi_nfc_probe,
.remove = hisi_nfc_remove, .remove_new = hisi_nfc_remove,
}; };
module_platform_driver(hisi_nfc_driver); module_platform_driver(hisi_nfc_driver);

View File

@ -522,7 +522,7 @@ static int ingenic_nand_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int ingenic_nand_remove(struct platform_device *pdev) static void ingenic_nand_remove(struct platform_device *pdev)
{ {
struct ingenic_nfc *nfc = platform_get_drvdata(pdev); struct ingenic_nfc *nfc = platform_get_drvdata(pdev);
@ -530,8 +530,6 @@ static int ingenic_nand_remove(struct platform_device *pdev)
ingenic_ecc_release(nfc->ecc); ingenic_ecc_release(nfc->ecc);
ingenic_nand_cleanup_chips(nfc); ingenic_nand_cleanup_chips(nfc);
return 0;
} }
static const struct jz_soc_info jz4740_soc_info = { static const struct jz_soc_info jz4740_soc_info = {
@ -564,7 +562,7 @@ MODULE_DEVICE_TABLE(of, ingenic_nand_dt_match);
static struct platform_driver ingenic_nand_driver = { static struct platform_driver ingenic_nand_driver = {
.probe = ingenic_nand_probe, .probe = ingenic_nand_probe,
.remove = ingenic_nand_remove, .remove_new = ingenic_nand_remove,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.of_match_table = ingenic_nand_dt_match, .of_match_table = ingenic_nand_dt_match,

View File

@ -706,7 +706,7 @@ err_of_node_put:
return ret; return ret;
} }
static int ebu_nand_remove(struct platform_device *pdev) static void ebu_nand_remove(struct platform_device *pdev)
{ {
struct ebu_nand_controller *ebu_host = platform_get_drvdata(pdev); struct ebu_nand_controller *ebu_host = platform_get_drvdata(pdev);
int ret; int ret;
@ -717,8 +717,6 @@ static int ebu_nand_remove(struct platform_device *pdev)
ebu_nand_disable(&ebu_host->chip); ebu_nand_disable(&ebu_host->chip);
ebu_dma_cleanup(ebu_host); ebu_dma_cleanup(ebu_host);
clk_disable_unprepare(ebu_host->clk); clk_disable_unprepare(ebu_host->clk);
return 0;
} }
static const struct of_device_id ebu_nand_match[] = { static const struct of_device_id ebu_nand_match[] = {
@ -729,7 +727,7 @@ MODULE_DEVICE_TABLE(of, ebu_nand_match);
static struct platform_driver ebu_nand_driver = { static struct platform_driver ebu_nand_driver = {
.probe = ebu_nand_probe, .probe = ebu_nand_probe,
.remove = ebu_nand_remove, .remove_new = ebu_nand_remove,
.driver = { .driver = {
.name = "intel-nand-controller", .name = "intel-nand-controller",
.of_match_table = ebu_nand_match, .of_match_table = ebu_nand_match,

View File

@ -827,7 +827,7 @@ free_gpio:
/* /*
* Remove NAND device * Remove NAND device
*/ */
static int lpc32xx_nand_remove(struct platform_device *pdev) static void lpc32xx_nand_remove(struct platform_device *pdev)
{ {
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
struct nand_chip *chip = &host->nand_chip; struct nand_chip *chip = &host->nand_chip;
@ -846,8 +846,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
lpc32xx_wp_enable(host); lpc32xx_wp_enable(host);
gpiod_put(host->wp_gpio); gpiod_put(host->wp_gpio);
return 0;
} }
static int lpc32xx_nand_resume(struct platform_device *pdev) static int lpc32xx_nand_resume(struct platform_device *pdev)
@ -889,7 +887,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
static struct platform_driver lpc32xx_nand_driver = { static struct platform_driver lpc32xx_nand_driver = {
.probe = lpc32xx_nand_probe, .probe = lpc32xx_nand_probe,
.remove = lpc32xx_nand_remove, .remove_new = lpc32xx_nand_remove,
.resume = pm_ptr(lpc32xx_nand_resume), .resume = pm_ptr(lpc32xx_nand_resume),
.suspend = pm_ptr(lpc32xx_nand_suspend), .suspend = pm_ptr(lpc32xx_nand_suspend),
.driver = { .driver = {

View File

@ -946,7 +946,7 @@ enable_wp:
/* /*
* Remove NAND device. * Remove NAND device.
*/ */
static int lpc32xx_nand_remove(struct platform_device *pdev) static void lpc32xx_nand_remove(struct platform_device *pdev)
{ {
uint32_t tmp; uint32_t tmp;
struct lpc32xx_nand_host *host = platform_get_drvdata(pdev); struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
@ -965,8 +965,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
clk_disable_unprepare(host->clk); clk_disable_unprepare(host->clk);
lpc32xx_wp_enable(host); lpc32xx_wp_enable(host);
return 0;
} }
static int lpc32xx_nand_resume(struct platform_device *pdev) static int lpc32xx_nand_resume(struct platform_device *pdev)
@ -1015,7 +1013,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
static struct platform_driver lpc32xx_nand_driver = { static struct platform_driver lpc32xx_nand_driver = {
.probe = lpc32xx_nand_probe, .probe = lpc32xx_nand_probe,
.remove = lpc32xx_nand_remove, .remove_new = lpc32xx_nand_remove,
.resume = pm_ptr(lpc32xx_nand_resume), .resume = pm_ptr(lpc32xx_nand_resume),
.suspend = pm_ptr(lpc32xx_nand_suspend), .suspend = pm_ptr(lpc32xx_nand_suspend),
.driver = { .driver = {

View File

@ -3004,7 +3004,7 @@ unprepare_core_clk:
return ret; return ret;
} }
static int marvell_nfc_remove(struct platform_device *pdev) static void marvell_nfc_remove(struct platform_device *pdev)
{ {
struct marvell_nfc *nfc = platform_get_drvdata(pdev); struct marvell_nfc *nfc = platform_get_drvdata(pdev);
@ -3017,8 +3017,6 @@ static int marvell_nfc_remove(struct platform_device *pdev)
clk_disable_unprepare(nfc->reg_clk); clk_disable_unprepare(nfc->reg_clk);
clk_disable_unprepare(nfc->core_clk); clk_disable_unprepare(nfc->core_clk);
return 0;
} }
static int __maybe_unused marvell_nfc_suspend(struct device *dev) static int __maybe_unused marvell_nfc_suspend(struct device *dev)
@ -3154,7 +3152,7 @@ static struct platform_driver marvell_nfc_driver = {
}, },
.id_table = marvell_nfc_platform_ids, .id_table = marvell_nfc_platform_ids,
.probe = marvell_nfc_probe, .probe = marvell_nfc_probe,
.remove = marvell_nfc_remove, .remove_new = marvell_nfc_remove,
}; };
module_platform_driver(marvell_nfc_driver); module_platform_driver(marvell_nfc_driver);

View File

@ -1440,20 +1440,18 @@ err_clk:
return ret; return ret;
} }
static int meson_nfc_remove(struct platform_device *pdev) static void meson_nfc_remove(struct platform_device *pdev)
{ {
struct meson_nfc *nfc = platform_get_drvdata(pdev); struct meson_nfc *nfc = platform_get_drvdata(pdev);
meson_nfc_nand_chip_cleanup(nfc); meson_nfc_nand_chip_cleanup(nfc);
meson_nfc_disable_clk(nfc); meson_nfc_disable_clk(nfc);
return 0;
} }
static struct platform_driver meson_nfc_driver = { static struct platform_driver meson_nfc_driver = {
.probe = meson_nfc_probe, .probe = meson_nfc_probe,
.remove = meson_nfc_remove, .remove_new = meson_nfc_remove,
.driver = { .driver = {
.name = "meson-nand", .name = "meson-nand",
.of_match_table = meson_nfc_id_table, .of_match_table = meson_nfc_id_table,

View File

@ -822,7 +822,7 @@ error:
return retval; return retval;
} }
static int mpc5121_nfc_remove(struct platform_device *op) static void mpc5121_nfc_remove(struct platform_device *op)
{ {
struct device *dev = &op->dev; struct device *dev = &op->dev;
struct mtd_info *mtd = dev_get_drvdata(dev); struct mtd_info *mtd = dev_get_drvdata(dev);
@ -832,8 +832,6 @@ static int mpc5121_nfc_remove(struct platform_device *op)
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(mtd_to_nand(mtd)); nand_cleanup(mtd_to_nand(mtd));
mpc5121_nfc_free(dev, mtd); mpc5121_nfc_free(dev, mtd);
return 0;
} }
static const struct of_device_id mpc5121_nfc_match[] = { static const struct of_device_id mpc5121_nfc_match[] = {
@ -844,7 +842,7 @@ MODULE_DEVICE_TABLE(of, mpc5121_nfc_match);
static struct platform_driver mpc5121_nfc_driver = { static struct platform_driver mpc5121_nfc_driver = {
.probe = mpc5121_nfc_probe, .probe = mpc5121_nfc_probe,
.remove = mpc5121_nfc_remove, .remove_new = mpc5121_nfc_remove,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.of_match_table = mpc5121_nfc_match, .of_match_table = mpc5121_nfc_match,

View File

@ -1601,7 +1601,7 @@ release_ecc:
return ret; return ret;
} }
static int mtk_nfc_remove(struct platform_device *pdev) static void mtk_nfc_remove(struct platform_device *pdev)
{ {
struct mtk_nfc *nfc = platform_get_drvdata(pdev); struct mtk_nfc *nfc = platform_get_drvdata(pdev);
struct mtk_nfc_nand_chip *mtk_chip; struct mtk_nfc_nand_chip *mtk_chip;
@ -1620,8 +1620,6 @@ static int mtk_nfc_remove(struct platform_device *pdev)
mtk_ecc_release(nfc->ecc); mtk_ecc_release(nfc->ecc);
mtk_nfc_disable_clk(&nfc->clk); mtk_nfc_disable_clk(&nfc->clk);
return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
@ -1663,7 +1661,7 @@ static SIMPLE_DEV_PM_OPS(mtk_nfc_pm_ops, mtk_nfc_suspend, mtk_nfc_resume);
static struct platform_driver mtk_nfc_driver = { static struct platform_driver mtk_nfc_driver = {
.probe = mtk_nfc_probe, .probe = mtk_nfc_probe,
.remove = mtk_nfc_remove, .remove_new = mtk_nfc_remove,
.driver = { .driver = {
.name = MTK_NAME, .name = MTK_NAME,
.of_match_table = mtk_nfc_id_table, .of_match_table = mtk_nfc_id_table,

View File

@ -1599,16 +1599,6 @@ static inline int is_imx25_nfc(struct mxc_nand_host *host)
return host->devtype_data == &imx25_nand_devtype_data; return host->devtype_data == &imx25_nand_devtype_data;
} }
static inline int is_imx51_nfc(struct mxc_nand_host *host)
{
return host->devtype_data == &imx51_nand_devtype_data;
}
static inline int is_imx53_nfc(struct mxc_nand_host *host)
{
return host->devtype_data == &imx53_nand_devtype_data;
}
static const struct of_device_id mxcnd_dt_ids[] = { static const struct of_device_id mxcnd_dt_ids[] = {
{ .compatible = "fsl,imx21-nand", .data = &imx21_nand_devtype_data, }, { .compatible = "fsl,imx21-nand", .data = &imx21_nand_devtype_data, },
{ .compatible = "fsl,imx27-nand", .data = &imx27_nand_devtype_data, }, { .compatible = "fsl,imx27-nand", .data = &imx27_nand_devtype_data, },
@ -1831,7 +1821,7 @@ escan:
return err; return err;
} }
static int mxcnd_remove(struct platform_device *pdev) static void mxcnd_remove(struct platform_device *pdev)
{ {
struct mxc_nand_host *host = platform_get_drvdata(pdev); struct mxc_nand_host *host = platform_get_drvdata(pdev);
struct nand_chip *chip = &host->nand; struct nand_chip *chip = &host->nand;
@ -1842,8 +1832,6 @@ static int mxcnd_remove(struct platform_device *pdev)
nand_cleanup(chip); nand_cleanup(chip);
if (host->clk_act) if (host->clk_act)
clk_disable_unprepare(host->clk); clk_disable_unprepare(host->clk);
return 0;
} }
static struct platform_driver mxcnd_driver = { static struct platform_driver mxcnd_driver = {
@ -1852,7 +1840,7 @@ static struct platform_driver mxcnd_driver = {
.of_match_table = mxcnd_dt_ids, .of_match_table = mxcnd_dt_ids,
}, },
.probe = mxcnd_probe, .probe = mxcnd_probe,
.remove = mxcnd_remove, .remove_new = mxcnd_remove,
}; };
module_platform_driver(mxcnd_driver); module_platform_driver(mxcnd_driver);

View File

@ -553,7 +553,7 @@ fail:
return err; return err;
} }
static int mxic_nfc_remove(struct platform_device *pdev) static void mxic_nfc_remove(struct platform_device *pdev)
{ {
struct mxic_nand_ctlr *nfc = platform_get_drvdata(pdev); struct mxic_nand_ctlr *nfc = platform_get_drvdata(pdev);
struct nand_chip *chip = &nfc->chip; struct nand_chip *chip = &nfc->chip;
@ -564,7 +564,6 @@ static int mxic_nfc_remove(struct platform_device *pdev)
nand_cleanup(chip); nand_cleanup(chip);
mxic_nfc_clk_disable(nfc); mxic_nfc_clk_disable(nfc);
return 0;
} }
static const struct of_device_id mxic_nfc_of_ids[] = { static const struct of_device_id mxic_nfc_of_ids[] = {
@ -575,7 +574,7 @@ MODULE_DEVICE_TABLE(of, mxic_nfc_of_ids);
static struct platform_driver mxic_nfc_driver = { static struct platform_driver mxic_nfc_driver = {
.probe = mxic_nfc_probe, .probe = mxic_nfc_probe,
.remove = mxic_nfc_remove, .remove_new = mxic_nfc_remove,
.driver = { .driver = {
.name = "mxic-nfc", .name = "mxic-nfc",
.of_match_table = mxic_nfc_of_ids, .of_match_table = mxic_nfc_of_ids,

View File

@ -728,8 +728,21 @@ static int hynix_nand_init(struct nand_chip *chip)
return ret; return ret;
} }
static void hynix_fixup_onfi_param_page(struct nand_chip *chip,
struct nand_onfi_params *p)
{
/*
* Certain chips might report a 0 on sdr_timing_mode field
* (bytes 129-130). This has been seen on H27U4G8F2GDA-BI.
* According to ONFI specification, bit 0 of this field "shall be 1".
* Forcibly set this bit.
*/
p->sdr_timing_modes |= cpu_to_le16(BIT(0));
}
const struct nand_manufacturer_ops hynix_nand_manuf_ops = { const struct nand_manufacturer_ops hynix_nand_manuf_ops = {
.detect = hynix_nand_decode_id, .detect = hynix_nand_decode_id,
.init = hynix_nand_init, .init = hynix_nand_init,
.cleanup = hynix_nand_cleanup, .cleanup = hynix_nand_cleanup,
.fixup_onfi_param_page = hynix_fixup_onfi_param_page,
}; };

View File

@ -93,14 +93,13 @@ static void macronix_nand_onfi_init(struct nand_chip *chip)
struct nand_parameters *p = &chip->parameters; struct nand_parameters *p = &chip->parameters;
struct nand_onfi_vendor_macronix *mxic; struct nand_onfi_vendor_macronix *mxic;
struct device_node *dn = nand_get_flash_node(chip); struct device_node *dn = nand_get_flash_node(chip);
int rand_otp = 0; int rand_otp;
int ret; int ret;
if (!p->onfi) if (!p->onfi)
return; return;
if (of_find_property(dn, "mxic,enable-randomizer-otp", NULL)) rand_otp = of_property_read_bool(dn, "mxic,enable-randomizer-otp");
rand_otp = 1;
mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor; mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor;
/* Subpage write is prohibited in randomizer operatoin */ /* Subpage write is prohibited in randomizer operatoin */

View File

@ -240,7 +240,7 @@ static int ndfc_probe(struct platform_device *ofdev)
return 0; return 0;
} }
static int ndfc_remove(struct platform_device *ofdev) static void ndfc_remove(struct platform_device *ofdev)
{ {
struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
struct nand_chip *chip = &ndfc->chip; struct nand_chip *chip = &ndfc->chip;
@ -251,8 +251,6 @@ static int ndfc_remove(struct platform_device *ofdev)
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(chip); nand_cleanup(chip);
kfree(mtd->name); kfree(mtd->name);
return 0;
} }
static const struct of_device_id ndfc_match[] = { static const struct of_device_id ndfc_match[] = {
@ -267,7 +265,7 @@ static struct platform_driver ndfc_driver = {
.of_match_table = ndfc_match, .of_match_table = ndfc_match,
}, },
.probe = ndfc_probe, .probe = ndfc_probe,
.remove = ndfc_remove, .remove_new = ndfc_remove,
}; };
module_platform_driver(ndfc_driver); module_platform_driver(ndfc_driver);

View File

@ -2273,7 +2273,7 @@ return_error:
return err; return err;
} }
static int omap_nand_remove(struct platform_device *pdev) static void omap_nand_remove(struct platform_device *pdev)
{ {
struct mtd_info *mtd = platform_get_drvdata(pdev); struct mtd_info *mtd = platform_get_drvdata(pdev);
struct nand_chip *nand_chip = mtd_to_nand(mtd); struct nand_chip *nand_chip = mtd_to_nand(mtd);
@ -2285,7 +2285,6 @@ static int omap_nand_remove(struct platform_device *pdev)
dma_release_channel(info->dma); dma_release_channel(info->dma);
WARN_ON(mtd_device_unregister(mtd)); WARN_ON(mtd_device_unregister(mtd));
nand_cleanup(nand_chip); nand_cleanup(nand_chip);
return 0;
} }
/* omap_nand_ids defined in linux/platform_data/mtd-nand-omap2.h */ /* omap_nand_ids defined in linux/platform_data/mtd-nand-omap2.h */
@ -2293,7 +2292,7 @@ MODULE_DEVICE_TABLE(of, omap_nand_ids);
static struct platform_driver omap_nand_driver = { static struct platform_driver omap_nand_driver = {
.probe = omap_nand_probe, .probe = omap_nand_probe,
.remove = omap_nand_remove, .remove_new = omap_nand_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = omap_nand_ids, .of_match_table = omap_nand_ids,

View File

@ -422,11 +422,10 @@ static int elm_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int elm_remove(struct platform_device *pdev) static void elm_remove(struct platform_device *pdev)
{ {
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
@ -561,7 +560,7 @@ static struct platform_driver elm_driver = {
.pm = &elm_pm_ops, .pm = &elm_pm_ops,
}, },
.probe = elm_probe, .probe = elm_probe,
.remove = elm_remove, .remove_new = elm_remove,
}; };
module_platform_driver(elm_driver); module_platform_driver(elm_driver);

View File

@ -102,7 +102,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)
struct mtd_info *mtd; struct mtd_info *mtd;
struct nand_chip *nc; struct nand_chip *nc;
struct orion_nand_data *board; struct orion_nand_data *board;
struct resource *res;
void __iomem *io_base; void __iomem *io_base;
int ret = 0; int ret = 0;
u32 val = 0; u32 val = 0;
@ -119,8 +118,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
info->controller.ops = &orion_nand_ops; info->controller.ops = &orion_nand_ops;
nc->controller = &info->controller; nc->controller = &info->controller;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); io_base = devm_platform_ioremap_resource(pdev, 0);
io_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(io_base)) if (IS_ERR(io_base))
return PTR_ERR(io_base); return PTR_ERR(io_base);
@ -207,7 +205,7 @@ no_dev:
return ret; return ret;
} }
static int orion_nand_remove(struct platform_device *pdev) static void orion_nand_remove(struct platform_device *pdev)
{ {
struct orion_nand_info *info = platform_get_drvdata(pdev); struct orion_nand_info *info = platform_get_drvdata(pdev);
struct nand_chip *chip = &info->chip; struct nand_chip *chip = &info->chip;
@ -219,8 +217,6 @@ static int orion_nand_remove(struct platform_device *pdev)
nand_cleanup(chip); nand_cleanup(chip);
clk_disable_unprepare(info->clk); clk_disable_unprepare(info->clk);
return 0;
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
@ -232,7 +228,7 @@ MODULE_DEVICE_TABLE(of, orion_nand_of_match_table);
#endif #endif
static struct platform_driver orion_nand_driver = { static struct platform_driver orion_nand_driver = {
.remove = orion_nand_remove, .remove_new = orion_nand_remove,
.driver = { .driver = {
.name = "orion_nand", .name = "orion_nand",
.of_match_table = of_match_ptr(orion_nand_of_match_table), .of_match_table = of_match_ptr(orion_nand_of_match_table),

View File

@ -171,7 +171,7 @@ err_clk_unprepare:
return err; return err;
} }
static int oxnas_nand_remove(struct platform_device *pdev) static void oxnas_nand_remove(struct platform_device *pdev)
{ {
struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev); struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
struct nand_chip *chip; struct nand_chip *chip;
@ -184,8 +184,6 @@ static int oxnas_nand_remove(struct platform_device *pdev)
} }
clk_disable_unprepare(oxnas->clk); clk_disable_unprepare(oxnas->clk);
return 0;
} }
static const struct of_device_id oxnas_nand_match[] = { static const struct of_device_id oxnas_nand_match[] = {
@ -196,7 +194,7 @@ MODULE_DEVICE_TABLE(of, oxnas_nand_match);
static struct platform_driver oxnas_nand_driver = { static struct platform_driver oxnas_nand_driver = {
.probe = oxnas_nand_probe, .probe = oxnas_nand_probe,
.remove = oxnas_nand_remove, .remove_new = oxnas_nand_remove,
.driver = { .driver = {
.name = "oxnas_nand", .name = "oxnas_nand",
.of_match_table = oxnas_nand_match, .of_match_table = oxnas_nand_match,

View File

@ -197,7 +197,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
return err; return err;
} }
static int pasemi_nand_remove(struct platform_device *ofdev) static void pasemi_nand_remove(struct platform_device *ofdev)
{ {
struct pasemi_ddata *ddata = platform_get_drvdata(ofdev); struct pasemi_ddata *ddata = platform_get_drvdata(ofdev);
struct mtd_info *pasemi_nand_mtd; struct mtd_info *pasemi_nand_mtd;
@ -218,8 +218,6 @@ static int pasemi_nand_remove(struct platform_device *ofdev)
/* Free the MTD device structure */ /* Free the MTD device structure */
kfree(ddata); kfree(ddata);
return 0;
} }
static const struct of_device_id pasemi_nand_match[] = static const struct of_device_id pasemi_nand_match[] =
@ -239,7 +237,7 @@ static struct platform_driver pasemi_nand_driver =
.of_match_table = pasemi_nand_match, .of_match_table = pasemi_nand_match,
}, },
.probe = pasemi_nand_probe, .probe = pasemi_nand_probe,
.remove = pasemi_nand_remove, .remove_new = pasemi_nand_remove,
}; };
module_platform_driver(pasemi_nand_driver); module_platform_driver(pasemi_nand_driver);

View File

@ -1163,13 +1163,11 @@ static int pl35x_nand_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int pl35x_nand_remove(struct platform_device *pdev) static void pl35x_nand_remove(struct platform_device *pdev)
{ {
struct pl35x_nandc *nfc = platform_get_drvdata(pdev); struct pl35x_nandc *nfc = platform_get_drvdata(pdev);
pl35x_nand_chips_cleanup(nfc); pl35x_nand_chips_cleanup(nfc);
return 0;
} }
static const struct of_device_id pl35x_nand_of_match[] = { static const struct of_device_id pl35x_nand_of_match[] = {
@ -1180,7 +1178,7 @@ MODULE_DEVICE_TABLE(of, pl35x_nand_of_match);
static struct platform_driver pl35x_nandc_driver = { static struct platform_driver pl35x_nandc_driver = {
.probe = pl35x_nand_probe, .probe = pl35x_nand_probe,
.remove = pl35x_nand_remove, .remove_new = pl35x_nand_remove,
.driver = { .driver = {
.name = PL35X_NANDC_DRIVER_NAME, .name = PL35X_NANDC_DRIVER_NAME,
.of_match_table = pl35x_nand_of_match, .of_match_table = pl35x_nand_of_match,

View File

@ -122,7 +122,7 @@ out:
/* /*
* Remove a NAND device. * Remove a NAND device.
*/ */
static int plat_nand_remove(struct platform_device *pdev) static void plat_nand_remove(struct platform_device *pdev)
{ {
struct plat_nand_data *data = platform_get_drvdata(pdev); struct plat_nand_data *data = platform_get_drvdata(pdev);
struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev); struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
@ -134,8 +134,6 @@ static int plat_nand_remove(struct platform_device *pdev)
nand_cleanup(chip); nand_cleanup(chip);
if (pdata->ctrl.remove) if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev); pdata->ctrl.remove(pdev);
return 0;
} }
static const struct of_device_id plat_nand_match[] = { static const struct of_device_id plat_nand_match[] = {
@ -146,7 +144,7 @@ MODULE_DEVICE_TABLE(of, plat_nand_match);
static struct platform_driver plat_nand_driver = { static struct platform_driver plat_nand_driver = {
.probe = plat_nand_probe, .probe = plat_nand_probe,
.remove = plat_nand_remove, .remove_new = plat_nand_remove,
.driver = { .driver = {
.name = "gen_nand", .name = "gen_nand",
.of_match_table = plat_nand_match, .of_match_table = plat_nand_match,

View File

@ -3054,7 +3054,7 @@ static int qcom_nand_host_parse_boot_partitions(struct qcom_nand_controller *nan
struct device *dev = nandc->dev; struct device *dev = nandc->dev;
int partitions_count, i, j, ret; int partitions_count, i, j, ret;
if (!of_find_property(dn, "qcom,boot-partitions", NULL)) if (!of_property_present(dn, "qcom,boot-partitions"))
return 0; return 0;
partitions_count = of_property_count_u32_elems(dn, "qcom,boot-partitions"); partitions_count = of_property_count_u32_elems(dn, "qcom,boot-partitions");
@ -3269,8 +3269,7 @@ static int qcom_nandc_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
nandc->base = devm_ioremap_resource(dev, res);
if (IS_ERR(nandc->base)) if (IS_ERR(nandc->base))
return PTR_ERR(nandc->base); return PTR_ERR(nandc->base);
@ -3315,7 +3314,7 @@ err_core_clk:
return ret; return ret;
} }
static int qcom_nandc_remove(struct platform_device *pdev) static void qcom_nandc_remove(struct platform_device *pdev)
{ {
struct qcom_nand_controller *nandc = platform_get_drvdata(pdev); struct qcom_nand_controller *nandc = platform_get_drvdata(pdev);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -3337,8 +3336,6 @@ static int qcom_nandc_remove(struct platform_device *pdev)
dma_unmap_resource(&pdev->dev, nandc->base_dma, resource_size(res), dma_unmap_resource(&pdev->dev, nandc->base_dma, resource_size(res),
DMA_BIDIRECTIONAL, 0); DMA_BIDIRECTIONAL, 0);
return 0;
} }
static const struct qcom_nandc_props ipq806x_nandc_props = { static const struct qcom_nandc_props ipq806x_nandc_props = {
@ -3405,7 +3402,7 @@ static struct platform_driver qcom_nandc_driver = {
.of_match_table = qcom_nandc_of_match, .of_match_table = qcom_nandc_of_match,
}, },
.probe = qcom_nandc_probe, .probe = qcom_nandc_probe,
.remove = qcom_nandc_remove, .remove_new = qcom_nandc_remove,
}; };
module_platform_driver(qcom_nandc_driver); module_platform_driver(qcom_nandc_driver);

View File

@ -1386,15 +1386,13 @@ dis_runtime_pm:
return ret; return ret;
} }
static int rnandc_remove(struct platform_device *pdev) static void rnandc_remove(struct platform_device *pdev)
{ {
struct rnandc *rnandc = platform_get_drvdata(pdev); struct rnandc *rnandc = platform_get_drvdata(pdev);
rnandc_chips_cleanup(rnandc); rnandc_chips_cleanup(rnandc);
pm_runtime_put(&pdev->dev); pm_runtime_put(&pdev->dev);
return 0;
} }
static const struct of_device_id rnandc_id_table[] = { static const struct of_device_id rnandc_id_table[] = {
@ -1410,7 +1408,7 @@ static struct platform_driver rnandc_driver = {
.of_match_table = rnandc_id_table, .of_match_table = rnandc_id_table,
}, },
.probe = rnandc_probe, .probe = rnandc_probe,
.remove = rnandc_remove, .remove_new = rnandc_remove,
}; };
module_platform_driver(rnandc_driver); module_platform_driver(rnandc_driver);

View File

@ -1427,7 +1427,7 @@ release_nfc:
return ret; return ret;
} }
static int rk_nfc_remove(struct platform_device *pdev) static void rk_nfc_remove(struct platform_device *pdev)
{ {
struct rk_nfc *nfc = platform_get_drvdata(pdev); struct rk_nfc *nfc = platform_get_drvdata(pdev);
@ -1435,8 +1435,6 @@ static int rk_nfc_remove(struct platform_device *pdev)
kfree(nfc->oob_buf); kfree(nfc->oob_buf);
rk_nfc_chips_cleanup(nfc); rk_nfc_chips_cleanup(nfc);
rk_nfc_disable_clks(nfc); rk_nfc_disable_clks(nfc);
return 0;
} }
static int __maybe_unused rk_nfc_suspend(struct device *dev) static int __maybe_unused rk_nfc_suspend(struct device *dev)
@ -1476,7 +1474,7 @@ static const struct dev_pm_ops rk_nfc_pm_ops = {
static struct platform_driver rk_nfc_driver = { static struct platform_driver rk_nfc_driver = {
.probe = rk_nfc_probe, .probe = rk_nfc_probe,
.remove = rk_nfc_remove, .remove_new = rk_nfc_remove,
.driver = { .driver = {
.name = "rockchip-nfc", .name = "rockchip-nfc",
.of_match_table = rk_nfc_id_table, .of_match_table = rk_nfc_id_table,

View File

@ -709,12 +709,12 @@ static void s3c2440_nand_write_buf(struct nand_chip *this, const u_char *buf,
/* device management functions */ /* device management functions */
static int s3c24xx_nand_remove(struct platform_device *pdev) static void s3c24xx_nand_remove(struct platform_device *pdev)
{ {
struct s3c2410_nand_info *info = to_nand_info(pdev); struct s3c2410_nand_info *info = to_nand_info(pdev);
if (info == NULL) if (info == NULL)
return 0; return;
/* Release all our mtds and their partitions, then go through /* Release all our mtds and their partitions, then go through
* freeing the resources used * freeing the resources used
@ -735,8 +735,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
if (!IS_ERR(info->clk)) if (!IS_ERR(info->clk))
s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
return 0;
} }
static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
@ -1218,7 +1216,7 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
static struct platform_driver s3c24xx_nand_driver = { static struct platform_driver s3c24xx_nand_driver = {
.probe = s3c24xx_nand_probe, .probe = s3c24xx_nand_probe,
.remove = s3c24xx_nand_remove, .remove_new = s3c24xx_nand_remove,
.suspend = s3c24xx_nand_suspend, .suspend = s3c24xx_nand_suspend,
.resume = s3c24xx_nand_resume, .resume = s3c24xx_nand_resume,
.id_table = s3c24xx_driver_ids, .id_table = s3c24xx_driver_ids,

View File

@ -1203,7 +1203,7 @@ err_chip:
return ret; return ret;
} }
static int flctl_remove(struct platform_device *pdev) static void flctl_remove(struct platform_device *pdev)
{ {
struct sh_flctl *flctl = platform_get_drvdata(pdev); struct sh_flctl *flctl = platform_get_drvdata(pdev);
struct nand_chip *chip = &flctl->chip; struct nand_chip *chip = &flctl->chip;
@ -1214,12 +1214,10 @@ static int flctl_remove(struct platform_device *pdev)
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(chip); nand_cleanup(chip);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
return 0;
} }
static struct platform_driver flctl_driver = { static struct platform_driver flctl_driver = {
.remove = flctl_remove, .remove_new = flctl_remove,
.driver = { .driver = {
.name = "sh_flctl", .name = "sh_flctl",
.of_match_table = of_flctl_match, .of_match_table = of_flctl_match,

View File

@ -210,7 +210,7 @@ err_get_res:
/* /*
* Clean up routine * Clean up routine
*/ */
static int sharpsl_nand_remove(struct platform_device *pdev) static void sharpsl_nand_remove(struct platform_device *pdev)
{ {
struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev); struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
struct nand_chip *chip = &sharpsl->chip; struct nand_chip *chip = &sharpsl->chip;
@ -227,8 +227,6 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
/* Free the driver's structure */ /* Free the driver's structure */
kfree(sharpsl); kfree(sharpsl);
return 0;
} }
static struct platform_driver sharpsl_nand_driver = { static struct platform_driver sharpsl_nand_driver = {
@ -236,7 +234,7 @@ static struct platform_driver sharpsl_nand_driver = {
.name = "sharpsl-nand", .name = "sharpsl-nand",
}, },
.probe = sharpsl_nand_probe, .probe = sharpsl_nand_probe,
.remove = sharpsl_nand_remove, .remove_new = sharpsl_nand_remove,
}; };
module_platform_driver(sharpsl_nand_driver); module_platform_driver(sharpsl_nand_driver);

View File

@ -201,7 +201,7 @@ out:
/* /*
* Remove a NAND device. * Remove a NAND device.
*/ */
static int socrates_nand_remove(struct platform_device *ofdev) static void socrates_nand_remove(struct platform_device *ofdev)
{ {
struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev); struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
struct nand_chip *chip = &host->nand_chip; struct nand_chip *chip = &host->nand_chip;
@ -212,8 +212,6 @@ static int socrates_nand_remove(struct platform_device *ofdev)
nand_cleanup(chip); nand_cleanup(chip);
iounmap(host->io_base); iounmap(host->io_base);
return 0;
} }
static const struct of_device_id socrates_nand_match[] = static const struct of_device_id socrates_nand_match[] =
@ -232,7 +230,7 @@ static struct platform_driver socrates_nand_driver = {
.of_match_table = socrates_nand_match, .of_match_table = socrates_nand_match,
}, },
.probe = socrates_nand_probe, .probe = socrates_nand_probe,
.remove = socrates_nand_remove, .remove_new = socrates_nand_remove,
}; };
module_platform_driver(socrates_nand_driver); module_platform_driver(socrates_nand_driver);

View File

@ -2024,7 +2024,7 @@ err_clk_disable:
return ret; return ret;
} }
static int stm32_fmc2_nfc_remove(struct platform_device *pdev) static void stm32_fmc2_nfc_remove(struct platform_device *pdev)
{ {
struct stm32_fmc2_nfc *nfc = platform_get_drvdata(pdev); struct stm32_fmc2_nfc *nfc = platform_get_drvdata(pdev);
struct stm32_fmc2_nand *nand = &nfc->nand; struct stm32_fmc2_nand *nand = &nfc->nand;
@ -2048,8 +2048,6 @@ static int stm32_fmc2_nfc_remove(struct platform_device *pdev)
clk_disable_unprepare(nfc->clk); clk_disable_unprepare(nfc->clk);
stm32_fmc2_nfc_wp_enable(nand); stm32_fmc2_nfc_wp_enable(nand);
return 0;
} }
static int __maybe_unused stm32_fmc2_nfc_suspend(struct device *dev) static int __maybe_unused stm32_fmc2_nfc_suspend(struct device *dev)
@ -2106,7 +2104,7 @@ MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match);
static struct platform_driver stm32_fmc2_nfc_driver = { static struct platform_driver stm32_fmc2_nfc_driver = {
.probe = stm32_fmc2_nfc_probe, .probe = stm32_fmc2_nfc_probe,
.remove = stm32_fmc2_nfc_remove, .remove_new = stm32_fmc2_nfc_remove,
.driver = { .driver = {
.name = "stm32_fmc2_nfc", .name = "stm32_fmc2_nfc",
.of_match_table = stm32_fmc2_nfc_match, .of_match_table = stm32_fmc2_nfc_match,

View File

@ -2173,7 +2173,7 @@ out_ahb_clk_unprepare:
return ret; return ret;
} }
static int sunxi_nfc_remove(struct platform_device *pdev) static void sunxi_nfc_remove(struct platform_device *pdev)
{ {
struct sunxi_nfc *nfc = platform_get_drvdata(pdev); struct sunxi_nfc *nfc = platform_get_drvdata(pdev);
@ -2185,8 +2185,6 @@ static int sunxi_nfc_remove(struct platform_device *pdev)
dma_release_channel(nfc->dmac); dma_release_channel(nfc->dmac);
clk_disable_unprepare(nfc->mod_clk); clk_disable_unprepare(nfc->mod_clk);
clk_disable_unprepare(nfc->ahb_clk); clk_disable_unprepare(nfc->ahb_clk);
return 0;
} }
static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = { static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
@ -2219,7 +2217,7 @@ static struct platform_driver sunxi_nfc_driver = {
.of_match_table = sunxi_nfc_ids, .of_match_table = sunxi_nfc_ids,
}, },
.probe = sunxi_nfc_probe, .probe = sunxi_nfc_probe,
.remove = sunxi_nfc_remove, .remove_new = sunxi_nfc_remove,
}; };
module_platform_driver(sunxi_nfc_driver); module_platform_driver(sunxi_nfc_driver);

View File

@ -1220,7 +1220,7 @@ err_dis_pm:
return err; return err;
} }
static int tegra_nand_remove(struct platform_device *pdev) static void tegra_nand_remove(struct platform_device *pdev)
{ {
struct tegra_nand_controller *ctrl = platform_get_drvdata(pdev); struct tegra_nand_controller *ctrl = platform_get_drvdata(pdev);
struct nand_chip *chip = ctrl->chip; struct nand_chip *chip = ctrl->chip;
@ -1232,8 +1232,6 @@ static int tegra_nand_remove(struct platform_device *pdev)
pm_runtime_put_sync_suspend(ctrl->dev); pm_runtime_put_sync_suspend(ctrl->dev);
pm_runtime_force_suspend(ctrl->dev); pm_runtime_force_suspend(ctrl->dev);
return 0;
} }
static int __maybe_unused tegra_nand_runtime_resume(struct device *dev) static int __maybe_unused tegra_nand_runtime_resume(struct device *dev)
@ -1277,7 +1275,7 @@ static struct platform_driver tegra_nand_driver = {
.pm = &tegra_nand_pm, .pm = &tegra_nand_pm,
}, },
.probe = tegra_nand_probe, .probe = tegra_nand_probe,
.remove = tegra_nand_remove, .remove_new = tegra_nand_remove,
}; };
module_platform_driver(tegra_nand_driver); module_platform_driver(tegra_nand_driver);

View File

@ -909,7 +909,7 @@ err_disable_clk:
return err; return err;
} }
static int vf610_nfc_remove(struct platform_device *pdev) static void vf610_nfc_remove(struct platform_device *pdev)
{ {
struct vf610_nfc *nfc = platform_get_drvdata(pdev); struct vf610_nfc *nfc = platform_get_drvdata(pdev);
struct nand_chip *chip = &nfc->chip; struct nand_chip *chip = &nfc->chip;
@ -919,7 +919,6 @@ static int vf610_nfc_remove(struct platform_device *pdev)
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(chip); nand_cleanup(chip);
clk_disable_unprepare(nfc->clk); clk_disable_unprepare(nfc->clk);
return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
@ -955,7 +954,7 @@ static struct platform_driver vf610_nfc_driver = {
.pm = &vf610_nfc_pm_ops, .pm = &vf610_nfc_pm_ops,
}, },
.probe = vf610_nfc_probe, .probe = vf610_nfc_probe,
.remove = vf610_nfc_remove, .remove_new = vf610_nfc_remove,
}; };
module_platform_driver(vf610_nfc_driver); module_platform_driver(vf610_nfc_driver);

View File

@ -238,7 +238,7 @@ static int xway_nand_probe(struct platform_device *pdev)
/* /*
* Remove a NAND device. * Remove a NAND device.
*/ */
static int xway_nand_remove(struct platform_device *pdev) static void xway_nand_remove(struct platform_device *pdev)
{ {
struct xway_nand_data *data = platform_get_drvdata(pdev); struct xway_nand_data *data = platform_get_drvdata(pdev);
struct nand_chip *chip = &data->chip; struct nand_chip *chip = &data->chip;
@ -247,8 +247,6 @@ static int xway_nand_remove(struct platform_device *pdev)
ret = mtd_device_unregister(nand_to_mtd(chip)); ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret); WARN_ON(ret);
nand_cleanup(chip); nand_cleanup(chip);
return 0;
} }
static const struct of_device_id xway_nand_match[] = { static const struct of_device_id xway_nand_match[] = {
@ -258,7 +256,7 @@ static const struct of_device_id xway_nand_match[] = {
static struct platform_driver xway_nand_driver = { static struct platform_driver xway_nand_driver = {
.probe = xway_nand_probe, .probe = xway_nand_probe,
.remove = xway_nand_remove, .remove_new = xway_nand_remove,
.driver = { .driver = {
.name = "lantiq,nand-xway", .name = "lantiq,nand-xway",
.of_match_table = xway_nand_match, .of_match_table = xway_nand_match,

View File

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
spinand-objs := core.o alliancememory.o ato.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o spinand-objs := core.o alliancememory.o ato.o esmt.o gigadevice.o macronix.o
spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o

View File

@ -939,6 +939,7 @@ static const struct nand_ops spinand_ops = {
static const struct spinand_manufacturer *spinand_manufacturers[] = { static const struct spinand_manufacturer *spinand_manufacturers[] = {
&alliancememory_spinand_manufacturer, &alliancememory_spinand_manufacturer,
&ato_spinand_manufacturer, &ato_spinand_manufacturer,
&esmt_c8_spinand_manufacturer,
&gigadevice_spinand_manufacturer, &gigadevice_spinand_manufacturer,
&macronix_spinand_manufacturer, &macronix_spinand_manufacturer,
&micron_spinand_manufacturer, &micron_spinand_manufacturer,

135
drivers/mtd/nand/spi/esmt.c Normal file
View File

@ -0,0 +1,135 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Author:
* Chuanhong Guo <gch981213@gmail.com> - the main driver logic
* Martin Kurbanov <mmkurbanov@sberdevices.ru> - OOB layout
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/mtd/spinand.h>
/* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
#define SPINAND_MFR_ESMT_C8 0xc8
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
static SPINAND_OP_VARIANTS(write_cache_variants,
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
SPINAND_PROG_LOAD(true, 0, NULL, 0));
static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
SPINAND_PROG_LOAD(false, 0, NULL, 0));
/*
* OOB spare area map (64 bytes)
*
* Bad Block Markers
* filled by HW and kernel Reserved
* | +-----------------------+-----------------------+
* | | | |
* | | OOB free data Area |non ECC protected |
* | +-------------|-----+-----------------|-----+-----------------|-----+
* | | | | | | | |
* +-|---|----------+--|-----|--------------+--|-----|--------------+--|-----|--------------+
* | | | section0 | | | section1 | | | section2 | | | section3 |
* +-v-+-v-+---+----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+
* | | | | | | | | | | | | | | | | |
* |0:1|2:3|4:7|8:15|16:17|18:19|20:23|24:31|32:33|34:35|36:39|40:47|48:49|50:51|52:55|56:63|
* | | | | | | | | | | | | | | | | |
* +---+---+-^-+--^-+-----+-----+--^--+--^--+-----+-----+--^--+--^--+-----+-----+--^--+--^--+
* | | | | | | | |
* | +----------------|-----+-----------------|-----+-----------------|-----+
* | ECC Area|(Main + Spare) - filled|by ESMT NAND HW |
* | | | |
* +---------------------+-----------------------+-----------------------+
* OOB ECC protected Area - not used due to
* partial programming from some filesystems
* (like JFFS2 with cleanmarkers)
*/
#define ESMT_OOB_SECTION_COUNT 4
#define ESMT_OOB_SECTION_SIZE(nand) \
(nanddev_per_page_oobsize(nand) / ESMT_OOB_SECTION_COUNT)
#define ESMT_OOB_FREE_SIZE(nand) \
(ESMT_OOB_SECTION_SIZE(nand) / 2)
#define ESMT_OOB_ECC_SIZE(nand) \
(ESMT_OOB_SECTION_SIZE(nand) - ESMT_OOB_FREE_SIZE(nand))
#define ESMT_OOB_BBM_SIZE 2
static int f50l1g41lb_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
struct nand_device *nand = mtd_to_nanddev(mtd);
if (section >= ESMT_OOB_SECTION_COUNT)
return -ERANGE;
region->offset = section * ESMT_OOB_SECTION_SIZE(nand) +
ESMT_OOB_FREE_SIZE(nand);
region->length = ESMT_OOB_ECC_SIZE(nand);
return 0;
}
static int f50l1g41lb_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
struct nand_device *nand = mtd_to_nanddev(mtd);
if (section >= ESMT_OOB_SECTION_COUNT)
return -ERANGE;
/*
* Reserve space for bad blocks markers (section0) and
* reserved bytes (sections 1-3)
*/
region->offset = section * ESMT_OOB_SECTION_SIZE(nand) + 2;
/* Use only 2 non-protected ECC bytes per each OOB section */
region->length = 2;
return 0;
}
static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
.ecc = f50l1g41lb_ooblayout_ecc,
.free = f50l1g41lb_ooblayout_free,
};
static const struct spinand_info esmt_c8_spinand_table[] = {
SPINAND_INFO("F50L1G41LB",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
SPINAND_INFO("F50D1G41LB",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
};
static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
};
const struct spinand_manufacturer esmt_c8_spinand_manufacturer = {
.id = SPINAND_MFR_ESMT_C8,
.name = "ESMT",
.chips = esmt_c8_spinand_table,
.nchips = ARRAY_SIZE(esmt_c8_spinand_table),
.ops = &esmt_spinand_manuf_ops,
};

View File

@ -149,7 +149,7 @@ config MTD_PARSER_TRX
config MTD_SHARPSL_PARTS config MTD_SHARPSL_PARTS
tristate "Sharp SL Series NAND flash partition parser" tristate "Sharp SL Series NAND flash partition parser"
depends on MTD_NAND_SHARPSL || MTD_NAND_TMIO || COMPILE_TEST depends on MTD_NAND_SHARPSL || COMPILE_TEST
help help
This provides the read-only FTL logic necessary to read the partition This provides the read-only FTL logic necessary to read the partition
table from the NAND flash of Sharp SL Series (Zaurus) and the MTD table from the NAND flash of Sharp SL Series (Zaurus) and the MTD

View File

@ -164,7 +164,6 @@ static struct mtd_part_parser bcm63xx_cfe_parser = {
}; };
module_mtd_part_parser(bcm63xx_cfe_parser); module_mtd_part_parser(bcm63xx_cfe_parser);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>"); MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>");
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>"); MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>");

View File

@ -305,10 +305,10 @@ static int nxp_spifi_setup_flash(struct nxp_spifi *spifi,
} }
} }
if (of_find_property(np, "spi-cpha", NULL)) if (of_property_read_bool(np, "spi-cpha"))
mode |= SPI_CPHA; mode |= SPI_CPHA;
if (of_find_property(np, "spi-cpol", NULL)) if (of_property_read_bool(np, "spi-cpol"))
mode |= SPI_CPOL; mode |= SPI_CPOL;
/* Setup control register defaults */ /* Setup control register defaults */

View File

@ -508,14 +508,16 @@ int spi_nor_read_cr(struct spi_nor *nor, u8 *cr)
} }
/** /**
* spi_nor_set_4byte_addr_mode() - Enter/Exit 4-byte address mode. * spi_nor_set_4byte_addr_mode_en4b_ex4b() - Enter/Exit 4-byte address mode
* using SPINOR_OP_EN4B/SPINOR_OP_EX4B. Typically used by
* Winbond and Macronix.
* @nor: pointer to 'struct spi_nor'. * @nor: pointer to 'struct spi_nor'.
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte * @enable: true to enter the 4-byte address mode, false to exit the 4-byte
* address mode. * address mode.
* *
* Return: 0 on success, -errno otherwise. * Return: 0 on success, -errno otherwise.
*/ */
int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) int spi_nor_set_4byte_addr_mode_en4b_ex4b(struct spi_nor *nor, bool enable)
{ {
int ret; int ret;
@ -539,15 +541,45 @@ int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
} }
/** /**
* spansion_set_4byte_addr_mode() - Set 4-byte address mode for Spansion * spi_nor_set_4byte_addr_mode_wren_en4b_ex4b() - Set 4-byte address mode using
* flashes. * SPINOR_OP_WREN followed by SPINOR_OP_EN4B or SPINOR_OP_EX4B. Typically used
* by ST and Micron flashes.
* @nor: pointer to 'struct spi_nor'. * @nor: pointer to 'struct spi_nor'.
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte * @enable: true to enter the 4-byte address mode, false to exit the 4-byte
* address mode. * address mode.
* *
* Return: 0 on success, -errno otherwise. * Return: 0 on success, -errno otherwise.
*/ */
static int spansion_set_4byte_addr_mode(struct spi_nor *nor, bool enable) int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor, bool enable)
{
int ret;
ret = spi_nor_write_enable(nor);
if (ret)
return ret;
ret = spi_nor_set_4byte_addr_mode_en4b_ex4b(nor, enable);
if (ret)
return ret;
return spi_nor_write_disable(nor);
}
/**
* spi_nor_set_4byte_addr_mode_brwr() - Set 4-byte address mode using
* SPINOR_OP_BRWR. Typically used by Spansion flashes.
* @nor: pointer to 'struct spi_nor'.
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte
* address mode.
*
* 8-bit volatile bank register used to define A[30:A24] bits. MSB (bit[7]) is
* used to enable/disable 4-byte address mode. When MSB is set to 1, 4-byte
* address mode is active and A[30:24] bits are dont care. Write instruction is
* SPINOR_OP_BRWR(17h) with 1 byte of data.
*
* Return: 0 on success, -errno otherwise.
*/
int spi_nor_set_4byte_addr_mode_brwr(struct spi_nor *nor, bool enable)
{ {
int ret; int ret;
@ -588,6 +620,65 @@ int spi_nor_sr_ready(struct spi_nor *nor)
return !(nor->bouncebuf[0] & SR_WIP); return !(nor->bouncebuf[0] & SR_WIP);
} }
/**
* spi_nor_use_parallel_locking() - Checks if RWW locking scheme shall be used
* @nor: pointer to 'struct spi_nor'.
*
* Return: true if parallel locking is enabled, false otherwise.
*/
static bool spi_nor_use_parallel_locking(struct spi_nor *nor)
{
return nor->flags & SNOR_F_RWW;
}
/* Locking helpers for status read operations */
static int spi_nor_rww_start_rdst(struct spi_nor *nor)
{
struct spi_nor_rww *rww = &nor->rww;
int ret = -EAGAIN;
mutex_lock(&nor->lock);
if (rww->ongoing_io || rww->ongoing_rd)
goto busy;
rww->ongoing_io = true;
rww->ongoing_rd = true;
ret = 0;
busy:
mutex_unlock(&nor->lock);
return ret;
}
static void spi_nor_rww_end_rdst(struct spi_nor *nor)
{
struct spi_nor_rww *rww = &nor->rww;
mutex_lock(&nor->lock);
rww->ongoing_io = false;
rww->ongoing_rd = false;
mutex_unlock(&nor->lock);
}
static int spi_nor_lock_rdst(struct spi_nor *nor)
{
if (spi_nor_use_parallel_locking(nor))
return spi_nor_rww_start_rdst(nor);
return 0;
}
static void spi_nor_unlock_rdst(struct spi_nor *nor)
{
if (spi_nor_use_parallel_locking(nor)) {
spi_nor_rww_end_rdst(nor);
wake_up(&nor->rww.wait);
}
}
/** /**
* spi_nor_ready() - Query the flash to see if it is ready for new commands. * spi_nor_ready() - Query the flash to see if it is ready for new commands.
* @nor: pointer to 'struct spi_nor'. * @nor: pointer to 'struct spi_nor'.
@ -596,11 +687,21 @@ int spi_nor_sr_ready(struct spi_nor *nor)
*/ */
static int spi_nor_ready(struct spi_nor *nor) static int spi_nor_ready(struct spi_nor *nor)
{ {
int ret;
ret = spi_nor_lock_rdst(nor);
if (ret)
return 0;
/* Flashes might override the standard routine. */ /* Flashes might override the standard routine. */
if (nor->params->ready) if (nor->params->ready)
return nor->params->ready(nor); ret = nor->params->ready(nor);
else
ret = spi_nor_sr_ready(nor);
return spi_nor_sr_ready(nor); spi_nor_unlock_rdst(nor);
return ret;
} }
/** /**
@ -1070,27 +1171,287 @@ static void spi_nor_set_4byte_opcodes(struct spi_nor *nor)
} }
} }
int spi_nor_lock_and_prep(struct spi_nor *nor) static int spi_nor_prep(struct spi_nor *nor)
{ {
int ret = 0; int ret = 0;
if (nor->controller_ops && nor->controller_ops->prepare)
ret = nor->controller_ops->prepare(nor);
return ret;
}
static void spi_nor_unprep(struct spi_nor *nor)
{
if (nor->controller_ops && nor->controller_ops->unprepare)
nor->controller_ops->unprepare(nor);
}
static void spi_nor_offset_to_banks(u64 bank_size, loff_t start, size_t len,
u8 *first, u8 *last)
{
/* This is currently safe, the number of banks being very small */
*first = DIV_ROUND_DOWN_ULL(start, bank_size);
*last = DIV_ROUND_DOWN_ULL(start + len - 1, bank_size);
}
/* Generic helpers for internal locking and serialization */
static bool spi_nor_rww_start_io(struct spi_nor *nor)
{
struct spi_nor_rww *rww = &nor->rww;
bool start = false;
mutex_lock(&nor->lock); mutex_lock(&nor->lock);
if (nor->controller_ops && nor->controller_ops->prepare) { if (rww->ongoing_io)
ret = nor->controller_ops->prepare(nor); goto busy;
if (ret) {
mutex_unlock(&nor->lock); rww->ongoing_io = true;
return ret; start = true;
}
busy:
mutex_unlock(&nor->lock);
return start;
}
static void spi_nor_rww_end_io(struct spi_nor *nor)
{
mutex_lock(&nor->lock);
nor->rww.ongoing_io = false;
mutex_unlock(&nor->lock);
}
static int spi_nor_lock_device(struct spi_nor *nor)
{
if (!spi_nor_use_parallel_locking(nor))
return 0;
return wait_event_killable(nor->rww.wait, spi_nor_rww_start_io(nor));
}
static void spi_nor_unlock_device(struct spi_nor *nor)
{
if (spi_nor_use_parallel_locking(nor)) {
spi_nor_rww_end_io(nor);
wake_up(&nor->rww.wait);
} }
}
/* Generic helpers for internal locking and serialization */
static bool spi_nor_rww_start_exclusive(struct spi_nor *nor)
{
struct spi_nor_rww *rww = &nor->rww;
bool start = false;
mutex_lock(&nor->lock);
if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe)
goto busy;
rww->ongoing_io = true;
rww->ongoing_rd = true;
rww->ongoing_pe = true;
start = true;
busy:
mutex_unlock(&nor->lock);
return start;
}
static void spi_nor_rww_end_exclusive(struct spi_nor *nor)
{
struct spi_nor_rww *rww = &nor->rww;
mutex_lock(&nor->lock);
rww->ongoing_io = false;
rww->ongoing_rd = false;
rww->ongoing_pe = false;
mutex_unlock(&nor->lock);
}
int spi_nor_prep_and_lock(struct spi_nor *nor)
{
int ret;
ret = spi_nor_prep(nor);
if (ret)
return ret;
if (!spi_nor_use_parallel_locking(nor))
mutex_lock(&nor->lock);
else
ret = wait_event_killable(nor->rww.wait,
spi_nor_rww_start_exclusive(nor));
return ret; return ret;
} }
void spi_nor_unlock_and_unprep(struct spi_nor *nor) void spi_nor_unlock_and_unprep(struct spi_nor *nor)
{ {
if (nor->controller_ops && nor->controller_ops->unprepare) if (!spi_nor_use_parallel_locking(nor)) {
nor->controller_ops->unprepare(nor); mutex_unlock(&nor->lock);
} else {
spi_nor_rww_end_exclusive(nor);
wake_up(&nor->rww.wait);
}
spi_nor_unprep(nor);
}
/* Internal locking helpers for program and erase operations */
static bool spi_nor_rww_start_pe(struct spi_nor *nor, loff_t start, size_t len)
{
struct spi_nor_rww *rww = &nor->rww;
unsigned int used_banks = 0;
bool started = false;
u8 first, last;
int bank;
mutex_lock(&nor->lock);
if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe)
goto busy;
spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last);
for (bank = first; bank <= last; bank++) {
if (rww->used_banks & BIT(bank))
goto busy;
used_banks |= BIT(bank);
}
rww->used_banks |= used_banks;
rww->ongoing_pe = true;
started = true;
busy:
mutex_unlock(&nor->lock); mutex_unlock(&nor->lock);
return started;
}
static void spi_nor_rww_end_pe(struct spi_nor *nor, loff_t start, size_t len)
{
struct spi_nor_rww *rww = &nor->rww;
u8 first, last;
int bank;
mutex_lock(&nor->lock);
spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last);
for (bank = first; bank <= last; bank++)
rww->used_banks &= ~BIT(bank);
rww->ongoing_pe = false;
mutex_unlock(&nor->lock);
}
static int spi_nor_prep_and_lock_pe(struct spi_nor *nor, loff_t start, size_t len)
{
int ret;
ret = spi_nor_prep(nor);
if (ret)
return ret;
if (!spi_nor_use_parallel_locking(nor))
mutex_lock(&nor->lock);
else
ret = wait_event_killable(nor->rww.wait,
spi_nor_rww_start_pe(nor, start, len));
return ret;
}
static void spi_nor_unlock_and_unprep_pe(struct spi_nor *nor, loff_t start, size_t len)
{
if (!spi_nor_use_parallel_locking(nor)) {
mutex_unlock(&nor->lock);
} else {
spi_nor_rww_end_pe(nor, start, len);
wake_up(&nor->rww.wait);
}
spi_nor_unprep(nor);
}
/* Internal locking helpers for read operations */
static bool spi_nor_rww_start_rd(struct spi_nor *nor, loff_t start, size_t len)
{
struct spi_nor_rww *rww = &nor->rww;
unsigned int used_banks = 0;
bool started = false;
u8 first, last;
int bank;
mutex_lock(&nor->lock);
if (rww->ongoing_io || rww->ongoing_rd)
goto busy;
spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last);
for (bank = first; bank <= last; bank++) {
if (rww->used_banks & BIT(bank))
goto busy;
used_banks |= BIT(bank);
}
rww->used_banks |= used_banks;
rww->ongoing_io = true;
rww->ongoing_rd = true;
started = true;
busy:
mutex_unlock(&nor->lock);
return started;
}
static void spi_nor_rww_end_rd(struct spi_nor *nor, loff_t start, size_t len)
{
struct spi_nor_rww *rww = &nor->rww;
u8 first, last;
int bank;
mutex_lock(&nor->lock);
spi_nor_offset_to_banks(nor->params->bank_size, start, len, &first, &last);
for (bank = first; bank <= last; bank++)
nor->rww.used_banks &= ~BIT(bank);
rww->ongoing_io = false;
rww->ongoing_rd = false;
mutex_unlock(&nor->lock);
}
static int spi_nor_prep_and_lock_rd(struct spi_nor *nor, loff_t start, size_t len)
{
int ret;
ret = spi_nor_prep(nor);
if (ret)
return ret;
if (!spi_nor_use_parallel_locking(nor))
mutex_lock(&nor->lock);
else
ret = wait_event_killable(nor->rww.wait,
spi_nor_rww_start_rd(nor, start, len));
return ret;
}
static void spi_nor_unlock_and_unprep_rd(struct spi_nor *nor, loff_t start, size_t len)
{
if (!spi_nor_use_parallel_locking(nor)) {
mutex_unlock(&nor->lock);
} else {
spi_nor_rww_end_rd(nor, start, len);
wake_up(&nor->rww.wait);
}
spi_nor_unprep(nor);
} }
static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr) static u32 spi_nor_convert_addr(struct spi_nor *nor, loff_t addr)
@ -1397,11 +1758,18 @@ static int spi_nor_erase_multi_sectors(struct spi_nor *nor, u64 addr, u32 len)
dev_vdbg(nor->dev, "erase_cmd->size = 0x%08x, erase_cmd->opcode = 0x%02x, erase_cmd->count = %u\n", dev_vdbg(nor->dev, "erase_cmd->size = 0x%08x, erase_cmd->opcode = 0x%02x, erase_cmd->count = %u\n",
cmd->size, cmd->opcode, cmd->count); cmd->size, cmd->opcode, cmd->count);
ret = spi_nor_write_enable(nor); ret = spi_nor_lock_device(nor);
if (ret) if (ret)
goto destroy_erase_cmd_list; goto destroy_erase_cmd_list;
ret = spi_nor_write_enable(nor);
if (ret) {
spi_nor_unlock_device(nor);
goto destroy_erase_cmd_list;
}
ret = spi_nor_erase_sector(nor, addr); ret = spi_nor_erase_sector(nor, addr);
spi_nor_unlock_device(nor);
if (ret) if (ret)
goto destroy_erase_cmd_list; goto destroy_erase_cmd_list;
@ -1446,7 +1814,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
addr = instr->addr; addr = instr->addr;
len = instr->len; len = instr->len;
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock_pe(nor, instr->addr, instr->len);
if (ret) if (ret)
return ret; return ret;
@ -1454,11 +1822,18 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) { if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
unsigned long timeout; unsigned long timeout;
ret = spi_nor_write_enable(nor); ret = spi_nor_lock_device(nor);
if (ret) if (ret)
goto erase_err; goto erase_err;
ret = spi_nor_write_enable(nor);
if (ret) {
spi_nor_unlock_device(nor);
goto erase_err;
}
ret = spi_nor_erase_chip(nor); ret = spi_nor_erase_chip(nor);
spi_nor_unlock_device(nor);
if (ret) if (ret)
goto erase_err; goto erase_err;
@ -1483,11 +1858,18 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
/* "sector"-at-a-time erase */ /* "sector"-at-a-time erase */
} else if (spi_nor_has_uniform_erase(nor)) { } else if (spi_nor_has_uniform_erase(nor)) {
while (len) { while (len) {
ret = spi_nor_write_enable(nor); ret = spi_nor_lock_device(nor);
if (ret) if (ret)
goto erase_err; goto erase_err;
ret = spi_nor_write_enable(nor);
if (ret) {
spi_nor_unlock_device(nor);
goto erase_err;
}
ret = spi_nor_erase_sector(nor, addr); ret = spi_nor_erase_sector(nor, addr);
spi_nor_unlock_device(nor);
if (ret) if (ret)
goto erase_err; goto erase_err;
@ -1509,7 +1891,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
ret = spi_nor_write_disable(nor); ret = spi_nor_write_disable(nor);
erase_err: erase_err:
spi_nor_unlock_and_unprep(nor); spi_nor_unlock_and_unprep_pe(nor, instr->addr, instr->len);
return ret; return ret;
} }
@ -1702,11 +2084,13 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf) size_t *retlen, u_char *buf)
{ {
struct spi_nor *nor = mtd_to_spi_nor(mtd); struct spi_nor *nor = mtd_to_spi_nor(mtd);
loff_t from_lock = from;
size_t len_lock = len;
ssize_t ret; ssize_t ret;
dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock_rd(nor, from_lock, len_lock);
if (ret) if (ret)
return ret; return ret;
@ -1733,7 +2117,8 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
ret = 0; ret = 0;
read_err: read_err:
spi_nor_unlock_and_unprep(nor); spi_nor_unlock_and_unprep_rd(nor, from_lock, len_lock);
return ret; return ret;
} }
@ -1752,7 +2137,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock_pe(nor, to, len);
if (ret) if (ret)
return ret; return ret;
@ -1777,11 +2162,18 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
addr = spi_nor_convert_addr(nor, addr); addr = spi_nor_convert_addr(nor, addr);
ret = spi_nor_write_enable(nor); ret = spi_nor_lock_device(nor);
if (ret) if (ret)
goto write_err; goto write_err;
ret = spi_nor_write_enable(nor);
if (ret) {
spi_nor_unlock_device(nor);
goto write_err;
}
ret = spi_nor_write_data(nor, addr, page_remain, buf + i); ret = spi_nor_write_data(nor, addr, page_remain, buf + i);
spi_nor_unlock_device(nor);
if (ret < 0) if (ret < 0)
goto write_err; goto write_err;
written = ret; written = ret;
@ -1794,7 +2186,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
} }
write_err: write_err:
spi_nor_unlock_and_unprep(nor); spi_nor_unlock_and_unprep_pe(nor, to, len);
return ret; return ret;
} }
@ -2470,6 +2863,10 @@ static void spi_nor_init_flags(struct spi_nor *nor)
if (flags & NO_CHIP_ERASE) if (flags & NO_CHIP_ERASE)
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
if (flags & SPI_NOR_RWW && nor->info->n_banks > 1 &&
!nor->controller_ops)
nor->flags |= SNOR_F_RWW;
} }
/** /**
@ -2501,6 +2898,8 @@ static void spi_nor_init_fixup_flags(struct spi_nor *nor)
*/ */
static void spi_nor_late_init_params(struct spi_nor *nor) static void spi_nor_late_init_params(struct spi_nor *nor)
{ {
struct spi_nor_flash_parameter *params = nor->params;
if (nor->manufacturer && nor->manufacturer->fixups && if (nor->manufacturer && nor->manufacturer->fixups &&
nor->manufacturer->fixups->late_init) nor->manufacturer->fixups->late_init)
nor->manufacturer->fixups->late_init(nor); nor->manufacturer->fixups->late_init(nor);
@ -2508,6 +2907,10 @@ static void spi_nor_late_init_params(struct spi_nor *nor)
if (nor->info->fixups && nor->info->fixups->late_init) if (nor->info->fixups && nor->info->fixups->late_init)
nor->info->fixups->late_init(nor); nor->info->fixups->late_init(nor);
/* Default method kept for backward compatibility. */
if (!params->set_4byte_addr_mode)
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr;
spi_nor_init_flags(nor); spi_nor_init_flags(nor);
spi_nor_init_fixup_flags(nor); spi_nor_init_fixup_flags(nor);
@ -2517,6 +2920,8 @@ static void spi_nor_late_init_params(struct spi_nor *nor)
*/ */
if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops) if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops)
spi_nor_init_default_locking_ops(nor); spi_nor_init_default_locking_ops(nor);
nor->params->bank_size = div64_u64(nor->params->size, nor->info->n_banks);
} }
/** /**
@ -2574,7 +2979,6 @@ static void spi_nor_init_default_params(struct spi_nor *nor)
struct device_node *np = spi_nor_get_flash_node(nor); struct device_node *np = spi_nor_get_flash_node(nor);
params->quad_enable = spi_nor_sr2_bit1_quad_enable; params->quad_enable = spi_nor_sr2_bit1_quad_enable;
params->set_4byte_addr_mode = spansion_set_4byte_addr_mode;
params->otp.org = &info->otp_org; params->otp.org = &info->otp_org;
/* Default to 16-bit Write Status (01h) Command */ /* Default to 16-bit Write Status (01h) Command */
@ -2730,6 +3134,33 @@ static int spi_nor_quad_enable(struct spi_nor *nor)
return nor->params->quad_enable(nor); return nor->params->quad_enable(nor);
} }
/**
* spi_nor_set_4byte_addr_mode() - Set address mode.
* @nor: pointer to a 'struct spi_nor'.
* @enable: enable/disable 4 byte address mode.
*
* Return: 0 on success, -errno otherwise.
*/
int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
{
struct spi_nor_flash_parameter *params = nor->params;
int ret;
ret = params->set_4byte_addr_mode(nor, enable);
if (ret && ret != -ENOTSUPP)
return ret;
if (enable) {
params->addr_nbytes = 4;
params->addr_mode_nbytes = 4;
} else {
params->addr_nbytes = 3;
params->addr_mode_nbytes = 3;
}
return 0;
}
static int spi_nor_init(struct spi_nor *nor) static int spi_nor_init(struct spi_nor *nor)
{ {
int err; int err;
@ -2773,8 +3204,8 @@ static int spi_nor_init(struct spi_nor *nor)
*/ */
WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET, WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
"enabling reset hack; may not recover from unexpected reboots\n"); "enabling reset hack; may not recover from unexpected reboots\n");
err = nor->params->set_4byte_addr_mode(nor, true); err = spi_nor_set_4byte_addr_mode(nor, true);
if (err && err != -ENOTSUPP) if (err)
return err; return err;
} }
@ -2887,14 +3318,14 @@ static void spi_nor_put_device(struct mtd_info *mtd)
module_put(dev->driver->owner); module_put(dev->driver->owner);
} }
void spi_nor_restore(struct spi_nor *nor) static void spi_nor_restore(struct spi_nor *nor)
{ {
int ret; int ret;
/* restore the addressing mode */ /* restore the addressing mode */
if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) && if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
nor->flags & SNOR_F_BROKEN_RESET) { nor->flags & SNOR_F_BROKEN_RESET) {
ret = nor->params->set_4byte_addr_mode(nor, false); ret = spi_nor_set_4byte_addr_mode(nor, false);
if (ret) if (ret)
/* /*
* Do not stop the execution in the hope that the flash * Do not stop the execution in the hope that the flash
@ -2907,7 +3338,6 @@ void spi_nor_restore(struct spi_nor *nor)
if (nor->flags & SNOR_F_SOFT_RESET) if (nor->flags & SNOR_F_SOFT_RESET)
spi_nor_soft_reset(nor); spi_nor_soft_reset(nor);
} }
EXPORT_SYMBOL_GPL(spi_nor_restore);
static const struct flash_info *spi_nor_match_name(struct spi_nor *nor, static const struct flash_info *spi_nor_match_name(struct spi_nor *nor,
const char *name) const char *name)
@ -2952,7 +3382,7 @@ static const struct flash_info *spi_nor_get_flash_info(struct spi_nor *nor,
* JEDEC knows better, so overwrite platform ID. We * JEDEC knows better, so overwrite platform ID. We
* can't trust partitions any longer, but we'll let * can't trust partitions any longer, but we'll let
* mtd apply them anyway, since some partitions may be * mtd apply them anyway, since some partitions may be
* marked read-only, and we don't want to lose that * marked read-only, and we don't want to loose that
* information, even if it's not 100% accurate. * information, even if it's not 100% accurate.
*/ */
dev_warn(nor->dev, "found %s, expected %s\n", dev_warn(nor->dev, "found %s, expected %s\n",
@ -2977,6 +3407,9 @@ static void spi_nor_set_mtd_info(struct spi_nor *nor)
mtd->name = dev_name(dev); mtd->name = dev_name(dev);
mtd->type = MTD_NORFLASH; mtd->type = MTD_NORFLASH;
mtd->flags = MTD_CAP_NORFLASH; mtd->flags = MTD_CAP_NORFLASH;
/* Unset BIT_WRITEABLE to enable JFFS2 write buffer for ECC'd NOR */
if (nor->flags & SNOR_F_ECC)
mtd->flags &= ~MTD_BIT_WRITEABLE;
if (nor->info->flags & SPI_NOR_NO_ERASE) if (nor->info->flags & SPI_NOR_NO_ERASE)
mtd->flags |= MTD_NO_ERASE; mtd->flags |= MTD_NO_ERASE;
else else
@ -3064,6 +3497,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (ret) if (ret)
return ret; return ret;
if (spi_nor_use_parallel_locking(nor))
init_waitqueue_head(&nor->rww.wait);
/* /*
* Configure the SPI memory: * Configure the SPI memory:
* - select op codes for (Fast) Read, Page Program and Sector Erase. * - select op codes for (Fast) Read, Page Program and Sector Erase.

View File

@ -130,6 +130,8 @@ enum spi_nor_option_flags {
SNOR_F_IO_MODE_EN_VOLATILE = BIT(11), SNOR_F_IO_MODE_EN_VOLATILE = BIT(11),
SNOR_F_SOFT_RESET = BIT(12), SNOR_F_SOFT_RESET = BIT(12),
SNOR_F_SWP_IS_VOLATILE = BIT(13), SNOR_F_SWP_IS_VOLATILE = BIT(13),
SNOR_F_RWW = BIT(14),
SNOR_F_ECC = BIT(15),
}; };
struct spi_nor_read_command { struct spi_nor_read_command {
@ -336,7 +338,8 @@ struct spi_nor_otp {
* by the spi_nor_fixups hooks, or dynamically when parsing the JESD216 * by the spi_nor_fixups hooks, or dynamically when parsing the JESD216
* Serial Flash Discoverable Parameters (SFDP) tables. * Serial Flash Discoverable Parameters (SFDP) tables.
* *
* @size: the flash memory density in bytes. * @bank_size: the flash memory bank density in bytes.
* @size: the total flash memory density in bytes.
* @writesize Minimal writable flash unit size. Defaults to 1. Set to * @writesize Minimal writable flash unit size. Defaults to 1. Set to
* ECC unit size for ECC-ed flashes. * ECC unit size for ECC-ed flashes.
* @page_size: the page size of the SPI NOR flash memory. * @page_size: the page size of the SPI NOR flash memory.
@ -349,6 +352,8 @@ struct spi_nor_otp {
* in octal DTR mode. * in octal DTR mode.
* @rdsr_addr_nbytes: dummy address bytes needed for Read Status Register * @rdsr_addr_nbytes: dummy address bytes needed for Read Status Register
* command in octal DTR mode. * command in octal DTR mode.
* @n_dice: number of dice in the flash memory.
* @vreg_offset: volatile register offset for each die.
* @hwcaps: describes the read and page program hardware * @hwcaps: describes the read and page program hardware
* capabilities. * capabilities.
* @reads: read capabilities ordered by priority: the higher index * @reads: read capabilities ordered by priority: the higher index
@ -374,6 +379,7 @@ struct spi_nor_otp {
* @locking_ops: SPI NOR locking methods. * @locking_ops: SPI NOR locking methods.
*/ */
struct spi_nor_flash_parameter { struct spi_nor_flash_parameter {
u64 bank_size;
u64 size; u64 size;
u32 writesize; u32 writesize;
u32 page_size; u32 page_size;
@ -381,6 +387,8 @@ struct spi_nor_flash_parameter {
u8 addr_mode_nbytes; u8 addr_mode_nbytes;
u8 rdsr_dummy; u8 rdsr_dummy;
u8 rdsr_addr_nbytes; u8 rdsr_addr_nbytes;
u8 n_dice;
u32 *vreg_offset;
struct spi_nor_hwcaps hwcaps; struct spi_nor_hwcaps hwcaps;
struct spi_nor_read_command reads[SNOR_CMD_READ_MAX]; struct spi_nor_read_command reads[SNOR_CMD_READ_MAX];
@ -422,7 +430,7 @@ struct spi_nor_fixups {
int (*post_bfpt)(struct spi_nor *nor, int (*post_bfpt)(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header, const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt); const struct sfdp_bfpt *bfpt);
void (*post_sfdp)(struct spi_nor *nor); int (*post_sfdp)(struct spi_nor *nor);
void (*late_init)(struct spi_nor *nor); void (*late_init)(struct spi_nor *nor);
}; };
@ -435,6 +443,7 @@ struct spi_nor_fixups {
* @sector_size: the size listed here is what works with SPINOR_OP_SE, which * @sector_size: the size listed here is what works with SPINOR_OP_SE, which
* isn't necessarily called a "sector" by the vendor. * isn't necessarily called a "sector" by the vendor.
* @n_sectors: the number of sectors. * @n_sectors: the number of sectors.
* @n_banks: the number of banks.
* @page_size: the flash's page size. * @page_size: the flash's page size.
* @addr_nbytes: number of address bytes to send. * @addr_nbytes: number of address bytes to send.
* *
@ -459,6 +468,7 @@ struct spi_nor_fixups {
* NO_CHIP_ERASE: chip does not support chip erase. * NO_CHIP_ERASE: chip does not support chip erase.
* SPI_NOR_NO_FR: can't do fastread. * SPI_NOR_NO_FR: can't do fastread.
* SPI_NOR_QUAD_PP: flash supports Quad Input Page Program. * SPI_NOR_QUAD_PP: flash supports Quad Input Page Program.
* SPI_NOR_RWW: flash supports reads while write.
* *
* @no_sfdp_flags: flags that indicate support that can be discovered via SFDP. * @no_sfdp_flags: flags that indicate support that can be discovered via SFDP.
* Used when SFDP tables are not defined in the flash. These * Used when SFDP tables are not defined in the flash. These
@ -495,6 +505,7 @@ struct flash_info {
unsigned sector_size; unsigned sector_size;
u16 n_sectors; u16 n_sectors;
u16 page_size; u16 page_size;
u8 n_banks;
u8 addr_nbytes; u8 addr_nbytes;
bool parse_sfdp; bool parse_sfdp;
@ -509,6 +520,7 @@ struct flash_info {
#define NO_CHIP_ERASE BIT(7) #define NO_CHIP_ERASE BIT(7)
#define SPI_NOR_NO_FR BIT(8) #define SPI_NOR_NO_FR BIT(8)
#define SPI_NOR_QUAD_PP BIT(9) #define SPI_NOR_QUAD_PP BIT(9)
#define SPI_NOR_RWW BIT(10)
u8 no_sfdp_flags; u8 no_sfdp_flags;
#define SPI_NOR_SKIP_SFDP BIT(0) #define SPI_NOR_SKIP_SFDP BIT(0)
@ -540,24 +552,30 @@ struct flash_info {
.id = { SPI_NOR_ID_3ITEMS(_jedec_id), SPI_NOR_ID_3ITEMS(_ext_id) }, \ .id = { SPI_NOR_ID_3ITEMS(_jedec_id), SPI_NOR_ID_3ITEMS(_ext_id) }, \
.id_len = 6 .id_len = 6
#define SPI_NOR_GEOMETRY(_sector_size, _n_sectors) \ #define SPI_NOR_GEOMETRY(_sector_size, _n_sectors, _n_banks) \
.sector_size = (_sector_size), \ .sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \ .n_sectors = (_n_sectors), \
.page_size = 256 .page_size = 256, \
.n_banks = (_n_banks)
/* Used when the "_ext_id" is two bytes at most */ /* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors) \ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors) \
SPI_NOR_ID((_jedec_id), (_ext_id)), \ SPI_NOR_ID((_jedec_id), (_ext_id)), \
SPI_NOR_GEOMETRY((_sector_size), (_n_sectors)), SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), 1),
#define INFOB(_jedec_id, _ext_id, _sector_size, _n_sectors, _n_banks) \
SPI_NOR_ID((_jedec_id), (_ext_id)), \
SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), (_n_banks)),
#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors) \ #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors) \
SPI_NOR_ID6((_jedec_id), (_ext_id)), \ SPI_NOR_ID6((_jedec_id), (_ext_id)), \
SPI_NOR_GEOMETRY((_sector_size), (_n_sectors)), SPI_NOR_GEOMETRY((_sector_size), (_n_sectors), 1),
#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_nbytes) \ #define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_nbytes) \
.sector_size = (_sector_size), \ .sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \ .n_sectors = (_n_sectors), \
.page_size = (_page_size), \ .page_size = (_page_size), \
.n_banks = 1, \
.addr_nbytes = (_addr_nbytes), \ .addr_nbytes = (_addr_nbytes), \
.flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR, \ .flags = SPI_NOR_NO_ERASE | SPI_NOR_NO_FR, \
@ -634,10 +652,14 @@ void spi_nor_spimem_setup_op(const struct spi_nor *nor,
const enum spi_nor_protocol proto); const enum spi_nor_protocol proto);
int spi_nor_write_enable(struct spi_nor *nor); int spi_nor_write_enable(struct spi_nor *nor);
int spi_nor_write_disable(struct spi_nor *nor); int spi_nor_write_disable(struct spi_nor *nor);
int spi_nor_set_4byte_addr_mode_en4b_ex4b(struct spi_nor *nor, bool enable);
int spi_nor_set_4byte_addr_mode_wren_en4b_ex4b(struct spi_nor *nor,
bool enable);
int spi_nor_set_4byte_addr_mode_brwr(struct spi_nor *nor, bool enable);
int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable); int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable);
int spi_nor_wait_till_ready(struct spi_nor *nor); int spi_nor_wait_till_ready(struct spi_nor *nor);
int spi_nor_global_block_unlock(struct spi_nor *nor); int spi_nor_global_block_unlock(struct spi_nor *nor);
int spi_nor_lock_and_prep(struct spi_nor *nor); int spi_nor_prep_and_lock(struct spi_nor *nor);
void spi_nor_unlock_and_unprep(struct spi_nor *nor); void spi_nor_unlock_and_unprep(struct spi_nor *nor);
int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor); int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor); int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);

View File

@ -25,6 +25,8 @@ static const char *const snor_f_names[] = {
SNOR_F_NAME(IO_MODE_EN_VOLATILE), SNOR_F_NAME(IO_MODE_EN_VOLATILE),
SNOR_F_NAME(SOFT_RESET), SNOR_F_NAME(SOFT_RESET),
SNOR_F_NAME(SWP_IS_VOLATILE), SNOR_F_NAME(SWP_IS_VOLATILE),
SNOR_F_NAME(RWW),
SNOR_F_NAME(ECC),
}; };
#undef SNOR_F_NAME #undef SNOR_F_NAME

View File

@ -82,6 +82,9 @@ static const struct flash_info macronix_nor_parts[] = {
{ "mx25u51245g", INFO(0xc2253a, 0, 64 * 1024, 1024) { "mx25u51245g", INFO(0xc2253a, 0, 64 * 1024, 1024)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
FIXUP_FLAGS(SPI_NOR_4B_OPCODES) }, FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
{ "mx25uw51245g", INFOB(0xc2813a, 0, 0, 0, 4)
PARSE_SFDP
FLAGS(SPI_NOR_RWW) },
{ "mx25v8035f", INFO(0xc22314, 0, 64 * 1024, 16) { "mx25v8035f", INFO(0xc22314, 0, 64 * 1024, 16)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
SPI_NOR_QUAD_READ) }, SPI_NOR_QUAD_READ) },
@ -105,11 +108,17 @@ static const struct flash_info macronix_nor_parts[] = {
static void macronix_nor_default_init(struct spi_nor *nor) static void macronix_nor_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;
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode; }
static void macronix_nor_late_init(struct spi_nor *nor)
{
if (!nor->params->set_4byte_addr_mode)
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
} }
static const struct spi_nor_fixups macronix_nor_fixups = { static const struct spi_nor_fixups macronix_nor_fixups = {
.default_init = macronix_nor_default_init, .default_init = macronix_nor_default_init,
.late_init = macronix_nor_late_init,
}; };
const struct spi_nor_manufacturer spi_nor_macronix = { const struct spi_nor_manufacturer spi_nor_macronix = {

View File

@ -131,7 +131,7 @@ static void mt35xu512aba_default_init(struct spi_nor *nor)
nor->params->octal_dtr_enable = micron_st_nor_octal_dtr_enable; nor->params->octal_dtr_enable = micron_st_nor_octal_dtr_enable;
} }
static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
{ {
/* Set the Fast Read settings. */ /* Set the Fast Read settings. */
nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
@ -149,6 +149,8 @@ static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
* disable it. * disable it.
*/ */
nor->params->quad_enable = NULL; nor->params->quad_enable = NULL;
return 0;
} }
static const struct spi_nor_fixups mt35xu512aba_fixups = { static const struct spi_nor_fixups mt35xu512aba_fixups = {
@ -301,30 +303,6 @@ static const struct flash_info st_nor_parts[] = {
{ "m25px80", INFO(0x207114, 0, 64 * 1024, 16) }, { "m25px80", INFO(0x207114, 0, 64 * 1024, 16) },
}; };
/**
* micron_st_nor_set_4byte_addr_mode() - Set 4-byte address mode for ST and
* Micron flashes.
* @nor: pointer to 'struct spi_nor'.
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte
* address mode.
*
* Return: 0 on success, -errno otherwise.
*/
static int micron_st_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
{
int ret;
ret = spi_nor_write_enable(nor);
if (ret)
return ret;
ret = spi_nor_set_4byte_addr_mode(nor, enable);
if (ret)
return ret;
return spi_nor_write_disable(nor);
}
/** /**
* micron_st_nor_read_fsr() - Read the Flag Status Register. * micron_st_nor_read_fsr() - Read the Flag Status Register.
* @nor: pointer to 'struct spi_nor' * @nor: pointer to 'struct spi_nor'
@ -449,13 +427,17 @@ static void micron_st_nor_default_init(struct spi_nor *nor)
nor->flags |= SNOR_F_HAS_LOCK; nor->flags |= SNOR_F_HAS_LOCK;
nor->flags &= ~SNOR_F_HAS_16BIT_SR; nor->flags &= ~SNOR_F_HAS_16BIT_SR;
nor->params->quad_enable = NULL; nor->params->quad_enable = NULL;
nor->params->set_4byte_addr_mode = micron_st_nor_set_4byte_addr_mode;
} }
static void micron_st_nor_late_init(struct spi_nor *nor) static void micron_st_nor_late_init(struct spi_nor *nor)
{ {
struct spi_nor_flash_parameter *params = nor->params;
if (nor->info->mfr_flags & USE_FSR) if (nor->info->mfr_flags & USE_FSR)
nor->params->ready = micron_st_nor_ready; params->ready = micron_st_nor_ready;
if (!params->set_4byte_addr_mode)
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;
} }
static const struct spi_nor_fixups micron_st_nor_fixups = { static const struct spi_nor_fixups micron_st_nor_fixups = {

View File

@ -255,7 +255,7 @@ static int spi_nor_mtd_otp_info(struct mtd_info *mtd, size_t len,
if (len < n_regions * sizeof(*buf)) if (len < n_regions * sizeof(*buf))
return -ENOSPC; return -ENOSPC;
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock(nor);
if (ret) if (ret)
return ret; return ret;
@ -325,7 +325,7 @@ static int spi_nor_mtd_otp_read_write(struct mtd_info *mtd, loff_t ofs,
if (!total_len) if (!total_len)
return 0; return 0;
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock(nor);
if (ret) if (ret)
return ret; return ret;
@ -415,7 +415,7 @@ static int spi_nor_mtd_otp_erase(struct mtd_info *mtd, loff_t from, size_t len)
if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen)) if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen))
return -EINVAL; return -EINVAL;
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock(nor);
if (ret) if (ret)
return ret; return ret;
@ -460,7 +460,7 @@ static int spi_nor_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len)
if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen)) if (!IS_ALIGNED(len, rlen) || !IS_ALIGNED(from, rlen))
return -EINVAL; return -EINVAL;
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock(nor);
if (ret) if (ret)
return ret; return ret;

View File

@ -26,6 +26,11 @@
* Status, Control and Configuration * Status, Control and Configuration
* Register Map. * Register Map.
*/ */
#define SFDP_SCCR_MAP_MC_ID 0xff88 /*
* Status, Control and Configuration
* Register Map Offsets for Multi-Chip
* SPI Memory Devices.
*/
#define SFDP_SIGNATURE 0x50444653U #define SFDP_SIGNATURE 0x50444653U
@ -438,6 +443,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
size_t len; size_t len;
int i, cmd, err; int i, cmd, err;
u32 addr, val; u32 addr, val;
u32 dword;
u16 half; u16 half;
u8 erase_mask; u8 erase_mask;
@ -607,6 +613,16 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
break; break;
} }
dword = bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_4B_ADDR_MODE_MASK;
if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_BRWR))
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_brwr;
else if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_WREN_EN4B_EX4B))
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;
else if (SFDP_MASK_CHECK(dword, BFPT_DWORD16_4B_ADDR_MODE_EN4B_EX4B))
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
else
dev_dbg(nor->dev, "BFPT: 4-Byte Address Mode method is not recognized or not implemented\n");
/* Soft Reset support. */ /* Soft Reset support. */
if (bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST) if (bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST)
nor->flags |= SNOR_F_SOFT_RESET; nor->flags |= SNOR_F_SOFT_RESET;
@ -1215,6 +1231,7 @@ out:
static int spi_nor_parse_sccr(struct spi_nor *nor, static int spi_nor_parse_sccr(struct spi_nor *nor,
const struct sfdp_parameter_header *sccr_header) const struct sfdp_parameter_header *sccr_header)
{ {
struct spi_nor_flash_parameter *params = nor->params;
u32 *dwords, addr; u32 *dwords, addr;
size_t len; size_t len;
int ret; int ret;
@ -1231,6 +1248,18 @@ static int spi_nor_parse_sccr(struct spi_nor *nor,
le32_to_cpu_array(dwords, sccr_header->length); le32_to_cpu_array(dwords, sccr_header->length);
/* Address offset for volatile registers (die 0) */
if (!params->vreg_offset) {
params->vreg_offset = devm_kmalloc(nor->dev, sizeof(*dwords),
GFP_KERNEL);
if (!params->vreg_offset) {
ret = -ENOMEM;
goto out;
}
}
params->vreg_offset[0] = dwords[SFDP_DWORD(1)];
params->n_dice = 1;
if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE,
dwords[SFDP_DWORD(22)])) dwords[SFDP_DWORD(22)]))
nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
@ -1240,6 +1269,63 @@ out:
return ret; return ret;
} }
/**
* spi_nor_parse_sccr_mc() - Parse the Status, Control and Configuration
* Register Map Offsets for Multi-Chip SPI Memory
* Devices.
* @nor: pointer to a 'struct spi_nor'
* @sccr_mc_header: pointer to the 'struct sfdp_parameter_header' describing
* the SCCR Map offsets table length and version.
*
* Return: 0 on success, -errno otherwise.
*/
static int spi_nor_parse_sccr_mc(struct spi_nor *nor,
const struct sfdp_parameter_header *sccr_mc_header)
{
struct spi_nor_flash_parameter *params = nor->params;
u32 *dwords, addr;
u8 i, n_dice;
size_t len;
int ret;
len = sccr_mc_header->length * sizeof(*dwords);
dwords = kmalloc(len, GFP_KERNEL);
if (!dwords)
return -ENOMEM;
addr = SFDP_PARAM_HEADER_PTP(sccr_mc_header);
ret = spi_nor_read_sfdp(nor, addr, len, dwords);
if (ret)
goto out;
le32_to_cpu_array(dwords, sccr_mc_header->length);
/*
* Pair of DOWRDs (volatile and non-volatile register offsets) per
* additional die. Hence, length = 2 * (number of additional dice).
*/
n_dice = 1 + sccr_mc_header->length / 2;
/* Address offset for volatile registers of additional dice */
params->vreg_offset =
devm_krealloc(nor->dev, params->vreg_offset,
n_dice * sizeof(*dwords),
GFP_KERNEL);
if (!params->vreg_offset) {
ret = -ENOMEM;
goto out;
}
for (i = 1; i < n_dice; i++)
params->vreg_offset[i] = dwords[SFDP_DWORD(i) * 2];
params->n_dice = n_dice;
out:
kfree(dwords);
return ret;
}
/** /**
* spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings * spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings
* after SFDP has been parsed. Called only for flashes that define JESD216 SFDP * after SFDP has been parsed. Called only for flashes that define JESD216 SFDP
@ -1249,14 +1335,21 @@ out:
* Used to tweak various flash parameters when information provided by the SFDP * Used to tweak various flash parameters when information provided by the SFDP
* tables are wrong. * tables are wrong.
*/ */
static void spi_nor_post_sfdp_fixups(struct spi_nor *nor) static int spi_nor_post_sfdp_fixups(struct spi_nor *nor)
{ {
int ret;
if (nor->manufacturer && nor->manufacturer->fixups && if (nor->manufacturer && nor->manufacturer->fixups &&
nor->manufacturer->fixups->post_sfdp) nor->manufacturer->fixups->post_sfdp) {
nor->manufacturer->fixups->post_sfdp(nor); ret = nor->manufacturer->fixups->post_sfdp(nor);
if (ret)
return ret;
}
if (nor->info->fixups && nor->info->fixups->post_sfdp) if (nor->info->fixups && nor->info->fixups->post_sfdp)
nor->info->fixups->post_sfdp(nor); return nor->info->fixups->post_sfdp(nor);
return 0;
} }
/** /**
@ -1449,6 +1542,10 @@ int spi_nor_parse_sfdp(struct spi_nor *nor)
err = spi_nor_parse_sccr(nor, param_header); err = spi_nor_parse_sccr(nor, param_header);
break; break;
case SFDP_SCCR_MAP_MC_ID:
err = spi_nor_parse_sccr_mc(nor, param_header);
break;
default: default:
break; break;
} }
@ -1466,7 +1563,7 @@ int spi_nor_parse_sfdp(struct spi_nor *nor)
} }
} }
spi_nor_post_sfdp_fixups(nor); err = spi_nor_post_sfdp_fixups(nor);
exit: exit:
kfree(param_headers); kfree(param_headers);
return err; return err;

View File

@ -15,6 +15,7 @@
/* SFDP DWORDS are indexed from 1 but C arrays are indexed from 0. */ /* SFDP DWORDS are indexed from 1 but C arrays are indexed from 0. */
#define SFDP_DWORD(i) ((i) - 1) #define SFDP_DWORD(i) ((i) - 1)
#define SFDP_MASK_CHECK(dword, mask) (((dword) & (mask)) == (mask))
/* Basic Flash Parameter Table */ /* Basic Flash Parameter Table */
@ -89,6 +90,32 @@ struct sfdp_bfpt {
#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20) #define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20)
#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */ #define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */
#define BFPT_DWORD16_EN4B_MASK GENMASK(31, 24)
#define BFPT_DWORD16_EN4B_ALWAYS_4B BIT(30)
#define BFPT_DWORD16_EN4B_4B_OPCODES BIT(29)
#define BFPT_DWORD16_EN4B_16BIT_NV_CR BIT(28)
#define BFPT_DWORD16_EN4B_BRWR BIT(27)
#define BFPT_DWORD16_EN4B_WREAR BIT(26)
#define BFPT_DWORD16_EN4B_WREN_EN4B BIT(25)
#define BFPT_DWORD16_EN4B_EN4B BIT(24)
#define BFPT_DWORD16_EX4B_MASK GENMASK(18, 14)
#define BFPT_DWORD16_EX4B_16BIT_NV_CR BIT(18)
#define BFPT_DWORD16_EX4B_BRWR BIT(17)
#define BFPT_DWORD16_EX4B_WREAR BIT(16)
#define BFPT_DWORD16_EX4B_WREN_EX4B BIT(15)
#define BFPT_DWORD16_EX4B_EX4B BIT(14)
#define BFPT_DWORD16_4B_ADDR_MODE_MASK \
(BFPT_DWORD16_EN4B_MASK | BFPT_DWORD16_EX4B_MASK)
#define BFPT_DWORD16_4B_ADDR_MODE_16BIT_NV_CR \
(BFPT_DWORD16_EN4B_16BIT_NV_CR | BFPT_DWORD16_EX4B_16BIT_NV_CR)
#define BFPT_DWORD16_4B_ADDR_MODE_BRWR \
(BFPT_DWORD16_EN4B_BRWR | BFPT_DWORD16_EX4B_BRWR)
#define BFPT_DWORD16_4B_ADDR_MODE_WREAR \
(BFPT_DWORD16_EN4B_WREAR | BFPT_DWORD16_EX4B_WREAR)
#define BFPT_DWORD16_4B_ADDR_MODE_WREN_EN4B_EX4B \
(BFPT_DWORD16_EN4B_WREN_EN4B | BFPT_DWORD16_EX4B_WREN_EX4B)
#define BFPT_DWORD16_4B_ADDR_MODE_EN4B_EX4B \
(BFPT_DWORD16_EN4B_EN4B | BFPT_DWORD16_EX4B_EX4B)
#define BFPT_DWORD16_SWRST_EN_RST BIT(12) #define BFPT_DWORD16_SWRST_EN_RST BIT(12)
#define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29) #define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29)

View File

@ -14,13 +14,26 @@
#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */ #define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */ #define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */ #define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
#define SPINOR_REG_CYPRESS_CFR1V 0x00800002 #define SPINOR_REG_CYPRESS_VREG 0x00800000
#define SPINOR_REG_CYPRESS_STR1 0x0
#define SPINOR_REG_CYPRESS_STR1V \
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_STR1)
#define SPINOR_REG_CYPRESS_CFR1 0x2
#define SPINOR_REG_CYPRESS_CFR1V \
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR1)
#define SPINOR_REG_CYPRESS_CFR1_QUAD_EN BIT(1) /* Quad Enable */ #define SPINOR_REG_CYPRESS_CFR1_QUAD_EN BIT(1) /* Quad Enable */
#define SPINOR_REG_CYPRESS_CFR2V 0x00800003 #define SPINOR_REG_CYPRESS_CFR2 0x3
#define SPINOR_REG_CYPRESS_CFR2V \
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR2)
#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb #define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb
#define SPINOR_REG_CYPRESS_CFR3V 0x00800004 #define SPINOR_REG_CYPRESS_CFR2_ADRBYT BIT(7)
#define SPINOR_REG_CYPRESS_CFR3 0x4
#define SPINOR_REG_CYPRESS_CFR3V \
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR3)
#define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */ #define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */
#define SPINOR_REG_CYPRESS_CFR5V 0x00800006 #define SPINOR_REG_CYPRESS_CFR5 0x6
#define SPINOR_REG_CYPRESS_CFR5V \
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR5)
#define SPINOR_REG_CYPRESS_CFR5_BIT6 BIT(6) #define SPINOR_REG_CYPRESS_CFR5_BIT6 BIT(6)
#define SPINOR_REG_CYPRESS_CFR5_DDR BIT(1) #define SPINOR_REG_CYPRESS_CFR5_DDR BIT(1)
#define SPINOR_REG_CYPRESS_CFR5_OPI BIT(0) #define SPINOR_REG_CYPRESS_CFR5_OPI BIT(0)
@ -29,6 +42,7 @@
SPINOR_REG_CYPRESS_CFR5_OPI) SPINOR_REG_CYPRESS_CFR5_OPI)
#define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS SPINOR_REG_CYPRESS_CFR5_BIT6 #define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS SPINOR_REG_CYPRESS_CFR5_BIT6
#define SPINOR_OP_CYPRESS_RD_FAST 0xee #define SPINOR_OP_CYPRESS_RD_FAST 0xee
#define SPINOR_REG_CYPRESS_ARCFN 0x00000006
/* Cypress SPI NOR flash operations. */ /* Cypress SPI NOR flash operations. */
#define CYPRESS_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \ #define CYPRESS_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \
@ -37,10 +51,10 @@
SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_DATA_OUT(ndata, buf, 0)) SPI_MEM_OP_DATA_OUT(ndata, buf, 0))
#define CYPRESS_NOR_RD_ANY_REG_OP(naddr, addr, buf) \ #define CYPRESS_NOR_RD_ANY_REG_OP(naddr, addr, ndummy, buf) \
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), \ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), \
SPI_MEM_OP_ADDR(naddr, addr, 0), \ SPI_MEM_OP_ADDR(naddr, addr, 0), \
SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_DUMMY(ndummy, 0), \
SPI_MEM_OP_DATA_IN(1, buf, 0)) SPI_MEM_OP_DATA_IN(1, buf, 0))
#define SPANSION_CLSR_OP \ #define SPANSION_CLSR_OP \
@ -49,6 +63,84 @@
SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA) SPI_MEM_OP_NO_DATA)
/**
* spansion_nor_clear_sr() - Clear the Status Register.
* @nor: pointer to 'struct spi_nor'.
*/
static void spansion_nor_clear_sr(struct spi_nor *nor)
{
int ret;
if (nor->spimem) {
struct spi_mem_op op = SPANSION_CLSR_OP;
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR,
NULL, 0);
}
if (ret)
dev_dbg(nor->dev, "error %d clearing SR\n", ret);
}
static int cypress_nor_sr_ready_and_clear_reg(struct spi_nor *nor, u64 addr)
{
struct spi_mem_op op =
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, addr,
0, nor->bouncebuf);
int ret;
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
if (nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) {
if (nor->bouncebuf[0] & SR_E_ERR)
dev_err(nor->dev, "Erase Error occurred\n");
else
dev_err(nor->dev, "Programming Error occurred\n");
spansion_nor_clear_sr(nor);
ret = spi_nor_write_disable(nor);
if (ret)
return ret;
return -EIO;
}
return !(nor->bouncebuf[0] & SR_WIP);
}
/**
* cypress_nor_sr_ready_and_clear() - Query the Status Register of each die by
* using Read Any Register command to see if the whole flash is ready for new
* commands and clear it if there are any errors.
* @nor: pointer to 'struct spi_nor'.
*
* Return: 1 if ready, 0 if not ready, -errno on errors.
*/
static int cypress_nor_sr_ready_and_clear(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
u64 addr;
int ret;
u8 i;
for (i = 0; i < params->n_dice; i++) {
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_STR1;
ret = cypress_nor_sr_ready_and_clear_reg(nor, addr);
if (ret < 0)
return ret;
else if (ret == 0)
return 0;
}
return 1;
}
static int cypress_nor_octal_dtr_en(struct spi_nor *nor) static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
{ {
struct spi_mem_op op; struct spi_mem_op op;
@ -125,6 +217,51 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
return 0; return 0;
} }
static int cypress_nor_quad_enable_volatile_reg(struct spi_nor *nor, u64 addr)
{
struct spi_mem_op op;
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
u8 cfr1v_written;
int ret;
op = (struct spi_mem_op)
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0,
nor->bouncebuf);
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1_QUAD_EN)
return 0;
/* Update the Quad Enable bit. */
nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1_QUAD_EN;
op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, addr, 1,
nor->bouncebuf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
cfr1v_written = nor->bouncebuf[0];
/* Read back and check it. */
op = (struct spi_mem_op)
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0,
nor->bouncebuf);
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
if (nor->bouncebuf[0] != cfr1v_written) {
dev_err(nor->dev, "CFR1: Read back test failed\n");
return -EIO;
}
return 0;
}
/** /**
* cypress_nor_quad_enable_volatile() - enable Quad I/O mode in volatile * cypress_nor_quad_enable_volatile() - enable Quad I/O mode in volatile
* register. * register.
@ -141,68 +278,141 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
*/ */
static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
{ {
struct spi_mem_op op; struct spi_nor_flash_parameter *params = nor->params;
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; u64 addr;
u8 cfr1v_written; u8 i;
int ret; int ret;
op = (struct spi_mem_op) if (!params->n_dice)
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, return cypress_nor_quad_enable_volatile_reg(nor,
SPINOR_REG_CYPRESS_CFR1V, SPINOR_REG_CYPRESS_CFR1V);
nor->bouncebuf);
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); for (i = 0; i < params->n_dice; i++) {
if (ret) addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR1;
return ret; ret = cypress_nor_quad_enable_volatile_reg(nor, addr);
if (ret)
if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1_QUAD_EN) return ret;
return 0;
/* Update the Quad Enable bit. */
nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1_QUAD_EN;
op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR1V, 1,
nor->bouncebuf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
cfr1v_written = nor->bouncebuf[0];
/* Read back and check it. */
op = (struct spi_mem_op)
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR1V,
nor->bouncebuf);
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
if (nor->bouncebuf[0] != cfr1v_written) {
dev_err(nor->dev, "CFR1: Read back test failed\n");
return -EIO;
} }
return 0; return 0;
} }
/** /**
* cypress_nor_set_page_size() - Set page size which corresponds to the flash * cypress_nor_determine_addr_mode_by_sr1() - Determine current address mode
* configuration. * (3 or 4-byte) by querying status
* @nor: pointer to a 'struct spi_nor' * register 1 (SR1).
* @nor: pointer to a 'struct spi_nor'
* @addr_mode: ponter to a buffer where we return the determined
* address mode.
* *
* The BFPT table advertises a 512B or 256B page size depending on part but the * This function tries to determine current address mode by comparing SR1 value
* page size is actually configurable (with the default being 256B). Read from * from RDSR1(no address), RDAR(3-byte address), and RDAR(4-byte address).
* CFR3V[4] and set the correct size.
* *
* Return: 0 on success, -errno otherwise. * Return: 0 on success, -errno otherwise.
*/ */
static int cypress_nor_set_page_size(struct spi_nor *nor) static int cypress_nor_determine_addr_mode_by_sr1(struct spi_nor *nor,
u8 *addr_mode)
{
struct spi_mem_op op =
CYPRESS_NOR_RD_ANY_REG_OP(3, SPINOR_REG_CYPRESS_STR1V, 0,
nor->bouncebuf);
bool is3byte, is4byte;
int ret;
ret = spi_nor_read_sr(nor, &nor->bouncebuf[1]);
if (ret)
return ret;
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
is3byte = (nor->bouncebuf[0] == nor->bouncebuf[1]);
op = (struct spi_mem_op)
CYPRESS_NOR_RD_ANY_REG_OP(4, SPINOR_REG_CYPRESS_STR1V, 0,
nor->bouncebuf);
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
is4byte = (nor->bouncebuf[0] == nor->bouncebuf[1]);
if (is3byte == is4byte)
return -EIO;
if (is3byte)
*addr_mode = 3;
else
*addr_mode = 4;
return 0;
}
/**
* cypress_nor_set_addr_mode_nbytes() - Set the number of address bytes mode of
* current address mode.
* @nor: pointer to a 'struct spi_nor'
*
* Determine current address mode by reading SR1 with different methods, then
* query CFR2V[7] to confirm. If determination is failed, force enter to 4-byte
* address mode.
*
* Return: 0 on success, -errno otherwise.
*/
static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor)
{
struct spi_mem_op op;
u8 addr_mode;
int ret;
/*
* Read SR1 by RDSR1 and RDAR(3- AND 4-byte addr). Use write enable
* that sets bit-1 in SR1.
*/
ret = spi_nor_write_enable(nor);
if (ret)
return ret;
ret = cypress_nor_determine_addr_mode_by_sr1(nor, &addr_mode);
if (ret) {
ret = spi_nor_set_4byte_addr_mode(nor, true);
if (ret)
return ret;
return spi_nor_write_disable(nor);
}
ret = spi_nor_write_disable(nor);
if (ret)
return ret;
/*
* Query CFR2V and make sure no contradiction between determined address
* mode and CFR2V[7].
*/
op = (struct spi_mem_op)
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode, SPINOR_REG_CYPRESS_CFR2V,
0, nor->bouncebuf);
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR2_ADRBYT) {
if (addr_mode != 4)
return spi_nor_set_4byte_addr_mode(nor, true);
} else {
if (addr_mode != 3)
return spi_nor_set_4byte_addr_mode(nor, true);
}
nor->params->addr_nbytes = addr_mode;
nor->params->addr_mode_nbytes = addr_mode;
return 0;
}
static int cypress_nor_get_page_size_single_chip(struct spi_nor *nor)
{ {
struct spi_mem_op op = struct spi_mem_op op =
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR3V, SPINOR_REG_CYPRESS_CFR3V, 0,
nor->bouncebuf); nor->bouncebuf);
int ret; int ret;
@ -218,18 +428,135 @@ static int cypress_nor_set_page_size(struct spi_nor *nor)
return 0; return 0;
} }
static int cypress_nor_get_page_size_mcp(struct spi_nor *nor)
{
struct spi_mem_op op =
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
0, 0, nor->bouncebuf);
struct spi_nor_flash_parameter *params = nor->params;
int ret;
u8 i;
/*
* Use the minimum common page size configuration. Programming 256-byte
* under 512-byte page size configuration is safe.
*/
params->page_size = 256;
for (i = 0; i < params->n_dice; i++) {
op.addr.val = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR3;
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
if (!(nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3_PGSZ))
return 0;
}
params->page_size = 512;
return 0;
}
/**
* cypress_nor_get_page_size() - Get flash page size configuration.
* @nor: pointer to a 'struct spi_nor'
*
* The BFPT table advertises a 512B or 256B page size depending on part but the
* page size is actually configurable (with the default being 256B). Read from
* CFR3V[4] and set the correct size.
*
* Return: 0 on success, -errno otherwise.
*/
static int cypress_nor_get_page_size(struct spi_nor *nor)
{
if (nor->params->n_dice)
return cypress_nor_get_page_size_mcp(nor);
return cypress_nor_get_page_size_single_chip(nor);
}
static void cypress_nor_ecc_init(struct spi_nor *nor)
{
/*
* Programming is supported only in 16-byte ECC data unit granularity.
* Byte-programming, bit-walking, or multiple program operations to the
* same ECC data unit without an erase are not allowed.
*/
nor->params->writesize = 16;
nor->flags |= SNOR_F_ECC;
}
static int
s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt)
{
struct spi_mem_op op;
int ret;
ret = cypress_nor_set_addr_mode_nbytes(nor);
if (ret)
return ret;
/* Read Architecture Configuration Register (ARCFN) */
op = (struct spi_mem_op)
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
SPINOR_REG_CYPRESS_ARCFN, 1,
nor->bouncebuf);
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
/* ARCFN value must be 0 if uniform sector is selected */
if (nor->bouncebuf[0])
return -ENODEV;
return cypress_nor_get_page_size(nor);
}
static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
/* PP_1_1_4_4B is supported but missing in 4BAIT. */
params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_1_1_4],
SPINOR_OP_PP_1_1_4_4B,
SNOR_PROTO_1_1_4);
return 0;
}
static void s25fs256t_late_init(struct spi_nor *nor)
{
cypress_nor_ecc_init(nor);
}
static struct spi_nor_fixups s25fs256t_fixups = {
.post_bfpt = s25fs256t_post_bfpt_fixup,
.post_sfdp = s25fs256t_post_sfdp_fixup,
.late_init = s25fs256t_late_init,
};
static int static int
s25hx_t_post_bfpt_fixup(struct spi_nor *nor, s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header, const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt) const struct sfdp_bfpt *bfpt)
{ {
int ret;
ret = cypress_nor_set_addr_mode_nbytes(nor);
if (ret)
return ret;
/* Replace Quad Enable with volatile version */ /* Replace Quad Enable with volatile version */
nor->params->quad_enable = cypress_nor_quad_enable_volatile; nor->params->quad_enable = cypress_nor_quad_enable_volatile;
return cypress_nor_set_page_size(nor); return 0;
} }
static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor) static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
{ {
struct spi_nor_erase_type *erase_type = struct spi_nor_erase_type *erase_type =
nor->params->erase_map.erase_type; nor->params->erase_map.erase_type;
@ -251,6 +578,12 @@ static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
break; break;
} }
} }
/* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
if (nor->params->size == SZ_256M)
nor->params->n_dice = 2;
return cypress_nor_get_page_size(nor);
} }
static void s25hx_t_late_init(struct spi_nor *nor) static void s25hx_t_late_init(struct spi_nor *nor)
@ -260,8 +593,11 @@ static void s25hx_t_late_init(struct spi_nor *nor)
/* Fast Read 4B requires mode cycles */ /* Fast Read 4B requires mode cycles */
params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
/* The writesize should be ECC data unit size */ cypress_nor_ecc_init(nor);
params->writesize = 16;
/* Replace ready() with multi die version */
if (params->n_dice)
params->ready = cypress_nor_sr_ready_and_clear;
} }
static struct spi_nor_fixups s25hx_t_fixups = { static struct spi_nor_fixups s25hx_t_fixups = {
@ -286,7 +622,7 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
cypress_nor_octal_dtr_dis(nor); cypress_nor_octal_dtr_dis(nor);
} }
static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor) static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
{ {
/* /*
* On older versions of the flash the xSPI Profile 1.0 table has the * On older versions of the flash the xSPI Profile 1.0 table has the
@ -312,19 +648,27 @@ static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
* actual value for that is 4. * actual value for that is 4.
*/ */
nor->params->rdsr_addr_nbytes = 4; nor->params->rdsr_addr_nbytes = 4;
return cypress_nor_get_page_size(nor);
} }
static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor, static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header, const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt) const struct sfdp_bfpt *bfpt)
{ {
return cypress_nor_set_page_size(nor); int ret;
ret = cypress_nor_set_addr_mode_nbytes(nor);
if (ret)
return ret;
return 0;
} }
static void s28hx_t_late_init(struct spi_nor *nor) static void s28hx_t_late_init(struct spi_nor *nor)
{ {
nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable; nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable;
nor->params->writesize = 16; cypress_nor_ecc_init(nor);
} }
static const struct spi_nor_fixups s28hx_t_fixups = { static const struct spi_nor_fixups s28hx_t_fixups = {
@ -446,6 +790,9 @@ static const struct flash_info spansion_nor_parts[] = {
{ "s25fl256l", INFO(0x016019, 0, 64 * 1024, 512) { "s25fl256l", INFO(0x016019, 0, 64 * 1024, 512)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
FIXUP_FLAGS(SPI_NOR_4B_OPCODES) }, FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
{ "s25fs256t", INFO6(0x342b19, 0x0f0890, 0, 0)
PARSE_SFDP
.fixups = &s25fs256t_fixups },
{ "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256) { "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256)
PARSE_SFDP PARSE_SFDP
MFR_FLAGS(USE_CLSR) MFR_FLAGS(USE_CLSR)
@ -454,6 +801,10 @@ static const struct flash_info spansion_nor_parts[] = {
PARSE_SFDP PARSE_SFDP
MFR_FLAGS(USE_CLSR) MFR_FLAGS(USE_CLSR)
.fixups = &s25hx_t_fixups }, .fixups = &s25hx_t_fixups },
{ "s25hl02gt", INFO6(0x342a1c, 0x0f0090, 0, 0)
PARSE_SFDP
FLAGS(NO_CHIP_ERASE)
.fixups = &s25hx_t_fixups },
{ "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256) { "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256)
PARSE_SFDP PARSE_SFDP
MFR_FLAGS(USE_CLSR) MFR_FLAGS(USE_CLSR)
@ -462,6 +813,10 @@ static const struct flash_info spansion_nor_parts[] = {
PARSE_SFDP PARSE_SFDP
MFR_FLAGS(USE_CLSR) MFR_FLAGS(USE_CLSR)
.fixups = &s25hx_t_fixups }, .fixups = &s25hx_t_fixups },
{ "s25hs02gt", INFO6(0x342b1c, 0x0f0090, 0, 0)
PARSE_SFDP
FLAGS(NO_CHIP_ERASE)
.fixups = &s25hx_t_fixups },
{ "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1) { "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1)
FLAGS(SPI_NOR_NO_ERASE) }, FLAGS(SPI_NOR_NO_ERASE) },
{ "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256) { "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256)
@ -482,29 +837,6 @@ static const struct flash_info spansion_nor_parts[] = {
}, },
}; };
/**
* spansion_nor_clear_sr() - Clear the Status Register.
* @nor: pointer to 'struct spi_nor'.
*/
static void spansion_nor_clear_sr(struct spi_nor *nor)
{
int ret;
if (nor->spimem) {
struct spi_mem_op op = SPANSION_CLSR_OP;
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR,
NULL, 0);
}
if (ret)
dev_dbg(nor->dev, "error %d clearing SR\n", ret);
}
/** /**
* spansion_nor_sr_ready_and_clear() - Query the Status Register to see if the * spansion_nor_sr_ready_and_clear() - Query the Status Register to see if the
* flash is ready for new commands and clear it if there are any errors. * flash is ready for new commands and clear it if there are any errors.

View File

@ -126,7 +126,7 @@ static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock(nor);
if (ret) if (ret)
return ret; return ret;

View File

@ -348,7 +348,7 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
struct spi_nor *nor = mtd_to_spi_nor(mtd); struct spi_nor *nor = mtd_to_spi_nor(mtd);
int ret; int ret;
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock(nor);
if (ret) if (ret)
return ret; return ret;
@ -363,7 +363,7 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
struct spi_nor *nor = mtd_to_spi_nor(mtd); struct spi_nor *nor = mtd_to_spi_nor(mtd);
int ret; int ret;
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock(nor);
if (ret) if (ret)
return ret; return ret;
@ -378,7 +378,7 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
struct spi_nor *nor = mtd_to_spi_nor(mtd); struct spi_nor *nor = mtd_to_spi_nor(mtd);
int ret; int ret;
ret = spi_nor_lock_and_prep(nor); ret = spi_nor_prep_and_lock(nor);
if (ret) if (ret)
return ret; return ret;

View File

@ -188,7 +188,7 @@ static int winbond_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
{ {
int ret; int ret;
ret = spi_nor_set_4byte_addr_mode(nor, enable); ret = spi_nor_set_4byte_addr_mode_en4b_ex4b(nor, enable);
if (ret || enable) if (ret || enable)
return ret; return ret;
@ -216,19 +216,25 @@ static const struct spi_nor_otp_ops winbond_nor_otp_ops = {
.is_locked = spi_nor_otp_is_locked_sr2, .is_locked = spi_nor_otp_is_locked_sr2,
}; };
static void winbond_nor_default_init(struct spi_nor *nor)
{
nor->params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode;
}
static void winbond_nor_late_init(struct spi_nor *nor) static void winbond_nor_late_init(struct spi_nor *nor)
{ {
if (nor->params->otp.org->n_regions) struct spi_nor_flash_parameter *params = nor->params;
nor->params->otp.ops = &winbond_nor_otp_ops;
if (params->otp.org->n_regions)
params->otp.ops = &winbond_nor_otp_ops;
/*
* Winbond seems to require that the Extended Address Register to be set
* to zero when exiting the 4-Byte Address Mode, at least for W25Q256FV.
* This requirement is not described in the JESD216 SFDP standard, thus
* it is Winbond specific. Since we do not know if other Winbond flashes
* have the same requirement, play safe and overwrite the method parsed
* from BFPT, if any.
*/
params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode;
} }
static const struct spi_nor_fixups winbond_nor_fixups = { static const struct spi_nor_fixups winbond_nor_fixups = {
.default_init = winbond_nor_default_init,
.late_init = winbond_nor_late_init, .late_init = winbond_nor_late_init,
}; };

View File

@ -31,6 +31,7 @@
.sector_size = (8 * (_page_size)), \ .sector_size = (8 * (_page_size)), \
.n_sectors = (_n_sectors), \ .n_sectors = (_n_sectors), \
.page_size = (_page_size), \ .page_size = (_page_size), \
.n_banks = 1, \
.addr_nbytes = 3, \ .addr_nbytes = 3, \
.flags = SPI_NOR_NO_FR .flags = SPI_NOR_NO_FR

View File

@ -1075,7 +1075,7 @@ static inline void nand_op_trace(const char *prefix,
* @exec_op: controller specific method to execute NAND operations. * @exec_op: controller specific method to execute NAND operations.
* This method replaces chip->legacy.cmdfunc(), * This method replaces chip->legacy.cmdfunc(),
* chip->legacy.{read,write}_{buf,byte,word}(), * chip->legacy.{read,write}_{buf,byte,word}(),
* chip->legacy.dev_ready() and chip->legacy.waifunc(). * chip->legacy.dev_ready() and chip->legacy.waitfunc().
* @setup_interface: setup the data interface and timing. If chipnr is set to * @setup_interface: setup the data interface and timing. If chipnr is set to
* %NAND_DATA_IFACE_CHECK_ONLY this means the configuration * %NAND_DATA_IFACE_CHECK_ONLY this means the configuration
* should not be applied but only checked. * should not be applied but only checked.

View File

@ -343,6 +343,12 @@ struct spi_nor_flash_parameter;
* struct spi_nor - Structure for defining the SPI NOR layer * struct spi_nor - Structure for defining the SPI NOR layer
* @mtd: an mtd_info structure * @mtd: an mtd_info structure
* @lock: the lock for the read/write/erase/lock/unlock operations * @lock: the lock for the read/write/erase/lock/unlock operations
* @rww: Read-While-Write (RWW) sync lock
* @rww.wait: wait queue for the RWW sync
* @rww.ongoing_io: the bus is busy
* @rww.ongoing_rd: a read is ongoing on the chip
* @rww.ongoing_pe: a program/erase is ongoing on the chip
* @rww.used_banks: bitmap of the banks in use
* @dev: pointer to an SPI device or an SPI NOR controller device * @dev: pointer to an SPI device or an SPI NOR controller device
* @spimem: pointer to the SPI memory device * @spimem: pointer to the SPI memory device
* @bouncebuf: bounce buffer used when the buffer passed by the MTD * @bouncebuf: bounce buffer used when the buffer passed by the MTD
@ -376,6 +382,13 @@ struct spi_nor_flash_parameter;
struct spi_nor { struct spi_nor {
struct mtd_info mtd; struct mtd_info mtd;
struct mutex lock; struct mutex lock;
struct spi_nor_rww {
wait_queue_head_t wait;
bool ongoing_io;
bool ongoing_rd;
bool ongoing_pe;
unsigned int used_banks;
} rww;
struct device *dev; struct device *dev;
struct spi_mem *spimem; struct spi_mem *spimem;
u8 *bouncebuf; u8 *bouncebuf;
@ -437,10 +450,4 @@ static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor)
int spi_nor_scan(struct spi_nor *nor, const char *name, int spi_nor_scan(struct spi_nor *nor, const char *name,
const struct spi_nor_hwcaps *hwcaps); const struct spi_nor_hwcaps *hwcaps);
/**
* spi_nor_restore_addr_mode() - restore the status of SPI NOR
* @nor: the spi_nor structure
*/
void spi_nor_restore(struct spi_nor *nor);
#endif #endif

View File

@ -262,6 +262,7 @@ struct spinand_manufacturer {
/* SPI NAND manufacturers */ /* SPI NAND manufacturers */
extern const struct spinand_manufacturer alliancememory_spinand_manufacturer; extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
extern const struct spinand_manufacturer ato_spinand_manufacturer; extern const struct spinand_manufacturer ato_spinand_manufacturer;
extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
extern const struct spinand_manufacturer macronix_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer;
extern const struct spinand_manufacturer micron_spinand_manufacturer; extern const struct spinand_manufacturer micron_spinand_manufacturer;