Core MTD changes:

* Use refcount to prevent corruption
 * Call external _get and _put in right order
 * Fix use-after-free in mtd release
 * Explicitly include correct DT includes
 * Clean refcounting with MTD_PARTITIONED_MASTER
 * mtdblock: make warning messages ratelimited
 * dt-bindings: Add SEAMA partition bindings
 
 MTD device driver changes:
 * spear_smi: Use helper function devm_clk_get_enabled()
 * maps: fix -Wvoid-pointer-to-enum-cast warning
 * docg3: Remove unnecessary (void*) conversions
 * physmap-core, spear_smi, st_spi_fsm, lpddr2_nvm, lantiq-flash, plat-ram:
   - Use devm_platform_get_and_ioremap_resource()
 
 Raw NAND core changes:
 * Fix -Wvoid-pointer-to-enum-cast warning
 * Export 'nand_exit_status_op()'
 * dt-bindings: Fix nand-controller.yaml license
 
 Raw NAND controller driver changes:
 * Omap, Omap2, Samsung, Atmel, fsl_upm, lpc32xx_slc, lpc32xx_mlc, STM32_FMC2,
   sh_ftlctl, MXC, Sunxi:
   - Use devm_platform_get_and_ioremap_resource()
 * Orion, vf610_nfc, Sunxi, STM32_FMC2, MTK, mpc5121, lpc32xx_slc, Intel,
   FSMC, Arasan:
   - Use helper function devm_clk_get_optional_enabled()
 * Brcmnand:
   - Use devm_platform_ioremap_resource_byname()
   - Propagate init error -EPROBE_DEFER up
   - Propagate error and simplify ternary operators
   - Fix mtd oobsize
   - Fix potential out-of-bounds access in oob write
   - Fix crash during the panic_write
   - Fix potential false time out warning
   - Fix ECC level field setting for v7.2 controller
 * fsmc: Handle clk prepare error in fsmc_nand_resume()
 * Marvell: Add support for AC5 SoC
 * Meson:
   - Support for 512B ECC step size
   - Fix build error
   - Use NAND core API to check status
   - dt-bindings:
     * Make ECC properties dependent
     * Support for 512B ECC step size
     * Drop unneeded quotes
 * Oxnas: Remove driver and bindings
 * Qcom:
   - Conversion to ->exec_op()
   - Removal of the legacy interface
   - Two full series of improvements/misc fixes
     * Use the BIT() macro
     * Use u8 instead of uint8_t
     * Fix alignment with open parenthesis
     * Fix the spacing
     * Fix wrong indentation
     * Fix a typo
     * Early structure initialization
     * Fix address parsing within ->exec_op()
     * Remove superfluous initialization of "ret"
     * Rename variables in qcom_op_cmd_mapping()
     * Handle unsupported opcode in qcom_op_cmd_mapping()
     * Fix the opcode check in qcom_check_op()
     * Use EOPNOTSUPP instead of ENOTSUPP
     * Wrap qcom_nand_exec_op() to 80 columns
     * Unmap sg_list and free desc within submic_descs()
     * Simplify the call to nand_prog_page_end_op()
     * Do not override the error no of submit_descs()
     * Sort includes alphabetically
     * Clear buf_count and buf_start in raw read
     * Add read/read_start ops in exec_op path
 * vf610_nfc: Do not check 0 for platform_get_irq()
 
 SPI NAND manufacturer driver changes:
 * gigadevice: Add support for GD5F1GQ{4,5}RExxH
 * esmt: Add support for F50D2G41KA
 * toshiba: Add support for T{C,H}58NYG{0,2}S3HBAI4 and TH58NYG3S0HBAI6
 
 SPI NOR core changes:
 * fix assumption on enabling quad mode in
   spi_nor_write_16bit_sr_and_check()
 * avoid setting SRWD bit in SR if WP# signal not connected as it will
   configure the SR permanently as read only. Add "no-wp" dt property.
 * clarify the need for spi-nor compatibles in dt-bindings
 
 SPI NOR manufacturer driver changes:
 * Spansion:
   - Add support for S28HS02GT
   - Switch methods to use vreg_offset from SFDP instead of hardcoding
     the register value
 * Microchip/SST:
   - Add support for sst26vf032b flash
 * Winbond:
   - Correct flags for Winbond w25q128
 * NXP spifi:
   - Use helper function devm_clk_get_enabled()
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAmTstY0ACgkQJWrqGEe9
 VoRpeggAmiUPLVEJRosvtOAaT+en2YTDiVZrRmQ8hjekjRc4FfY6C7DPNWNua3zx
 SaVqLEF7ScjnKH1YYwXN3XG3j4+1NPRV/VmR89yD6NVOcLs8BEJk/Ooc6LQrHAAf
 E87jVafbPLWq8MkcVcnHbdijgHVh2onMbUQtkqjFSn6WAolSmZFJotocfKT12uuY
 K9Hn5TLjRiH5e7O1rQnBcATMXjHIA1o0G1RCklm+T1MojNXIO1KN8yMYRjUoGbEJ
 afFdwczNiTFgL4MJ3qL6NhqhSGC6V6QsUcsYvEjmComepAuZBP2wGnuQMHOxKqYV
 Tl93LW8FOdyWHdCSgJdYkctoRPU6KQ==
 =uMXQ
 -----END PGP SIGNATURE-----

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

Pull MTD updates from Miquel Raynal:
 "Core MTD changes:
   - Use refcount to prevent corruption
   - Call external _get and _put in right order
   - Fix use-after-free in mtd release
   - Explicitly include correct DT includes
   - Clean refcounting with MTD_PARTITIONED_MASTER
   - mtdblock: make warning messages ratelimited
   - dt-bindings: Add SEAMA partition bindings

  Device driver changes:
   - Use devm helper functions
   - Fix questionable cast, remove pointless ones.
   - error handling fixes
   - add support for new chip versions
   - update DT bindings
   - misc cleanups - fix typos, whitespace, indentation"

* tag 'mtd/for-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (105 commits)
  dt-bindings: mtd: amlogic,meson-nand: drop unneeded quotes
  mtd: spear_smi: Use helper function devm_clk_get_enabled()
  mtd: rawnand: orion: Use helper function devm_clk_get_optional_enabled()
  mtd: rawnand: vf610_nfc: Use helper function devm_clk_get_enabled()
  mtd: rawnand: sunxi: Use helper function devm_clk_get_enabled()
  mtd: rawnand: stm32_fmc2: Use helper function devm_clk_get_enabled()
  mtd: rawnand: mtk: Use helper function devm_clk_get_enabled()
  mtd: rawnand: mpc5121: Use helper function devm_clk_get_enabled()
  mtd: rawnand: lpc32xx_slc: Use helper function devm_clk_get_enabled()
  mtd: rawnand: intel: Use helper function devm_clk_get_enabled()
  mtd: rawnand: fsmc: Use helper function devm_clk_get_enabled()
  mtd: rawnand: arasan: Use helper function devm_clk_get_enabled()
  mtd: rawnand: qcom: Add read/read_start ops in exec_op path
  mtd: rawnand: qcom: Clear buf_count and buf_start in raw read
  mtd: maps: fix -Wvoid-pointer-to-enum-cast warning
  mtd: rawnand: fix -Wvoid-pointer-to-enum-cast warning
  mtd: rawnand: fsmc: handle clk prepare error in fsmc_nand_resume()
  mtd: rawnand: Propagate error and simplify ternary operators for brcmstb_nand_wait_for_completion()
  mtd: rawnand: qcom: Sort includes alphabetically
  mtd: rawnand: qcom: Do not override the error no of submit_descs()
  ...
This commit is contained in:
Linus Torvalds 2023-09-03 09:59:53 -07:00
commit bac8a20fa3
88 changed files with 1352 additions and 1311 deletions

View File

@ -50,7 +50,7 @@ patternProperties:
const: hw
nand-ecc-step-size:
const: 1024
enum: [512, 1024]
nand-ecc-strength:
enum: [8, 16, 24, 30, 40, 50, 60]
@ -66,6 +66,10 @@ patternProperties:
unevaluatedProperties: false
dependencies:
nand-ecc-strength: [nand-ecc-step-size]
nand-ecc-step-size: [nand-ecc-strength]
required:
- compatible

View File

@ -43,8 +43,10 @@ properties:
- const: jedec,spi-nor
- const: jedec,spi-nor
description:
Must also include "jedec,spi-nor" for any SPI NOR flash that can be
identified by the JEDEC READ ID opcode (0x9F).
SPI NOR flashes compatible with the JEDEC SFDP standard or which may be
identified with the READ ID opcode (0x9F) do not deserve a specific
compatible. They should instead only be matched against the generic
"jedec,spi-nor" compatible.
reg:
minItems: 1
@ -70,6 +72,21 @@ properties:
be used on such systems, to denote the absence of a reliable reset
mechanism.
no-wp:
type: boolean
description:
The status register write disable (SRWD) bit in status register, combined
with the WP# signal, provides hardware data protection for the device. When
the SRWD bit is set to 1, and the WP# signal is either driven LOW or hard
strapped to LOW, the status register nonvolatile bits become read-only and
the WRITE STATUS REGISTER operation will not execute. The only way to exit
this hardware-protected mode is to drive WP# HIGH. If the WP# signal of the
flash device is not connected or is wrongly tied to GND (that includes internal
pull-downs) then status register permanently becomes read-only as the SRWD bit
cannot be reset. This boolean flag can be used on such systems to avoid setting
the SRWD bit while writing the status register. WP# signal hard strapped to GND
can be a valid use case.
reset-gpios:
description:
A GPIO line connected to the RESET (active low) signal of the device.

View File

@ -16,6 +16,7 @@ properties:
- const: marvell,armada-8k-nand-controller
- const: marvell,armada370-nand-controller
- enum:
- marvell,ac5-nand-controller
- marvell,armada370-nand-controller
- marvell,pxa3xx-nand-controller
- description: legacy bindings

View File

@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mtd/nand-controller.yaml#

View File

@ -1,41 +0,0 @@
* Oxford Semiconductor OXNAS NAND Controller
Please refer to nand-controller.yaml for generic information regarding MTD NAND bindings.
Required properties:
- compatible: "oxsemi,ox820-nand"
- reg: Base address and length for NAND mapped memory.
Optional Properties:
- clocks: phandle to the NAND gate clock if needed.
- resets: phandle to the NAND reset control if needed.
Example:
nandc: nand-controller@41000000 {
compatible = "oxsemi,ox820-nand";
reg = <0x41000000 0x100000>;
clocks = <&stdclk CLK_820_NAND>;
resets = <&reset RESET_NAND>;
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-ecc-mode = "soft";
nand-ecc-algo = "hamming";
partition@0 {
label = "boot";
reg = <0x00000000 0x00e00000>;
read-only;
};
partition@e00000 {
label = "ubi";
reg = <0x00e00000 0x07200000>;
};
};
};

View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mtd/partitions/seama.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Seattle Image Partitions
description: The SEAttle iMAge (SEAMA) partition is a type of partition
used for NAND flash devices. This type of flash image is found in some
D-Link routers such as DIR-645, DIR-842, DIR-859, DIR-860L, DIR-885L,
DIR890L and DCH-M225, as well as in WD and NEC routers on the ath79
(MIPS), Broadcom BCM53xx, and RAMIPS platforms. This partition type
does not have children defined in the device tree, they need to be
detected by software.
allOf:
- $ref: partition.yaml#
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
properties:
compatible:
const: seama
required:
- compatible
unevaluatedProperties: false
examples:
- |
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
compatible = "seama";
reg = <0x0 0x800000>;
label = "firmware";
};
};

View File

@ -1599,7 +1599,7 @@ static void doc_unregister_sysfs(struct platform_device *pdev,
*/
static int flashcontrol_show(struct seq_file *s, void *p)
{
struct docg3 *docg3 = (struct docg3 *)s->private;
struct docg3 *docg3 = s->private;
u8 fctrl;
@ -1621,7 +1621,7 @@ DEFINE_SHOW_ATTRIBUTE(flashcontrol);
static int asic_mode_show(struct seq_file *s, void *p)
{
struct docg3 *docg3 = (struct docg3 *)s->private;
struct docg3 *docg3 = s->private;
int pctrl, mode;
@ -1658,7 +1658,7 @@ DEFINE_SHOW_ATTRIBUTE(asic_mode);
static int device_id_show(struct seq_file *s, void *p)
{
struct docg3 *docg3 = (struct docg3 *)s->private;
struct docg3 *docg3 = s->private;
int id;
mutex_lock(&docg3->cascade->lock);
@ -1672,7 +1672,7 @@ DEFINE_SHOW_ATTRIBUTE(device_id);
static int protection_show(struct seq_file *s, void *p)
{
struct docg3 *docg3 = (struct docg3 *)s->private;
struct docg3 *docg3 = s->private;
int protect, dps0, dps0_low, dps0_high, dps1, dps1_low, dps1_high;
mutex_lock(&docg3->cascade->lock);

View File

@ -15,7 +15,7 @@
#include <linux/sizes.h>
#include <linux/spi/flash.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
#include <linux/of.h>
#define MAX_CMD_SIZE 4

View File

@ -22,7 +22,7 @@
#include <linux/sizes.h>
#include <linux/spi/flash.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
#include <linux/of.h>
struct mchp48_caps {
unsigned int size;

View File

@ -13,7 +13,6 @@
#include <linux/err.h>
#include <linux/math64.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>

View File

@ -937,7 +937,6 @@ static int spear_smi_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct spear_smi_plat_data *pdata = NULL;
struct spear_smi *dev;
struct resource *smi_base;
int irq, ret = 0;
int i;
@ -975,9 +974,7 @@ static int spear_smi_probe(struct platform_device *pdev)
goto err;
}
smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->io_base = devm_ioremap_resource(&pdev->dev, smi_base);
dev->io_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(dev->io_base)) {
ret = PTR_ERR(dev->io_base);
goto err;
@ -996,21 +993,17 @@ static int spear_smi_probe(struct platform_device *pdev)
dev->num_flashes = MAX_NUM_FLASH_CHIP;
}
dev->clk = devm_clk_get(&pdev->dev, NULL);
dev->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
ret = PTR_ERR(dev->clk);
goto err;
}
ret = clk_prepare_enable(dev->clk);
if (ret)
goto err;
ret = devm_request_irq(&pdev->dev, irq, spear_smi_int_handler, 0,
pdev->name, dev);
if (ret) {
dev_err(&dev->pdev->dev, "SMI IRQ allocation failed\n");
goto err_irq;
goto err;
}
mutex_init(&dev->lock);
@ -1023,14 +1016,11 @@ static int spear_smi_probe(struct platform_device *pdev)
ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
if (ret) {
dev_err(&dev->pdev->dev, "bank setup failed\n");
goto err_irq;
goto err;
}
}
return 0;
err_irq:
clk_disable_unprepare(dev->clk);
err:
return ret;
}
@ -1059,8 +1049,6 @@ static int spear_smi_remove(struct platform_device *pdev)
WARN_ON(mtd_device_unregister(&flash->mtd));
}
clk_disable_unprepare(dev->clk);
return 0;
}

