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
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAmRANmIACgkQJWrqGEe9
 VoRU2QgAl8XFkLs1h88wGi6ln/MSK0cQJZWUzteGgWuaBQCMNfgGFzqPHyJ7ygO9
 l4U4O1L/IvACvJx5QHm/lH5Mig23jym9J8YfV1Kf9aVYOlBKRNysbi+DdktESGG9
 6HmpS0nQfkC84qA8ouInOp+AZYjFEPRrBfp5UWkSRHiQJvcYnt2iS2oOLk3LNY6y
 zduBOno3mric2ZlBbg+ZCURhQzrr3k8c4VXV+LHSslqsmH/2sOFlg78hLJx922Y+
 FTfYnx82iLIvFAJttRi2bXWKuE1Yr2XWJ3iEHKxmOA2vPmYi6mDBHTYhnikGSpm+
 GhARHH+JhW7qzLbaq5ZC3HGH58aC/g==
 =aYlo
 -----END PGP SIGNATURE-----

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
commit eb8322d714
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
allOf:
- $ref: "nand-controller.yaml"
- $ref: nand-controller.yaml
maintainers:
- 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
allOf:
- $ref: "nand-controller.yaml"
- $ref: nand-controller.yaml
maintainers:
- 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
allOf:
- $ref: "nand-controller.yaml"
- $ref: nand-controller.yaml
maintainers:
- Miquel Raynal <miquel.raynal@bootlin.com>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -36,10 +36,10 @@ properties:
patternProperties:
"@[0-9a-f]+$":
$ref: "/schemas/mtd/partitions/partition.yaml"
$ref: /schemas/mtd/partitions/partition.yaml
allOf:
- $ref: "/schemas/memory-controllers/ti,gpmc-child.yaml"
- $ref: /schemas/memory-controllers/ti,gpmc-child.yaml
required:
- 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
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.
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->size = be32_to_cpup(&addr[1]);
if (of_get_property(pp, "st,smi-fast-mode", NULL))
pdata->board_flash_info->fast_mode = 1;
pdata->board_flash_info->fast_mode =
of_property_read_bool(pp, "st,smi-fast-mode");
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;
map_word datum;
int ret, wbufsize, word_gap, words;
int ret, wbufsize, word_gap;
const struct kvec *vec;
unsigned long vec_seek;
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 */
word_gap = (-adr & (map_bankwidth(map)-1));
words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
if (!word_gap) {
words--;
} else {
if (word_gap) {
word_gap = map_bankwidth(map) - word_gap;
adr -= word_gap;
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
* be used by this driver.
*/
if (!of_find_property(dp, "user", NULL))
if (!of_property_read_bool(dp, "user"))
return -ENODEV;
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)
{
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 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 nvmem_config config = {};
config.id = -1;
config.id = NVMEM_DEVID_NONE;
config.dev = &mtd->dev;
config.name = dev_name(&mtd->dev);
config.owner = THIS_MODULE;
@ -536,12 +536,11 @@ static int mtd_nvmem_add(struct mtd_info *mtd)
mtd->nvmem = nvmem_register(&config);
if (IS_ERR(mtd->nvmem)) {
/* 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;
} else {
dev_err(&mtd->dev, "Failed to register NVMEM device\n");
return PTR_ERR(mtd->nvmem);
}
else
return dev_err_probe(&mtd->dev, PTR_ERR(mtd->nvmem),
"Failed to register NVMEM device\n");
}
return 0;
@ -739,7 +738,7 @@ int add_mtd_device(struct mtd_info *mtd)
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)) {
pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name);
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 */
config.dev = mtd->dev.parent;
config.name = kasprintf(GFP_KERNEL, "%s-%s", dev_name(&mtd->dev), compatible);
config.id = NVMEM_DEVID_NONE;
config.name = compatible;
config.id = NVMEM_DEVID_AUTO;
config.owner = THIS_MODULE;
config.type = NVMEM_TYPE_OTP;
config.root_only = true;
@ -905,7 +904,6 @@ static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd,
nvmem = NULL;
of_node_put(np);
kfree(config.name);
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)
{
struct device *dev = mtd->dev.parent;
struct nvmem_device *nvmem;
ssize_t size;
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,
mtd_nvmem_user_otp_reg_read);
if (IS_ERR(nvmem)) {
dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n");
return PTR_ERR(nvmem);
err = PTR_ERR(nvmem);
goto err;
}
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,
mtd_nvmem_fact_otp_reg_read);
if (IS_ERR(nvmem)) {
dev_err(&mtd->dev, "Failed to register OTP NVMEM device\n");
err = PTR_ERR(nvmem);
goto err;
}
@ -983,7 +981,7 @@ static int mtd_otp_nvmem_add(struct mtd_info *mtd)
err:
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);
ret = mtd_otp_nvmem_add(mtd);
if (ret)
goto out;
if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
ret = add_mtd_device(mtd);
if (ret)
return ret;
goto out;
}
/* 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);
}
ret = mtd_otp_nvmem_add(mtd);
out:
if (ret) {
nvmem_unregister(mtd->otp_user_nvmem);
nvmem_unregister(mtd->otp_factory_nvmem);
}
if (ret && device_is_registered(&mtd->dev))
del_mtd_device(mtd);

View File

@ -848,13 +848,11 @@ static int mxic_ecc_probe(struct platform_device *pdev)
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);
nand_ecc_unregister_on_host_hw_engine(&mxic->external_engine);
return 0;
}
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,
},
.probe = mxic_ecc_probe,
.remove = mxic_ecc_remove,
.remove_new = mxic_ecc_remove,
};
module_platform_driver(mxic_ecc_driver);

View File

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

View File

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

View File

@ -581,7 +581,7 @@ err_release_dma:
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);
@ -589,8 +589,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
if (c->dma_chan)
dma_release_channel(c->dma_chan);
omap2_onenand_shutdown(pdev);
return 0;
}
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 = {
.probe = omap2_onenand_probe,
.remove = omap2_onenand_remove,
.remove_new = omap2_onenand_remove,
.shutdown = omap2_onenand_shutdown,
.driver = {
.name = DRIVER_NAME,

View File

@ -943,13 +943,11 @@ static int s3c_onenand_probe(struct platform_device *pdev)
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);
onenand_release(mtd);
return 0;
}
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,
.probe = s3c_onenand_probe,
.remove = s3c_onenand_remove,
.remove_new = s3c_onenand_remove,
};
module_platform_driver(s3c_onenand_driver);

View File

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

View File

@ -397,7 +397,7 @@ err_nand_cleanup:
/*
* 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 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);
WARN_ON(ret);
nand_cleanup(mtd_to_nand(mtd));
return 0;
}
#ifdef CONFIG_OF
@ -434,7 +432,7 @@ MODULE_DEVICE_TABLE(platform, gpio_nand_plat_id_table);
static struct platform_driver gpio_nand_driver = {
.probe = gpio_nand_probe,
.remove = gpio_nand_remove,
.remove_new = gpio_nand_remove,
.id_table = gpio_nand_plat_id_table,
.driver = {
.name = "ams-delta-nand",

View File

@ -1496,7 +1496,7 @@ disable_controller_clk:
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);
@ -1504,8 +1504,6 @@ static int anfc_remove(struct platform_device *pdev)
clk_disable_unprepare(nfc->bus_clk);
clk_disable_unprepare(nfc->controller_clk);
return 0;
}
static const struct of_device_id anfc_ids[] = {
@ -1525,7 +1523,7 @@ static struct platform_driver anfc_driver = {
.of_match_table = anfc_ids,
},
.probe = anfc_probe,
.remove = anfc_remove,
.remove_new = anfc_remove,
};
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);
}
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);
WARN_ON(nc->caps->ops->remove(nc));
return 0;
}
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,
},
.probe = atmel_nand_controller_probe,
.remove = atmel_nand_controller_remove,
.remove_new = atmel_nand_controller_remove,
};
module_platform_driver(atmel_nand_controller_driver);

View File

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

View File

@ -57,7 +57,7 @@ static int bcm47xxnflash_probe(struct platform_device *pdev)
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 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));
WARN_ON(ret);
nand_cleanup(chip);
return 0;
}
static struct platform_driver bcm47xxnflash_driver = {
.probe = bcm47xxnflash_probe,
.remove = bcm47xxnflash_remove,
.remove_new = bcm47xxnflash_remove,
.driver = {
.name = "bcma_nflash",
},

View File

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

View File

@ -821,7 +821,7 @@ err_cleanup_nand:
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 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));
WARN_ON(ret);
nand_cleanup(chip);
return 0;
}
static struct platform_driver nand_davinci_driver = {
.probe = nand_davinci_probe,
.remove = nand_davinci_remove,
.remove_new = nand_davinci_remove,
.driver = {
.name = "davinci_nand",
.of_match_table = of_match_ptr(davinci_nand_of_match),

View File

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

View File

@ -963,7 +963,7 @@ err:
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_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);
return 0;
}
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,
},
.probe = fsl_elbc_nand_probe,
.remove = fsl_elbc_nand_remove,
.remove_new = fsl_elbc_nand_remove,
};
module_platform_driver(fsl_elbc_nand_driver);

View File

@ -1094,7 +1094,7 @@ err:
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 nand_chip *chip = &priv->chip;
@ -1113,8 +1113,6 @@ static int fsl_ifc_nand_remove(struct platform_device *dev)
kfree(ifc_nand_ctrl);
}
mutex_unlock(&fsl_ifc_nand_mutex);
return 0;
}
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,
},
.probe = fsl_ifc_nand_probe,
.remove = fsl_ifc_nand_remove,
.remove_new = fsl_ifc_nand_remove,
};
module_platform_driver(fsl_ifc_nand_driver);

View File

@ -235,7 +235,7 @@ static int fun_probe(struct platform_device *ofdev)
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 nand_chip *chip = &fun->chip;
@ -245,8 +245,6 @@ static int fun_remove(struct platform_device *ofdev)
ret = mtd_device_unregister(mtd);
WARN_ON(ret);
nand_cleanup(chip);
return 0;
}
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,
},
.probe = fun_probe,
.remove = fun_remove,
.remove_new = fun_remove,
};
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;
host->dev_timings = devm_kzalloc(&pdev->dev,
@ -1165,7 +1165,7 @@ disable_clk:
/*
* 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);
@ -1184,8 +1184,6 @@ static int fsmc_nand_remove(struct platform_device *pdev)
}
clk_disable_unprepare(host->clk);
}
return 0;
}
#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);
static struct platform_driver fsmc_nand_driver = {
.remove = fsmc_nand_remove,
.remove_new = fsmc_nand_remove,
.driver = {
.name = "fsmc-nand",
.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);
}
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 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);
if (gpiomtd->nce && !IS_ERR(gpiomtd->nce))
gpiod_set_value(gpiomtd->nce, 0);
return 0;
}
static int gpio_nand_probe(struct platform_device *pdev)
@ -394,7 +392,7 @@ out_ce:
static struct platform_driver gpio_nand_driver = {
.probe = gpio_nand_probe,
.remove = gpio_nand_remove,
.remove_new = gpio_nand_remove,
.driver = {
.name = "gpio-nand",
.of_match_table = of_match_ptr(gpio_nand_id_table),

View File

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

View File

@ -798,7 +798,7 @@ static int hisi_nfc_probe(struct platform_device *pdev)
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 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));
WARN_ON(ret);
nand_cleanup(chip);
return 0;
}
#ifdef CONFIG_PM_SLEEP
@ -860,7 +858,7 @@ static struct platform_driver hisi_nfc_driver = {
.pm = &hisi_nfc_pm_ops,
},
.probe = hisi_nfc_probe,
.remove = hisi_nfc_remove,
.remove_new = hisi_nfc_remove,
};
module_platform_driver(hisi_nfc_driver);

View File

@ -522,7 +522,7 @@ static int ingenic_nand_probe(struct platform_device *pdev)
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);
@ -530,8 +530,6 @@ static int ingenic_nand_remove(struct platform_device *pdev)
ingenic_ecc_release(nfc->ecc);
ingenic_nand_cleanup_chips(nfc);
return 0;
}
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 = {
.probe = ingenic_nand_probe,
.remove = ingenic_nand_remove,
.remove_new = ingenic_nand_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = ingenic_nand_dt_match,

View File

@ -706,7 +706,7 @@ err_of_node_put:
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);
int ret;
@ -717,8 +717,6 @@ static int ebu_nand_remove(struct platform_device *pdev)
ebu_nand_disable(&ebu_host->chip);
ebu_dma_cleanup(ebu_host);
clk_disable_unprepare(ebu_host->clk);
return 0;
}
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 = {
.probe = ebu_nand_probe,
.remove = ebu_nand_remove,
.remove_new = ebu_nand_remove,
.driver = {
.name = "intel-nand-controller",
.of_match_table = ebu_nand_match,

View File

@ -827,7 +827,7 @@ free_gpio:
/*
* 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 nand_chip *chip = &host->nand_chip;
@ -846,8 +846,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
lpc32xx_wp_enable(host);
gpiod_put(host->wp_gpio);
return 0;
}
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 = {
.probe = lpc32xx_nand_probe,
.remove = lpc32xx_nand_remove,
.remove_new = lpc32xx_nand_remove,
.resume = pm_ptr(lpc32xx_nand_resume),
.suspend = pm_ptr(lpc32xx_nand_suspend),
.driver = {

View File

@ -946,7 +946,7 @@ enable_wp:
/*
* Remove NAND device.
*/
static int lpc32xx_nand_remove(struct platform_device *pdev)
static void lpc32xx_nand_remove(struct platform_device *pdev)
{
uint32_t tmp;
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);
lpc32xx_wp_enable(host);
return 0;
}
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 = {
.probe = lpc32xx_nand_probe,
.remove = lpc32xx_nand_remove,
.remove_new = lpc32xx_nand_remove,
.resume = pm_ptr(lpc32xx_nand_resume),
.suspend = pm_ptr(lpc32xx_nand_suspend),
.driver = {

View File

@ -3004,7 +3004,7 @@ unprepare_core_clk:
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);
@ -3017,8 +3017,6 @@ static int marvell_nfc_remove(struct platform_device *pdev)
clk_disable_unprepare(nfc->reg_clk);
clk_disable_unprepare(nfc->core_clk);
return 0;
}
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,
.probe = marvell_nfc_probe,
.remove = marvell_nfc_remove,
.remove_new = marvell_nfc_remove,
};
module_platform_driver(marvell_nfc_driver);

