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:
commit
bac8a20fa3
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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#
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
44
Documentation/devicetree/bindings/mtd/partitions/seama.yaml
Normal file
44
Documentation/devicetree/bindings/mtd/partitions/seama.yaml
Normal 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";
|
||||
};
|
||||
};
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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, <q_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;
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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 */
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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[] = {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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[] = {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
@ -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
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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(¶ms->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(¶ms->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(¶ms->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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -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 = {
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user