View File

@ -2016,7 +2016,6 @@ static int stfsm_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct flash_info *info;
struct resource *res;
struct stfsm *fsm;
int ret;
@ -2033,18 +2032,9 @@ static int stfsm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fsm);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "Resource not found\n");
return -ENODEV;
}
fsm->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(fsm->base)) {
dev_err(&pdev->dev,
"Failed to reserve memory region %pR\n", res);
fsm->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(fsm->base))
return PTR_ERR(fsm->base);
}
fsm->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(fsm->clk)) {

View File

@ -412,7 +412,6 @@ static int lpddr2_nvm_probe(struct platform_device *pdev)
struct map_info *map;
struct mtd_info *mtd;
struct resource *add_range;
struct resource *control_regs;
struct pcm_int_data *pcm_data;
/* Allocate memory control_regs data structures */
@ -452,8 +451,7 @@ static int lpddr2_nvm_probe(struct platform_device *pdev)
simple_map_init(map); /* fill with default methods */
control_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
pcm_data->ctl_regs = devm_ioremap_resource(&pdev->dev, control_regs);
pcm_data->ctl_regs = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(pcm_data->ctl_regs))
return PTR_ERR(pcm_data->ctl_regs);

View File

@ -118,11 +118,9 @@ ltq_mtd_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ltq_mtd);
ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!ltq_mtd->res) {
dev_err(&pdev->dev, "failed to get memory resource\n");
return -ENOENT;
}
ltq_mtd->map->virt = devm_platform_get_and_ioremap_resource(pdev, 0, &ltq_mtd->res);
if (IS_ERR(ltq_mtd->map->virt))
return PTR_ERR(ltq_mtd->map->virt);
ltq_mtd->map = devm_kzalloc(&pdev->dev, sizeof(struct map_info),
GFP_KERNEL);
@ -131,9 +129,6 @@ ltq_mtd_probe(struct platform_device *pdev)
ltq_mtd->map->phys = ltq_mtd->res->start;
ltq_mtd->map->size = resource_size(ltq_mtd->res);
ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res);
if (IS_ERR(ltq_mtd->map->virt))
return PTR_ERR(ltq_mtd->map->virt);
ltq_mtd->map->name = ltq_map_name;
ltq_mtd->map->bankwidth = 2;

View File

@ -14,7 +14,6 @@
#include <linux/mtd/xip.h>
#include <linux/mux/consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <linux/types.h>

View File

@ -508,8 +508,7 @@ static int physmap_flash_probe(struct platform_device *dev)
for (i = 0; i < info->nmaps; i++) {
struct resource *res;
res = platform_get_resource(dev, IORESOURCE_MEM, i);
info->maps[i].virt = devm_ioremap_resource(&dev->dev, res);
info->maps[i].virt = devm_platform_get_and_ioremap_resource(dev, i, &res);
if (IS_ERR(info->maps[i].virt)) {
err = PTR_ERR(info->maps[i].virt);
goto err_out;

View File

@ -8,10 +8,10 @@
*/
#include <linux/export.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mtd/map.h>
#include <linux/mtd/xip.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/bitops.h>
#include <linux/pinctrl/consumer.h>

View File

@ -11,7 +11,7 @@
*/
#include <linux/export.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/mtd/map.h>
#include <linux/mtd/xip.h>
#include "physmap-ixp4xx.h"

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/mtd/map.h>
#ifdef CONFIG_MTD_PHYSMAP_IXP4XX

View File

@ -9,9 +9,9 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/mtd/map.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/bitops.h>
#include "physmap-versatile.h"
@ -206,7 +206,7 @@ int of_flash_probe_versatile(struct platform_device *pdev,
if (!sysnp)
return -ENODEV;
versatile_flashprot = (enum versatile_flashprot)devid->data;
versatile_flashprot = (uintptr_t)devid->data;
rmap = syscon_node_to_regmap(sysnp);
of_node_put(sysnp);
if (IS_ERR(rmap))

View File

@ -123,8 +123,7 @@ static int platram_probe(struct platform_device *pdev)
info->pdata = pdata;
/* get the resource for the memory mapping */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->map.virt = devm_ioremap_resource(&pdev->dev, res);
info->map.virt = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(info->map.virt)) {
err = PTR_ERR(info->map.virt);
goto exit_free;

View File

@ -14,7 +14,7 @@
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/prom.h>
#include <linux/uaccess.h>

View File

@ -262,7 +262,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
}
if (mtd_type_is_nand(mbd->mtd))
pr_warn("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n",
pr_warn_ratelimited("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n",
mbd->tr->name, mbd->mtd->name);
/* OK, it's not open. Create cache info for it */

View File

@ -49,7 +49,7 @@ static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
dev->readonly = 1;
if (mtd_type_is_nand(mtd))
pr_warn("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n",
pr_warn_ratelimited("%s: MTD device '%s' is NAND, please consider using UBI block devices instead.\n",
tr->name, mtd->name);
if (add_mtd_blktrans_dev(dev))

View File

@ -93,10 +93,39 @@ static void mtd_release(struct device *dev)
struct mtd_info *mtd = dev_get_drvdata(dev);
dev_t index = MTD_DEVT(mtd->index);
idr_remove(&mtd_idr, mtd->index);
of_node_put(mtd_get_of_node(mtd));
if (mtd_is_partition(mtd))
release_mtd_partition(mtd);
/* remove /dev/mtdXro node */
device_destroy(&mtd_class, index + 1);
}
static void mtd_device_release(struct kref *kref)
{
struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt);
bool is_partition = mtd_is_partition(mtd);
debugfs_remove_recursive(mtd->dbg.dfs_dir);
/* Try to remove the NVMEM provider */
nvmem_unregister(mtd->nvmem);
device_unregister(&mtd->dev);
/*
* Clear dev so mtd can be safely re-registered later if desired.
* Should not be done for partition,
* as it was already destroyed in device_unregister().
*/
if (!is_partition)
memset(&mtd->dev, 0, sizeof(mtd->dev));
module_put(THIS_MODULE);
}
#define MTD_DEVICE_ATTR_RO(name) \
static DEVICE_ATTR(name, 0444, mtd_##name##_show, NULL)
@ -666,7 +695,7 @@ int add_mtd_device(struct mtd_info *mtd)
}
mtd->index = i;
mtd->usecount = 0;
kref_init(&mtd->refcnt);
/* default value if not set by driver */
if (mtd->bitflip_threshold == 0)
@ -779,7 +808,6 @@ int del_mtd_device(struct mtd_info *mtd)
{
int ret;
struct mtd_notifier *not;
struct device_node *mtd_of_node;
mutex_lock(&mtd_table_mutex);
@ -793,28 +821,8 @@ int del_mtd_device(struct mtd_info *mtd)
list_for_each_entry(not, &mtd_notifiers, list)
not->remove(mtd);
if (mtd->usecount) {
printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
mtd->index, mtd->name, mtd->usecount);
ret = -EBUSY;
} else {
mtd_of_node = mtd_get_of_node(mtd);
debugfs_remove_recursive(mtd->dbg.dfs_dir);
/* Try to remove the NVMEM provider */
nvmem_unregister(mtd->nvmem);
device_unregister(&mtd->dev);
/* Clear dev so mtd can be safely re-registered later if desired */
memset(&mtd->dev, 0, sizeof(mtd->dev));
idr_remove(&mtd_idr, mtd->index);
of_node_put(mtd_of_node);
module_put(THIS_MODULE);
ret = 0;
}
kref_put(&mtd->refcnt, mtd_device_release);
ret = 0;
out_error:
mutex_unlock(&mtd_table_mutex);
@ -1227,25 +1235,27 @@ int __get_mtd_device(struct mtd_info *mtd)
struct mtd_info *master = mtd_get_master(mtd);
int err;
if (!try_module_get(master->owner))
return -ENODEV;
if (master->_get_device) {
err = master->_get_device(mtd);
if (err) {
module_put(master->owner);
if (err)
return err;
}
}
master->usecount++;
if (!try_module_get(master->owner)) {
if (master->_put_device)
master->_put_device(master);
return -ENODEV;
}
while (mtd->parent) {
mtd->usecount++;
while (mtd) {
if (mtd != master)
kref_get(&mtd->refcnt);
mtd = mtd->parent;
}
if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
kref_get(&master->refcnt);
return 0;
}
EXPORT_SYMBOL_GPL(__get_mtd_device);
@ -1329,18 +1339,23 @@ void __put_mtd_device(struct mtd_info *mtd)
{
struct mtd_info *master = mtd_get_master(mtd);
while (mtd->parent) {
--mtd->usecount;
BUG_ON(mtd->usecount < 0);
mtd = mtd->parent;
while (mtd) {
/* kref_put() can relese mtd, so keep a reference mtd->parent */
struct mtd_info *parent = mtd->parent;
if (mtd != master)
kref_put(&mtd->refcnt, mtd_device_release);
mtd = parent;
}
master->usecount--;
if (master->_put_device)
master->_put_device(master);
if (IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
kref_put(&master->refcnt, mtd_device_release);
module_put(master->owner);
/* must be the last as master can be freed in the _put_device */
if (master->_put_device)
master->_put_device(master);
}
EXPORT_SYMBOL_GPL(__put_mtd_device);

View File

@ -12,6 +12,7 @@ int __must_check add_mtd_device(struct mtd_info *mtd);
int del_mtd_device(struct mtd_info *mtd);
int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
int del_mtd_partitions(struct mtd_info *);
void release_mtd_partition(struct mtd_info *mtd);
struct mtd_partitions;

View File

@ -32,6 +32,12 @@ static inline void free_partition(struct mtd_info *mtd)
kfree(mtd);
}
void release_mtd_partition(struct mtd_info *mtd)
{
WARN_ON(!list_empty(&mtd->part.node));
free_partition(mtd);
}
static struct mtd_info *allocate_partition(struct mtd_info *parent,
const struct mtd_partition *part,
int partno, uint64_t cur_offset)
@ -309,13 +315,11 @@ static int __mtd_del_partition(struct mtd_info *mtd)
sysfs_remove_files(&mtd->dev.kobj, mtd_partition_attrs);
list_del_init(&mtd->part.node);
err = del_mtd_device(mtd);
if (err)
return err;
list_del(&mtd->part.node);
free_partition(mtd);
return 0;
}
@ -333,6 +337,7 @@ static int __del_mtd_partitions(struct mtd_info *mtd)
__del_mtd_partitions(child);
pr_info("Deleting %s MTD partition\n", child->name);
list_del_init(&child->part.node);
ret = del_mtd_device(child);
if (ret < 0) {
pr_err("Error when deleting partition \"%s\" (%d)\n",
@ -340,9 +345,6 @@ static int __del_mtd_partitions(struct mtd_info *mtd)
err = ret;
continue;
}
list_del(&child->part.node);
free_partition(child);
}
return err;

View File

@ -18,7 +18,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/nand-ecc-mxic.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

View File

@ -95,9 +95,9 @@
#include <linux/module.h>
#include <linux/mtd/nand.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
static LIST_HEAD(on_host_hw_engines);

View File

@ -13,7 +13,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/onenand.h>
#include <linux/mtd/partitions.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/omap-gpmc.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
@ -467,12 +467,6 @@ static int omap2_onenand_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "error getting memory resource\n");
return -EINVAL;
}
r = of_property_read_u32(np, "reg", &val);
if (r) {
dev_err(dev, "reg not found in DT\n");
@ -486,11 +480,11 @@ static int omap2_onenand_probe(struct platform_device *pdev)
init_completion(&c->irq_done);
init_completion(&c->dma_done);
c->gpmc_cs = val;
c->phys_base = res->start;
c->onenand.base = devm_ioremap_resource(dev, res);
c->onenand.base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(c->onenand.base))
return PTR_ERR(c->onenand.base);
c->phys_base = res->start;
c->int_gpiod = devm_gpiod_get_optional(dev, "int", GPIOD_IN);
if (IS_ERR(c->int_gpiod)) {

View File

@ -860,8 +860,7 @@ static int s3c_onenand_probe(struct platform_device *pdev)
s3c_onenand_setup(mtd);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
onenand->base = devm_ioremap_resource(&pdev->dev, r);
onenand->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(onenand->base))
return PTR_ERR(onenand->base);
@ -874,8 +873,7 @@ static int s3c_onenand_probe(struct platform_device *pdev)
this->options |= ONENAND_SKIP_UNLOCK_CHECK;
if (onenand->type != TYPE_S5PC110) {
r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
onenand->ahb_addr = devm_ioremap_resource(&pdev->dev, r);
onenand->ahb_addr = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(onenand->ahb_addr))
return PTR_ERR(onenand->ahb_addr);
@ -895,8 +893,7 @@ static int s3c_onenand_probe(struct platform_device *pdev)
this->subpagesize = mtd->writesize;
} else { /* S5PC110 */
r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
onenand->dma_addr = devm_ioremap_resource(&pdev->dev, r);
onenand->dma_addr = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(onenand->dma_addr))
return PTR_ERR(onenand->dma_addr);