View File

@ -1440,20 +1440,18 @@ err_clk:
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);
meson_nfc_nand_chip_cleanup(nfc);
meson_nfc_disable_clk(nfc);
return 0;
}
static struct platform_driver meson_nfc_driver = {
.probe = meson_nfc_probe,
.remove = meson_nfc_remove,
.remove_new = meson_nfc_remove,
.driver = {
.name = "meson-nand",
.of_match_table = meson_nfc_id_table,

View File

@ -822,7 +822,7 @@ error:
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 mtd_info *mtd = dev_get_drvdata(dev);
@ -832,8 +832,6 @@ static int mpc5121_nfc_remove(struct platform_device *op)
WARN_ON(ret);
nand_cleanup(mtd_to_nand(mtd));
mpc5121_nfc_free(dev, mtd);
return 0;
}
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 = {
.probe = mpc5121_nfc_probe,
.remove = mpc5121_nfc_remove,
.remove_new = mpc5121_nfc_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = mpc5121_nfc_match,

View File

@ -1601,7 +1601,7 @@ release_ecc:
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_nand_chip *mtk_chip;
@ -1620,8 +1620,6 @@ static int mtk_nfc_remove(struct platform_device *pdev)
mtk_ecc_release(nfc->ecc);
mtk_nfc_disable_clk(&nfc->clk);
return 0;
}
#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 = {
.probe = mtk_nfc_probe,
.remove = mtk_nfc_remove,
.remove_new = mtk_nfc_remove,
.driver = {
.name = MTK_NAME,
.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;
}
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[] = {
{ .compatible = "fsl,imx21-nand", .data = &imx21_nand_devtype_data, },
{ .compatible = "fsl,imx27-nand", .data = &imx27_nand_devtype_data, },
@ -1831,7 +1821,7 @@ escan:
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 nand_chip *chip = &host->nand;
@ -1842,8 +1832,6 @@ static int mxcnd_remove(struct platform_device *pdev)
nand_cleanup(chip);
if (host->clk_act)
clk_disable_unprepare(host->clk);
return 0;
}
static struct platform_driver mxcnd_driver = {
@ -1852,7 +1840,7 @@ static struct platform_driver mxcnd_driver = {
.of_match_table = mxcnd_dt_ids,
},
.probe = mxcnd_probe,
.remove = mxcnd_remove,
.remove_new = mxcnd_remove,
};
module_platform_driver(mxcnd_driver);

View File

@ -553,7 +553,7 @@ fail:
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 nand_chip *chip = &nfc->chip;
@ -564,7 +564,6 @@ static int mxic_nfc_remove(struct platform_device *pdev)
nand_cleanup(chip);
mxic_nfc_clk_disable(nfc);
return 0;
}
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 = {
.probe = mxic_nfc_probe,
.remove = mxic_nfc_remove,
.remove_new = mxic_nfc_remove,
.driver = {
.name = "mxic-nfc",
.of_match_table = mxic_nfc_of_ids,

View File

@ -728,8 +728,21 @@ static int hynix_nand_init(struct nand_chip *chip)
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 = {
.detect = hynix_nand_decode_id,
.init = hynix_nand_init,
.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_onfi_vendor_macronix *mxic;
struct device_node *dn = nand_get_flash_node(chip);
int rand_otp = 0;
int rand_otp;
int ret;
if (!p->onfi)
return;
if (of_find_property(dn, "mxic,enable-randomizer-otp", NULL))
rand_otp = 1;
rand_otp = of_property_read_bool(dn, "mxic,enable-randomizer-otp");
mxic = (struct nand_onfi_vendor_macronix *)p->onfi->vendor;
/* Subpage write is prohibited in randomizer operatoin */

View File

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

View File

@ -2273,7 +2273,7 @@ return_error:
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 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);
WARN_ON(mtd_device_unregister(mtd));
nand_cleanup(nand_chip);
return 0;
}
/* 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 = {
.probe = omap_nand_probe,
.remove = omap_nand_remove,
.remove_new = omap_nand_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = omap_nand_ids,

View File

@ -422,11 +422,10 @@ static int elm_probe(struct platform_device *pdev)
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_disable(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
@ -561,7 +560,7 @@ static struct platform_driver elm_driver = {
.pm = &elm_pm_ops,
},
.probe = elm_probe,
.remove = elm_remove,
.remove_new = elm_remove,
};
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 nand_chip *nc;
struct orion_nand_data *board;
struct resource *res;
void __iomem *io_base;
int ret = 0;
u32 val = 0;
@ -119,8 +118,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
info->controller.ops = &orion_nand_ops;
nc->controller = &info->controller;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
io_base = devm_ioremap_resource(&pdev->dev, res);
io_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(io_base))
return PTR_ERR(io_base);
@ -207,7 +205,7 @@ no_dev:
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 nand_chip *chip = &info->chip;
@ -219,8 +217,6 @@ static int orion_nand_remove(struct platform_device *pdev)
nand_cleanup(chip);
clk_disable_unprepare(info->clk);
return 0;
}
#ifdef CONFIG_OF
@ -232,7 +228,7 @@ MODULE_DEVICE_TABLE(of, orion_nand_of_match_table);
#endif
static struct platform_driver orion_nand_driver = {
.remove = orion_nand_remove,
.remove_new = orion_nand_remove,
.driver = {
.name = "orion_nand",
.of_match_table = of_match_ptr(orion_nand_of_match_table),

View File

@ -171,7 +171,7 @@ err_clk_unprepare:
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 nand_chip *chip;
@ -184,8 +184,6 @@ static int oxnas_nand_remove(struct platform_device *pdev)
}
clk_disable_unprepare(oxnas->clk);
return 0;
}
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 = {
.probe = oxnas_nand_probe,
.remove = oxnas_nand_remove,
.remove_new = oxnas_nand_remove,
.driver = {
.name = "oxnas_nand",
.of_match_table = oxnas_nand_match,

View File

@ -197,7 +197,7 @@ static int pasemi_nand_probe(struct platform_device *ofdev)
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 mtd_info *pasemi_nand_mtd;
@ -218,8 +218,6 @@ static int pasemi_nand_remove(struct platform_device *ofdev)
/* Free the MTD device structure */
kfree(ddata);
return 0;
}
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,
},
.probe = pasemi_nand_probe,
.remove = pasemi_nand_remove,
.remove_new = pasemi_nand_remove,
};
module_platform_driver(pasemi_nand_driver);