View File

@ -160,7 +160,7 @@ config MTD_NAND_MARVELL
including:
- PXA3xx processors (NFCv1)
- 32-bit Armada platforms (XP, 37x, 38x, 39x) (NFCv2)
- 64-bit Aramda platforms (7k, 8k) (NFCv2)
- 64-bit Aramda platforms (7k, 8k, ac5) (NFCv2)
config MTD_NAND_SLC_LPC32XX
tristate "NXP LPC32xx SLC NAND controller"
@ -204,13 +204,6 @@ config MTD_NAND_BCM47XXNFLASH
registered by bcma as platform devices. This enables driver for
NAND flash memories. For now only BCM4706 is supported.
config MTD_NAND_OXNAS
tristate "Oxford Semiconductor NAND controller"
depends on ARCH_OXNAS || COMPILE_TEST
depends on HAS_IOMEM
help
This enables the NAND flash controller on Oxford Semiconductor SoCs.
config MTD_NAND_MPC5121_NFC
tristate "MPC5121 NAND controller"
depends on PPC_MPC512x

View File

@ -26,7 +26,6 @@ obj-$(CONFIG_MTD_NAND_MARVELL) += marvell_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o

View File

@ -22,7 +22,7 @@
#include <linux/mtd/nand-gpio.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/sizes.h>

View File

@ -1440,45 +1440,29 @@ static int anfc_probe(struct platform_device *pdev)
anfc_reset(nfc);
nfc->controller_clk = devm_clk_get(&pdev->dev, "controller");
nfc->controller_clk = devm_clk_get_enabled(&pdev->dev, "controller");
if (IS_ERR(nfc->controller_clk))
return PTR_ERR(nfc->controller_clk);
nfc->bus_clk = devm_clk_get(&pdev->dev, "bus");
nfc->bus_clk = devm_clk_get_enabled(&pdev->dev, "bus");
if (IS_ERR(nfc->bus_clk))
return PTR_ERR(nfc->bus_clk);
ret = clk_prepare_enable(nfc->controller_clk);
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
if (ret)
return ret;
ret = clk_prepare_enable(nfc->bus_clk);
if (ret)
goto disable_controller_clk;
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
if (ret)
goto disable_bus_clk;
ret = anfc_parse_cs(nfc);
if (ret)
goto disable_bus_clk;
return ret;
ret = anfc_chips_init(nfc);
if (ret)
goto disable_bus_clk;
return ret;
platform_set_drvdata(pdev, nfc);
return 0;
disable_bus_clk:
clk_disable_unprepare(nfc->bus_clk);
disable_controller_clk:
clk_disable_unprepare(nfc->controller_clk);
return ret;
}
static void anfc_remove(struct platform_device *pdev)
@ -1486,9 +1470,6 @@ static void anfc_remove(struct platform_device *pdev)
struct arasan_nfc *nfc = platform_get_drvdata(pdev);
anfc_chips_cleanup(nfc);
clk_disable_unprepare(nfc->bus_clk);
clk_disable_unprepare(nfc->controller_clk);
}
static const struct of_device_id anfc_ids[] = {

View File

@ -1791,8 +1791,7 @@ atmel_nand_controller_legacy_add_nands(struct atmel_nand_controller *nc)
nand->numcs = 1;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nand->cs[0].io.virt = devm_ioremap_resource(dev, res);
nand->cs[0].io.virt = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(nand->cs[0].io.virt))
return PTR_ERR(nand->cs[0].io.virt);

View File

@ -61,15 +61,13 @@ static int bcm63138_nand_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct bcm63138_nand_soc *priv;
struct brcmnand_soc *soc;
struct resource *res;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
soc = &priv->soc;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base");
priv->base = devm_ioremap_resource(dev, res);
priv->base = devm_platform_ioremap_resource_byname(pdev, "nand-int-base");
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);

View File

@ -272,6 +272,7 @@ struct brcmnand_controller {
const unsigned int *page_sizes;
unsigned int page_size_shift;
unsigned int max_oob;
u32 ecc_level_shift;
u32 features;
/* for low-power standby/resume only */
@ -596,6 +597,34 @@ enum {
INTFC_CTLR_READY = BIT(31),
};
/***********************************************************************
* NAND ACC CONTROL bitfield
*
* Some bits have remained constant throughout hardware revision, while
* others have shifted around.
***********************************************************************/
/* Constant for all versions (where supported) */
enum {
/* See BRCMNAND_HAS_CACHE_MODE */
ACC_CONTROL_CACHE_MODE = BIT(22),
/* See BRCMNAND_HAS_PREFETCH */
ACC_CONTROL_PREFETCH = BIT(23),
ACC_CONTROL_PAGE_HIT = BIT(24),
ACC_CONTROL_WR_PREEMPT = BIT(25),
ACC_CONTROL_PARTIAL_PAGE = BIT(26),
ACC_CONTROL_RD_ERASED = BIT(27),
ACC_CONTROL_FAST_PGM_RDIN = BIT(28),
ACC_CONTROL_WR_ECC = BIT(30),
ACC_CONTROL_RD_ECC = BIT(31),
};
#define ACC_CONTROL_ECC_SHIFT 16
/* Only for v7.2 */
#define ACC_CONTROL_ECC_EXT_SHIFT 13
static inline bool brcmnand_non_mmio_ops(struct brcmnand_controller *ctrl)
{
#if IS_ENABLED(CONFIG_MTD_NAND_BRCMNAND_BCMA)
@ -737,6 +766,12 @@ static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp"))
ctrl->features |= BRCMNAND_HAS_WP;
/* v7.2 has different ecc level shift in the acc register */
if (ctrl->nand_version == 0x0702)
ctrl->ecc_level_shift = ACC_CONTROL_ECC_EXT_SHIFT;
else
ctrl->ecc_level_shift = ACC_CONTROL_ECC_SHIFT;
return 0;
}
@ -931,30 +966,6 @@ static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl)
return 0;
}
/***********************************************************************
* NAND ACC CONTROL bitfield
*
* Some bits have remained constant throughout hardware revision, while
* others have shifted around.
***********************************************************************/
/* Constant for all versions (where supported) */
enum {
/* See BRCMNAND_HAS_CACHE_MODE */
ACC_CONTROL_CACHE_MODE = BIT(22),
/* See BRCMNAND_HAS_PREFETCH */
ACC_CONTROL_PREFETCH = BIT(23),
ACC_CONTROL_PAGE_HIT = BIT(24),
ACC_CONTROL_WR_PREEMPT = BIT(25),
ACC_CONTROL_PARTIAL_PAGE = BIT(26),
ACC_CONTROL_RD_ERASED = BIT(27),
ACC_CONTROL_FAST_PGM_RDIN = BIT(28),
ACC_CONTROL_WR_ECC = BIT(30),
ACC_CONTROL_RD_ECC = BIT(31),
};
static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
{
if (ctrl->nand_version == 0x0702)
@ -967,18 +978,15 @@ static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
return GENMASK(4, 0);
}
#define NAND_ACC_CONTROL_ECC_SHIFT 16
#define NAND_ACC_CONTROL_ECC_EXT_SHIFT 13
static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
{
u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
mask <<= NAND_ACC_CONTROL_ECC_SHIFT;
mask <<= ACC_CONTROL_ECC_SHIFT;
/* v7.2 includes additional ECC levels */
if (ctrl->nand_version >= 0x0702)
mask |= 0x7 << NAND_ACC_CONTROL_ECC_EXT_SHIFT;
if (ctrl->nand_version == 0x0702)
mask |= 0x7 << ACC_CONTROL_ECC_EXT_SHIFT;
return mask;
}
@ -992,8 +1000,8 @@ static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
if (en) {
acc_control |= ecc_flags; /* enable RD/WR ECC */
acc_control |= host->hwcfg.ecc_level
<< NAND_ACC_CONTROL_ECC_SHIFT;
acc_control &= ~brcmnand_ecc_level_mask(ctrl);
acc_control |= host->hwcfg.ecc_level << ctrl->ecc_level_shift;
} else {
acc_control &= ~ecc_flags; /* disable RD/WR ECC */
acc_control &= ~brcmnand_ecc_level_mask(ctrl);
@ -1072,6 +1080,14 @@ static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl,
cpu_relax();
} while (time_after(limit, jiffies));
/*
* do a final check after time out in case the CPU was busy and the driver
* did not get enough time to perform the polling to avoid false alarms
*/
val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
if ((val & mask) == expected_val)
return 0;
dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
expected_val, val & mask);
@ -1461,19 +1477,33 @@ static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i,
const u8 *oob, int sas, int sector_1k)
{
int tbytes = sas << sector_1k;
int j;
int j, k = 0;
u32 last = 0xffffffff;
u8 *plast = (u8 *)&last;
/* Adjust OOB values for 1K sector size */
if (sector_1k && (i & 0x01))
tbytes = max(0, tbytes - (int)ctrl->max_oob);
tbytes = min_t(int, tbytes, ctrl->max_oob);
for (j = 0; j < tbytes; j += 4)
/*
* tbytes may not be multiple of words. Make sure we don't read out of
* the boundary and stop at last word.
*/
for (j = 0; (j + 3) < tbytes; j += 4)
oob_reg_write(ctrl, j,
(oob[j + 0] << 24) |
(oob[j + 1] << 16) |
(oob[j + 2] << 8) |
(oob[j + 3] << 0));
/* handle the remaing bytes */
while (j < tbytes)
plast[k++] = oob[j++];
if (tbytes & 0x3)
oob_reg_write(ctrl, (tbytes & ~0x3), (__force u32)cpu_to_be32(last));
return tbytes;
}
@ -1592,7 +1622,17 @@ static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
dev_dbg(ctrl->dev, "send native cmd %d addr 0x%llx\n", cmd, cmd_addr);
BUG_ON(ctrl->cmd_pending != 0);
/*
* If we came here through _panic_write and there is a pending
* command, try to wait for it. If it times out, rather than
* hitting BUG_ON, just return so we don't crash while crashing.
*/
if (oops_in_progress) {
if (ctrl->cmd_pending &&
bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0))
return;
} else
BUG_ON(ctrl->cmd_pending != 0);
ctrl->cmd_pending = cmd;
ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
@ -1626,13 +1666,13 @@ static bool brcmstb_nand_wait_for_completion(struct nand_chip *chip)
disable_ctrl_irqs(ctrl);
sts = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY,
NAND_CTRL_RDY, 0);
err = (sts < 0) ? true : false;
err = sts < 0;
} else {
unsigned long timeo = msecs_to_jiffies(
NAND_POLL_STATUS_TIMEOUT_MS);
/* wait for completion interrupt */
sts = wait_for_completion_timeout(&ctrl->done, timeo);
err = (sts <= 0) ? true : false;
err = !sts;
}
return err;
@ -1648,6 +1688,7 @@ static int brcmnand_waitfunc(struct nand_chip *chip)
if (ctrl->cmd_pending)
err = brcmstb_nand_wait_for_completion(chip);
ctrl->cmd_pending = 0;
if (err) {
u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START)
>> brcmnand_cmd_shift(ctrl);
@ -1656,8 +1697,8 @@ static int brcmnand_waitfunc(struct nand_chip *chip)
"timeout waiting for command %#02x\n", cmd);
dev_err_ratelimited(ctrl->dev, "intfc status %08x\n",
brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS));
return -ETIMEDOUT;
}
ctrl->cmd_pending = 0;
return brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
INTFC_FLASH_STATUS;
}
@ -2561,7 +2602,7 @@ static int brcmnand_set_cfg(struct brcmnand_host *host,
tmp &= ~brcmnand_ecc_level_mask(ctrl);
tmp &= ~brcmnand_spare_area_mask(ctrl);
if (ctrl->nand_version >= 0x0302) {
tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
tmp |= cfg->ecc_level << ctrl->ecc_level_shift;
tmp |= cfg->spare_area_size;
}
nand_writereg(ctrl, acc_control_offs, tmp);
@ -2612,6 +2653,8 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
struct nand_chip *chip = &host->chip;
const struct nand_ecc_props *requirements =
nanddev_get_ecc_requirements(&chip->base);
struct nand_memory_organization *memorg =
nanddev_get_memorg(&chip->base);
struct brcmnand_controller *ctrl = host->ctrl;
struct brcmnand_cfg *cfg = &host->hwcfg;
char msg[128];
@ -2633,10 +2676,11 @@ static int brcmnand_setup_dev(struct brcmnand_host *host)
if (cfg->spare_area_size > ctrl->max_oob)
cfg->spare_area_size = ctrl->max_oob;
/*
* Set oobsize to be consistent with controller's spare_area_size, as
* the rest is inaccessible.
* Set mtd and memorg oobsize to be consistent with controller's
* spare_area_size, as the rest is inaccessible.
*/
mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT);
memorg->oobsize = mtd->oobsize;
cfg->device_size = mtd->size;
cfg->block_size = mtd->erasesize;
@ -3202,6 +3246,10 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
ret = brcmnand_init_cs(host, NULL);
if (ret) {
if (ret == -EPROBE_DEFER) {
of_node_put(child);
goto err;
}
devm_kfree(dev, host);
continue; /* Try all chip-selects */
}

View File

@ -103,7 +103,6 @@ static int iproc_nand_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct iproc_nand_soc *priv;
struct brcmnand_soc *soc;
struct resource *res;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@ -112,13 +111,11 @@ static int iproc_nand_probe(struct platform_device *pdev)
spin_lock_init(&priv->idm_lock);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm");
priv->idm_base = devm_ioremap_resource(dev, res);
priv->idm_base = devm_platform_ioremap_resource_byname(pdev, "iproc-idm");
if (IS_ERR(priv->idm_base))
return PTR_ERR(priv->idm_base);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext");
priv->ext_base = devm_ioremap_resource(dev, res);
priv->ext_base = devm_platform_ioremap_resource_byname(pdev, "iproc-ext");
if (IS_ERR(priv->ext_base))
return PTR_ERR(priv->ext_base);

View File

@ -18,7 +18,6 @@
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_data/mtd-davinci.h>

View File

@ -13,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reset.h>

View File

@ -8,6 +8,7 @@
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/of_address.h>

View File

@ -13,7 +13,8 @@
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/mtd.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <asm/fsl_lbc.h>
@ -172,8 +173,7 @@ static int fun_probe(struct platform_device *ofdev)
if (!fun)
return -ENOMEM;
io_res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
fun->io_base = devm_ioremap_resource(&ofdev->dev, io_res);
fun->io_base = devm_platform_get_and_ioremap_resource(ofdev, 0, &io_res);
if (IS_ERR(fun->io_base))
return PTR_ERR(fun->io_base);

View File

@ -1066,16 +1066,12 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
host->regs_va = base + FSMC_NOR_REG_SIZE +
(host->bank * FSMC_NAND_BANK_SZ);
host->clk = devm_clk_get(&pdev->dev, NULL);
host->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(host->clk)) {
dev_err(&pdev->dev, "failed to fetch block clock\n");
return PTR_ERR(host->clk);
}
ret = clk_prepare_enable(host->clk);
if (ret)
return ret;
/*
* This device ID is actually a common AMBA ID as used on the
* AMBA PrimeCell bus. However it is not a PrimeCell.
@ -1111,7 +1107,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (!host->read_dma_chan) {
dev_err(&pdev->dev, "Unable to get read dma channel\n");
ret = -ENODEV;
goto disable_clk;
goto disable_fsmc;
}
host->write_dma_chan = dma_request_channel(mask, filter, NULL);
if (!host->write_dma_chan) {
@ -1155,9 +1151,8 @@ release_dma_write_chan:
release_dma_read_chan:
if (host->mode == USE_DMA_ACCESS)
dma_release_channel(host->read_dma_chan);
disable_clk:
disable_fsmc:
fsmc_nand_disable(host);
clk_disable_unprepare(host->clk);
return ret;
}
@ -1182,7 +1177,6 @@ static void fsmc_nand_remove(struct platform_device *pdev)
dma_release_channel(host->write_dma_chan);
dma_release_channel(host->read_dma_chan);
}
clk_disable_unprepare(host->clk);
}
}
@ -1200,9 +1194,14 @@ static int fsmc_nand_suspend(struct device *dev)
static int fsmc_nand_resume(struct device *dev)
{
struct fsmc_nand_data *host = dev_get_drvdata(dev);
int ret;
if (host) {
clk_prepare_enable(host->clk);
ret = clk_prepare_enable(host->clk);
if (ret) {
dev_err(dev, "failed to enable clk\n");
return ret;
}
if (host->dev_timings)
fsmc_nand_setup(host, host->dev_timings);
nand_reset(&host->nand, 0);

View File

@ -13,7 +13,7 @@
#include <linux/module.h>
#include <linux/mtd/partitions.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/dma/mxs-dma.h>
#include "gpmi-nand.h"

View File

@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>

View File

@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

View File

@ -626,16 +626,10 @@ static int ebu_nand_probe(struct platform_device *pdev)
goto err_of_node_put;
}
ebu_host->clk = devm_clk_get(dev, NULL);
ebu_host->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(ebu_host->clk)) {
ret = dev_err_probe(dev, PTR_ERR(ebu_host->clk),
"failed to get clock\n");
goto err_of_node_put;
}
ret = clk_prepare_enable(ebu_host->clk);
if (ret) {
dev_err(dev, "failed to enable clock: %d\n", ret);
"failed to get and enable clock\n");
goto err_of_node_put;
}
@ -643,7 +637,7 @@ static int ebu_nand_probe(struct platform_device *pdev)
if (IS_ERR(ebu_host->dma_tx)) {
ret = dev_err_probe(dev, PTR_ERR(ebu_host->dma_tx),
"failed to request DMA tx chan!.\n");
goto err_disable_unprepare_clk;
goto err_of_node_put;
}
ebu_host->dma_rx = dma_request_chan(dev, "rx");
@ -698,8 +692,6 @@ err_clean_nand:
nand_cleanup(&ebu_host->chip);
err_cleanup_dma:
ebu_dma_cleanup(ebu_host);
err_disable_unprepare_clk:
clk_disable_unprepare(ebu_host->clk);
err_of_node_put:
of_node_put(chip_np);
@ -716,7 +708,6 @@ static void ebu_nand_remove(struct platform_device *pdev)
nand_cleanup(&ebu_host->chip);
ebu_nand_disable(&ebu_host->chip);
ebu_dma_cleanup(ebu_host);
clk_disable_unprepare(ebu_host->clk);
}
static const struct of_device_id ebu_nand_match[] = {

View File

@ -695,8 +695,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
host->pdev = pdev;
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->io_base = devm_ioremap_resource(&pdev->dev, rc);
host->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &rc);
if (IS_ERR(host->io_base))
return PTR_ERR(host->io_base);

View File

@ -836,8 +836,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
if (!host)
return -ENOMEM;
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->io_base = devm_ioremap_resource(&pdev->dev, rc);
host->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &rc);
if (IS_ERR(host->io_base))
return PTR_ERR(host->io_base);
@ -872,15 +871,12 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
mtd->dev.parent = &pdev->dev;
/* Get NAND clock */
host->clk = devm_clk_get(&pdev->dev, NULL);
host->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(host->clk)) {
dev_err(&pdev->dev, "Clock failure\n");
res = -ENOENT;
goto enable_wp;
}
res = clk_prepare_enable(host->clk);
if (res)
goto enable_wp;
/* Set NAND IO addresses and command/ready functions */
chip->legacy.IO_ADDR_R = SLC_DATA(host->io_base);
@ -908,13 +904,13 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
GFP_KERNEL);
if (host->data_buf == NULL) {
res = -ENOMEM;
goto unprepare_clk;
goto enable_wp;
}
res = lpc32xx_nand_dma_setup(host);
if (res) {
res = -EIO;
goto unprepare_clk;
goto enable_wp;
}
/* Find NAND device */
@ -935,8 +931,6 @@ cleanup_nand:
nand_cleanup(chip);
release_dma:
dma_release_channel(host->dma_chan);
unprepare_clk:
clk_disable_unprepare(host->clk);
enable_wp:
lpc32xx_wp_enable(host);
@ -963,7 +957,6 @@ static void lpc32xx_nand_remove(struct platform_device *pdev)
tmp &= ~SLCCFG_CE_LOW;
writel(tmp, SLC_CTRL(host->io_base));
clk_disable_unprepare(host->clk);
lpc32xx_wp_enable(host);
}

View File