View File

@ -1163,13 +1163,11 @@ static int pl35x_nand_probe(struct platform_device *pdev)
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);
pl35x_nand_chips_cleanup(nfc);
return 0;
}
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 = {
.probe = pl35x_nand_probe,
.remove = pl35x_nand_remove,
.remove_new = pl35x_nand_remove,
.driver = {
.name = PL35X_NANDC_DRIVER_NAME,
.of_match_table = pl35x_nand_of_match,

View File

@ -122,7 +122,7 @@ out:
/*
* 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 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);
if (pdata->ctrl.remove)
pdata->ctrl.remove(pdev);
return 0;
}
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 = {
.probe = plat_nand_probe,
.remove = plat_nand_remove,
.remove_new = plat_nand_remove,
.driver = {
.name = "gen_nand",
.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;
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;
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)
return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nandc->base = devm_ioremap_resource(dev, res);
nandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(nandc->base))
return PTR_ERR(nandc->base);
@ -3315,7 +3314,7 @@ err_core_clk:
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 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_BIDIRECTIONAL, 0);
return 0;
}
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,
},
.probe = qcom_nandc_probe,
.remove = qcom_nandc_remove,
.remove_new = qcom_nandc_remove,
};
module_platform_driver(qcom_nandc_driver);

View File

@ -1386,15 +1386,13 @@ dis_runtime_pm:
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);
rnandc_chips_cleanup(rnandc);
pm_runtime_put(&pdev->dev);
return 0;
}
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,
},
.probe = rnandc_probe,
.remove = rnandc_remove,
.remove_new = rnandc_remove,
};
module_platform_driver(rnandc_driver);

View File

@ -1427,7 +1427,7 @@ release_nfc:
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);
@ -1435,8 +1435,6 @@ static int rk_nfc_remove(struct platform_device *pdev)
kfree(nfc->oob_buf);
rk_nfc_chips_cleanup(nfc);
rk_nfc_disable_clks(nfc);
return 0;
}
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 = {
.probe = rk_nfc_probe,
.remove = rk_nfc_remove,
.remove_new = rk_nfc_remove,
.driver = {
.name = "rockchip-nfc",
.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 */
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);
if (info == NULL)
return 0;
return;
/* Release all our mtds and their partitions, then go through
* freeing the resources used
@ -735,8 +735,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
if (!IS_ERR(info->clk))
s3c2410_nand_clk_set_state(info, CLOCK_DISABLE);
return 0;
}
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 = {
.probe = s3c24xx_nand_probe,
.remove = s3c24xx_nand_remove,
.remove_new = s3c24xx_nand_remove,
.suspend = s3c24xx_nand_suspend,
.resume = s3c24xx_nand_resume,
.id_table = s3c24xx_driver_ids,

View File

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

View File

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

View File

@ -201,7 +201,7 @@ out:
/*
* 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 nand_chip *chip = &host->nand_chip;
@ -212,8 +212,6 @@ static int socrates_nand_remove(struct platform_device *ofdev)
nand_cleanup(chip);
iounmap(host->io_base);
return 0;
}
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,
},
.probe = socrates_nand_probe,
.remove = socrates_nand_remove,
.remove_new = socrates_nand_remove,
};
module_platform_driver(socrates_nand_driver);

View File

@ -2024,7 +2024,7 @@ err_clk_disable:
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_nand *nand = &nfc->nand;
@ -2048,8 +2048,6 @@ static int stm32_fmc2_nfc_remove(struct platform_device *pdev)
clk_disable_unprepare(nfc->clk);
stm32_fmc2_nfc_wp_enable(nand);
return 0;
}
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 = {
.probe = stm32_fmc2_nfc_probe,
.remove = stm32_fmc2_nfc_remove,
.remove_new = stm32_fmc2_nfc_remove,
.driver = {
.name = "stm32_fmc2_nfc",
.of_match_table = stm32_fmc2_nfc_match,

View File

@ -2173,7 +2173,7 @@ out_ahb_clk_unprepare:
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);
@ -2185,8 +2185,6 @@ static int sunxi_nfc_remove(struct platform_device *pdev)
dma_release_channel(nfc->dmac);
clk_disable_unprepare(nfc->mod_clk);
clk_disable_unprepare(nfc->ahb_clk);
return 0;
}
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,
},
.probe = sunxi_nfc_probe,
.remove = sunxi_nfc_remove,
.remove_new = sunxi_nfc_remove,
};
module_platform_driver(sunxi_nfc_driver);

View File

@ -1220,7 +1220,7 @@ err_dis_pm:
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 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_force_suspend(ctrl->dev);
return 0;
}
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,
},
.probe = tegra_nand_probe,
.remove = tegra_nand_remove,
.remove_new = tegra_nand_remove,
};
module_platform_driver(tegra_nand_driver);

View File

@ -909,7 +909,7 @@ err_disable_clk:
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 nand_chip *chip = &nfc->chip;
@ -919,7 +919,6 @@ static int vf610_nfc_remove(struct platform_device *pdev)
WARN_ON(ret);
nand_cleanup(chip);
clk_disable_unprepare(nfc->clk);
return 0;
}
#ifdef CONFIG_PM_SLEEP
@ -955,7 +954,7 @@ static struct platform_driver vf610_nfc_driver = {
.pm = &vf610_nfc_pm_ops,
},
.probe = vf610_nfc_probe,
.remove = vf610_nfc_remove,
.remove_new = vf610_nfc_remove,
};
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.
*/
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 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));
WARN_ON(ret);
nand_cleanup(chip);
return 0;
}
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 = {
.probe = xway_nand_probe,
.remove = xway_nand_remove,
.remove_new = xway_nand_remove,
.driver = {
.name = "lantiq,nand-xway",
.of_match_table = xway_nand_match,

View File

@ -1,3 +1,4 @@
# 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

View File

@ -939,6 +939,7 @@ static const struct nand_ops spinand_ops = {
static const struct spinand_manufacturer *spinand_manufacturers[] = {
&alliancememory_spinand_manufacturer,
&ato_spinand_manufacturer,
&esmt_c8_spinand_manufacturer,
&gigadevice_spinand_manufacturer,
&macronix_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
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
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

View File

@ -164,7 +164,6 @@ static struct 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("Florian Fainelli <florian@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;
if (of_find_property(np, "spi-cpol", NULL))
if (of_property_read_bool(np, "spi-cpol"))
mode |= SPI_CPOL;
/* 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'.
* @enable: true to enter the 4-byte address mode, false to exit the 4-byte
* address mode.
*
* 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;
@ -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
* flashes.
* spi_nor_set_4byte_addr_mode_wren_en4b_ex4b() - Set 4-byte address mode using
* 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'.
* @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 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;
@ -588,6 +620,65 @@ int spi_nor_sr_ready(struct spi_nor *nor)
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.
* @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)
{
int ret;
ret = spi_nor_lock_rdst(nor);
if (ret)
return 0;
/* Flashes might override the standard routine. */
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;
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);
if (nor->controller_ops && nor->controller_ops->prepare) {
ret = nor->controller_ops->prepare(nor);
if (ret) {
mutex_unlock(&nor->lock);
return ret;
}
if (rww->ongoing_io)
goto busy;
rww->ongoing_io = true;
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;
}
void spi_nor_unlock_and_unprep(struct spi_nor *nor)
{
if (nor->controller_ops && nor->controller_ops->unprepare)
nor->controller_ops->unprepare(nor);
if (!spi_nor_use_parallel_locking(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);
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)
@ -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",
cmd->size, cmd->opcode, cmd->count);
ret = spi_nor_write_enable(nor);
ret = spi_nor_lock_device(nor);
if (ret)
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);
spi_nor_unlock_device(nor);
if (ret)
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;
len = instr->len;
ret = spi_nor_lock_and_prep(nor);
ret = spi_nor_prep_and_lock_pe(nor, instr->addr, instr->len);
if (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)) {
unsigned long timeout;
ret = spi_nor_write_enable(nor);
ret = spi_nor_lock_device(nor);
if (ret)
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);
spi_nor_unlock_device(nor);
if (ret)
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 */
} else if (spi_nor_has_uniform_erase(nor)) {
while (len) {
ret = spi_nor_write_enable(nor);
ret = spi_nor_lock_device(nor);
if (ret)
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);
spi_nor_unlock_device(nor);
if (ret)
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);
erase_err:
spi_nor_unlock_and_unprep(nor);
spi_nor_unlock_and_unprep_pe(nor, instr->addr, instr->len);
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)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
loff_t from_lock = from;
size_t len_lock = len;
ssize_t ret;
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)
return ret;
@ -1733,7 +2117,8 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
ret = 0;
read_err:
spi_nor_unlock_and_unprep(nor);
spi_nor_unlock_and_unprep_rd(nor, from_lock, len_lock);
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);
ret = spi_nor_lock_and_prep(nor);
ret = spi_nor_prep_and_lock_pe(nor, to, len);
if (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);
ret = spi_nor_write_enable(nor);
ret = spi_nor_lock_device(nor);
if (ret)
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);
spi_nor_unlock_device(nor);
if (ret < 0)
goto write_err;
written = ret;
@ -1794,7 +2186,8 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
}
write_err:
spi_nor_unlock_and_unprep(nor);
spi_nor_unlock_and_unprep_pe(nor, to, len);
return ret;
}
@ -2470,6 +2863,10 @@ static void spi_nor_init_flags(struct spi_nor *nor)
if (flags & NO_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)
{
struct spi_nor_flash_parameter *params = nor->params;
if (nor->manufacturer && nor->manufacturer->fixups &&
nor->manufacturer->fixups->late_init)
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)
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_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)
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);
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;
/* 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);
}
/**
* 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)
{
int err;
@ -2773,8 +3204,8 @@ static int spi_nor_init(struct spi_nor *nor)
*/
WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
"enabling reset hack; may not recover from unexpected reboots\n");
err = nor->params->set_4byte_addr_mode(nor, true);
if (err && err != -ENOTSUPP)
err = spi_nor_set_4byte_addr_mode(nor, true);
if (err)
return err;
}
@ -2887,14 +3318,14 @@ static void spi_nor_put_device(struct mtd_info *mtd)
module_put(dev->driver->owner);
}
void spi_nor_restore(struct spi_nor *nor)
static void spi_nor_restore(struct spi_nor *nor)
{
int ret;
/* restore the addressing mode */
if (nor->addr_nbytes == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
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)
/*
* 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)
spi_nor_soft_reset(nor);
}
EXPORT_SYMBOL_GPL(spi_nor_restore);
static const struct flash_info *spi_nor_match_name(struct spi_nor *nor,
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
* can't trust partitions any longer, but we'll let
* 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.
*/
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->type = MTD_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)
mtd->flags |= MTD_NO_ERASE;
else
@ -3064,6 +3497,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
if (ret)
return ret;
if (spi_nor_use_parallel_locking(nor))
init_waitqueue_head(&nor->rww.wait);
/*
* Configure the SPI memory:
* - 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_SOFT_RESET = BIT(12),
SNOR_F_SWP_IS_VOLATILE = BIT(13),
SNOR_F_RWW = BIT(14),
SNOR_F_ECC = BIT(15),
};
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
* 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
* ECC unit size for ECC-ed flashes.
* @page_size: the page size of the SPI NOR flash memory.
@ -349,6 +352,8 @@ struct spi_nor_otp {
* in octal DTR mode.
* @rdsr_addr_nbytes: dummy address bytes needed for Read Status Register
* 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
* capabilities.
* @reads: read capabilities ordered by priority: the higher index
@ -374,6 +379,7 @@ struct spi_nor_otp {
* @locking_ops: SPI NOR locking methods.
*/
struct spi_nor_flash_parameter {
u64 bank_size;
u64 size;
u32 writesize;
u32 page_size;
@ -381,6 +387,8 @@ struct spi_nor_flash_parameter {
u8 addr_mode_nbytes;
u8 rdsr_dummy;
u8 rdsr_addr_nbytes;
u8 n_dice;
u32 *vreg_offset;
struct spi_nor_hwcaps hwcaps;
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,
const struct sfdp_parameter_header *bfpt_header,
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);
};
@ -435,6 +443,7 @@ struct spi_nor_fixups {
* @sector_size: the size listed here is what works with SPINOR_OP_SE, which
* isn't necessarily called a "sector" by the vendor.
* @n_sectors: the number of sectors.
* @n_banks: the number of banks.
* @page_size: the flash's page size.
* @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.
* SPI_NOR_NO_FR: can't do fastread.
* 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.
* Used when SFDP tables are not defined in the flash. These
@ -495,6 +505,7 @@ struct flash_info {
unsigned sector_size;
u16 n_sectors;
u16 page_size;
u8 n_banks;
u8 addr_nbytes;
bool parse_sfdp;
@ -509,6 +520,7 @@ struct flash_info {
#define NO_CHIP_ERASE BIT(7)
#define SPI_NOR_NO_FR BIT(8)
#define SPI_NOR_QUAD_PP BIT(9)
#define SPI_NOR_RWW BIT(10)
u8 no_sfdp_flags;
#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_len = 6
#define SPI_NOR_GEOMETRY(_sector_size, _n_sectors) \
#define SPI_NOR_GEOMETRY(_sector_size, _n_sectors, _n_banks) \
.sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \
.page_size = 256
.page_size = 256, \
.n_banks = (_n_banks)
/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors) \
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) \
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) \
.sector_size = (_sector_size), \
.n_sectors = (_n_sectors), \
.page_size = (_page_size), \
.n_banks = 1, \
.addr_nbytes = (_addr_nbytes), \
.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);
int spi_nor_write_enable(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_wait_till_ready(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);
int spi_nor_sr1_bit6_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(SOFT_RESET),
SNOR_F_NAME(SWP_IS_VOLATILE),
SNOR_F_NAME(RWW),
SNOR_F_NAME(ECC),
};
#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)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
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)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_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)
{
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 = {
.default_init = macronix_nor_default_init,
.late_init = macronix_nor_late_init,
};
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;
}
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. */
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.
*/
nor->params->quad_enable = NULL;
return 0;
}
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) },
};
/**
* 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.
* @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_16BIT_SR;
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)
{
struct spi_nor_flash_parameter *params = nor->params;
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 = {

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))
return -ENOSPC;
ret = spi_nor_lock_and_prep(nor);
ret = spi_nor_prep_and_lock(nor);
if (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)
return 0;
ret = spi_nor_lock_and_prep(nor);
ret = spi_nor_prep_and_lock(nor);
if (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))
return -EINVAL;
ret = spi_nor_lock_and_prep(nor);
ret = spi_nor_prep_and_lock(nor);
if (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))
return -EINVAL;
ret = spi_nor_lock_and_prep(nor);
ret = spi_nor_prep_and_lock(nor);
if (ret)
return ret;

View File

@ -26,6 +26,11 @@
* Status, Control and Configuration
* 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
@ -438,6 +443,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
size_t len;
int i, cmd, err;
u32 addr, val;
u32 dword;
u16 half;
u8 erase_mask;
@ -607,6 +613,16 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
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. */
if (bfpt.dwords[SFDP_DWORD(16)] & BFPT_DWORD16_SWRST_EN_RST)
nor->flags |= SNOR_F_SOFT_RESET;
@ -1215,6 +1231,7 @@ out:
static int spi_nor_parse_sccr(struct spi_nor *nor,
const struct sfdp_parameter_header *sccr_header)
{
struct spi_nor_flash_parameter *params = nor->params;
u32 *dwords, addr;
size_t len;
int ret;
@ -1231,6 +1248,18 @@ static int spi_nor_parse_sccr(struct spi_nor *nor,
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,
dwords[SFDP_DWORD(22)]))
nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
@ -1240,6 +1269,63 @@ out:
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
* 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
* 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 &&
nor->manufacturer->fixups->post_sfdp)
nor->manufacturer->fixups->post_sfdp(nor);
nor->manufacturer->fixups->post_sfdp) {
ret = nor->manufacturer->fixups->post_sfdp(nor);
if (ret)
return ret;
}
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);
break;
case SFDP_SCCR_MAP_MC_ID:
err = spi_nor_parse_sccr_mc(nor, param_header);
break;
default:
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:
kfree(param_headers);
return err;