@ -77,9 +77,10 @@
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/mtd/rawnand.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@ -375,6 +376,7 @@ static inline struct marvell_nand_chip_sel *to_nand_sel(struct marvell_nand_chip
* BCH error detection and correction algorithm,
* NDCB3 register has been added
* @use_dma: Use dma for data transfers
* @max_mode_number: Maximum timing mode supported by the controller
*/
struct marvell_nfc_caps {
unsigned int max_cs_nb;
@ -383,6 +385,7 @@ struct marvell_nfc_caps {
bool legacy_of_bindings;
bool is_nfcv2;
bool use_dma;
unsigned int max_mode_number;
};
/**
@ -2376,6 +2379,9 @@ static int marvell_nfc_setup_interface(struct nand_chip *chip, int chipnr,
if (IS_ERR(sdr))
return PTR_ERR(sdr);
if (nfc->caps->max_mode_number && nfc->caps->max_mode_number < conf->timings.mode)
return -EOPNOTSUPP;
/*
* SDR timings are given in pico-seconds while NFC timings must be
* expressed in NAND controller clock cycles, which is half of the
@ -3073,6 +3079,13 @@ static const struct marvell_nfc_caps marvell_armada_8k_nfc_caps = {
.is_nfcv2 = true,
};
static const struct marvell_nfc_caps marvell_ac5_caps = {
.max_cs_nb = 2,
.max_rb_nb = 1,
.is_nfcv2 = true,
.max_mode_number = 3,
};
static const struct marvell_nfc_caps marvell_armada370_nfc_caps = {
.max_cs_nb = 4,
.max_rb_nb = 2,
@ -3121,6 +3134,10 @@ static const struct of_device_id marvell_nfc_of_ids[] = {
.compatible = "marvell,armada-8k-nand-controller",
.data = &marvell_armada_8k_nfc_caps,
},
{
.compatible = "marvell,ac5-nand-controller",
.data = &marvell_ac5_caps,
},
{
.compatible = "marvell,armada370-nand-controller",
.data = &marvell_armada370_nfc_caps,

View File

@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/sched/task_stack.h>
#define NFC_REG_CMD 0x00
@ -135,6 +134,7 @@ struct meson_nfc_nand_chip {
struct meson_nand_ecc {
u32 bch;
u32 strength;
u32 size;
};
struct meson_nfc_data {
@ -190,7 +190,8 @@ struct meson_nfc {
};
enum {
NFC_ECC_BCH8_1K = 2,
NFC_ECC_BCH8_512 = 1,
NFC_ECC_BCH8_1K,
NFC_ECC_BCH24_1K,
NFC_ECC_BCH30_1K,
NFC_ECC_BCH40_1K,
@ -198,15 +199,16 @@ enum {
NFC_ECC_BCH60_1K,
};
#define MESON_ECC_DATA(b, s) { .bch = (b), .strength = (s)}
#define MESON_ECC_DATA(b, s, sz) { .bch = (b), .strength = (s), .size = (sz) }
static struct meson_nand_ecc meson_ecc[] = {
MESON_ECC_DATA(NFC_ECC_BCH8_1K, 8),
MESON_ECC_DATA(NFC_ECC_BCH24_1K, 24),
MESON_ECC_DATA(NFC_ECC_BCH30_1K, 30),
MESON_ECC_DATA(NFC_ECC_BCH40_1K, 40),
MESON_ECC_DATA(NFC_ECC_BCH50_1K, 50),
MESON_ECC_DATA(NFC_ECC_BCH60_1K, 60),
MESON_ECC_DATA(NFC_ECC_BCH8_512, 8, 512),
MESON_ECC_DATA(NFC_ECC_BCH8_1K, 8, 1024),
MESON_ECC_DATA(NFC_ECC_BCH24_1K, 24, 1024),
MESON_ECC_DATA(NFC_ECC_BCH30_1K, 30, 1024),
MESON_ECC_DATA(NFC_ECC_BCH40_1K, 40, 1024),
MESON_ECC_DATA(NFC_ECC_BCH50_1K, 50, 1024),
MESON_ECC_DATA(NFC_ECC_BCH60_1K, 60, 1024),
};
static int meson_nand_calc_ecc_bytes(int step_size, int strength)
@ -224,8 +226,27 @@ static int meson_nand_calc_ecc_bytes(int step_size, int strength)
NAND_ECC_CAPS_SINGLE(meson_gxl_ecc_caps,
meson_nand_calc_ecc_bytes, 1024, 8, 24, 30, 40, 50, 60);
NAND_ECC_CAPS_SINGLE(meson_axg_ecc_caps,
meson_nand_calc_ecc_bytes, 1024, 8);
static const int axg_stepinfo_strengths[] = { 8 };
static const struct nand_ecc_step_info axg_stepinfo[] = {
{
.stepsize = 1024,
.strengths = axg_stepinfo_strengths,
.nstrengths = ARRAY_SIZE(axg_stepinfo_strengths)
},
{
.stepsize = 512,
.strengths = axg_stepinfo_strengths,
.nstrengths = ARRAY_SIZE(axg_stepinfo_strengths)
},
};
static const struct nand_ecc_caps meson_axg_ecc_caps = {
.stepinfos = axg_stepinfo,
.nstepinfos = ARRAY_SIZE(axg_stepinfo),
.calc_ecc_bytes = meson_nand_calc_ecc_bytes,
};
static struct meson_nfc_nand_chip *to_meson_nand(struct nand_chip *nand)
{
@ -400,9 +421,10 @@ static void meson_nfc_set_data_oob(struct nand_chip *nand,
}
}
static int meson_nfc_wait_no_rb_pin(struct meson_nfc *nfc, int timeout_ms,
static int meson_nfc_wait_no_rb_pin(struct nand_chip *nand, int timeout_ms,
bool need_cmd_read0)
{
struct meson_nfc *nfc = nand_get_controller_data(nand);
u32 cmd, cfg;
meson_nfc_cmd_idle(nfc, nfc->timing.twb);
@ -414,8 +436,7 @@ static int meson_nfc_wait_no_rb_pin(struct meson_nfc *nfc, int timeout_ms,
writel(cfg, nfc->reg_base + NFC_REG_CFG);
reinit_completion(&nfc->completion);
cmd = nfc->param.chip_select | NFC_CMD_CLE | NAND_CMD_STATUS;
writel(cmd, nfc->reg_base + NFC_REG_CMD);
nand_status_op(nand, NULL);
/* use the max erase time as the maximum clock for waiting R/B */
cmd = NFC_CMD_RB | NFC_CMD_RB_INT_NO_PIN | nfc->timing.tbers_max;
@ -425,12 +446,8 @@ static int meson_nfc_wait_no_rb_pin(struct meson_nfc *nfc, int timeout_ms,
msecs_to_jiffies(timeout_ms)))
return -ETIMEDOUT;
if (need_cmd_read0) {
cmd = nfc->param.chip_select | NFC_CMD_CLE | NAND_CMD_READ0;
writel(cmd, nfc->reg_base + NFC_REG_CMD);
meson_nfc_drain_cmd(nfc);
meson_nfc_wait_cmd_finish(nfc, CMD_FIFO_EMPTY_TIMEOUT);
}
if (need_cmd_read0)
nand_exit_status_op(nand);
return 0;
}
@ -463,9 +480,11 @@ static int meson_nfc_wait_rb_pin(struct meson_nfc *nfc, int timeout_ms)
return ret;
}
static int meson_nfc_queue_rb(struct meson_nfc *nfc, int timeout_ms,
static int meson_nfc_queue_rb(struct nand_chip *nand, int timeout_ms,
bool need_cmd_read0)
{
struct meson_nfc *nfc = nand_get_controller_data(nand);
if (nfc->no_rb_pin) {
/* This mode is used when there is no wired R/B pin.
* It works like 'nand_soft_waitrdy()', but instead of
@ -477,7 +496,7 @@ static int meson_nfc_queue_rb(struct meson_nfc *nfc, int timeout_ms,
* needed (for all cases except page programming - this
* is reason of 'need_cmd_read0' flag).
*/
return meson_nfc_wait_no_rb_pin(nfc, timeout_ms,
return meson_nfc_wait_no_rb_pin(nand, timeout_ms,
need_cmd_read0);
} else {
return meson_nfc_wait_rb_pin(nfc, timeout_ms);
@ -687,7 +706,7 @@ static int meson_nfc_rw_cmd_prepare_and_execute(struct nand_chip *nand,
if (in) {
nfc->cmdfifo.rw.cmd1 = cs | NFC_CMD_CLE | NAND_CMD_READSTART;
writel(nfc->cmdfifo.rw.cmd1, nfc->reg_base + NFC_REG_CMD);
meson_nfc_queue_rb(nfc, PSEC_TO_MSEC(sdr->tR_max), true);
meson_nfc_queue_rb(nand, PSEC_TO_MSEC(sdr->tR_max), true);
} else {
meson_nfc_cmd_idle(nfc, nfc->timing.tadl);
}
@ -733,7 +752,7 @@ static int meson_nfc_write_page_sub(struct nand_chip *nand,
cmd = nfc->param.chip_select | NFC_CMD_CLE | NAND_CMD_PAGEPROG;
writel(cmd, nfc->reg_base + NFC_REG_CMD);
meson_nfc_queue_rb(nfc, PSEC_TO_MSEC(sdr->tPROG_max), false);
meson_nfc_queue_rb(nand, PSEC_TO_MSEC(sdr->tPROG_max), false);
meson_nfc_dma_buffer_release(nand, data_len, info_len, DMA_TO_DEVICE);
@ -1049,7 +1068,7 @@ static int meson_nfc_exec_op(struct nand_chip *nand,
break;
case NAND_OP_WAITRDY_INSTR:
meson_nfc_queue_rb(nfc, instr->ctx.waitrdy.timeout_ms,
meson_nfc_queue_rb(nand, instr->ctx.waitrdy.timeout_ms,
true);
if (instr->delay_ns)
meson_nfc_cmd_idle(nfc, delay_idle);
@ -1259,7 +1278,8 @@ static int meson_nand_bch_mode(struct nand_chip *nand)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(meson_ecc); i++) {
if (meson_ecc[i].strength == nand->ecc.strength) {
if (meson_ecc[i].strength == nand->ecc.strength &&
meson_ecc[i].size == nand->ecc.size) {
meson_chip->bch_mode = meson_ecc[i].bch;
return 0;
}

View File

@ -21,10 +21,10 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <asm/mpc5121.h>
@ -595,8 +595,6 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
struct nand_chip *chip = mtd_to_nand(mtd);
struct mpc5121_nfc_prv *prv = nand_get_controller_data(chip);
clk_disable_unprepare(prv->clk);
if (prv->csreg)
iounmap(prv->csreg);
}
@ -717,17 +715,12 @@ static int mpc5121_nfc_probe(struct platform_device *op)
}
/* Enable NFC clock */
clk = devm_clk_get(dev, "ipg");
clk = devm_clk_get_enabled(dev, "ipg");
if (IS_ERR(clk)) {
dev_err(dev, "Unable to acquire NFC clock!\n");
dev_err(dev, "Unable to acquire and enable NFC clock!\n");
retval = PTR_ERR(clk);
goto error;
}
retval = clk_prepare_enable(clk);
if (retval) {
dev_err(dev, "Unable to enable NFC clock!\n");
goto error;
}
prv->clk = clk;
/* Reset NAND Flash controller */

View File

@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mtd/nand-ecc-mtk.h>
/* NAND controller register definition */
@ -1119,32 +1118,6 @@ static irqreturn_t mtk_nfc_irq(int irq, void *id)
return IRQ_HANDLED;
}
static int mtk_nfc_enable_clk(struct device *dev, struct mtk_nfc_clk *clk)
{
int ret;
ret = clk_prepare_enable(clk->nfi_clk);
if (ret) {
dev_err(dev, "failed to enable nfi clk\n");
return ret;
}
ret = clk_prepare_enable(clk->pad_clk);
if (ret) {
dev_err(dev, "failed to enable pad clk\n");
clk_disable_unprepare(clk->nfi_clk);
return ret;
}
return 0;
}
static void mtk_nfc_disable_clk(struct mtk_nfc_clk *clk)
{
clk_disable_unprepare(clk->nfi_clk);
clk_disable_unprepare(clk->pad_clk);
}
static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *oob_region)
{
@ -1546,40 +1519,36 @@ static int mtk_nfc_probe(struct platform_device *pdev)
goto release_ecc;
}
nfc->clk.nfi_clk = devm_clk_get(dev, "nfi_clk");
nfc->clk.nfi_clk = devm_clk_get_enabled(dev, "nfi_clk");
if (IS_ERR(nfc->clk.nfi_clk)) {
dev_err(dev, "no clk\n");
ret = PTR_ERR(nfc->clk.nfi_clk);
goto release_ecc;
}
nfc->clk.pad_clk = devm_clk_get(dev, "pad_clk");
nfc->clk.pad_clk = devm_clk_get_enabled(dev, "pad_clk");
if (IS_ERR(nfc->clk.pad_clk)) {
dev_err(dev, "no pad clk\n");
ret = PTR_ERR(nfc->clk.pad_clk);
goto release_ecc;
}
ret = mtk_nfc_enable_clk(dev, &nfc->clk);
if (ret)
goto release_ecc;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -EINVAL;
goto clk_disable;
goto release_ecc;
}
ret = devm_request_irq(dev, irq, mtk_nfc_irq, 0x0, "mtk-nand", nfc);
if (ret) {
dev_err(dev, "failed to request nfi irq\n");
goto clk_disable;
goto release_ecc;
}
ret = dma_set_mask(dev, DMA_BIT_MASK(32));
if (ret) {
dev_err(dev, "failed to set dma mask\n");
goto clk_disable;
goto release_ecc;
}
platform_set_drvdata(pdev, nfc);
@ -1587,14 +1556,11 @@ static int mtk_nfc_probe(struct platform_device *pdev)
ret = mtk_nfc_nand_chips_init(dev, nfc);
if (ret) {
dev_err(dev, "failed to init nand chips\n");
goto clk_disable;
goto release_ecc;
}
return 0;
clk_disable:
mtk_nfc_disable_clk(&nfc->clk);
release_ecc:
mtk_ecc_release(nfc->ecc);
@ -1619,7 +1585,6 @@ static void mtk_nfc_remove(struct platform_device *pdev)
}
mtk_ecc_release(nfc->ecc);
mtk_nfc_disable_clk(&nfc->clk);
}
#ifdef CONFIG_PM_SLEEP
@ -1627,7 +1592,8 @@ static int mtk_nfc_suspend(struct device *dev)
{
struct mtk_nfc *nfc = dev_get_drvdata(dev);
mtk_nfc_disable_clk(&nfc->clk);
clk_disable_unprepare(nfc->clk.nfi_clk);
clk_disable_unprepare(nfc->clk.pad_clk);
return 0;
}
@ -1642,9 +1608,18 @@ static int mtk_nfc_resume(struct device *dev)
udelay(200);
ret = mtk_nfc_enable_clk(dev, &nfc->clk);
if (ret)
ret = clk_prepare_enable(nfc->clk.nfi_clk);
if (ret) {
dev_err(dev, "failed to enable nfi clk\n");
return ret;
}
ret = clk_prepare_enable(nfc->clk.pad_clk);
if (ret) {
dev_err(dev, "failed to enable pad clk\n");
clk_disable_unprepare(nfc->clk.nfi_clk);
return ret;
}
/* reset NAND chip if VCC was powered off */
list_for_each_entry(chip, &nfc->chips, node) {

View File

@ -20,7 +20,6 @@
#include <linux/irq.h>
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/of_device.h>
#define DRIVER_NAME "mxc_nand"
@ -1696,7 +1695,6 @@ static int mxcnd_probe(struct platform_device *pdev)
struct nand_chip *this;
struct mtd_info *mtd;
struct mxc_nand_host *host;
struct resource *res;
int err = 0;
/* Allocate memory for MTD device structure and private data */
@ -1740,17 +1738,15 @@ static int mxcnd_probe(struct platform_device *pdev)
this->options |= NAND_KEEP_TIMINGS;
if (host->devtype_data->needs_ip) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
host->regs_ip = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(host->regs_ip))
return PTR_ERR(host->regs_ip);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
host->base = devm_platform_ioremap_resource(pdev, 1);
} else {
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
host->base = devm_platform_ioremap_resource(pdev, 0);
}
host->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->base))
return PTR_ERR(host->base);

View File

@ -1885,6 +1885,7 @@ int nand_exit_status_op(struct nand_chip *chip)
return 0;
}
EXPORT_SYMBOL_GPL(nand_exit_status_op);
/**
* nand_erase_op - Do an erase operation

View File

@ -22,8 +22,9 @@
#include <linux/mtd/ndfc.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#define NDFC_MAX_CS 4

View File

@ -22,7 +22,7 @@
#include <linux/iopoll.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_data/elm.h>
@ -2219,8 +2219,7 @@ static int omap_nand_probe(struct platform_device *pdev)
}
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
vaddr = devm_ioremap_resource(&pdev->dev, res);
vaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(vaddr))
return PTR_ERR(vaddr);

View File

@ -169,16 +169,10 @@ static int __init orion_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
/* Not all platforms can gate the clock, so it is optional. */
info->clk = devm_clk_get_optional(&pdev->dev, NULL);
info->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
if (IS_ERR(info->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(info->clk),
"failed to get clock!\n");
ret = clk_prepare_enable(info->clk);
if (ret) {
dev_err(&pdev->dev, "failed to prepare clock!\n");
return ret;
}
"failed to get and enable clock!\n");
/*
* This driver assumes that the default ECC engine should be TYPE_SOFT.
@ -189,19 +183,13 @@ static int __init orion_nand_probe(struct platform_device *pdev)
ret = nand_scan(nc, 1);
if (ret)
goto no_dev;
return ret;
mtd->name = "orion_nand";
ret = mtd_device_register(mtd, board->parts, board->nr_parts);
if (ret) {
if (ret)
nand_cleanup(nc);
goto no_dev;
}
return 0;
no_dev:
clk_disable_unprepare(info->clk);
return ret;
}
@ -215,8 +203,6 @@ static void orion_nand_remove(struct platform_device *pdev)
WARN_ON(ret);
nand_cleanup(chip);
clk_disable_unprepare(info->clk);
}
#ifdef CONFIG_OF

View File

@ -1,209 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Oxford Semiconductor OXNAS NAND driver
* Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
* Heavily based on plat_nand.c :
* Author: Vitaly Wool <vitalywool@gmail.com>
* Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/of.h>
/* Nand commands */
#define OXNAS_NAND_CMD_ALE BIT(18)
#define OXNAS_NAND_CMD_CLE BIT(19)
#define OXNAS_NAND_MAX_CHIPS 1
struct oxnas_nand_ctrl {
struct nand_controller base;
void __iomem *io_base;
struct clk *clk;
struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
unsigned int nchips;
};
static uint8_t oxnas_nand_read_byte(struct nand_chip *chip)
{
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
return readb(oxnas->io_base);
}
static void oxnas_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
{
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
ioread8_rep(oxnas->io_base, buf, len);
}
static void oxnas_nand_write_buf(struct nand_chip *chip, const u8 *buf,
int len)
{
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
iowrite8_rep(oxnas->io_base, buf, len);
}
/* Single CS command control */
static void oxnas_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
unsigned int ctrl)
{
struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
if (ctrl & NAND_CLE)
writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
else if (ctrl & NAND_ALE)
writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
}
/*
* Probe for the NAND device.
*/
static int oxnas_nand_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *nand_np;
struct oxnas_nand_ctrl *oxnas;
struct nand_chip *chip;
struct mtd_info *mtd;
int count = 0;
int err = 0;
int i;
/* Allocate memory for the device structure (and zero it) */
oxnas = devm_kzalloc(&pdev->dev, sizeof(*oxnas),
GFP_KERNEL);
if (!oxnas)
return -ENOMEM;
nand_controller_init(&oxnas->base);
oxnas->io_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(oxnas->io_base))
return PTR_ERR(oxnas->io_base);
oxnas->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(oxnas->clk))
oxnas->clk = NULL;
/* Only a single chip node is supported */
count = of_get_child_count(np);
if (count > 1)
return -EINVAL;
err = clk_prepare_enable(oxnas->clk);
if (err)
return err;
device_reset_optional(&pdev->dev);
for_each_child_of_node(np, nand_np) {
chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
GFP_KERNEL);
if (!chip) {
err = -ENOMEM;
goto err_release_child;
}
chip->controller = &oxnas->base;
nand_set_flash_node(chip, nand_np);
nand_set_controller_data(chip, oxnas);
mtd = nand_to_mtd(chip);
mtd->dev.parent = &pdev->dev;
mtd->priv = chip;
chip->legacy.cmd_ctrl = oxnas_nand_cmd_ctrl;
chip->legacy.read_buf = oxnas_nand_read_buf;
chip->legacy.read_byte = oxnas_nand_read_byte;
chip->legacy.write_buf = oxnas_nand_write_buf;
chip->legacy.chip_delay = 30;
/* Scan to find existence of the device */
err = nand_scan(chip, 1);
if (err)
goto err_release_child;
err = mtd_device_register(mtd, NULL, 0);
if (err)
goto err_cleanup_nand;
oxnas->chips[oxnas->nchips++] = chip;
}
/* Exit if no chips found */
if (!oxnas->nchips) {
err = -ENODEV;
goto err_clk_unprepare;
}
platform_set_drvdata(pdev, oxnas);
return 0;
err_cleanup_nand:
nand_cleanup(chip);
err_release_child:
of_node_put(nand_np);
for (i = 0; i < oxnas->nchips; i++) {
chip = oxnas->chips[i];
WARN_ON(mtd_device_unregister(nand_to_mtd(chip)));
nand_cleanup(chip);
}
err_clk_unprepare:
clk_disable_unprepare(oxnas->clk);
return err;
}
static void oxnas_nand_remove(struct platform_device *pdev)
{
struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
struct nand_chip *chip;
int i;
for (i = 0; i < oxnas->nchips; i++) {
chip = oxnas->chips[i];
WARN_ON(mtd_device_unregister(nand_to_mtd(chip)));
nand_cleanup(chip);
}
clk_disable_unprepare(oxnas->clk);
}
static const struct of_device_id oxnas_nand_match[] = {
{ .compatible = "oxsemi,ox820-nand" },
{},
};
MODULE_DEVICE_TABLE(of, oxnas_nand_match);
static struct platform_driver oxnas_nand_driver = {
.probe = oxnas_nand_probe,
.remove_new = oxnas_nand_remove,
.driver = {
.name = "oxnas_nand",
.of_match_table = oxnas_nand_match,
},
};
module_platform_driver(oxnas_nand_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
MODULE_DESCRIPTION("Oxnas NAND driver");
MODULE_ALIAS("platform:oxnas_nand");

View File

@ -23,9 +23,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/clk.h>

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

View File

@ -26,7 +26,6 @@
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>

View File

@ -17,7 +17,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sh_dma.h>
@ -1124,8 +1123,7 @@ static int flctl_probe(struct platform_device *pdev)
if (!flctl)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
flctl->reg = devm_ioremap_resource(&pdev->dev, res);
flctl->reg = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(flctl->reg))
return PTR_ERR(flctl->reg);
flctl->fifo = res->start + 0x24; /* FLDTFIFO */

View File

@ -8,8 +8,9 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#define FPGA_NAND_CMD_MASK (0x7 << 28)

View File

@ -1922,8 +1922,8 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
if (!(nfc->cs_assigned & BIT(chip_cs)))
continue;
res = platform_get_resource(pdev, IORESOURCE_MEM, mem_region);
nfc->data_base[chip_cs] = devm_ioremap_resource(dev, res);
nfc->data_base[chip_cs] = devm_platform_get_and_ioremap_resource(pdev,
mem_region, &res);
if (IS_ERR(nfc->data_base[chip_cs]))
return PTR_ERR(nfc->data_base[chip_cs]);
@ -1951,21 +1951,17 @@ static int stm32_fmc2_nfc_probe(struct platform_device *pdev)
init_completion(&nfc->complete);
nfc->clk = devm_clk_get(nfc->cdev, NULL);
if (IS_ERR(nfc->clk))
nfc->clk = devm_clk_get_enabled(nfc->cdev, NULL);
if (IS_ERR(nfc->clk)) {
dev_err(dev, "can not get and enable the clock\n");
return PTR_ERR(nfc->clk);
ret = clk_prepare_enable(nfc->clk);
if (ret) {
dev_err(dev, "can not enable the clock\n");
return ret;
}
rstc = devm_reset_control_get(dev, NULL);
if (IS_ERR(rstc)) {
ret = PTR_ERR(rstc);
if (ret == -EPROBE_DEFER)
goto err_clk_disable;
return ret;
} else {
reset_control_assert(rstc);
reset_control_deassert(rstc);
@ -2018,9 +2014,6 @@ err_release_dma:
sg_free_table(&nfc->dma_data_sg);
sg_free_table(&nfc->dma_ecc_sg);
err_clk_disable:
clk_disable_unprepare(nfc->clk);
return ret;
}
@ -2045,8 +2038,6 @@ static void stm32_fmc2_nfc_remove(struct platform_device *pdev)
sg_free_table(&nfc->dma_data_sg);
sg_free_table(&nfc->dma_ecc_sg);
clk_disable_unprepare(nfc->clk);
stm32_fmc2_nfc_wp_enable(nand);
}

View File