View File

@ -15,6 +15,7 @@
/* SFDP DWORDS are indexed from 1 but C arrays are indexed from 0. */
#define SFDP_DWORD(i) ((i) - 1)
#define SFDP_MASK_CHECK(dword, mask) (((dword) & (mask)) == (mask))
/* 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 (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_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_RD_ANY_REG 0x65 /* Read 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_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_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_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_DDR BIT(1)
#define SPINOR_REG_CYPRESS_CFR5_OPI BIT(0)
@ -29,6 +42,7 @@
SPINOR_REG_CYPRESS_CFR5_OPI)
#define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS SPINOR_REG_CYPRESS_CFR5_BIT6
#define SPINOR_OP_CYPRESS_RD_FAST 0xee
#define SPINOR_REG_CYPRESS_ARCFN 0x00000006
/* Cypress SPI NOR flash operations. */
#define CYPRESS_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \
@ -37,10 +51,10 @@
SPI_MEM_OP_NO_DUMMY, \
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_ADDR(naddr, addr, 0), \
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_DUMMY(ndummy, 0), \
SPI_MEM_OP_DATA_IN(1, buf, 0))
#define SPANSION_CLSR_OP \
@ -49,6 +63,84 @@
SPI_MEM_OP_NO_DUMMY, \
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)
{
struct spi_mem_op op;
@ -125,6 +217,51 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
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
* 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)
{
struct spi_mem_op op;
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
u8 cfr1v_written;
struct spi_nor_flash_parameter *params = nor->params;
u64 addr;
u8 i;
int ret;
op = (struct spi_mem_op)
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR1V,
nor->bouncebuf);
if (!params->n_dice)
return cypress_nor_quad_enable_volatile_reg(nor,
SPINOR_REG_CYPRESS_CFR1V);
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,
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;
for (i = 0; i < params->n_dice; i++) {
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR1;
ret = cypress_nor_quad_enable_volatile_reg(nor, addr);
if (ret)
return ret;
}
return 0;
}
/**
* cypress_nor_set_page_size() - Set page size which corresponds to the flash
* configuration.
* @nor: pointer to a 'struct spi_nor'
* cypress_nor_determine_addr_mode_by_sr1() - Determine current address mode
* (3 or 4-byte) by querying status
* 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
* page size is actually configurable (with the default being 256B). Read from
* CFR3V[4] and set the correct size.
* This function tries to determine current address mode by comparing SR1 value
* from RDSR1(no address), RDAR(3-byte address), and RDAR(4-byte address).
*
* 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 =
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR3V,
SPINOR_REG_CYPRESS_CFR3V, 0,
nor->bouncebuf);
int ret;
@ -218,18 +428,135 @@ static int cypress_nor_set_page_size(struct spi_nor *nor)
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
s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
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 */
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 =
nor->params->erase_map.erase_type;
@ -251,6 +578,12 @@ static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
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)
@ -260,8 +593,11 @@ static void s25hx_t_late_init(struct spi_nor *nor)
/* Fast Read 4B requires mode cycles */
params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
/* The writesize should be ECC data unit size */
params->writesize = 16;
cypress_nor_ecc_init(nor);
/* 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 = {
@ -286,7 +622,7 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
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
@ -312,19 +648,27 @@ static void s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
* actual value for that is 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,
const struct sfdp_parameter_header *bfpt_header,
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)
{
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 = {
@ -446,6 +790,9 @@ static const struct flash_info spansion_nor_parts[] = {
{ "s25fl256l", INFO(0x016019, 0, 64 * 1024, 512)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
{ "s25fs256t", INFO6(0x342b19, 0x0f0890, 0, 0)
PARSE_SFDP
.fixups = &s25fs256t_fixups },
{ "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256)
PARSE_SFDP
MFR_FLAGS(USE_CLSR)
@ -454,6 +801,10 @@ static const struct flash_info spansion_nor_parts[] = {
PARSE_SFDP
MFR_FLAGS(USE_CLSR)
.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)
PARSE_SFDP
MFR_FLAGS(USE_CLSR)
@ -462,6 +813,10 @@ static const struct flash_info spansion_nor_parts[] = {
PARSE_SFDP
MFR_FLAGS(USE_CLSR)
.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)
FLAGS(SPI_NOR_NO_ERASE) },
{ "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
* 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);
ret = spi_nor_lock_and_prep(nor);
ret = spi_nor_prep_and_lock(nor);
if (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);
int ret;
ret = spi_nor_lock_and_prep(nor);
ret = spi_nor_prep_and_lock(nor);
if (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);
int ret;
ret = spi_nor_lock_and_prep(nor);
ret = spi_nor_prep_and_lock(nor);
if (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);
int ret;
ret = spi_nor_lock_and_prep(nor);
ret = spi_nor_prep_and_lock(nor);
if (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;
ret = spi_nor_set_4byte_addr_mode(nor, enable);
ret = spi_nor_set_4byte_addr_mode_en4b_ex4b(nor, enable);
if (ret || enable)
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,
};
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)
{
if (nor->params->otp.org->n_regions)
nor->params->otp.ops = &winbond_nor_otp_ops;
struct spi_nor_flash_parameter *params = nor->params;
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 = {
.default_init = winbond_nor_default_init,
.late_init = winbond_nor_late_init,
};

View File

@ -31,6 +31,7 @@
.sector_size = (8 * (_page_size)), \
.n_sectors = (_n_sectors), \
.page_size = (_page_size), \
.n_banks = 1, \
.addr_nbytes = 3, \
.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.
* This method replaces chip->legacy.cmdfunc(),
* 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
* %NAND_DATA_IFACE_CHECK_ONLY this means the configuration
* 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
* @mtd: an mtd_info structure
* @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
* @spimem: pointer to the SPI memory device
* @bouncebuf: bounce buffer used when the buffer passed by the MTD
@ -376,6 +382,13 @@ struct spi_nor_flash_parameter;
struct spi_nor {
struct mtd_info mtd;
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 spi_mem *spimem;
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,
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

View File

@ -262,6 +262,7 @@ struct spinand_manufacturer {
/* SPI NAND manufacturers */
extern const struct spinand_manufacturer alliancememory_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 macronix_spinand_manufacturer;
extern const struct spinand_manufacturer micron_spinand_manufacturer;