@ -19,7 +19,6 @@
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
@ -2087,8 +2086,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
nand_controller_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nfc->regs = devm_ioremap_resource(dev, r);
nfc->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(nfc->regs))
return PTR_ERR(nfc->regs);
@ -2096,37 +2094,26 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
nfc->ahb_clk = devm_clk_get(dev, "ahb");
nfc->ahb_clk = devm_clk_get_enabled(dev, "ahb");
if (IS_ERR(nfc->ahb_clk)) {
dev_err(dev, "failed to retrieve ahb clk\n");
return PTR_ERR(nfc->ahb_clk);
}
ret = clk_prepare_enable(nfc->ahb_clk);
if (ret)
return ret;
nfc->mod_clk = devm_clk_get(dev, "mod");
nfc->mod_clk = devm_clk_get_enabled(dev, "mod");
if (IS_ERR(nfc->mod_clk)) {
dev_err(dev, "failed to retrieve mod clk\n");
ret = PTR_ERR(nfc->mod_clk);
goto out_ahb_clk_unprepare;
return PTR_ERR(nfc->mod_clk);
}
ret = clk_prepare_enable(nfc->mod_clk);
if (ret)
goto out_ahb_clk_unprepare;
nfc->reset = devm_reset_control_get_optional_exclusive(dev, "ahb");
if (IS_ERR(nfc->reset)) {
ret = PTR_ERR(nfc->reset);
goto out_mod_clk_unprepare;
}
if (IS_ERR(nfc->reset))
return PTR_ERR(nfc->reset);
ret = reset_control_deassert(nfc->reset);
if (ret) {
dev_err(dev, "reset err %d\n", ret);
goto out_mod_clk_unprepare;
return ret;
}
nfc->caps = of_device_get_match_data(&pdev->dev);
@ -2165,10 +2152,6 @@ out_release_dmac:
dma_release_channel(nfc->dmac);
out_ahb_reset_reassert:
reset_control_assert(nfc->reset);
out_mod_clk_unprepare:
clk_disable_unprepare(nfc->mod_clk);
out_ahb_clk_unprepare:
clk_disable_unprepare(nfc->ahb_clk);
return ret;
}
@ -2183,8 +2166,6 @@ static void sunxi_nfc_remove(struct platform_device *pdev)
if (nfc->dmac)
dma_release_channel(nfc->dmac);
clk_disable_unprepare(nfc->mod_clk);
clk_disable_unprepare(nfc->ahb_clk);
}
static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {

View File

@ -827,30 +827,24 @@ static int vf610_nfc_probe(struct platform_device *pdev)
mtd->name = DRV_NAME;
irq = platform_get_irq(pdev, 0);
if (irq <= 0)
return -EINVAL;
if (irq < 0)
return irq;
nfc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(nfc->regs))
return PTR_ERR(nfc->regs);
nfc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(nfc->clk))
nfc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(nfc->clk)) {
dev_err(nfc->dev, "Unable to get and enable clock!\n");
return PTR_ERR(nfc->clk);
err = clk_prepare_enable(nfc->clk);
if (err) {
dev_err(nfc->dev, "Unable to enable clock!\n");
return err;
}
of_id = of_match_device(vf610_nfc_dt_ids, &pdev->dev);
if (!of_id) {
err = -ENODEV;
goto err_disable_clk;
}
if (!of_id)
return -ENODEV;
nfc->variant = (enum vf610_nfc_variant)of_id->data;
nfc->variant = (uintptr_t)of_id->data;
for_each_available_child_of_node(nfc->dev->of_node, child) {
if (of_device_is_compatible(child, "fsl,vf610-nfc-nandcs")) {
@ -858,9 +852,8 @@ static int vf610_nfc_probe(struct platform_device *pdev)
if (nand_get_flash_node(chip)) {
dev_err(nfc->dev,
"Only one NAND chip supported!\n");
err = -EINVAL;
of_node_put(child);
goto err_disable_clk;
return -EINVAL;
}
nand_set_flash_node(chip, child);
@ -869,8 +862,7 @@ static int vf610_nfc_probe(struct platform_device *pdev)
if (!nand_get_flash_node(chip)) {
dev_err(nfc->dev, "NAND chip sub-node missing!\n");
err = -ENODEV;
goto err_disable_clk;
return -ENODEV;
}
chip->options |= NAND_NO_SUBPAGE_WRITE;
@ -880,7 +872,7 @@ static int vf610_nfc_probe(struct platform_device *pdev)
err = devm_request_irq(nfc->dev, irq, vf610_nfc_irq, 0, DRV_NAME, nfc);
if (err) {
dev_err(nfc->dev, "Error requesting IRQ!\n");
goto err_disable_clk;
return err;
}
vf610_nfc_preinit_controller(nfc);
@ -892,7 +884,7 @@ static int vf610_nfc_probe(struct platform_device *pdev)
/* Scan the NAND chip */
err = nand_scan(chip, 1);
if (err)
goto err_disable_clk;
return err;
platform_set_drvdata(pdev, nfc);
@ -904,8 +896,6 @@ static int vf610_nfc_probe(struct platform_device *pdev)
err_cleanup_nand:
nand_cleanup(chip);
err_disable_clk:
clk_disable_unprepare(nfc->clk);
return err;
}
@ -918,7 +908,6 @@ static void vf610_nfc_remove(struct platform_device *pdev)
ret = mtd_device_unregister(nand_to_mtd(chip));
WARN_ON(ret);
nand_cleanup(chip);
clk_disable_unprepare(nfc->clk);
}
#ifdef CONFIG_PM_SLEEP

View File

@ -7,7 +7,8 @@
#include <linux/mtd/rawnand.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <lantiq_soc.h>

View File

@ -121,6 +121,15 @@ static const struct spinand_info esmt_c8_spinand_table[] = {
&update_cache_variants),
0,
SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
SPINAND_INFO("F50D2G41KA",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 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 = {

View File

@ -511,6 +511,26 @@ static const struct spinand_info gigadevice_spinand_table[] = {
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
gd5fxgq4uexxg_ecc_get_status)),
SPINAND_INFO("GD5F1GQ5RExxH",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x21),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
gd5fxgq4uexxg_ecc_get_status)),
SPINAND_INFO("GD5F1GQ4RExxH",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xc9),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
gd5fxgq4uexxg_ecc_get_status)),
};
static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {

View File

@ -266,6 +266,39 @@ static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 1.8V 1Gb (1st generation) */
SPINAND_INFO("TC58NYG0S3HBAI4",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1),
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 1.8V 4Gb (1st generation) */
SPINAND_INFO("TH58NYG2S3HBAI4",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAC),
NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 2, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
&update_cache_x4_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
/* 1.8V 8Gb (1st generation) */
SPINAND_INFO("TH58NYG3S0HBAI6",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA3),
NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_x4_variants,
&update_cache_x4_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
tx58cxgxsxraix_ecc_get_status)),
};
static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {

View File

@ -48,9 +48,11 @@ static const struct spi_nor_locking_ops at25fs_nor_locking_ops = {
.is_locked = at25fs_nor_is_locked,
};
static void at25fs_nor_late_init(struct spi_nor *nor)
static int at25fs_nor_late_init(struct spi_nor *nor)
{
nor->params->locking_ops = &at25fs_nor_locking_ops;
return 0;
}
static const struct spi_nor_fixups at25fs_nor_fixups = {
@ -149,9 +151,11 @@ static const struct spi_nor_locking_ops atmel_nor_global_protection_ops = {
.is_locked = atmel_nor_is_global_protected,
};
static void atmel_nor_global_protection_late_init(struct spi_nor *nor)
static int atmel_nor_global_protection_late_init(struct spi_nor *nor)
{
nor->params->locking_ops = &atmel_nor_global_protection_ops;
return 0;
}
static const struct spi_nor_fixups atmel_nor_global_protection_fixups = {

View File

@ -17,7 +17,6 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/spi-nor.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
@ -395,30 +394,18 @@ static int nxp_spifi_probe(struct platform_device *pdev)
if (IS_ERR(spifi->flash_base))
return PTR_ERR(spifi->flash_base);
spifi->clk_spifi = devm_clk_get(&pdev->dev, "spifi");
spifi->clk_spifi = devm_clk_get_enabled(&pdev->dev, "spifi");
if (IS_ERR(spifi->clk_spifi)) {
dev_err(&pdev->dev, "spifi clock not found\n");
dev_err(&pdev->dev, "spifi clock not found or unable to enable\n");
return PTR_ERR(spifi->clk_spifi);
}
spifi->clk_reg = devm_clk_get(&pdev->dev, "reg");
spifi->clk_reg = devm_clk_get_enabled(&pdev->dev, "reg");
if (IS_ERR(spifi->clk_reg)) {
dev_err(&pdev->dev, "reg clock not found\n");
dev_err(&pdev->dev, "reg clock not found or unable to enable\n");
return PTR_ERR(spifi->clk_reg);
}
ret = clk_prepare_enable(spifi->clk_reg);
if (ret) {
dev_err(&pdev->dev, "unable to enable reg clock\n");
return ret;
}
ret = clk_prepare_enable(spifi->clk_spifi);
if (ret) {
dev_err(&pdev->dev, "unable to enable spifi clock\n");
goto dis_clk_reg;
}
spifi->dev = &pdev->dev;
platform_set_drvdata(pdev, spifi);
@ -431,24 +418,17 @@ static int nxp_spifi_probe(struct platform_device *pdev)
flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
if (!flash_np) {
dev_err(&pdev->dev, "no SPI flash device to configure\n");
ret = -ENODEV;
goto dis_clks;
return -ENODEV;
}
ret = nxp_spifi_setup_flash(spifi, flash_np);
of_node_put(flash_np);
if (ret) {
dev_err(&pdev->dev, "unable to setup flash chip\n");
goto dis_clks;
return ret;
}
return 0;
dis_clks:
clk_disable_unprepare(spifi->clk_spifi);
dis_clk_reg:
clk_disable_unprepare(spifi->clk_reg);
return ret;
}
static int nxp_spifi_remove(struct platform_device *pdev)
@ -456,8 +436,6 @@ static int nxp_spifi_remove(struct platform_device *pdev)
struct nxp_spifi *spifi = platform_get_drvdata(pdev);
mtd_device_unregister(&spifi->nor.mtd);
clk_disable_unprepare(spifi->clk_spifi);
clk_disable_unprepare(spifi->clk_reg);
return 0;
}

View File

@ -870,21 +870,22 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1)
ret = spi_nor_read_cr(nor, &sr_cr[1]);
if (ret)
return ret;
} else if (nor->params->quad_enable) {
} else if (spi_nor_get_protocol_width(nor->read_proto) == 4 &&
spi_nor_get_protocol_width(nor->write_proto) == 4 &&
nor->params->quad_enable) {
/*
* If the Status Register 2 Read command (35h) is not
* supported, we should at least be sure we don't
* change the value of the SR2 Quad Enable bit.
*
* We can safely assume that when the Quad Enable method is
* set, the value of the QE bit is one, as a consequence of the
* nor->params->quad_enable() call.
* When the Quad Enable method is set and the buswidth is 4, we
* can safely assume that the value of the QE bit is one, as a
* consequence of the nor->params->quad_enable() call.
*
* We can safely assume that the Quad Enable bit is present in
* the Status Register 2 at BIT(1). According to the JESD216
* revB standard, BFPT DWORDS[15], bits 22:20, the 16-bit
* Write Status (01h) command is available just for the cases
* in which the QE bit is described in SR2 at BIT(1).
* According to the JESD216 revB standard, BFPT DWORDS[15],
* bits 22:20, the 16-bit Write Status (01h) command is
* available just for the cases in which the QE bit is
* described in SR2 at BIT(1).
*/
sr_cr[1] = SR2_QUAD_EN_BIT1;
} else {
@ -2844,6 +2845,9 @@ static void spi_nor_init_flags(struct spi_nor *nor)
if (of_property_read_bool(np, "broken-flash-reset"))
nor->flags |= SNOR_F_BROKEN_RESET;
if (of_property_read_bool(np, "no-wp"))
nor->flags |= SNOR_F_NO_WP;
if (flags & SPI_NOR_SWP_IS_VOLATILE)
nor->flags |= SNOR_F_SWP_IS_VOLATILE;
@ -2897,16 +2901,23 @@ static void spi_nor_init_fixup_flags(struct spi_nor *nor)
* SFDP standard, or where SFDP tables are not defined at all.
* Will replace the spi_nor_manufacturer_init_params() method.
*/
static void spi_nor_late_init_params(struct spi_nor *nor)
static int spi_nor_late_init_params(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
int ret;
if (nor->manufacturer && nor->manufacturer->fixups &&
nor->manufacturer->fixups->late_init)
nor->manufacturer->fixups->late_init(nor);
nor->manufacturer->fixups->late_init) {
ret = nor->manufacturer->fixups->late_init(nor);
if (ret)
return ret;
}
if (nor->info->fixups && nor->info->fixups->late_init)
nor->info->fixups->late_init(nor);
if (nor->info->fixups && nor->info->fixups->late_init) {
ret = nor->info->fixups->late_init(nor);
if (ret)
return ret;
}
/* Default method kept for backward compatibility. */
if (!params->set_4byte_addr_mode)
@ -2924,6 +2935,8 @@ static void spi_nor_late_init_params(struct spi_nor *nor)
if (nor->info->n_banks > 1)
params->bank_size = div64_u64(params->size, nor->info->n_banks);
return 0;
}
/**
@ -3082,22 +3095,20 @@ static int spi_nor_init_params(struct spi_nor *nor)
spi_nor_init_params_deprecated(nor);
}
spi_nor_late_init_params(nor);
return 0;
return spi_nor_late_init_params(nor);
}
/** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed
/** spi_nor_set_octal_dtr() - enable or disable Octal DTR I/O.
* @nor: pointer to a 'struct spi_nor'
* @enable: whether to enable or disable Octal DTR
*
* Return: 0 on success, -errno otherwise.
*/
static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
static int spi_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
{
int ret;
if (!nor->params->octal_dtr_enable)
if (!nor->params->set_octal_dtr)
return 0;
if (!(nor->read_proto == SNOR_PROTO_8_8_8_DTR &&
@ -3107,7 +3118,7 @@ static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE))
return 0;
ret = nor->params->octal_dtr_enable(nor, enable);
ret = nor->params->set_octal_dtr(nor, enable);
if (ret)
return ret;
@ -3168,7 +3179,7 @@ static int spi_nor_init(struct spi_nor *nor)
{
int err;
err = spi_nor_octal_dtr_enable(nor, true);
err = spi_nor_set_octal_dtr(nor, true);
if (err) {
dev_dbg(nor->dev, "octal mode not supported\n");
return err;
@ -3270,7 +3281,7 @@ static int spi_nor_suspend(struct mtd_info *mtd)
int ret;
/* Disable octal DTR mode if we enabled it. */
ret = spi_nor_octal_dtr_enable(nor, false);
ret = spi_nor_set_octal_dtr(nor, false);
if (ret)
dev_err(nor->dev, "suspend() failed\n");

View File

@ -132,6 +132,7 @@ enum spi_nor_option_flags {
SNOR_F_SWP_IS_VOLATILE = BIT(13),
SNOR_F_RWW = BIT(14),
SNOR_F_ECC = BIT(15),
SNOR_F_NO_WP = BIT(16),
};
struct spi_nor_read_command {
@ -363,7 +364,7 @@ struct spi_nor_otp {
* @erase_map: the erase map parsed from the SFDP Sector Map Parameter
* Table.
* @otp: SPI NOR OTP info.
* @octal_dtr_enable: enables SPI NOR octal DTR mode.
* @set_octal_dtr: enables or disables SPI NOR octal DTR mode.
* @quad_enable: enables SPI NOR quad mode.
* @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode.
* @convert_addr: converts an absolute address into something the flash
@ -377,6 +378,7 @@ struct spi_nor_otp {
* than reading the status register to indicate they
* are ready for a new command
* @locking_ops: SPI NOR locking methods.
* @priv: flash's private data.
*/
struct spi_nor_flash_parameter {
u64 bank_size;
@ -397,7 +399,7 @@ struct spi_nor_flash_parameter {
struct spi_nor_erase_map erase_map;
struct spi_nor_otp otp;
int (*octal_dtr_enable)(struct spi_nor *nor, bool enable);
int (*set_octal_dtr)(struct spi_nor *nor, bool enable);
int (*quad_enable)(struct spi_nor *nor);
int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable);
u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
@ -405,6 +407,7 @@ struct spi_nor_flash_parameter {
int (*ready)(struct spi_nor *nor);
const struct spi_nor_locking_ops *locking_ops;
void *priv;
};
/**
@ -431,7 +434,7 @@ struct spi_nor_fixups {
const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt);
int (*post_sfdp)(struct spi_nor *nor);
void (*late_init)(struct spi_nor *nor);
int (*late_init)(struct spi_nor *nor);
};
/**

View File

@ -27,6 +27,7 @@ static const char *const snor_f_names[] = {
SNOR_F_NAME(SWP_IS_VOLATILE),
SNOR_F_NAME(RWW),
SNOR_F_NAME(ECC),
SNOR_F_NAME(NO_WP),
};
#undef SNOR_F_NAME

View File

@ -29,7 +29,7 @@ static const struct spi_nor_fixups is25lp256_fixups = {
.post_bfpt = is25lp256_post_bfpt_fixups,
};
static void pm25lv_nor_late_init(struct spi_nor *nor)
static int pm25lv_nor_late_init(struct spi_nor *nor)
{
struct spi_nor_erase_map *map = &nor->params->erase_map;
int i;
@ -38,6 +38,8 @@ static void pm25lv_nor_late_init(struct spi_nor *nor)
for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++)
if (map->erase_type[i].size == 4096)
map->erase_type[i].opcode = SPINOR_OP_BE_4K_PMC;
return 0;
}
static const struct spi_nor_fixups pm25lv_nor_fixups = {

View File

@ -110,10 +110,12 @@ static void macronix_nor_default_init(struct spi_nor *nor)
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
}
static void macronix_nor_late_init(struct spi_nor *nor)
static int 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;
return 0;
}
static const struct spi_nor_fixups macronix_nor_fixups = {

View File

@ -120,7 +120,7 @@ static int micron_st_nor_octal_dtr_dis(struct spi_nor *nor)
return 0;
}
static int micron_st_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
static int micron_st_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
{
return enable ? micron_st_nor_octal_dtr_en(nor) :
micron_st_nor_octal_dtr_dis(nor);
@ -128,7 +128,7 @@ static int micron_st_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
static void mt35xu512aba_default_init(struct spi_nor *nor)
{
nor->params->octal_dtr_enable = micron_st_nor_octal_dtr_enable;
nor->params->set_octal_dtr = micron_st_nor_set_octal_dtr;
}
static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
@ -429,7 +429,7 @@ static void micron_st_nor_default_init(struct spi_nor *nor)
nor->params->quad_enable = NULL;
}
static void micron_st_nor_late_init(struct spi_nor *nor)
static int micron_st_nor_late_init(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
@ -438,6 +438,8 @@ static void micron_st_nor_late_init(struct spi_nor *nor)
if (!params->set_4byte_addr_mode)
params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;
return 0;
}
static const struct spi_nor_fixups micron_st_nor_fixups = {

View File

@ -4,14 +4,19 @@
* Copyright (C) 2014, Freescale Semiconductor, Inc.
*/
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/mtd/spi-nor.h>
#include "core.h"
/* flash_info mfr_flag. Used to clear sticky prorietary SR bits. */
#define USE_CLSR BIT(0)
#define USE_CLPEF BIT(1)
#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
#define SPINOR_OP_CLPEF 0x82 /* Clear program/erase failure flags */
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
#define SPINOR_REG_CYPRESS_VREG 0x00800000
@ -19,21 +24,16 @@
#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_CFR2 0x3
#define SPINOR_REG_CYPRESS_CFR2V \
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR2)
#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK GENMASK(3, 0)
#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb
#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_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)
@ -57,22 +57,32 @@
SPI_MEM_OP_DUMMY(ndummy, 0), \
SPI_MEM_OP_DATA_IN(1, buf, 0))
#define SPANSION_CLSR_OP \
SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0), \
#define SPANSION_OP(opcode) \
SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0), \
SPI_MEM_OP_NO_ADDR, \
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA)
/**
* struct spansion_nor_params - Spansion private parameters.
* @clsr: Clear Status Register or Clear Program and Erase Failure Flag
* opcode.
*/
struct spansion_nor_params {
u8 clsr;
};
/**
* spansion_nor_clear_sr() - Clear the Status Register.
* @nor: pointer to 'struct spi_nor'.
*/
static void spansion_nor_clear_sr(struct spi_nor *nor)
{
const struct spansion_nor_params *priv_params = nor->params->priv;
int ret;
if (nor->spimem) {
struct spi_mem_op op = SPANSION_CLSR_OP;
struct spi_mem_op op = SPANSION_OP(priv_params->clsr);
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
@ -88,11 +98,17 @@ static void spansion_nor_clear_sr(struct spi_nor *nor)
static int cypress_nor_sr_ready_and_clear_reg(struct spi_nor *nor, u64 addr)
{
struct spi_nor_flash_parameter *params = nor->params;
struct spi_mem_op op =
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, addr,
CYPRESS_NOR_RD_ANY_REG_OP(params->addr_mode_nbytes, addr,
0, nor->bouncebuf);
int ret;
if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
op.dummy.nbytes = params->rdsr_dummy;
op.data.nbytes = 2;
}
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
@ -141,18 +157,26 @@ static int cypress_nor_sr_ready_and_clear(struct spi_nor *nor)
return 1;
}
static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
static int cypress_nor_set_memlat(struct spi_nor *nor, u64 addr)
{
struct spi_mem_op op;
u8 *buf = nor->bouncebuf;
int ret;
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
/* Use 24 dummy cycles for memory array reads. */
*buf = SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24;
op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR2V, 1, buf);
CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0, buf);
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
/* Use 24 dummy cycles for memory array reads. */
*buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK;
*buf |= FIELD_PREP(SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK,
SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24);
op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, addr, 1, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
@ -160,15 +184,41 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
nor->read_dummy = 24;
return 0;
}
static int cypress_nor_set_octal_dtr_bits(struct spi_nor *nor, u64 addr)
{
struct spi_mem_op op;
u8 *buf = nor->bouncebuf;
/* Set the octal and DTR enable bits. */
buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN;
op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
SPINOR_REG_CYPRESS_CFR5V, 1, buf);
CYPRESS_NOR_WR_ANY_REG_OP(nor->params->addr_mode_nbytes,
addr, 1, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
return spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
}
static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
{
const struct spi_nor_flash_parameter *params = nor->params;
u8 *buf = nor->bouncebuf;
u64 addr;
int i, ret;
for (i = 0; i < params->n_dice; i++) {
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR2;
ret = cypress_nor_set_memlat(nor, addr);
if (ret)
return ret;
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5;
ret = cypress_nor_set_octal_dtr_bits(nor, addr);
if (ret)
return ret;
}
/* Read flash ID to make sure the switch was successful. */
ret = spi_nor_read_id(nor, nor->addr_nbytes, 3, buf,
@ -184,11 +234,10 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
return 0;
}
static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
static int cypress_nor_set_single_spi_bits(struct spi_nor *nor, u64 addr)
{
struct spi_mem_op op;
u8 *buf = nor->bouncebuf;
int ret;
/*
* The register is 1-byte wide, but 1-byte transactions are not allowed
@ -198,11 +247,23 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS;
buf[1] = 0;
op = (struct spi_mem_op)
CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes,
SPINOR_REG_CYPRESS_CFR5V, 2, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
if (ret)
return ret;
CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, addr, 2, buf);
return spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
}
static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
{
const struct spi_nor_flash_parameter *params = nor->params;
u8 *buf = nor->bouncebuf;
u64 addr;
int i, ret;
for (i = 0; i < params->n_dice; i++) {
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5;
ret = cypress_nor_set_single_spi_bits(nor, addr);
if (ret)
return ret;
}
/* Read flash ID to make sure the switch was successful. */
ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1);
@ -283,10 +344,6 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
u8 i;
int ret;
if (!params->n_dice)
return cypress_nor_quad_enable_volatile_reg(nor,
SPINOR_REG_CYPRESS_CFR1V);
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);
@ -408,28 +465,17 @@ static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor)
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, 0,
nor->bouncebuf);
int ret;
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3_PGSZ)
nor->params->page_size = 512;
else
nor->params->page_size = 256;
return 0;
}
static int cypress_nor_get_page_size_mcp(struct spi_nor *nor)
/**
* 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)
{
struct spi_mem_op op =
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
@ -459,23 +505,6 @@ static int cypress_nor_get_page_size_mcp(struct spi_nor *nor)
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)
{
/*
@ -512,25 +541,39 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
if (nor->bouncebuf[0])
return -ENODEV;
return cypress_nor_get_page_size(nor);
return 0;
}
static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
/*
* S25FS256T does not define the SCCR map, but we would like to use the
* same code base for both single and multi chip package devices, thus
* set the vreg_offset and n_dice to be able to do so.
*/
params->vreg_offset = devm_kmalloc(nor->dev, sizeof(u32), GFP_KERNEL);
if (!params->vreg_offset)
return -ENOMEM;
params->vreg_offset[0] = SPINOR_REG_CYPRESS_VREG;
params->n_dice = 1;
/* 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;
return cypress_nor_get_page_size(nor);
}
static void s25fs256t_late_init(struct spi_nor *nor)
static int s25fs256t_late_init(struct spi_nor *nor)
{
cypress_nor_ecc_init(nor);
return 0;
}
static struct spi_nor_fixups s25fs256t_fixups = {
@ -558,10 +601,20 @@ s25hx_t_post_bfpt_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;
struct spi_nor_flash_parameter *params = nor->params;
struct spi_nor_erase_type *erase_type = params->erase_map.erase_type;
unsigned int i;
if (!params->n_dice || !params->vreg_offset) {
dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n",
__func__);
return -EOPNOTSUPP;
}
/* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
if (params->size == SZ_256M)
params->n_dice = 2;
/*
* In some parts, 3byte erase opcodes are advertised by 4BAIT.
* Convert them to 4byte erase opcodes.
@ -579,25 +632,19 @@ static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
}
}
/* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
if (nor->params->size == SZ_256M)
nor->params->n_dice = 2;
return cypress_nor_get_page_size(nor);
}
static void s25hx_t_late_init(struct spi_nor *nor)
static int s25hx_t_late_init(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
/* Fast Read 4B requires mode cycles */
params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
params->ready = cypress_nor_sr_ready_and_clear;
cypress_nor_ecc_init(nor);
/* Replace ready() with multi die version */
if (params->n_dice)
params->ready = cypress_nor_sr_ready_and_clear;
return 0;
}
static struct spi_nor_fixups s25hx_t_fixups = {
@ -607,7 +654,7 @@ static struct spi_nor_fixups s25hx_t_fixups = {
};
/**
* cypress_nor_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
* cypress_nor_set_octal_dtr() - Enable or disable octal DTR on Cypress flashes.
* @nor: pointer to a 'struct spi_nor'
* @enable: whether to enable or disable Octal DTR
*
@ -616,7 +663,7 @@ static struct spi_nor_fixups s25hx_t_fixups = {
*
* Return: 0 on success, -errno otherwise.
*/
static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
static int cypress_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
{
return enable ? cypress_nor_octal_dtr_en(nor) :
cypress_nor_octal_dtr_dis(nor);
@ -624,22 +671,34 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
if (!params->n_dice || !params->vreg_offset) {
dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n",
__func__);
return -EOPNOTSUPP;
}
/* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
if (params->size == SZ_256M)
params->n_dice = 2;
/*
* On older versions of the flash the xSPI Profile 1.0 table has the
* 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE.
*/
if (nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
if (params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
SPINOR_OP_CYPRESS_RD_FAST;
/* This flash is also missing the 4-byte Page Program opcode bit. */
spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP],
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
/*
* Since xSPI Page Program opcode is backward compatible with
* Legacy SPI, use Legacy SPI opcode there as well.
*/
spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
/*
@ -647,7 +706,7 @@ static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
* address bytes needed for Read Status Register command as 0 but the
* actual value for that is 4.
*/
nor->params->rdsr_addr_nbytes = 4;
params->rdsr_addr_nbytes = 4;
return cypress_nor_get_page_size(nor);
}
@ -656,19 +715,18 @@ static int s28hx_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;
return 0;
return cypress_nor_set_addr_mode_nbytes(nor);
}
static void s28hx_t_late_init(struct spi_nor *nor)
static int s28hx_t_late_init(struct spi_nor *nor)
{
nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable;
struct spi_nor_flash_parameter *params = nor->params;
params->set_octal_dtr = cypress_nor_set_octal_dtr;
params->ready = cypress_nor_sr_ready_and_clear;
cypress_nor_ecc_init(nor);
return 0;
}
static const struct spi_nor_fixups s28hx_t_fixups = {
@ -792,47 +850,59 @@ static const struct flash_info spansion_nor_parts[] = {
FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
{ "s25fs256t", INFO6(0x342b19, 0x0f0890, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLPEF)
.fixups = &s25fs256t_fixups },
{ "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256)
{ "s25hl512t", INFO6(0x342a1a, 0x0f0390, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLSR)
MFR_FLAGS(USE_CLPEF)
.fixups = &s25hx_t_fixups },
{ "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 256 * 1024, 512)
{ "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLSR)
MFR_FLAGS(USE_CLPEF)
.fixups = &s25hx_t_fixups },
{ "s25hl02gt", INFO6(0x342a1c, 0x0f0090, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLPEF)
FLAGS(NO_CHIP_ERASE)
.fixups = &s25hx_t_fixups },
{ "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256)
{ "s25hs512t", INFO6(0x342b1a, 0x0f0390, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLSR)
MFR_FLAGS(USE_CLPEF)
.fixups = &s25hx_t_fixups },
{ "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 256 * 1024, 512)
{ "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLSR)
MFR_FLAGS(USE_CLPEF)
.fixups = &s25hx_t_fixups },
{ "s25hs02gt", INFO6(0x342b1c, 0x0f0090, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLPEF)
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)
{ "s28hl512t", INFO(0x345a1a, 0, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLPEF)
.fixups = &s28hx_t_fixups,
},
{ "s28hl01gt", INFO(0x345a1b, 0, 256 * 1024, 512)
{ "s28hl01gt", INFO(0x345a1b, 0, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLPEF)
.fixups = &s28hx_t_fixups,
},
{ "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256)
{ "s28hs512t", INFO(0x345b1a, 0, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLPEF)
.fixups = &s28hx_t_fixups,
},
{ "s28hs01gt", INFO(0x345b1b, 0, 256 * 1024, 512)
{ "s28hs01gt", INFO(0x345b1b, 0, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLPEF)
.fixups = &s28hx_t_fixups,
},
{ "s28hs02gt", INFO(0x345b1c, 0, 0, 0)
PARSE_SFDP
MFR_FLAGS(USE_CLPEF)
.fixups = &s28hx_t_fixups,
},
};
@ -876,17 +946,35 @@ static int spansion_nor_sr_ready_and_clear(struct spi_nor *nor)
return !(nor->bouncebuf[0] & SR_WIP);
}
static void spansion_nor_late_init(struct spi_nor *nor)
static int spansion_nor_late_init(struct spi_nor *nor)
{
if (nor->params->size > SZ_16M) {
struct spi_nor_flash_parameter *params = nor->params;
struct spansion_nor_params *priv_params;
u8 mfr_flags = nor->info->mfr_flags;
if (params->size > SZ_16M) {
nor->flags |= SNOR_F_4B_OPCODES;
/* No small sector erase for 4-byte command set */
nor->erase_opcode = SPINOR_OP_SE;
nor->mtd.erasesize = nor->info->sector_size;
}
if (nor->info->mfr_flags & USE_CLSR)
nor->params->ready = spansion_nor_sr_ready_and_clear;
if (mfr_flags & (USE_CLSR | USE_CLPEF)) {
priv_params = devm_kmalloc(nor->dev, sizeof(*priv_params),
GFP_KERNEL);
if (!priv_params)
return -ENOMEM;
if (mfr_flags & USE_CLSR)
priv_params->clsr = SPINOR_OP_CLSR;
else if (mfr_flags & USE_CLPEF)
priv_params->clsr = SPINOR_OP_CLPEF;
params->priv = priv_params;
params->ready = spansion_nor_sr_ready_and_clear;
}
return 0;
}
static const struct spi_nor_fixups spansion_nor_fixups = {

View File

@ -49,9 +49,11 @@ static const struct spi_nor_locking_ops sst26vf_nor_locking_ops = {
.is_locked = sst26vf_nor_is_locked,
};
static void sst26vf_nor_late_init(struct spi_nor *nor)
static int sst26vf_nor_late_init(struct spi_nor *nor)
{
nor->params->locking_ops = &sst26vf_nor_locking_ops;
return 0;
}
static const struct spi_nor_fixups sst26vf_nor_fixups = {
@ -111,6 +113,10 @@ static const struct flash_info sst_nor_parts[] = {
SPI_NOR_QUAD_READ) },
{ "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
{ "sst26vf032b", INFO(0xbf2642, 0, 0, 0)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
PARSE_SFDP
.fixups = &sst26vf_nor_fixups },
{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128)
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
@ -203,10 +209,12 @@ out:
return ret;
}
static void sst_nor_late_init(struct spi_nor *nor)
static int sst_nor_late_init(struct spi_nor *nor)
{
if (nor->info->mfr_flags & SST_WRITE)
nor->mtd._write = sst_nor_write;
return 0;
}
static const struct spi_nor_fixups sst_nor_fixups = {

View File

@ -214,8 +214,13 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
status_new = (status_old & ~mask & ~tb_mask) | val;
/* Disallow further writes if WP pin is asserted */
status_new |= SR_SRWD;
/*
* Disallow further writes if WP# pin is neither left floating nor
* wrongly tied to GND (that includes internal pull-downs).
* WP# pin hard strapped to GND can be a valid use case.
*/
if (!(nor->flags & SNOR_F_NO_WP))
status_new |= SR_SRWD;
if (!use_top)
status_new |= tb_mask;

View File

@ -120,8 +120,9 @@ static const struct flash_info winbond_nor_parts[] = {
NO_SFDP_FLAGS(SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16)
NO_SFDP_FLAGS(SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256)
NO_SFDP_FLAGS(SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 0, 0)
PARSE_SFDP
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512)
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
.fixups = &w25q256_fixups },
@ -216,7 +217,7 @@ static const struct spi_nor_otp_ops winbond_nor_otp_ops = {
.is_locked = spi_nor_otp_is_locked_sr2,
};
static void winbond_nor_late_init(struct spi_nor *nor)
static int winbond_nor_late_init(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
@ -232,6 +233,8 @@ static void winbond_nor_late_init(struct spi_nor *nor)
* from BFPT, if any.
*/
params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode;
return 0;
}
static const struct spi_nor_fixups winbond_nor_fixups = {

View File

@ -155,10 +155,12 @@ static int xilinx_nor_setup(struct spi_nor *nor,
return 0;
}
static void xilinx_nor_late_init(struct spi_nor *nor)
static int xilinx_nor_late_init(struct spi_nor *nor)
{
nor->params->setup = xilinx_nor_setup;
nor->params->ready = xilinx_nor_sr_ready;
return 0;
}
static const struct spi_nor_fixups xilinx_nor_fixups = {

View File

@ -379,7 +379,7 @@ struct mtd_info {
struct module *owner;
struct device dev;
int usecount;
struct kref refcnt;
struct mtd_debug_info dbg;
struct nvmem_device *nvmem;
struct nvmem_device *otp_user_nvmem;

View File

@ -1540,6 +1540,7 @@ int nand_reset_op(struct nand_chip *chip);
int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf,
unsigned int len);
int nand_status_op(struct nand_chip *chip, u8 *status);
int nand_exit_status_op(struct nand_chip *chip);
int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock);
int nand_read_page_op(struct nand_chip *chip, unsigned int page,
unsigned int offset_in_page, void *buf, unsigned int len);