diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2018-11-21 11:18:30 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2018-11-21 11:18:30 +1100 |
commit | e5550b5eaf7b9d15acb982188af18fb9e5ed2565 (patch) | |
tree | 0eb89902aa98128685a125b5a7632ac57b5f60c3 /drivers | |
parent | c00ff0caa9f359ad565f07c11e79cba604c1b7a3 (diff) | |
parent | c41b8b4e44ebd1a7d49f13445cde0182c3b77e8d (diff) |
Merge remote-tracking branch 'nand/nand/next'
Diffstat (limited to 'drivers')
50 files changed, 1017 insertions, 1860 deletions
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index c7efc31384d5..1a55d3e3d4c5 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -70,7 +70,7 @@ config MTD_NAND_GPIO config MTD_NAND_AMS_DELTA tristate "NAND Flash device on Amstrad E3" - depends on MACH_AMS_DELTA + depends on MACH_AMS_DELTA || COMPILE_TEST default y help Support for NAND flash on Amstrad E3 (Delta). diff --git a/drivers/mtd/nand/raw/ams-delta.c b/drivers/mtd/nand/raw/ams-delta.c index 5ba180a291eb..f8eb4a419e77 100644 --- a/drivers/mtd/nand/raw/ams-delta.c +++ b/drivers/mtd/nand/raw/ams-delta.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li> * @@ -8,10 +9,6 @@ * Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> * Partially stolen from plat_nand.c * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Overview: * This is a device driver for the NAND flash device found on the * Amstrad E3 (Delta). @@ -21,21 +18,18 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> +#include <linux/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/rawnand.h> #include <linux/mtd/partitions.h> #include <linux/platform_data/gpio-omap.h> - -#include <asm/io.h> -#include <asm/sizes.h> - -#include <mach/hardware.h> +#include <linux/sizes.h> /* * MTD structure for E3 (Delta) */ - struct ams_delta_nand { + struct nand_controller base; struct nand_chip nand_chip; struct gpio_desc *gpiod_rdy; struct gpio_desc *gpiod_nce; @@ -73,21 +67,21 @@ static const struct mtd_partition partition_info[] = { .size = 3 * SZ_256K }, }; -static void ams_delta_io_write(struct ams_delta_nand *priv, u_char byte) +static void ams_delta_io_write(struct ams_delta_nand *priv, u8 byte) { - writew(byte, priv->nand_chip.legacy.IO_ADDR_W); + writew(byte, priv->io_base + OMAP_MPUIO_OUTPUT); gpiod_set_value(priv->gpiod_nwe, 0); ndelay(40); gpiod_set_value(priv->gpiod_nwe, 1); } -static u_char ams_delta_io_read(struct ams_delta_nand *priv) +static u8 ams_delta_io_read(struct ams_delta_nand *priv) { - u_char res; + u8 res; gpiod_set_value(priv->gpiod_nre, 0); ndelay(40); - res = readw(priv->nand_chip.legacy.IO_ADDR_R); + res = readw(priv->io_base + OMAP_MPUIO_INPUT_LATCH); gpiod_set_value(priv->gpiod_nre, 1); return res; @@ -99,10 +93,9 @@ static void ams_delta_dir_input(struct ams_delta_nand *priv, bool in) priv->data_in = in; } -static void ams_delta_write_buf(struct nand_chip *this, const u_char *buf, +static void ams_delta_write_buf(struct ams_delta_nand *priv, const u8 *buf, int len) { - struct ams_delta_nand *priv = nand_get_controller_data(this); int i; if (priv->data_in) @@ -112,9 +105,8 @@ static void ams_delta_write_buf(struct nand_chip *this, const u_char *buf, ams_delta_io_write(priv, buf[i]); } -static void ams_delta_read_buf(struct nand_chip *this, u_char *buf, int len) +static void ams_delta_read_buf(struct ams_delta_nand *priv, u8 *buf, int len) { - struct ams_delta_nand *priv = nand_get_controller_data(this); int i; if (!priv->data_in) @@ -124,48 +116,69 @@ static void ams_delta_read_buf(struct nand_chip *this, u_char *buf, int len) buf[i] = ams_delta_io_read(priv); } -static u_char ams_delta_read_byte(struct nand_chip *this) +static void ams_delta_ctrl_cs(struct ams_delta_nand *priv, bool assert) { - u_char res; - - ams_delta_read_buf(this, &res, 1); - - return res; + gpiod_set_value(priv->gpiod_nce, assert ? 0 : 1); } -/* - * Command control function - * - * ctrl: - * NAND_NCE: bit 0 -> bit 2 - * NAND_CLE: bit 1 -> bit 7 - * NAND_ALE: bit 2 -> bit 6 - */ -static void ams_delta_hwcontrol(struct nand_chip *this, int cmd, - unsigned int ctrl) +static int ams_delta_exec_op(struct nand_chip *this, + const struct nand_operation *op, bool check_only) { struct ams_delta_nand *priv = nand_get_controller_data(this); - - if (ctrl & NAND_CTRL_CHANGE) { - gpiod_set_value(priv->gpiod_nce, !(ctrl & NAND_NCE)); - gpiod_set_value(priv->gpiod_cle, !!(ctrl & NAND_CLE)); - gpiod_set_value(priv->gpiod_ale, !!(ctrl & NAND_ALE)); - } - - if (cmd != NAND_CMD_NONE) { - u_char byte = cmd; - - ams_delta_write_buf(this, &byte, 1); + const struct nand_op_instr *instr; + int ret = 0; + + if (check_only) + return 0; + + ams_delta_ctrl_cs(priv, 1); + + for (instr = op->instrs; instr < op->instrs + op->ninstrs; instr++) { + switch (instr->type) { + case NAND_OP_CMD_INSTR: + gpiod_set_value(priv->gpiod_cle, 1); + ams_delta_write_buf(priv, &instr->ctx.cmd.opcode, 1); + gpiod_set_value(priv->gpiod_cle, 0); + break; + + case NAND_OP_ADDR_INSTR: + gpiod_set_value(priv->gpiod_ale, 1); + ams_delta_write_buf(priv, instr->ctx.addr.addrs, + instr->ctx.addr.naddrs); + gpiod_set_value(priv->gpiod_ale, 0); + break; + + case NAND_OP_DATA_IN_INSTR: + ams_delta_read_buf(priv, instr->ctx.data.buf.in, + instr->ctx.data.len); + break; + + case NAND_OP_DATA_OUT_INSTR: + ams_delta_write_buf(priv, instr->ctx.data.buf.out, + instr->ctx.data.len); + break; + + case NAND_OP_WAITRDY_INSTR: + ret = priv->gpiod_rdy ? + nand_gpio_waitrdy(this, priv->gpiod_rdy, + instr->ctx.waitrdy.timeout_ms) : + nand_soft_waitrdy(this, + instr->ctx.waitrdy.timeout_ms); + break; + } + + if (ret) + break; } -} -static int ams_delta_nand_ready(struct nand_chip *this) -{ - struct ams_delta_nand *priv = nand_get_controller_data(this); + ams_delta_ctrl_cs(priv, 0); - return gpiod_get_value(priv->gpiod_rdy); + return ret; } +static const struct nand_controller_ops ams_delta_ops = { + .exec_op = ams_delta_exec_op, +}; /* * Main initialization routine @@ -185,10 +198,9 @@ static int ams_delta_init(struct platform_device *pdev) /* Allocate memory for MTD device structure and private data */ priv = devm_kzalloc(&pdev->dev, sizeof(struct ams_delta_nand), GFP_KERNEL); - if (!priv) { - pr_warn("Unable to allocate E3 NAND MTD device structure.\n"); + if (!priv) return -ENOMEM; - } + this = &priv->nand_chip; mtd = nand_to_mtd(this); @@ -199,37 +211,22 @@ static int ams_delta_init(struct platform_device *pdev) * it should have been already requested from the * gpio-omap driver and requesting it again would fail. */ - io_base = ioremap(res->start, resource_size(res)); - if (io_base == NULL) { + if (!io_base) { dev_err(&pdev->dev, "ioremap failed\n"); - err = -EIO; - goto out_free; + return -EIO; } priv->io_base = io_base; nand_set_controller_data(this, priv); - /* Set address of NAND IO lines */ - this->legacy.IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH; - this->legacy.IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT; - this->legacy.read_byte = ams_delta_read_byte; - this->legacy.write_buf = ams_delta_write_buf; - this->legacy.read_buf = ams_delta_read_buf; - this->legacy.cmd_ctrl = ams_delta_hwcontrol; - priv->gpiod_rdy = devm_gpiod_get_optional(&pdev->dev, "rdy", GPIOD_IN); if (IS_ERR(priv->gpiod_rdy)) { err = PTR_ERR(priv->gpiod_rdy); dev_warn(&pdev->dev, "RDY GPIO request failed (%d)\n", err); - goto out_mtd; + goto err_unmap; } - if (priv->gpiod_rdy) - this->legacy.dev_ready = ams_delta_nand_ready; - - /* 25 us command delay time */ - this->legacy.chip_delay = 30; this->ecc.mode = NAND_ECC_SOFT; this->ecc.algo = NAND_ECC_HAMMING; @@ -240,61 +237,71 @@ static int ams_delta_init(struct platform_device *pdev) if (IS_ERR(priv->gpiod_nwp)) { err = PTR_ERR(priv->gpiod_nwp); dev_err(&pdev->dev, "NWP GPIO request failed (%d)\n", err); - goto out_mtd; + goto err_unmap; } priv->gpiod_nce = devm_gpiod_get(&pdev->dev, "nce", GPIOD_OUT_HIGH); if (IS_ERR(priv->gpiod_nce)) { err = PTR_ERR(priv->gpiod_nce); dev_err(&pdev->dev, "NCE GPIO request failed (%d)\n", err); - goto out_mtd; + goto err_unmap; } priv->gpiod_nre = devm_gpiod_get(&pdev->dev, "nre", GPIOD_OUT_HIGH); if (IS_ERR(priv->gpiod_nre)) { err = PTR_ERR(priv->gpiod_nre); dev_err(&pdev->dev, "NRE GPIO request failed (%d)\n", err); - goto out_mtd; + goto err_unmap; } priv->gpiod_nwe = devm_gpiod_get(&pdev->dev, "nwe", GPIOD_OUT_HIGH); if (IS_ERR(priv->gpiod_nwe)) { err = PTR_ERR(priv->gpiod_nwe); dev_err(&pdev->dev, "NWE GPIO request failed (%d)\n", err); - goto out_mtd; + goto err_unmap; } priv->gpiod_ale = devm_gpiod_get(&pdev->dev, "ale", GPIOD_OUT_LOW); if (IS_ERR(priv->gpiod_ale)) { err = PTR_ERR(priv->gpiod_ale); dev_err(&pdev->dev, "ALE GPIO request failed (%d)\n", err); - goto out_mtd; + goto err_unmap; } priv->gpiod_cle = devm_gpiod_get(&pdev->dev, "cle", GPIOD_OUT_LOW); if (IS_ERR(priv->gpiod_cle)) { err = PTR_ERR(priv->gpiod_cle); dev_err(&pdev->dev, "CLE GPIO request failed (%d)\n", err); - goto out_mtd; + goto err_unmap; } /* Initialize data port direction to a known state */ ams_delta_dir_input(priv, true); + /* Initialize the NAND controller object embedded in ams_delta_nand. */ + priv->base.ops = &ams_delta_ops; + nand_controller_init(&priv->base); + this->controller = &priv->base; + /* Scan to find existence of the device */ err = nand_scan(this, 1); if (err) - goto out_mtd; + goto err_unmap; /* Register the partitions */ - mtd_device_register(mtd, partition_info, ARRAY_SIZE(partition_info)); + err = mtd_device_register(mtd, partition_info, + ARRAY_SIZE(partition_info)); + if (err) + goto err_nand_cleanup; - goto out; + return 0; + +err_nand_cleanup: + nand_cleanup(this); - out_mtd: +err_unmap: iounmap(io_base); -out_free: - out: + return err; } @@ -325,6 +332,6 @@ static struct platform_driver ams_delta_nand_driver = { module_platform_driver(ams_delta_nand_driver); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>"); MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)"); diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index ad720494e8f7..5781fcf6b76c 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1477,10 +1477,10 @@ static void atmel_nand_init(struct atmel_nand_controller *nc, chip->legacy.write_byte = atmel_nand_write_byte; chip->legacy.read_buf = atmel_nand_read_buf; chip->legacy.write_buf = atmel_nand_write_buf; - chip->select_chip = atmel_nand_select_chip; + chip->legacy.select_chip = atmel_nand_select_chip; - if (nc->mck && nc->caps->ops->setup_data_interface) - chip->setup_data_interface = atmel_nand_setup_data_interface; + if (!nc->mck || !nc->caps->ops->setup_data_interface) + chip->options |= NAND_KEEP_TIMINGS; /* Some NANDs require a longer delay than the default one (20us). */ chip->legacy.chip_delay = 40; @@ -1525,7 +1525,7 @@ static void atmel_hsmc_nand_init(struct atmel_nand_controller *nc, /* Overload some methods for the HSMC controller. */ chip->legacy.cmd_ctrl = atmel_hsmc_nand_cmd_ctrl; - chip->select_chip = atmel_hsmc_nand_select_chip; + chip->legacy.select_chip = atmel_hsmc_nand_select_chip; } static int atmel_nand_controller_remove_nand(struct atmel_nand *nand) @@ -1908,6 +1908,7 @@ static int atmel_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops atmel_nand_controller_ops = { .attach_chip = atmel_nand_attach_chip, + .setup_data_interface = atmel_nand_setup_data_interface, }; static int atmel_nand_controller_init(struct atmel_nand_controller *nc, diff --git a/drivers/mtd/nand/raw/au1550nd.c b/drivers/mtd/nand/raw/au1550nd.c index 9731c1c487f6..a963002663ed 100644 --- a/drivers/mtd/nand/raw/au1550nd.c +++ b/drivers/mtd/nand/raw/au1550nd.c @@ -430,7 +430,7 @@ static int au1550nd_probe(struct platform_device *pdev) ctx->cs = cs; this->legacy.dev_ready = au1550_device_ready; - this->select_chip = au1550_select_chip; + this->legacy.select_chip = au1550_select_chip; this->legacy.cmdfunc = au1550_command; /* 30 us command delay time */ diff --git a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c index 9095a79ebc7d..a37cbfe56567 100644 --- a/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c +++ b/drivers/mtd/nand/raw/bcm47xxnflash/ops_bcm4706.c @@ -383,7 +383,7 @@ int bcm47xxnflash_ops_bcm4706_init(struct bcm47xxnflash *b47n) u8 tbits, col_bits, col_size, row_bits, row_bsize; u32 val; - b47n->nand_chip.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; + nand_chip->legacy.select_chip = bcm47xxnflash_ops_bcm4706_select_chip; nand_chip->legacy.cmd_ctrl = bcm47xxnflash_ops_bcm4706_cmd_ctrl; nand_chip->legacy.dev_ready = bcm47xxnflash_ops_bcm4706_dev_ready; b47n->nand_chip.legacy.cmdfunc = bcm47xxnflash_ops_bcm4706_cmdfunc; diff --git a/drivers/mtd/nand/raw/cafe_nand.c b/drivers/mtd/nand/raw/cafe_nand.c index c1a745940d12..a85f5fa5c66d 100644 --- a/drivers/mtd/nand/raw/cafe_nand.c +++ b/drivers/mtd/nand/raw/cafe_nand.c @@ -708,7 +708,7 @@ static int cafe_nand_probe(struct pci_dev *pdev, cafe->nand.legacy.read_byte = cafe_read_byte; cafe->nand.legacy.read_buf = cafe_read_buf; cafe->nand.legacy.write_buf = cafe_write_buf; - cafe->nand.select_chip = cafe_select_chip; + cafe->nand.legacy.select_chip = cafe_select_chip; cafe->nand.legacy.set_features = nand_get_set_features_notsupp; cafe->nand.legacy.get_features = nand_get_set_features_notsupp; diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 80f228d23cd2..f430aeb917e8 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -762,7 +762,7 @@ static int nand_davinci_probe(struct platform_device *pdev) info->chip.legacy.IO_ADDR_R = vaddr; info->chip.legacy.IO_ADDR_W = vaddr; info->chip.legacy.chip_delay = 0; - info->chip.select_chip = nand_davinci_select_chip; + info->chip.legacy.select_chip = nand_davinci_select_chip; /* options such as NAND_BBT_USE_FLASH */ info->chip.bbt_options = pdata->bbt_options; diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index 830ea247277b..bad3b8ad5e0a 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -1316,6 +1316,7 @@ static void denali_detach_chip(struct nand_chip *chip) static const struct nand_controller_ops denali_controller_ops = { .attach_chip = denali_attach_chip, .detach_chip = denali_detach_chip, + .setup_data_interface = denali_setup_data_interface, }; int denali_init(struct denali_nand_info *denali) @@ -1355,7 +1356,7 @@ int denali_init(struct denali_nand_info *denali) if (!mtd->name) mtd->name = "denali-nand"; - chip->select_chip = denali_select_chip; + chip->legacy.select_chip = denali_select_chip; chip->legacy.read_byte = denali_read_byte; chip->legacy.write_byte = denali_write_byte; chip->legacy.cmd_ctrl = denali_cmd_ctrl; @@ -1372,7 +1373,7 @@ int denali_init(struct denali_nand_info *denali) /* clk rate info is needed for setup_data_interface */ if (denali->clk_rate && denali->clk_x_rate) - chip->setup_data_interface = denali_setup_data_interface; + chip->options |= NAND_KEEP_TIMINGS; chip->dummy_controller.ops = &denali_controller_ops; ret = nand_scan(chip, denali->max_banks); diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h index 57a5498f58bb..25c00601b8b3 100644 --- a/drivers/mtd/nand/raw/denali.h +++ b/drivers/mtd/nand/raw/denali.h @@ -7,7 +7,7 @@ #ifndef __DENALI_H__ #define __DENALI_H__ -#include <linux/bitops.h> +#include <linux/bits.h> #include <linux/completion.h> #include <linux/mtd/rawnand.h> #include <linux/spinlock_types.h> diff --git a/drivers/mtd/nand/raw/diskonchip.c b/drivers/mtd/nand/raw/diskonchip.c index 3a4c373affab..53f57e0f007e 100644 --- a/drivers/mtd/nand/raw/diskonchip.c +++ b/drivers/mtd/nand/raw/diskonchip.c @@ -1390,7 +1390,7 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd) this->legacy.read_buf = doc2001plus_readbuf; doc->late_init = inftl_scan_bbt; this->legacy.cmd_ctrl = NULL; - this->select_chip = doc2001plus_select_chip; + this->legacy.select_chip = doc2001plus_select_chip; this->legacy.cmdfunc = doc2001plus_command; this->ecc.hwctl = doc2001plus_enable_hwecc; @@ -1568,7 +1568,7 @@ static int __init doc_probe(unsigned long physadr) mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops); nand_set_controller_data(nand, doc); - nand->select_chip = doc200x_select_chip; + nand->legacy.select_chip = doc200x_select_chip; nand->legacy.cmd_ctrl = doc200x_hwcontrol; nand->legacy.dev_ready = doc200x_dev_ready; nand->legacy.waitfunc = doc200x_wait; diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c index d6ed697fcfe6..70f0d2b450ea 100644 --- a/drivers/mtd/nand/raw/fsl_elbc_nand.c +++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c @@ -779,7 +779,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->legacy.read_byte = fsl_elbc_read_byte; chip->legacy.write_buf = fsl_elbc_write_buf; chip->legacy.read_buf = fsl_elbc_read_buf; - chip->select_chip = fsl_elbc_select_chip; + chip->legacy.select_chip = fsl_elbc_select_chip; chip->legacy.cmdfunc = fsl_elbc_cmdfunc; chip->legacy.waitfunc = fsl_elbc_wait; chip->legacy.set_features = nand_get_set_features_notsupp; diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c index 6f4afc44381a..e65d274399f9 100644 --- a/drivers/mtd/nand/raw/fsl_ifc_nand.c +++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c @@ -864,7 +864,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) chip->legacy.write_buf = fsl_ifc_write_buf; chip->legacy.read_buf = fsl_ifc_read_buf; - chip->select_chip = fsl_ifc_select_chip; + chip->legacy.select_chip = fsl_ifc_select_chip; chip->legacy.cmdfunc = fsl_ifc_cmdfunc; chip->legacy.waitfunc = fsl_ifc_wait; chip->legacy.set_features = nand_get_set_features_notsupp; diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 673c5a0c9345..5ccc28ec0985 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -170,7 +170,7 @@ static int fun_chip_init(struct fsl_upm_nand *fun, fun->chip.ecc.mode = NAND_ECC_SOFT; fun->chip.ecc.algo = NAND_ECC_HAMMING; if (fun->mchip_count > 1) - fun->chip.select_chip = fun_select_chip; + fun->chip.legacy.select_chip = fun_select_chip; if (fun->rnb_gpio[0] >= 0) fun->chip.legacy.dev_ready = fun_chip_ready; diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c index 70ac8d875218..61927c4c2650 100644 --- a/drivers/mtd/nand/raw/fsmc_nand.c +++ b/drivers/mtd/nand/raw/fsmc_nand.c @@ -609,22 +609,19 @@ static void fsmc_write_buf_dma(struct mtd_info *mtd, const uint8_t *buf, } /* fsmc_select_chip - assert or deassert nCE */ -static void fsmc_select_chip(struct nand_chip *chip, int chipnr) +static void fsmc_ce_ctrl(struct fsmc_nand_data *host, bool assert) { - struct fsmc_nand_data *host = mtd_to_fsmc(nand_to_mtd(chip)); - u32 pc; - - /* Support only one CS */ - if (chipnr > 0) - return; + u32 pc = readl(host->regs_va + FSMC_PC); - pc = readl(host->regs_va + FSMC_PC); - if (chipnr < 0) + if (!assert) writel_relaxed(pc & ~FSMC_ENABLE, host->regs_va + FSMC_PC); else writel_relaxed(pc | FSMC_ENABLE, host->regs_va + FSMC_PC); - /* nCE line must be asserted before starting any operation */ + /* + * nCE line changes must be applied before returning from this + * function. + */ mb(); } @@ -645,6 +642,9 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, int i; pr_debug("Executing operation [%d instructions]:\n", op->ninstrs); + + fsmc_ce_ctrl(host, true); + for (op_id = 0; op_id < op->ninstrs; op_id++) { instr = &op->instrs[op_id]; @@ -701,6 +701,8 @@ static int fsmc_exec_op(struct nand_chip *chip, const struct nand_operation *op, } } + fsmc_ce_ctrl(host, false); + return ret; } @@ -727,7 +729,7 @@ static int fsmc_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, uint8_t *p = buf; uint8_t *ecc_calc = chip->ecc.calc_buf; uint8_t *ecc_code = chip->ecc.code_buf; - int off, len, group = 0; + int off, len, ret, group = 0; /* * ecc_oob is intentionally taken as uint16_t. In 16bit devices, we * end up reading 14 bytes (7 words) from oob. The local array is @@ -740,11 +742,12 @@ static int fsmc_read_page_hwecc(struct nand_chip *chip, uint8_t *buf, for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) { nand_read_page_op(chip, page, s * eccsize, NULL, 0); chip->ecc.hwctl(chip, NAND_ECC_READ); - nand_read_data_op(chip, p, eccsize, false); + ret = nand_read_data_op(chip, p, eccsize, false); + if (ret) + return ret; for (j = 0; j < eccbytes;) { struct mtd_oob_region oobregion; - int ret; ret = mtd_ooblayout_ecc(mtd, group++, &oobregion); if (ret) @@ -992,6 +995,8 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand) static const struct nand_controller_ops fsmc_nand_controller_ops = { .attach_chip = fsmc_nand_attach_chip, + .exec_op = fsmc_exec_op, + .setup_data_interface = fsmc_setup_data_interface, }; /* @@ -1079,8 +1084,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) nand_set_flash_node(nand, pdev->dev.of_node); mtd->dev.parent = &pdev->dev; - nand->exec_op = fsmc_exec_op; - nand->select_chip = fsmc_select_chip; /* * Setup default ECC mode. nand_dt_init() called from nand_scan_ident() @@ -1106,10 +1109,10 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) } } - if (host->dev_timings) + if (host->dev_timings) { fsmc_nand_setup(host, host->dev_timings); - else - nand->setup_data_interface = fsmc_setup_data_interface; + nand->options |= NAND_KEEP_TIMINGS; + } if (AMBA_REV_BITS(host->pid) >= 8) { nand->ecc.read_page = fsmc_read_page_hwecc; diff --git a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c index 94c2b7525c85..25f9fe79796a 100644 --- a/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/raw/gpmi-nand/gpmi-nand.c @@ -1549,7 +1549,7 @@ static int gpmi_block_markbad(struct nand_chip *chip, loff_t ofs) int column, page, chipnr; chipnr = (int)(ofs >> chip->chip_shift); - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); column = !GPMI_IS_MX23(this) ? mtd->writesize : 0; @@ -1562,7 +1562,7 @@ static int gpmi_block_markbad(struct nand_chip *chip, loff_t ofs) ret = nand_prog_page_op(chip, page, column, block_mark, 1); - chip->select_chip(chip, -1); + nand_deselect_target(chip); return ret; } @@ -1610,7 +1610,7 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; saved_chip_number = this->current_chip; - chip->select_chip(chip, 0); + nand_select_target(chip, 0); /* * Loop through the first search area, looking for the NCB fingerprint. @@ -1638,7 +1638,10 @@ static int mx23_check_transcription_stamp(struct gpmi_nand_data *this) } - chip->select_chip(chip, saved_chip_number); + if (saved_chip_number >= 0) + nand_select_target(chip, saved_chip_number); + else + nand_deselect_target(chip); if (found_an_ncb_fingerprint) dev_dbg(dev, "\tFound a fingerprint\n"); @@ -1681,7 +1684,7 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) /* Select chip 0. */ saved_chip_number = this->current_chip; - chip->select_chip(chip, 0); + nand_select_target(chip, 0); /* Loop over blocks in the first search area, erasing them. */ dev_dbg(dev, "Erasing the search area...\n"); @@ -1713,7 +1716,11 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this) } /* Deselect chip 0. */ - chip->select_chip(chip, saved_chip_number); + if (saved_chip_number >= 0) + nand_select_target(chip, saved_chip_number); + else + nand_deselect_target(chip); + return 0; } @@ -1762,10 +1769,10 @@ static int mx23_boot_init(struct gpmi_nand_data *this) byte = block << chip->phys_erase_shift; /* Send the command to read the conventional block mark. */ - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); nand_read_page_op(chip, page, mtd->writesize, NULL, 0); block_mark = chip->legacy.read_byte(chip); - chip->select_chip(chip, -1); + nand_deselect_target(chip); /* * Check if the block is marked bad. If so, we need to mark it @@ -1882,6 +1889,7 @@ static int gpmi_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops gpmi_nand_controller_ops = { .attach_chip = gpmi_nand_attach_chip, + .setup_data_interface = gpmi_setup_data_interface, }; static int gpmi_nand_init(struct gpmi_nand_data *this) @@ -1900,8 +1908,7 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) /* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */ nand_set_controller_data(chip, this); nand_set_flash_node(chip, this->pdev->dev.of_node); - chip->select_chip = gpmi_select_chip; - chip->setup_data_interface = gpmi_setup_data_interface; + chip->legacy.select_chip = gpmi_select_chip; chip->legacy.cmd_ctrl = gpmi_cmd_ctrl; chip->legacy.dev_ready = gpmi_dev_ready; chip->legacy.read_byte = gpmi_read_byte; diff --git a/drivers/mtd/nand/raw/hisi504_nand.c b/drivers/mtd/nand/raw/hisi504_nand.c index f043938ee36b..e41c13499fd5 100644 --- a/drivers/mtd/nand/raw/hisi504_nand.c +++ b/drivers/mtd/nand/raw/hisi504_nand.c @@ -783,7 +783,7 @@ static int hisi_nfc_probe(struct platform_device *pdev) nand_set_controller_data(chip, host); nand_set_flash_node(chip, np); chip->legacy.cmdfunc = hisi_nfc_cmdfunc; - chip->select_chip = hisi_nfc_select_chip; + chip->legacy.select_chip = hisi_nfc_select_chip; chip->legacy.read_byte = hisi_nfc_read_byte; chip->legacy.write_buf = hisi_nfc_write_buf; chip->legacy.read_buf = hisi_nfc_read_buf; diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index 04c2cf74eff3..fbf6ca015cd7 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -95,6 +95,39 @@ void nand_decode_ext_id(struct nand_chip *chip); void panic_nand_wait(struct nand_chip *chip, unsigned long timeo); void sanitize_string(uint8_t *s, size_t len); +static inline bool nand_has_exec_op(struct nand_chip *chip) +{ + if (!chip->controller || !chip->controller->ops || + !chip->controller->ops->exec_op) + return false; + + return true; +} + +static inline int nand_exec_op(struct nand_chip *chip, + const struct nand_operation *op) +{ + if (!nand_has_exec_op(chip)) + return -ENOTSUPP; + + if (WARN_ON(op->cs >= chip->numchips)) + return -EINVAL; + + return chip->controller->ops->exec_op(chip, op, false); +} + +static inline bool nand_has_setup_data_iface(struct nand_chip *chip) +{ + if (!chip->controller || !chip->controller->ops || + !chip->controller->ops->setup_data_interface) + return false; + + if (chip->options & NAND_KEEP_TIMINGS) + return false; + + return true; +} + /* BBT functions */ int nand_markbad_bbt(struct nand_chip *chip, loff_t offs); int nand_isreserved_bbt(struct nand_chip *chip, loff_t offs); diff --git a/drivers/mtd/nand/raw/jz4740_nand.c b/drivers/mtd/nand/raw/jz4740_nand.c index fb59cfca11a7..0bcfdd3d66a8 100644 --- a/drivers/mtd/nand/raw/jz4740_nand.c +++ b/drivers/mtd/nand/raw/jz4740_nand.c @@ -335,14 +335,14 @@ static int jz_nand_detect_bank(struct platform_device *pdev, goto notfound_id; /* Retrieve the IDs from the first chip. */ - chip->select_chip(chip, 0); + nand_select_target(chip, 0); nand_reset_op(chip); nand_readid_op(chip, 0, id, sizeof(id)); *nand_maf_id = id[0]; *nand_dev_id = id[1]; } else { /* Detect additional chip. */ - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); nand_reset_op(chip); nand_readid_op(chip, 0, id, sizeof(id)); if (*nand_maf_id != id[0] || *nand_dev_id != id[1]) { @@ -427,7 +427,7 @@ static int jz_nand_probe(struct platform_device *pdev) chip->legacy.chip_delay = 50; chip->legacy.cmd_ctrl = jz_nand_cmd_ctrl; - chip->select_chip = jz_nand_select_chip; + chip->legacy.select_chip = jz_nand_select_chip; chip->dummy_controller.ops = &jz_nand_controller_ops; if (nand->busy_gpio) diff --git a/drivers/mtd/nand/raw/jz4780_nand.c b/drivers/mtd/nand/raw/jz4780_nand.c index cdf22100ab77..22e58975f0d5 100644 --- a/drivers/mtd/nand/raw/jz4780_nand.c +++ b/drivers/mtd/nand/raw/jz4780_nand.c @@ -279,7 +279,7 @@ static int jz4780_nand_init_chip(struct platform_device *pdev, chip->legacy.IO_ADDR_W = cs->base + OFFSET_DATA; chip->legacy.chip_delay = RB_DELAY_US; chip->options = NAND_NO_SUBPAGE_WRITE; - chip->select_chip = jz4780_nand_select_chip; + chip->legacy.select_chip = jz4780_nand_select_chip; chip->legacy.cmd_ctrl = jz4780_nand_cmd_ctrl; chip->ecc.mode = NAND_ECC_HW; chip->controller = &nfc->controller; diff --git a/drivers/mtd/nand/raw/marvell_nand.c b/drivers/mtd/nand/raw/marvell_nand.c index 650f2b490a05..b7b4d9b14da1 100644 --- a/drivers/mtd/nand/raw/marvell_nand.c +++ b/drivers/mtd/nand/raw/marvell_nand.c @@ -704,7 +704,8 @@ static int marvell_nfc_wait_op(struct nand_chip *chip, unsigned int timeout_ms) return 0; } -static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr) +static void marvell_nfc_select_target(struct nand_chip *chip, + unsigned int die_nr) { struct marvell_nand_chip *marvell_nand = to_marvell_nand(chip); struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); @@ -713,12 +714,6 @@ static void marvell_nfc_select_chip(struct nand_chip *chip, int die_nr) if (chip == nfc->selected_chip && die_nr == marvell_nand->selected_die) return; - if (die_nr < 0 || die_nr >= marvell_nand->nsels) { - nfc->selected_chip = NULL; - marvell_nand->selected_die = -1; - return; - } - writel_relaxed(marvell_nand->ndtr0, nfc->regs + NDTR0); writel_relaxed(marvell_nand->ndtr1, nfc->regs + NDTR1); @@ -1024,13 +1019,13 @@ static int marvell_nfc_hw_ecc_hmg_do_read_page(struct nand_chip *chip, } ret = marvell_nfc_wait_cmdd(chip); - return ret; } static int marvell_nfc_hw_ecc_hmg_read_page_raw(struct nand_chip *chip, u8 *buf, int oob_required, int page) { + marvell_nfc_select_target(chip, chip->cur_cs); return marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi, true, page); } @@ -1043,6 +1038,7 @@ static int marvell_nfc_hw_ecc_hmg_read_page(struct nand_chip *chip, u8 *buf, int max_bitflips = 0, ret; u8 *raw_buf; + marvell_nfc_select_target(chip, chip->cur_cs); marvell_nfc_enable_hw_ecc(chip); marvell_nfc_hw_ecc_hmg_do_read_page(chip, buf, chip->oob_poi, false, page); @@ -1079,6 +1075,7 @@ static int marvell_nfc_hw_ecc_hmg_read_oob_raw(struct nand_chip *chip, int page) /* Invalidate page cache */ chip->pagebuf = -1; + marvell_nfc_select_target(chip, chip->cur_cs); return marvell_nfc_hw_ecc_hmg_do_read_page(chip, chip->data_buf, chip->oob_poi, true, page); } @@ -1142,6 +1139,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page_raw(struct nand_chip *chip, const u8 *buf, int oob_required, int page) { + marvell_nfc_select_target(chip, chip->cur_cs); return marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi, true, page); } @@ -1152,6 +1150,7 @@ static int marvell_nfc_hw_ecc_hmg_write_page(struct nand_chip *chip, { int ret; + marvell_nfc_select_target(chip, chip->cur_cs); marvell_nfc_enable_hw_ecc(chip); ret = marvell_nfc_hw_ecc_hmg_do_write_page(chip, buf, chip->oob_poi, false, page); @@ -1175,6 +1174,7 @@ static int marvell_nfc_hw_ecc_hmg_write_oob_raw(struct nand_chip *chip, memset(chip->data_buf, 0xFF, mtd->writesize); + marvell_nfc_select_target(chip, chip->cur_cs); return marvell_nfc_hw_ecc_hmg_do_write_page(chip, chip->data_buf, chip->oob_poi, true, page); } @@ -1194,6 +1194,8 @@ static int marvell_nfc_hw_ecc_bch_read_page_raw(struct nand_chip *chip, u8 *buf, int ecc_len = lt->ecc_bytes; int chunk; + marvell_nfc_select_target(chip, chip->cur_cs); + if (oob_required) memset(chip->oob_poi, 0xFF, mtd->oobsize); @@ -1304,6 +1306,8 @@ static int marvell_nfc_hw_ecc_bch_read_page(struct nand_chip *chip, u32 failure_mask = 0; int chunk, ret; + marvell_nfc_select_target(chip, chip->cur_cs); + /* * With BCH, OOB is not fully used (and thus not read entirely), not * expected bytes could show up at the end of the OOB buffer if not @@ -1448,6 +1452,8 @@ static int marvell_nfc_hw_ecc_bch_write_page_raw(struct nand_chip *chip, lt->last_spare_bytes; int chunk; + marvell_nfc_select_target(chip, chip->cur_cs); + nand_prog_page_begin_op(chip, page, 0, NULL, 0); for (chunk = 0; chunk < lt->nchunks; chunk++) { @@ -1559,6 +1565,8 @@ static int marvell_nfc_hw_ecc_bch_write_page(struct nand_chip *chip, int spare_len = lt->spare_bytes; int chunk, ret; + marvell_nfc_select_target(chip, chip->cur_cs); + /* Spare data will be written anyway, so clear it to avoid garbage */ if (!oob_required) memset(chip->oob_poi, 0xFF, mtd->oobsize); @@ -2097,6 +2105,8 @@ static int marvell_nfc_exec_op(struct nand_chip *chip, { struct marvell_nfc *nfc = to_marvell_nfc(chip->controller); + marvell_nfc_select_target(chip, op->cs); + if (nfc->caps->is_nfcv2) return nand_op_parser_exec_op(chip, &marvell_nfcv2_op_parser, op, check_only); @@ -2495,6 +2505,8 @@ static int marvell_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops marvell_nand_controller_ops = { .attach_chip = marvell_nand_attach_chip, + .exec_op = marvell_nfc_exec_op, + .setup_data_interface = marvell_nfc_setup_data_interface, }; static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, @@ -2617,10 +2629,8 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, chip->controller = &nfc->controller; nand_set_flash_node(chip, np); - chip->exec_op = marvell_nfc_exec_op; - chip->select_chip = marvell_nfc_select_chip; if (!of_property_read_bool(np, "marvell,nand-keep-config")) - chip->setup_data_interface = marvell_nfc_setup_data_interface; + chip->options |= NAND_KEEP_TIMINGS; mtd = nand_to_mtd(chip); mtd->dev.parent = dev; diff --git a/drivers/mtd/nand/raw/mpc5121_nfc.c b/drivers/mtd/nand/raw/mpc5121_nfc.c index 86a0aabe08df..062cd1eb2861 100644 --- a/drivers/mtd/nand/raw/mpc5121_nfc.c +++ b/drivers/mtd/nand/raw/mpc5121_nfc.c @@ -697,7 +697,7 @@ static int mpc5121_nfc_probe(struct platform_device *op) chip->legacy.read_byte = mpc5121_nfc_read_byte; chip->legacy.read_buf = mpc5121_nfc_read_buf; chip->legacy.write_buf = mpc5121_nfc_write_buf; - chip->select_chip = mpc5121_nfc_select_chip; + chip->legacy.select_chip = mpc5121_nfc_select_chip; chip->legacy.set_features = nand_get_set_features_notsupp; chip->legacy.get_features = nand_get_set_features_notsupp; chip->bbt_options = NAND_BBT_USE_FLASH; @@ -712,7 +712,7 @@ static int mpc5121_nfc_probe(struct platform_device *op) return retval; } - chip->select_chip = ads5121_select_chip; + chip->legacy.select_chip = ads5121_select_chip; } /* Enable NFC clock */ diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c index 2bb0df1b7244..b6b4602f5132 100644 --- a/drivers/mtd/nand/raw/mtk_nand.c +++ b/drivers/mtd/nand/raw/mtk_nand.c @@ -1288,6 +1288,7 @@ static int mtk_nfc_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops mtk_nfc_controller_ops = { .attach_chip = mtk_nfc_attach_chip, + .setup_data_interface = mtk_nfc_setup_data_interface, }; static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, @@ -1333,13 +1334,12 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, nand->options |= NAND_USE_BOUNCE_BUFFER | NAND_SUBPAGE_READ; nand->legacy.dev_ready = mtk_nfc_dev_ready; - nand->select_chip = mtk_nfc_select_chip; + nand->legacy.select_chip = mtk_nfc_select_chip; nand->legacy.write_byte = mtk_nfc_write_byte; nand->legacy.write_buf = mtk_nfc_write_buf; nand->legacy.read_byte = mtk_nfc_read_byte; nand->legacy.read_buf = mtk_nfc_read_buf; nand->legacy.cmd_ctrl = mtk_nfc_cmd_ctrl; - nand->setup_data_interface = mtk_nfc_setup_data_interface; /* set default mode in case dt entry is missing */ nand->ecc.mode = NAND_ECC_HW; diff --git a/drivers/mtd/nand/raw/mxc_nand.c b/drivers/mtd/nand/raw/mxc_nand.c index 88bd3f6a499c..9b75d894cb74 100644 --- a/drivers/mtd/nand/raw/mxc_nand.c +++ b/drivers/mtd/nand/raw/mxc_nand.c @@ -1738,8 +1738,17 @@ static int mxcnd_attach_chip(struct nand_chip *chip) return 0; } +static int mxcnd_setup_data_interface(struct nand_chip *chip, int chipnr, + const struct nand_data_interface *conf) +{ + struct mxc_nand_host *host = nand_get_controller_data(chip); + + return host->devtype_data->setup_data_interface(chip, chipnr, conf); +} + static const struct nand_controller_ops mxcnd_controller_ops = { .attach_chip = mxcnd_attach_chip, + .setup_data_interface = mxcnd_setup_data_interface, }; static int mxcnd_probe(struct platform_device *pdev) @@ -1800,7 +1809,8 @@ static int mxcnd_probe(struct platform_device *pdev) if (err < 0) return err; - this->setup_data_interface = host->devtype_data->setup_data_interface; + if (!host->devtype_data->setup_data_interface) + this->options |= NAND_KEEP_TIMINGS; if (host->devtype_data->needs_ip) { res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1828,7 +1838,7 @@ static int mxcnd_probe(struct platform_device *pdev) this->ecc.bytes = host->devtype_data->eccbytes; host->eccsize = host->devtype_data->eccsize; - this->select_chip = host->devtype_data->select_chip; + this->legacy.select_chip = host->devtype_data->select_chip; this->ecc.size = 512; mtd_set_ooblayout(mtd, host->devtype_data->ooblayout); diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 71050a0b31df..a036333629dc 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -45,14 +45,10 @@ #include <linux/io.h> #include <linux/mtd/partitions.h> #include <linux/of.h> +#include <linux/gpio/consumer.h> #include "internals.h" -static int nand_get_device(struct mtd_info *mtd, int new_state); - -static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops); - /* Define default oob placement schemes for large and small page devices */ static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) @@ -213,10 +209,8 @@ static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = { .free = nand_ooblayout_free_lp_hamming, }; -static int check_offs_len(struct mtd_info *mtd, - loff_t ofs, uint64_t len) +static int check_offs_len(struct nand_chip *chip, loff_t ofs, uint64_t len) { - struct nand_chip *chip = mtd_to_nand(mtd); int ret = 0; /* Start address must align on block boundary */ @@ -235,15 +229,54 @@ static int check_offs_len(struct mtd_info *mtd, } /** + * nand_select_target() - Select a NAND target (A.K.A. die) + * @chip: NAND chip object + * @cs: the CS line to select. Note that this CS id is always from the chip + * PoV, not the controller one + * + * Select a NAND target so that further operations executed on @chip go to the + * selected NAND target. + */ +void nand_select_target(struct nand_chip *chip, unsigned int cs) +{ + /* + * cs should always lie between 0 and chip->numchips, when that's not + * the case it's a bug and the caller should be fixed. + */ + if (WARN_ON(cs > chip->numchips)) + return; + + chip->cur_cs = cs; + + if (chip->legacy.select_chip) + chip->legacy.select_chip(chip, cs); +} +EXPORT_SYMBOL_GPL(nand_select_target); + +/** + * nand_deselect_target() - Deselect the currently selected target + * @chip: NAND chip object + * + * Deselect the currently selected NAND target. The result of operations + * executed on @chip after the target has been deselected is undefined. + */ +void nand_deselect_target(struct nand_chip *chip) +{ + if (chip->legacy.select_chip) + chip->legacy.select_chip(chip, -1); + + chip->cur_cs = -1; +} +EXPORT_SYMBOL_GPL(nand_deselect_target); + +/** * nand_release_device - [GENERIC] release chip - * @mtd: MTD device structure + * @chip: NAND chip object * * Release chip lock and wake up anyone waiting on the device. */ -static void nand_release_device(struct mtd_info *mtd) +static void nand_release_device(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); - /* Release the controller and the chip */ spin_lock(&chip->controller->lock); chip->controller->active = NULL; @@ -289,6 +322,197 @@ static int nand_block_bad(struct nand_chip *chip, loff_t ofs) return 0; } +static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) +{ + if (chip->legacy.block_bad) + return chip->legacy.block_bad(chip, ofs); + + return nand_block_bad(chip, ofs); +} + +/** + * panic_nand_get_device - [GENERIC] Get chip for selected access + * @chip: the nand chip descriptor + * @new_state: the state which is requested + * + * Used when in panic, no locks are taken. + */ +static void panic_nand_get_device(struct nand_chip *chip, int new_state) +{ + /* Hardware controller shared among independent devices */ + chip->controller->active = chip; + chip->state = new_state; +} + +/** + * nand_get_device - [GENERIC] Get chip for selected access + * @chip: NAND chip structure + * @new_state: the state which is requested + * + * Get the device and lock it for exclusive access + */ +static int +nand_get_device(struct nand_chip *chip, int new_state) +{ + spinlock_t *lock = &chip->controller->lock; + wait_queue_head_t *wq = &chip->controller->wq; + DECLARE_WAITQUEUE(wait, current); +retry: + spin_lock(lock); + + /* Hardware controller shared among independent devices */ + if (!chip->controller->active) + chip->controller->active = chip; + + if (chip->controller->active == chip && chip->state == FL_READY) { + chip->state = new_state; + spin_unlock(lock); + return 0; + } + if (new_state == FL_PM_SUSPENDED) { + if (chip->controller->active->state == FL_PM_SUSPENDED) { + chip->state = FL_PM_SUSPENDED; + spin_unlock(lock); + return 0; + } + } + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(wq, &wait); + spin_unlock(lock); + schedule(); + remove_wait_queue(wq, &wait); + goto retry; +} + +/** + * nand_check_wp - [GENERIC] check if the chip is write protected + * @chip: NAND chip object + * + * Check, if the device is write protected. The function expects, that the + * device is already selected. + */ +static int nand_check_wp(struct nand_chip *chip) +{ + u8 status; + int ret; + + /* Broken xD cards report WP despite being writable */ + if (chip->options & NAND_BROKEN_XD) + return 0; + + /* Check the WP bit */ + ret = nand_status_op(chip, &status); + if (ret) + return ret; + + return status & NAND_STATUS_WP ? 0 : 1; +} + +/** + * nand_fill_oob - [INTERN] Transfer client buffer to oob + * @oob: oob data buffer + * @len: oob data write length + * @ops: oob ops structure + */ +static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, + struct mtd_oob_ops *ops) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + + /* + * Initialise to all 0xFF, to avoid the possibility of left over OOB + * data from a previous OOB read. + */ + memset(chip->oob_poi, 0xff, mtd->oobsize); + + switch (ops->mode) { + + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: + memcpy(chip->oob_poi + ops->ooboffs, oob, len); + return oob + len; + + case MTD_OPS_AUTO_OOB: + ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi, + ops->ooboffs, len); + BUG_ON(ret); + return oob + len; + + default: + BUG(); + } + return NULL; +} + +/** + * nand_do_write_oob - [MTD Interface] NAND write out-of-band + * @chip: NAND chip object + * @to: offset to write to + * @ops: oob operation description structure + * + * NAND write out-of-band. + */ +static int nand_do_write_oob(struct nand_chip *chip, loff_t to, + struct mtd_oob_ops *ops) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + int chipnr, page, status, len; + + pr_debug("%s: to = 0x%08x, len = %i\n", + __func__, (unsigned int)to, (int)ops->ooblen); + + len = mtd_oobavail(mtd, ops); + + /* Do not allow write past end of page */ + if ((ops->ooboffs + ops->ooblen) > len) { + pr_debug("%s: attempt to write past end of page\n", + __func__); + return -EINVAL; + } + + chipnr = (int)(to >> chip->chip_shift); + + /* + * Reset the chip. Some chips (like the Toshiba TC5832DC found in one + * of my DiskOnChip 2000 test units) will clear the whole data page too + * if we don't do this. I have no clue why, but I seem to have 'fixed' + * it in the doc2000 driver in August 1999. dwmw2. + */ + nand_reset(chip, chipnr); + + nand_select_target(chip, chipnr); + + /* Shift to get page */ + page = (int)(to >> chip->page_shift); + + /* Check, if it is write protected */ + if (nand_check_wp(chip)) { + nand_deselect_target(chip); + return -EROFS; + } + + /* Invalidate the page cache, if we write to the cached page */ + if (page == chip->pagebuf) + chip->pagebuf = -1; + + nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); + + if (ops->mode == MTD_OPS_RAW) + status = chip->ecc.write_oob_raw(chip, page & chip->pagemask); + else + status = chip->ecc.write_oob(chip, page & chip->pagemask); + + nand_deselect_target(chip); + + if (status) + return status; + + ops->oobretlen = ops->ooblen; + + return 0; +} + /** * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker * @chip: NAND chip object @@ -320,7 +544,7 @@ static int nand_default_block_markbad(struct nand_chip *chip, loff_t ofs) if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ofs += mtd->erasesize - mtd->writesize; do { - res = nand_do_write_oob(mtd, ofs, &ops); + res = nand_do_write_oob(chip, ofs, &ops); if (!ret) ret = res; @@ -344,17 +568,9 @@ int nand_markbad_bbm(struct nand_chip *chip, loff_t ofs) return nand_default_block_markbad(chip, ofs); } -static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) -{ - if (chip->legacy.block_bad) - return chip->legacy.block_bad(chip, ofs); - - return nand_block_bad(chip, ofs); -} - /** * nand_block_markbad_lowlevel - mark a block bad - * @mtd: MTD device structure + * @chip: NAND chip object * @ofs: offset from device start * * This function performs the generic NAND bad block marking steps (i.e., bad @@ -371,9 +587,9 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) * Note that we retain the first error encountered in (2) or (3), finish the * procedures, and dump the error in the end. */ -static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) +static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); int res, ret = 0; if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) { @@ -386,9 +602,9 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) nand_erase_nand(chip, &einfo, 0); /* Write bad block marker to OOB */ - nand_get_device(mtd, FL_WRITING); + nand_get_device(chip, FL_WRITING); ret = nand_markbad_bbm(chip, ofs); - nand_release_device(mtd); + nand_release_device(chip); } /* Mark block bad in BBT */ @@ -405,31 +621,6 @@ static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs) } /** - * nand_check_wp - [GENERIC] check if the chip is write protected - * @mtd: MTD device structure - * - * Check, if the device is write protected. The function expects, that the - * device is already selected. - */ -static int nand_check_wp(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - u8 status; - int ret; - - /* Broken xD cards report WP despite being writable */ - if (chip->options & NAND_BROKEN_XD) - return 0; - - /* Check the WP bit */ - ret = nand_status_op(chip, &status); - if (ret) - return ret; - - return status & NAND_STATUS_WP ? 0 : 1; -} - -/** * nand_block_isreserved - [GENERIC] Check if a block is marked reserved. * @mtd: MTD device structure * @ofs: offset from device start @@ -448,17 +639,15 @@ static int nand_block_isreserved(struct mtd_info *mtd, loff_t ofs) /** * nand_block_checkbad - [GENERIC] Check if a block is marked bad - * @mtd: MTD device structure + * @chip: NAND chip object * @ofs: offset from device start * @allowbbt: 1, if its allowed to access the bbt area * * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. */ -static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int allowbbt) +static int nand_block_checkbad(struct nand_chip *chip, loff_t ofs, int allowbbt) { - struct nand_chip *chip = mtd_to_nand(mtd); - /* Return info from the table */ if (chip->bbt) return nand_isbad_bbt(chip, ofs, allowbbt); @@ -489,7 +678,7 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms) u8 status = 0; int ret; - if (!chip->exec_op) + if (!nand_has_exec_op(chip)) return -ENOTSUPP; /* Wait tWB before polling the STATUS reg. */ @@ -532,61 +721,34 @@ int nand_soft_waitrdy(struct nand_chip *chip, unsigned long timeout_ms) EXPORT_SYMBOL_GPL(nand_soft_waitrdy); /** - * panic_nand_get_device - [GENERIC] Get chip for selected access - * @chip: the nand chip descriptor - * @mtd: MTD device structure - * @new_state: the state which is requested + * nand_gpio_waitrdy - Poll R/B GPIO pin until ready + * @chip: NAND chip structure + * @gpiod: GPIO descriptor of R/B pin + * @timeout_ms: Timeout in ms * - * Used when in panic, no locks are taken. - */ -static void panic_nand_get_device(struct nand_chip *chip, - struct mtd_info *mtd, int new_state) -{ - /* Hardware controller shared among independent devices */ - chip->controller->active = chip; - chip->state = new_state; -} - -/** - * nand_get_device - [GENERIC] Get chip for selected access - * @mtd: MTD device structure - * @new_state: the state which is requested + * Poll the R/B GPIO pin until it becomes ready. If that does not happen + * whitin the specified timeout, -ETIMEDOUT is returned. * - * Get the device and lock it for exclusive access + * This helper is intended to be used when the controller has access to the + * NAND R/B pin over GPIO. + * + * Return 0 if the R/B pin indicates chip is ready, a negative error otherwise. */ -static int -nand_get_device(struct mtd_info *mtd, int new_state) +int nand_gpio_waitrdy(struct nand_chip *chip, struct gpio_desc *gpiod, + unsigned long timeout_ms) { - struct nand_chip *chip = mtd_to_nand(mtd); - spinlock_t *lock = &chip->controller->lock; - wait_queue_head_t *wq = &chip->controller->wq; - DECLARE_WAITQUEUE(wait, current); -retry: - spin_lock(lock); + /* Wait until R/B pin indicates chip is ready or timeout occurs */ + timeout_ms = jiffies + msecs_to_jiffies(timeout_ms); + do { + if (gpiod_get_value_cansleep(gpiod)) + return 0; - /* Hardware controller shared among independent devices */ - if (!chip->controller->active) - chip->controller->active = chip; + cond_resched(); + } while (time_before(jiffies, timeout_ms)); - if (chip->controller->active == chip && chip->state == FL_READY) { - chip->state = new_state; - spin_unlock(lock); - return 0; - } - if (new_state == FL_PM_SUSPENDED) { - if (chip->controller->active->state == FL_PM_SUSPENDED) { - chip->state = FL_PM_SUSPENDED; - spin_unlock(lock); - return 0; - } - } - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(wq, &wait); - spin_unlock(lock); - schedule(); - remove_wait_queue(wq, &wait); - goto retry; -} + return gpiod_get_value_cansleep(gpiod) ? 0 : -ETIMEDOUT; +}; +EXPORT_SYMBOL_GPL(nand_gpio_waitrdy); /** * panic_nand_wait - [GENERIC] wait until the command is done @@ -645,7 +807,7 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) { int ret; - if (!chip->setup_data_interface) + if (!nand_has_setup_data_iface(chip)) return 0; /* @@ -663,7 +825,8 @@ static int nand_reset_data_interface(struct nand_chip *chip, int chipnr) */ onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0); - ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface); + ret = chip->controller->ops->setup_data_interface(chip, chipnr, + &chip->data_interface); if (ret) pr_err("Failed to configure data interface to SDR timing mode 0\n"); @@ -690,21 +853,22 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) }; int ret; - if (!chip->setup_data_interface) + if (!nand_has_setup_data_iface(chip)) return 0; /* Change the mode on the chip side (if supported by the NAND chip) */ if (nand_supports_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE)) { - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); ret = nand_set_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, tmode_param); - chip->select_chip(chip, -1); + nand_deselect_target(chip); if (ret) return ret; } /* Change the mode on the controller side */ - ret = chip->setup_data_interface(chip, chipnr, &chip->data_interface); + ret = chip->controller->ops->setup_data_interface(chip, chipnr, + &chip->data_interface); if (ret) return ret; @@ -713,10 +877,10 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr) return 0; memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN); - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); ret = nand_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE, tmode_param); - chip->select_chip(chip, -1); + nand_deselect_target(chip); if (ret) goto err_reset_chip; @@ -734,9 +898,9 @@ err_reset_chip: * timing mode. */ nand_reset_data_interface(chip, chipnr); - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); nand_reset_op(chip); - chip->select_chip(chip, -1); + nand_deselect_target(chip); return ret; } @@ -759,7 +923,7 @@ static int nand_init_data_interface(struct nand_chip *chip) { int modes, mode, ret; - if (!chip->setup_data_interface) + if (!nand_has_setup_data_iface(chip)) return 0; /* @@ -785,7 +949,7 @@ static int nand_init_data_interface(struct nand_chip *chip) * Pass NAND_DATA_IFACE_CHECK_ONLY to only check if the * controller supports the requested timings. */ - ret = chip->setup_data_interface(chip, + ret = chip->controller->ops->setup_data_interface(chip, NAND_DATA_IFACE_CHECK_ONLY, &chip->data_interface); if (!ret) { @@ -866,7 +1030,7 @@ static int nand_sp_exec_read_page_op(struct nand_chip *chip, unsigned int page, PSEC_TO_NSEC(sdr->tRR_min)), NAND_OP_DATA_IN(len, buf, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); int ret; /* Drop the DATA_IN instruction if len is set to 0. */ @@ -909,7 +1073,7 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page, PSEC_TO_NSEC(sdr->tRR_min)), NAND_OP_DATA_IN(len, buf, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); int ret; /* Drop the DATA_IN instruction if len is set to 0. */ @@ -955,7 +1119,7 @@ int nand_read_page_op(struct nand_chip *chip, unsigned int page, if (offset_in_page + len > mtd->writesize + mtd->oobsize) return -EINVAL; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { if (mtd->writesize > 512) return nand_lp_exec_read_page_op(chip, page, offset_in_page, buf, @@ -994,7 +1158,7 @@ int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf, if (len && !buf) return -EINVAL; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); struct nand_op_instr instrs[] = { @@ -1004,7 +1168,7 @@ int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf, PSEC_TO_NSEC(sdr->tRR_min)), NAND_OP_8BIT_DATA_IN(len, buf, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); /* Drop the DATA_IN instruction if len is set to 0. */ if (!len) @@ -1049,7 +1213,7 @@ int nand_change_read_column_op(struct nand_chip *chip, if (mtd->writesize <= 512) return -ENOTSUPP; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); u8 addrs[2] = {}; @@ -1060,7 +1224,7 @@ int nand_change_read_column_op(struct nand_chip *chip, PSEC_TO_NSEC(sdr->tCCS_min)), NAND_OP_DATA_IN(len, buf, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); int ret; ret = nand_fill_column_cycles(chip, addrs, offset_in_page); @@ -1108,7 +1272,7 @@ int nand_read_oob_op(struct nand_chip *chip, unsigned int page, if (offset_in_oob + len > mtd->oobsize) return -EINVAL; - if (chip->exec_op) + if (nand_has_exec_op(chip)) return nand_read_page_op(chip, page, mtd->writesize + offset_in_oob, buf, len); @@ -1142,7 +1306,7 @@ static int nand_exec_prog_page_op(struct nand_chip *chip, unsigned int page, NAND_OP_CMD(NAND_CMD_PAGEPROG, PSEC_TO_NSEC(sdr->tWB_max)), NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); int naddrs = nand_fill_column_cycles(chip, addrs, offset_in_page); int ret; u8 status; @@ -1221,7 +1385,7 @@ int nand_prog_page_begin_op(struct nand_chip *chip, unsigned int page, if (offset_in_page + len > mtd->writesize + mtd->oobsize) return -EINVAL; - if (chip->exec_op) + if (nand_has_exec_op(chip)) return nand_exec_prog_page_op(chip, page, offset_in_page, buf, len, false); @@ -1248,7 +1412,7 @@ int nand_prog_page_end_op(struct nand_chip *chip) int ret; u8 status; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); struct nand_op_instr instrs[] = { @@ -1256,7 +1420,7 @@ int nand_prog_page_end_op(struct nand_chip *chip) PSEC_TO_NSEC(sdr->tWB_max)), NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tPROG_max), 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); ret = nand_exec_op(chip, &op); if (ret) @@ -1307,7 +1471,7 @@ int nand_prog_page_op(struct nand_chip *chip, unsigned int page, if (offset_in_page + len > mtd->writesize + mtd->oobsize) return -EINVAL; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { status = nand_exec_prog_page_op(chip, page, offset_in_page, buf, len, true); } else { @@ -1355,7 +1519,7 @@ int nand_change_write_column_op(struct nand_chip *chip, if (mtd->writesize <= 512) return -ENOTSUPP; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); u8 addrs[2]; @@ -1364,7 +1528,7 @@ int nand_change_write_column_op(struct nand_chip *chip, NAND_OP_ADDR(2, addrs, PSEC_TO_NSEC(sdr->tCCS_min)), NAND_OP_DATA_OUT(len, buf, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); int ret; ret = nand_fill_column_cycles(chip, addrs, offset_in_page); @@ -1410,7 +1574,7 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf, if (len && !buf) return -EINVAL; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); struct nand_op_instr instrs[] = { @@ -1418,7 +1582,7 @@ int nand_readid_op(struct nand_chip *chip, u8 addr, void *buf, NAND_OP_ADDR(1, &addr, PSEC_TO_NSEC(sdr->tADL_min)), NAND_OP_8BIT_DATA_IN(len, buf, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); /* Drop the DATA_IN instruction if len is set to 0. */ if (!len) @@ -1449,7 +1613,7 @@ EXPORT_SYMBOL_GPL(nand_readid_op); */ int nand_status_op(struct nand_chip *chip, u8 *status) { - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); struct nand_op_instr instrs[] = { @@ -1457,7 +1621,7 @@ int nand_status_op(struct nand_chip *chip, u8 *status) PSEC_TO_NSEC(sdr->tADL_min)), NAND_OP_8BIT_DATA_IN(1, status, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); if (!status) op.ninstrs--; @@ -1486,11 +1650,11 @@ EXPORT_SYMBOL_GPL(nand_status_op); */ int nand_exit_status_op(struct nand_chip *chip) { - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_READ0, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); return nand_exec_op(chip, &op); } @@ -1518,7 +1682,7 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock) int ret; u8 status; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); u8 addrs[3] = { page, page >> 8, page >> 16 }; @@ -1529,7 +1693,7 @@ int nand_erase_op(struct nand_chip *chip, unsigned int eraseblock) PSEC_TO_MSEC(sdr->tWB_max)), NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tBERS_max), 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); if (chip->options & NAND_ROW_ADDR_3) instrs[1].ctx.addr.naddrs++; @@ -1577,7 +1741,7 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature, const u8 *params = data; int i, ret; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); struct nand_op_instr instrs[] = { @@ -1587,7 +1751,7 @@ static int nand_set_features_op(struct nand_chip *chip, u8 feature, PSEC_TO_NSEC(sdr->tWB_max)), NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tFEAT_max), 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); return nand_exec_op(chip, &op); } @@ -1624,7 +1788,7 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature, u8 *params = data; int i; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); struct nand_op_instr instrs[] = { @@ -1635,7 +1799,7 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature, NAND_OP_8BIT_DATA_IN(ONFI_SUBFEATURE_PARAM_LEN, data, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); return nand_exec_op(chip, &op); } @@ -1650,12 +1814,12 @@ static int nand_get_features_op(struct nand_chip *chip, u8 feature, static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms, unsigned int delay_ns) { - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { struct nand_op_instr instrs[] = { NAND_OP_WAIT_RDY(PSEC_TO_MSEC(timeout_ms), PSEC_TO_NSEC(delay_ns)), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); return nand_exec_op(chip, &op); } @@ -1681,14 +1845,14 @@ static int nand_wait_rdy_op(struct nand_chip *chip, unsigned int timeout_ms, */ int nand_reset_op(struct nand_chip *chip) { - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { const struct nand_sdr_timings *sdr = nand_get_sdr_timings(&chip->data_interface); struct nand_op_instr instrs[] = { NAND_OP_CMD(NAND_CMD_RESET, PSEC_TO_NSEC(sdr->tWB_max)), NAND_OP_WAIT_RDY(PSEC_TO_MSEC(sdr->tRST_max), 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); return nand_exec_op(chip, &op); } @@ -1718,11 +1882,11 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len, if (!len || !buf) return -EINVAL; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { struct nand_op_instr instrs[] = { NAND_OP_DATA_IN(len, buf, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); instrs[0].ctx.data.force_8bit = force_8bit; @@ -1762,11 +1926,11 @@ int nand_write_data_op(struct nand_chip *chip, const void *buf, if (!len || !buf) return -EINVAL; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { struct nand_op_instr instrs[] = { NAND_OP_DATA_OUT(len, buf, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); instrs[0].ctx.data.force_8bit = force_8bit; @@ -2224,11 +2388,12 @@ int nand_reset(struct nand_chip *chip, int chipnr) /* * The CS line has to be released before we can apply the new NAND - * interface settings, hence this weird ->select_chip() dance. + * interface settings, hence this weird nand_select_target() + * nand_deselect_target() dance. */ - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); ret = nand_reset_op(chip); - chip->select_chip(chip, -1); + nand_deselect_target(chip); if (ret) return ret; @@ -2924,15 +3089,15 @@ static int nand_read_page_syndrome(struct nand_chip *chip, uint8_t *buf, /** * nand_transfer_oob - [INTERN] Transfer oob to client buffer - * @mtd: mtd info structure + * @chip: NAND chip object * @oob: oob destination address * @ops: oob ops structure * @len: size of oob to transfer */ -static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob, +static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops, size_t len) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); int ret; switch (ops->mode) { @@ -2989,17 +3154,17 @@ static void nand_wait_readrdy(struct nand_chip *chip) /** * nand_do_read_ops - [INTERN] Read data with ECC - * @mtd: MTD device structure + * @chip: NAND chip object * @from: offset to read from * @ops: oob ops structure * * Internal function. Called with chip held. */ -static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, +static int nand_do_read_ops(struct nand_chip *chip, loff_t from, struct mtd_oob_ops *ops) { int chipnr, page, realpage, col, bytes, aligned, oob_required; - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); int ret = 0; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; @@ -3012,7 +3177,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, bool ecc_fail = false; chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); realpage = (int)(from >> chip->page_shift); page = realpage & chip->pagemask; @@ -3087,8 +3252,8 @@ read_retry: int toread = min(oobreadlen, max_oobsize); if (toread) { - oob = nand_transfer_oob(mtd, - oob, ops, toread); + oob = nand_transfer_oob(chip, oob, ops, + toread); oobreadlen -= toread; } } @@ -3143,11 +3308,11 @@ read_retry: /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - chip->select_chip(chip, -1); - chip->select_chip(chip, chipnr); + nand_deselect_target(chip); + nand_select_target(chip, chipnr); } } - chip->select_chip(chip, -1); + nand_deselect_target(chip); ops->retlen = ops->len - (size_t) readlen; if (oob) @@ -3318,18 +3483,18 @@ static int nand_write_oob_syndrome(struct nand_chip *chip, int page) /** * nand_do_read_oob - [INTERN] NAND read out-of-band - * @mtd: MTD device structure + * @chip: NAND chip object * @from: offset to read from * @ops: oob operations description structure * * NAND read out-of-band data from the spare area. */ -static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, +static int nand_do_read_oob(struct nand_chip *chip, loff_t from, struct mtd_oob_ops *ops) { + struct mtd_info *mtd = nand_to_mtd(chip); unsigned int max_bitflips = 0; int page, realpage, chipnr; - struct nand_chip *chip = mtd_to_nand(mtd); struct mtd_ecc_stats stats; int readlen = ops->ooblen; int len; @@ -3344,7 +3509,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, len = mtd_oobavail(mtd, ops); chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); /* Shift to get page */ realpage = (int)(from >> chip->page_shift); @@ -3360,7 +3525,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, break; len = min(len, readlen); - buf = nand_transfer_oob(mtd, buf, ops, len); + buf = nand_transfer_oob(chip, buf, ops, len); nand_wait_readrdy(chip); @@ -3377,11 +3542,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - chip->select_chip(chip, -1); - chip->select_chip(chip, chipnr); + nand_deselect_target(chip); + nand_select_target(chip, chipnr); } } - chip->select_chip(chip, -1); + nand_deselect_target(chip); ops->oobretlen = ops->ooblen - readlen; @@ -3405,6 +3570,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, static int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { + struct nand_chip *chip = mtd_to_nand(mtd); int ret; ops->retlen = 0; @@ -3414,14 +3580,14 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, ops->mode != MTD_OPS_RAW) return -ENOTSUPP; - nand_get_device(mtd, FL_READING); + nand_get_device(chip, FL_READING); if (!ops->datbuf) - ret = nand_do_read_oob(mtd, from, ops); + ret = nand_do_read_oob(chip, from, ops); else - ret = nand_do_read_ops(mtd, from, ops); + ret = nand_do_read_ops(chip, from, ops); - nand_release_device(mtd); + nand_release_device(chip); return ret; } @@ -3749,7 +3915,6 @@ static int nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf, /** * nand_write_page - write one page - * @mtd: MTD device structure * @chip: NAND chip descriptor * @offset: address offset within the page * @data_len: length of actual data to be written @@ -3758,10 +3923,11 @@ static int nand_write_page_syndrome(struct nand_chip *chip, const uint8_t *buf, * @page: page number to write * @raw: use _raw version of write_page */ -static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, int data_len, const uint8_t *buf, - int oob_required, int page, int raw) +static int nand_write_page(struct nand_chip *chip, uint32_t offset, + int data_len, const uint8_t *buf, int oob_required, + int page, int raw) { + struct mtd_info *mtd = nand_to_mtd(chip); int status, subpage; if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && @@ -3785,59 +3951,21 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -/** - * nand_fill_oob - [INTERN] Transfer client buffer to oob - * @mtd: MTD device structure - * @oob: oob data buffer - * @len: oob data write length - * @ops: oob ops structure - */ -static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, - struct mtd_oob_ops *ops) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - int ret; - - /* - * Initialise to all 0xFF, to avoid the possibility of left over OOB - * data from a previous OOB read. - */ - memset(chip->oob_poi, 0xff, mtd->oobsize); - - switch (ops->mode) { - - case MTD_OPS_PLACE_OOB: - case MTD_OPS_RAW: - memcpy(chip->oob_poi + ops->ooboffs, oob, len); - return oob + len; - - case MTD_OPS_AUTO_OOB: - ret = mtd_ooblayout_set_databytes(mtd, oob, chip->oob_poi, - ops->ooboffs, len); - BUG_ON(ret); - return oob + len; - - default: - BUG(); - } - return NULL; -} - #define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) /** * nand_do_write_ops - [INTERN] NAND write with ECC - * @mtd: MTD device structure + * @chip: NAND chip object * @to: offset to write to * @ops: oob operations description structure * * NAND write with ECC. */ -static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, +static int nand_do_write_ops(struct nand_chip *chip, loff_t to, struct mtd_oob_ops *ops) { + struct mtd_info *mtd = nand_to_mtd(chip); int chipnr, realpage, page, column; - struct nand_chip *chip = mtd_to_nand(mtd); uint32_t writelen = ops->len; uint32_t oobwritelen = ops->ooblen; @@ -3862,10 +3990,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, column = to & (mtd->writesize - 1); chipnr = (int)(to >> chip->chip_shift); - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { + if (nand_check_wp(chip)) { ret = -EIO; goto err_out; } @@ -3913,14 +4041,14 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (unlikely(oob)) { size_t len = min(oobwritelen, oobmaxlen); - oob = nand_fill_oob(mtd, oob, len, ops); + oob = nand_fill_oob(chip, oob, len, ops); oobwritelen -= len; } else { /* We still need to erase leftover OOB data */ memset(chip->oob_poi, 0xff, mtd->oobsize); } - ret = nand_write_page(mtd, chip, column, bytes, wbuf, + ret = nand_write_page(chip, column, bytes, wbuf, oob_required, page, (ops->mode == MTD_OPS_RAW)); if (ret) @@ -3938,8 +4066,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, /* Check, if we cross a chip boundary */ if (!page) { chipnr++; - chip->select_chip(chip, -1); - chip->select_chip(chip, chipnr); + nand_deselect_target(chip); + nand_select_target(chip, chipnr); } } @@ -3948,7 +4076,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, ops->oobretlen = ops->ooblen; err_out: - chip->select_chip(chip, -1); + nand_deselect_target(chip); return ret; } @@ -3972,9 +4100,9 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, int ret; /* Grab the device */ - panic_nand_get_device(chip, mtd, FL_WRITING); + panic_nand_get_device(chip, FL_WRITING); - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); /* Wait for the device to get ready */ panic_nand_wait(chip, 400); @@ -3984,81 +4112,13 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, ops.datbuf = (uint8_t *)buf; ops.mode = MTD_OPS_PLACE_OOB; - ret = nand_do_write_ops(mtd, to, &ops); + ret = nand_do_write_ops(chip, to, &ops); *retlen = ops.retlen; return ret; } /** - * nand_do_write_oob - [MTD Interface] NAND write out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure - * - * NAND write out-of-band. - */ -static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, - struct mtd_oob_ops *ops) -{ - int chipnr, page, status, len; - struct nand_chip *chip = mtd_to_nand(mtd); - - pr_debug("%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int)to, (int)ops->ooblen); - - len = mtd_oobavail(mtd, ops); - - /* Do not allow write past end of page */ - if ((ops->ooboffs + ops->ooblen) > len) { - pr_debug("%s: attempt to write past end of page\n", - __func__); - return -EINVAL; - } - - chipnr = (int)(to >> chip->chip_shift); - - /* - * Reset the chip. Some chips (like the Toshiba TC5832DC found in one - * of my DiskOnChip 2000 test units) will clear the whole data page too - * if we don't do this. I have no clue why, but I seem to have 'fixed' - * it in the doc2000 driver in August 1999. dwmw2. - */ - nand_reset(chip, chipnr); - - chip->select_chip(chip, chipnr); - - /* Shift to get page */ - page = (int)(to >> chip->page_shift); - - /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { - chip->select_chip(chip, -1); - return -EROFS; - } - - /* Invalidate the page cache, if we write to the cached page */ - if (page == chip->pagebuf) - chip->pagebuf = -1; - - nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); - - if (ops->mode == MTD_OPS_RAW) - status = chip->ecc.write_oob_raw(chip, page & chip->pagemask); - else - status = chip->ecc.write_oob(chip, page & chip->pagemask); - - chip->select_chip(chip, -1); - - if (status) - return status; - - ops->oobretlen = ops->ooblen; - - return 0; -} - -/** * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band * @mtd: MTD device structure * @to: offset to write to @@ -4067,11 +4127,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { + struct nand_chip *chip = mtd_to_nand(mtd); int ret = -ENOTSUPP; ops->retlen = 0; - nand_get_device(mtd, FL_WRITING); + nand_get_device(chip, FL_WRITING); switch (ops->mode) { case MTD_OPS_PLACE_OOB: @@ -4084,12 +4145,12 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, } if (!ops->datbuf) - ret = nand_do_write_oob(mtd, to, ops); + ret = nand_do_write_oob(chip, to, ops); else - ret = nand_do_write_ops(mtd, to, ops); + ret = nand_do_write_ops(chip, to, ops); out: - nand_release_device(mtd); + nand_release_device(chip); return ret; } @@ -4133,7 +4194,6 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, int allowbbt) { - struct mtd_info *mtd = nand_to_mtd(chip); int page, status, pages_per_block, ret, chipnr; loff_t len; @@ -4141,11 +4201,11 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, __func__, (unsigned long long)instr->addr, (unsigned long long)instr->len); - if (check_offs_len(mtd, instr->addr, instr->len)) + if (check_offs_len(chip, instr->addr, instr->len)) return -EINVAL; /* Grab the lock and see if the device is available */ - nand_get_device(mtd, FL_ERASING); + nand_get_device(chip, FL_ERASING); /* Shift to get first page */ page = (int)(instr->addr >> chip->page_shift); @@ -4155,10 +4215,10 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); /* Select the NAND device */ - chip->select_chip(chip, chipnr); + nand_select_target(chip, chipnr); /* Check, if it is write protected */ - if (nand_check_wp(mtd)) { + if (nand_check_wp(chip)) { pr_debug("%s: device is write protected!\n", __func__); ret = -EIO; @@ -4170,7 +4230,7 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, while (len) { /* Check if we have a bad block, we do not erase bad blocks! */ - if (nand_block_checkbad(mtd, ((loff_t) page) << + if (nand_block_checkbad(chip, ((loff_t) page) << chip->page_shift, allowbbt)) { pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", __func__, page); @@ -4209,8 +4269,8 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, /* Check, if we cross a chip boundary */ if (len && !(page & chip->pagemask)) { chipnr++; - chip->select_chip(chip, -1); - chip->select_chip(chip, chipnr); + nand_deselect_target(chip); + nand_select_target(chip, chipnr); } } @@ -4218,8 +4278,8 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, erase_exit: /* Deselect and wake up anyone waiting on the device */ - chip->select_chip(chip, -1); - nand_release_device(mtd); + nand_deselect_target(chip); + nand_release_device(chip); /* Return more or less happy */ return ret; @@ -4233,12 +4293,14 @@ erase_exit: */ static void nand_sync(struct mtd_info *mtd) { + struct nand_chip *chip = mtd_to_nand(mtd); + pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ - nand_get_device(mtd, FL_SYNCING); + nand_get_device(chip, FL_SYNCING); /* Release it and go back */ - nand_release_device(mtd); + nand_release_device(chip); } /** @@ -4253,13 +4315,13 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) int ret; /* Select the NAND device */ - nand_get_device(mtd, FL_READING); - chip->select_chip(chip, chipnr); + nand_get_device(chip, FL_READING); + nand_select_target(chip, chipnr); - ret = nand_block_checkbad(mtd, offs, 0); + ret = nand_block_checkbad(chip, offs, 0); - chip->select_chip(chip, -1); - nand_release_device(mtd); + nand_deselect_target(chip); + nand_release_device(chip); return ret; } @@ -4281,7 +4343,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) return ret; } - return nand_block_markbad_lowlevel(mtd, ofs); + return nand_block_markbad_lowlevel(mtd_to_nand(mtd), ofs); } /** @@ -4326,7 +4388,7 @@ static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) */ static int nand_suspend(struct mtd_info *mtd) { - return nand_get_device(mtd, FL_PM_SUSPENDED); + return nand_get_device(mtd_to_nand(mtd), FL_PM_SUSPENDED); } /** @@ -4338,7 +4400,7 @@ static void nand_resume(struct mtd_info *mtd) struct nand_chip *chip = mtd_to_nand(mtd); if (chip->state == FL_PM_SUSPENDED) - nand_release_device(mtd); + nand_release_device(chip); else pr_err("%s called for a chip which is not in suspended state\n", __func__); @@ -4351,7 +4413,7 @@ static void nand_resume(struct mtd_info *mtd) */ static void nand_shutdown(struct mtd_info *mtd) { - nand_get_device(mtd, FL_PM_SUSPENDED); + nand_get_device(mtd_to_nand(mtd), FL_PM_SUSPENDED); } /* Set default functions */ @@ -4627,7 +4689,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) return ret; /* Select the device */ - chip->select_chip(chip, 0); + nand_select_target(chip, 0); /* Send the command for reading device ID */ ret = nand_readid_op(chip, 0, id_data, 2); @@ -4952,6 +5014,9 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, unsigned int i; int ret; + /* Assume all dies are deselected when we enter nand_scan_ident(). */ + chip->cur_cs = -1; + /* Enforce the right timings for reset/detection */ onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0); @@ -4962,15 +5027,16 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, if (!mtd->name && mtd->dev.parent) mtd->name = dev_name(mtd->dev.parent); - if (chip->exec_op && !chip->select_chip) { - pr_err("->select_chip() is mandatory when implementing ->exec_op()\n"); - return -EINVAL; - } - ret = nand_legacy_check_hooks(chip); if (ret) return ret; + /* + * Start with chips->numchips = maxchips to let nand_select_target() do + * its job. chip->numchips will be adjusted after. + */ + chip->numchips = maxchips; + /* Set the default functions */ nand_set_defaults(chip); @@ -4979,14 +5045,14 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, if (ret) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) pr_warn("No NAND device found\n"); - chip->select_chip(chip, -1); + nand_deselect_target(chip); return ret; } nand_maf_id = chip->id.data[0]; nand_dev_id = chip->id.data[1]; - chip->select_chip(chip, -1); + nand_deselect_target(chip); /* Check for a chip array */ for (i = 1; i < maxchips; i++) { @@ -4995,15 +5061,15 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, /* See comment in nand_get_flash_type for reset */ nand_reset(chip, i); - chip->select_chip(chip, i); + nand_select_target(chip, i); /* Send the command for reading device ID */ nand_readid_op(chip, 0, id, sizeof(id)); /* Read manufacturer and device IDs */ if (nand_maf_id != id[0] || nand_dev_id != id[1]) { - chip->select_chip(chip, -1); + nand_deselect_target(chip); break; } - chip->select_chip(chip, -1); + nand_deselect_target(chip); } if (i > 1) pr_info("%d chips detected\n", i); @@ -5021,9 +5087,9 @@ static void nand_scan_ident_cleanup(struct nand_chip *chip) kfree(chip->parameters.onfi); } -static int nand_set_ecc_soft_ops(struct mtd_info *mtd) +static int nand_set_ecc_soft_ops(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; if (WARN_ON(ecc->mode != NAND_ECC_SOFT)) @@ -5379,9 +5445,9 @@ EXPORT_SYMBOL_GPL(nand_ecc_choose_conf); * Requirement (2) ensures we can correct even when all bitflips are clumped * in the same sector. */ -static bool nand_ecc_strength_good(struct mtd_info *mtd) +static bool nand_ecc_strength_good(struct nand_chip *chip) { - struct nand_chip *chip = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; int corr, ds_corr; @@ -5429,9 +5495,9 @@ static int nand_scan_tail(struct nand_chip *chip) * to explictly select the relevant die when interacting with the NAND * chip. */ - chip->select_chip(chip, 0); + nand_select_target(chip, 0); ret = nand_manufacturer_init(chip); - chip->select_chip(chip, -1); + nand_deselect_target(chip); if (ret) goto err_free_buf; @@ -5546,7 +5612,7 @@ static int nand_scan_tail(struct nand_chip *chip) ecc->algo = NAND_ECC_HAMMING; case NAND_ECC_SOFT: - ret = nand_set_ecc_soft_ops(mtd); + ret = nand_set_ecc_soft_ops(chip); if (ret) { ret = -EINVAL; goto err_nand_manuf_cleanup; @@ -5631,7 +5697,7 @@ static int nand_scan_tail(struct nand_chip *chip) mtd->oobavail = ret; /* ECC sanity check: warn if it's too weak */ - if (!nand_ecc_strength_good(mtd)) + if (!nand_ecc_strength_good(chip)) pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n", mtd->name); diff --git a/drivers/mtd/nand/raw/nand_bbt.c b/drivers/mtd/nand/raw/nand_bbt.c index 98a826838b60..1b722fe9213c 100644 --- a/drivers/mtd/nand/raw/nand_bbt.c +++ b/drivers/mtd/nand/raw/nand_bbt.c @@ -77,8 +77,6 @@ #define BBT_ENTRY_MASK 0x03 #define BBT_ENTRY_SHIFT 2 -static int nand_update_bbt(struct mtd_info *mtd, loff_t offs); - static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block) { uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT]; @@ -160,7 +158,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td) /** * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd: MTD device structure + * @chip: NAND chip object * @buf: temporary buffer * @page: the starting page * @num: the number of bbt descriptors to read @@ -169,11 +167,11 @@ static u32 add_marker_len(struct nand_bbt_descr *td) * * Read the bad block table starting from page. */ -static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, - struct nand_bbt_descr *td, int offs) +static int read_bbt(struct nand_chip *this, uint8_t *buf, int page, int num, + struct nand_bbt_descr *td, int offs) { + struct mtd_info *mtd = nand_to_mtd(this); int res, ret = 0, i, j, act = 0; - struct nand_chip *this = mtd_to_nand(mtd); size_t retlen, len, totlen; loff_t from; int bits = td->options & NAND_BBT_NRBITS_MSK; @@ -253,7 +251,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, /** * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @td: descriptor for the bad block table * @chip: read the table for a specific chip, -1 read all chips; applies only if @@ -262,16 +260,17 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, * Read the bad block table for all chips starting at a given page. We assume * that the bbt bits are in consecutive order. */ -static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) +static int read_abs_bbt(struct nand_chip *this, uint8_t *buf, + struct nand_bbt_descr *td, int chip) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); int res = 0, i; if (td->options & NAND_BBT_PERCHIP) { int offs = 0; for (i = 0; i < this->numchips; i++) { if (chip == -1 || chip == i) - res = read_bbt(mtd, buf, td->pages[i], + res = read_bbt(this, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, td, offs); if (res) @@ -279,7 +278,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc offs += this->chipsize >> this->bbt_erase_shift; } } else { - res = read_bbt(mtd, buf, td->pages[0], + res = read_bbt(this, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, td, 0); if (res) return res; @@ -288,9 +287,10 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } /* BBT marker is in the first page, no OOB */ -static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - struct nand_bbt_descr *td) +static int scan_read_data(struct nand_chip *this, uint8_t *buf, loff_t offs, + struct nand_bbt_descr *td) { + struct mtd_info *mtd = nand_to_mtd(this); size_t retlen; size_t len; @@ -303,7 +303,7 @@ static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, /** * scan_read_oob - [GENERIC] Scan data+OOB region to buffer - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @offs: offset at which to scan * @len: length of data region to read @@ -312,9 +312,10 @@ static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest" * ECC condition (error or bitflip). May quit on the first (non-ECC) error. */ -static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +static int scan_read_oob(struct nand_chip *this, uint8_t *buf, loff_t offs, size_t len) { + struct mtd_info *mtd = nand_to_mtd(this); struct mtd_oob_ops ops; int res, ret = 0; @@ -342,19 +343,20 @@ static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, return ret; } -static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - size_t len, struct nand_bbt_descr *td) +static int scan_read(struct nand_chip *this, uint8_t *buf, loff_t offs, + size_t len, struct nand_bbt_descr *td) { if (td->options & NAND_BBT_NO_OOB) - return scan_read_data(mtd, buf, offs, td); + return scan_read_data(this, buf, offs, td); else - return scan_read_oob(mtd, buf, offs, len); + return scan_read_oob(this, buf, offs, len); } /* Scan write data with oob to flash */ -static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, +static int scan_write_bbt(struct nand_chip *this, loff_t offs, size_t len, uint8_t *buf, uint8_t *oob) { + struct mtd_info *mtd = nand_to_mtd(this); struct mtd_oob_ops ops; ops.mode = MTD_OPS_PLACE_OOB; @@ -367,8 +369,9 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, return mtd_write_oob(mtd, offs, &ops); } -static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) +static u32 bbt_get_ver_offs(struct nand_chip *this, struct nand_bbt_descr *td) { + struct mtd_info *mtd = nand_to_mtd(this); u32 ver_offs = td->veroffs; if (!(td->options & NAND_BBT_NO_OOB)) @@ -378,7 +381,7 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror @@ -386,34 +389,35 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) * Read the bad block table(s) for all chips starting at a given page. We * assume that the bbt bits are in consecutive order. */ -static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, +static void read_abs_bbts(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { - scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift, - mtd->writesize, td); - td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; + scan_read(this, buf, (loff_t)td->pages[0] << this->page_shift, + mtd->writesize, td); + td->version[0] = buf[bbt_get_ver_offs(this, td)]; pr_info("Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { - scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift, - mtd->writesize, md); - md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; + scan_read(this, buf, (loff_t)md->pages[0] << this->page_shift, + mtd->writesize, md); + md->version[0] = buf[bbt_get_ver_offs(this, md)]; pr_info("Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } } /* Scan a given block partially */ -static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, +static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd, loff_t offs, uint8_t *buf, int numpages) { + struct mtd_info *mtd = nand_to_mtd(this); struct mtd_oob_ops ops; int j, ret; @@ -443,7 +447,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, /** * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @bd: descriptor for the good/bad block search pattern * @chip: create the table for a specific chip, -1 read all chips; applies only @@ -452,10 +456,10 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, * Create a bad block table by scanning the device for the given good/bad block * identify pattern. */ -static int create_bbt(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *bd, int chip) +static int create_bbt(struct nand_chip *this, uint8_t *buf, + struct nand_bbt_descr *bd, int chip) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); int i, numblocks, numpages; int startblock; loff_t from; @@ -491,7 +495,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, BUG_ON(bd->options & NAND_BBT_NO_OOB); - ret = scan_block_fast(mtd, bd, from, buf, numpages); + ret = scan_block_fast(this, bd, from, buf, numpages); if (ret < 0) return ret; @@ -509,7 +513,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, /** * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @td: descriptor for the bad block table * @@ -522,9 +526,10 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, * * The bbt ident pattern resides in the oob area of the first page in a block. */ -static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) +static int search_bbt(struct nand_chip *this, uint8_t *buf, + struct nand_bbt_descr *td) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); int i, chips; int startblock, block, dir; int scanlen = mtd->writesize + mtd->oobsize; @@ -561,11 +566,11 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr loff_t offs = (loff_t)actblock << this->bbt_erase_shift; /* Read first page */ - scan_read(mtd, buf, offs, mtd->writesize, td); + scan_read(this, buf, offs, mtd->writesize, td); if (!check_pattern(buf, scanlen, mtd->writesize, td)) { td->pages[i] = actblock << blocktopage; if (td->options & NAND_BBT_VERSION) { - offs = bbt_get_ver_offs(mtd, td); + offs = bbt_get_ver_offs(this, td); td->version[i] = buf[offs]; } break; @@ -586,23 +591,23 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /** * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror * * Search and read the bad block table(s). */ -static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf, +static void search_read_bbts(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { /* Search the primary table */ - search_bbt(mtd, buf, td); + search_bbt(this, buf, td); /* Search the mirror table */ if (md) - search_bbt(mtd, buf, md); + search_bbt(this, buf, md); } /** @@ -700,7 +705,7 @@ static void mark_bbt_block_bad(struct nand_chip *this, /** * write_bbt - [GENERIC] (Re)write the bad block table - * @mtd: MTD device structure + * @this: NAND chip object * @buf: temporary buffer * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror @@ -708,11 +713,11 @@ static void mark_bbt_block_bad(struct nand_chip *this, * * (Re)write the bad block table. */ -static int write_bbt(struct mtd_info *mtd, uint8_t *buf, +static int write_bbt(struct nand_chip *this, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); struct erase_info einfo; int i, res, chip = 0; int bits, page, offs, numblocks, sft, sftmsk; @@ -862,9 +867,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, continue; } - res = scan_write_bbt(mtd, to, len, buf, - td->options & NAND_BBT_NO_OOB ? NULL : - &buf[len]); + res = scan_write_bbt(this, to, len, buf, + td->options & NAND_BBT_NO_OOB ? + NULL : &buf[len]); if (res < 0) { pr_warn("nand_bbt: error while writing BBT block %d\n", res); @@ -887,22 +892,21 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, /** * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd: MTD device structure + * @this: NAND chip object * @bd: descriptor for the good/bad block search pattern * * The function creates a memory based bbt by scanning the device for * manufacturer / software marked good / bad blocks. */ -static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) +static inline int nand_memory_bbt(struct nand_chip *this, + struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd_to_nand(mtd); - - return create_bbt(mtd, this->data_buf, bd, -1); + return create_bbt(this, this->data_buf, bd, -1); } /** * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd: MTD device structure + * @this: the NAND device * @buf: temporary buffer * @bd: descriptor for the good/bad block search pattern * @@ -911,10 +915,10 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b * for the chip/device. Update is necessary if one of the tables is missing or * the version nr. of one table is less than the other. */ -static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) +static int check_create(struct nand_chip *this, uint8_t *buf, + struct nand_bbt_descr *bd) { int i, chips, writeops, create, chipsel, res, res2; - struct nand_chip *this = mtd_to_nand(mtd); struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; struct nand_bbt_descr *rd, *rd2; @@ -971,7 +975,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /* Create the table in memory by scanning the chip(s) */ if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) - create_bbt(mtd, buf, bd, chipsel); + create_bbt(this, buf, bd, chipsel); td->version[i] = 1; if (md) @@ -980,7 +984,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /* Read back first? */ if (rd) { - res = read_abs_bbt(mtd, buf, rd, chipsel); + res = read_abs_bbt(this, buf, rd, chipsel); if (mtd_is_eccerr(res)) { /* Mark table as invalid */ rd->pages[i] = -1; @@ -991,7 +995,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } /* If they weren't versioned, read both */ if (rd2) { - res2 = read_abs_bbt(mtd, buf, rd2, chipsel); + res2 = read_abs_bbt(this, buf, rd2, chipsel); if (mtd_is_eccerr(res2)) { /* Mark table as invalid */ rd2->pages[i] = -1; @@ -1013,14 +1017,14 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /* Write the bad block table to the device? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, td, md, chipsel); + res = write_bbt(this, buf, td, md, chipsel); if (res < 0) return res; } /* Write the mirror bad block table to the device? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); + res = write_bbt(this, buf, md, td, chipsel); if (res < 0) return res; } @@ -1029,16 +1033,71 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc } /** + * nand_update_bbt - update bad block table(s) + * @this: the NAND device + * @offs: the offset of the newly marked block + * + * The function updates the bad block table(s). + */ +static int nand_update_bbt(struct nand_chip *this, loff_t offs) +{ + struct mtd_info *mtd = nand_to_mtd(this); + int len, res = 0; + int chip, chipsel; + uint8_t *buf; + struct nand_bbt_descr *td = this->bbt_td; + struct nand_bbt_descr *md = this->bbt_md; + + if (!this->bbt || !td) + return -EINVAL; + + /* Allocate a temporary buffer for one eraseblock incl. oob */ + len = (1 << this->bbt_erase_shift); + len += (len >> this->page_shift) * mtd->oobsize; + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* Do we have a bbt per chip? */ + if (td->options & NAND_BBT_PERCHIP) { + chip = (int)(offs >> this->chip_shift); + chipsel = chip; + } else { + chip = 0; + chipsel = -1; + } + + td->version[chip]++; + if (md) + md->version[chip]++; + + /* Write the bad block table to the device? */ + if (td->options & NAND_BBT_WRITE) { + res = write_bbt(this, buf, td, md, chipsel); + if (res < 0) + goto out; + } + /* Write the mirror bad block table to the device? */ + if (md && (md->options & NAND_BBT_WRITE)) { + res = write_bbt(this, buf, md, td, chipsel); + } + + out: + kfree(buf); + return res; +} + +/** * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd: MTD device structure + * @this: the NAND device * @td: bad block table descriptor * * The bad block table regions are marked as "bad" to prevent accidental * erasures / writes. The regions are identified by the mark 0x02. */ -static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) +static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); int i, j, chips, block, nrblocks, update; uint8_t oldval; @@ -1061,7 +1120,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) bbt_mark_entry(this, block, BBT_BLOCK_RESERVED); if ((oldval != BBT_BLOCK_RESERVED) && td->reserved_block_code) - nand_update_bbt(mtd, (loff_t)block << + nand_update_bbt(this, (loff_t)block << this->bbt_erase_shift); continue; } @@ -1083,22 +1142,22 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) * bbts. This should only happen once. */ if (update && td->reserved_block_code) - nand_update_bbt(mtd, (loff_t)(block - 1) << + nand_update_bbt(this, (loff_t)(block - 1) << this->bbt_erase_shift); } } /** * verify_bbt_descr - verify the bad block description - * @mtd: MTD device structure + * @this: the NAND device * @bd: the table to verify * * This functions performs a few sanity checks on the bad block description * table. */ -static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) +static void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); u32 pattern_len; u32 bits; u32 table_size; @@ -1138,7 +1197,7 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) /** * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd: MTD device structure + * @this: the NAND device * @bd: descriptor for the good/bad block search pattern * * The function checks, if a bad block table(s) is/are already available. If @@ -1148,9 +1207,9 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) * The bad block table memory is allocated here. It must be freed by calling * the nand_free_bbt function. */ -static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) +static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd) { - struct nand_chip *this = mtd_to_nand(mtd); + struct mtd_info *mtd = nand_to_mtd(this); int len, res; uint8_t *buf; struct nand_bbt_descr *td = this->bbt_td; @@ -1170,14 +1229,14 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) * memory based bad block table. */ if (!td) { - if ((res = nand_memory_bbt(mtd, bd))) { + if ((res = nand_memory_bbt(this, bd))) { pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); goto err; } return 0; } - verify_bbt_descr(mtd, td); - verify_bbt_descr(mtd, md); + verify_bbt_descr(this, td); + verify_bbt_descr(this, md); /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); @@ -1190,20 +1249,20 @@ static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) /* Is the bbt at a given page? */ if (td->options & NAND_BBT_ABSPAGE) { - read_abs_bbts(mtd, buf, td, md); + read_abs_bbts(this, buf, td, md); } else { /* Search the bad block table using a pattern in oob */ - search_read_bbts(mtd, buf, td, md); + search_read_bbts(this, buf, td, md); } - res = check_create(mtd, buf, bd); + res = check_create(this, buf, bd); if (res) goto err; /* Prevent the bbt regions from erasing / writing */ - mark_bbt_region(mtd, td); + mark_bbt_region(this, td); if (md) - mark_bbt_region(mtd, md); + mark_bbt_region(this, md); vfree(buf); return 0; @@ -1214,61 +1273,6 @@ err: return res; } -/** - * nand_update_bbt - update bad block table(s) - * @mtd: MTD device structure - * @offs: the offset of the newly marked block - * - * The function updates the bad block table(s). - */ -static int nand_update_bbt(struct mtd_info *mtd, loff_t offs) -{ - struct nand_chip *this = mtd_to_nand(mtd); - int len, res = 0; - int chip, chipsel; - uint8_t *buf; - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - - if (!this->bbt || !td) - return -EINVAL; - - /* Allocate a temporary buffer for one eraseblock incl. oob */ - len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* Do we have a bbt per chip? */ - if (td->options & NAND_BBT_PERCHIP) { - chip = (int)(offs >> this->chip_shift); - chipsel = chip; - } else { - chip = 0; - chipsel = -1; - } - - td->version[chip]++; - if (md) - md->version[chip]++; - - /* Write the bad block table to the device? */ - if (td->options & NAND_BBT_WRITE) { - res = write_bbt(mtd, buf, td, md, chipsel); - if (res < 0) - goto out; - } - /* Write the mirror bad block table to the device? */ - if (md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); - } - - out: - kfree(buf); - return res; -} - /* * Define some generic bad / good block scan pattern which are used * while scanning a device for factory marked good / bad blocks. @@ -1382,7 +1386,7 @@ int nand_create_bbt(struct nand_chip *this) return ret; } - return nand_scan_bbt(nand_to_mtd(this), this->badblock_pattern); + return nand_scan_bbt(this, this->badblock_pattern); } EXPORT_SYMBOL(nand_create_bbt); @@ -1433,7 +1437,6 @@ int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt) */ int nand_markbad_bbt(struct nand_chip *this, loff_t offs) { - struct mtd_info *mtd = nand_to_mtd(this); int block, ret = 0; block = (int)(offs >> this->bbt_erase_shift); @@ -1443,7 +1446,7 @@ int nand_markbad_bbt(struct nand_chip *this, loff_t offs) /* Update flash-based bad block table */ if (this->bbt_options & NAND_BBT_USE_FLASH) - ret = nand_update_bbt(mtd, offs); + ret = nand_update_bbt(this, offs); return ret; } diff --git a/drivers/mtd/nand/raw/nand_hynix.c b/drivers/mtd/nand/raw/nand_hynix.c index ac1b5c103968..343f477362d1 100644 --- a/drivers/mtd/nand/raw/nand_hynix.c +++ b/drivers/mtd/nand/raw/nand_hynix.c @@ -80,11 +80,11 @@ static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip) static int hynix_nand_cmd_op(struct nand_chip *chip, u8 cmd) { - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { struct nand_op_instr instrs[] = { NAND_OP_CMD(cmd, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); return nand_exec_op(chip, &op); } @@ -98,12 +98,12 @@ static int hynix_nand_reg_write_op(struct nand_chip *chip, u8 addr, u8 val) { u16 column = ((u16)addr << 8) | addr; - if (chip->exec_op) { + if (nand_has_exec_op(chip)) { struct nand_op_instr instrs[] = { NAND_OP_ADDR(1, &addr, 0), NAND_OP_8BIT_DATA_OUT(1, &val, 0), }; - struct nand_operation op = NAND_OPERATION(instrs); + struct nand_operation op = NAND_OPERATION(chip->cur_cs, instrs); return nand_exec_op(chip, &op); } diff --git a/drivers/mtd/nand/raw/nand_legacy.c b/drivers/mtd/nand/raw/nand_legacy.c index c5ddc86cd98c..43575943f13b 100644 --- a/drivers/mtd/nand/raw/nand_legacy.c +++ b/drivers/mtd/nand/raw/nand_legacy.c @@ -165,15 +165,14 @@ static void nand_read_buf16(struct nand_chip *chip, uint8_t *buf, int len) /** * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands. - * @mtd: MTD device structure + * @chip: NAND chip object * @timeo: Timeout * * Helper function for nand_wait_ready used when needing to wait in interrupt * context. */ -static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) +static void panic_nand_wait_ready(struct nand_chip *chip, unsigned long timeo) { - struct nand_chip *chip = mtd_to_nand(mtd); int i; /* Wait for the device to get ready */ @@ -193,11 +192,10 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) */ void nand_wait_ready(struct nand_chip *chip) { - struct mtd_info *mtd = nand_to_mtd(chip); unsigned long timeo = 400; if (in_interrupt() || oops_in_progress) - return panic_nand_wait_ready(mtd, timeo); + return panic_nand_wait_ready(chip, timeo); /* Wait until command is processed or timeout occurs */ timeo = jiffies + msecs_to_jiffies(timeo); @@ -214,14 +212,13 @@ EXPORT_SYMBOL_GPL(nand_wait_ready); /** * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands. - * @mtd: MTD device structure + * @chip: NAND chip object * @timeo: Timeout in ms * * Wait for status ready (i.e. command done) or timeout. */ -static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo) +static void nand_wait_status_ready(struct nand_chip *chip, unsigned long timeo) { - register struct nand_chip *chip = mtd_to_nand(mtd); int ret; timeo = jiffies + msecs_to_jiffies(timeo); @@ -321,7 +318,7 @@ static void nand_command(struct nand_chip *chip, unsigned int command, chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ - nand_wait_status_ready(mtd, 250); + nand_wait_status_ready(chip, 250); return; /* This applies to read commands */ @@ -367,7 +364,7 @@ static void nand_ccs_delay(struct nand_chip *chip) * Wait tCCS_min if it is correctly defined, otherwise wait 500ns * (which should be safe for all NANDs). */ - if (chip->setup_data_interface) + if (nand_has_setup_data_iface(chip)) ndelay(chip->data_interface.timings.sdr.tCCS_min / 1000); else ndelay(500); @@ -458,7 +455,7 @@ static void nand_command_lp(struct nand_chip *chip, unsigned int command, chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ - nand_wait_status_ready(mtd, 250); + nand_wait_status_ready(chip, 250); return; case NAND_CMD_RNDOUT: @@ -525,7 +522,6 @@ EXPORT_SYMBOL(nand_get_set_features_notsupp); /** * nand_wait - [DEFAULT] wait until the command is done - * @mtd: MTD device structure * @chip: NAND chip structure * * Wait for command done. This applies to erase and program only. @@ -581,7 +577,7 @@ void nand_legacy_set_defaults(struct nand_chip *chip) { unsigned int busw = chip->options & NAND_BUSWIDTH_16; - if (chip->exec_op) + if (nand_has_exec_op(chip)) return; /* check for proper chip_delay setup, set 20us if not */ @@ -589,15 +585,15 @@ void nand_legacy_set_defaults(struct nand_chip *chip) chip->legacy.chip_delay = 20; /* check, if a user supplied command function given */ - if (!chip->legacy.cmdfunc && !chip->exec_op) + if (!chip->legacy.cmdfunc) chip->legacy.cmdfunc = nand_command; /* check, if a user supplied wait function given */ if (chip->legacy.waitfunc == NULL) chip->legacy.waitfunc = nand_wait; - if (!chip->select_chip) - chip->select_chip = nand_select_chip; + if (!chip->legacy.select_chip) + chip->legacy.select_chip = nand_select_chip; /* If called twice, pointers that depend on busw may need to be reset */ if (!chip->legacy.read_byte || chip->legacy.read_byte == nand_read_byte) @@ -625,14 +621,15 @@ int nand_legacy_check_hooks(struct nand_chip *chip) * ->legacy.cmdfunc() is legacy and will only be used if ->exec_op() is * not populated. */ - if (chip->exec_op) + if (nand_has_exec_op(chip)) return 0; /* * Default functions assigned for ->legacy.cmdfunc() and - * ->select_chip() both expect ->legacy.cmd_ctrl() to be populated. + * ->legacy.select_chip() both expect ->legacy.cmd_ctrl() to be + * populated. */ - if ((!chip->legacy.cmdfunc || !chip->select_chip) && + if ((!chip->legacy.cmdfunc || !chip->legacy.select_chip) && !chip->legacy.cmd_ctrl) { pr_err("->legacy.cmd_ctrl() should be provided\n"); return -EINVAL; diff --git a/drivers/mtd/nand/raw/nand_macronix.c b/drivers/mtd/nand/raw/nand_macronix.c index 358dcc957bb2..47d8cda547cf 100644 --- a/drivers/mtd/nand/raw/nand_macronix.c +++ b/drivers/mtd/nand/raw/nand_macronix.c @@ -33,6 +33,13 @@ static void macronix_nand_fix_broken_get_timings(struct nand_chip *chip) "MX30LF4G18AC", "MX30LF4G28AC", "MX60LF8G18AC", + "MX30UF1G18AC", + "MX30UF1G16AC", + "MX30UF2G18AC", + "MX30UF2G16AC", + "MX30UF4G18AC", + "MX30UF4G16AC", + "MX30UF4G28AC", }; if (!chip->parameters.supports_set_get_features) diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c index d49a7a17146c..9857e0e5acd4 100644 --- a/drivers/mtd/nand/raw/ndfc.c +++ b/drivers/mtd/nand/raw/ndfc.c @@ -146,7 +146,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, chip->legacy.IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; chip->legacy.cmd_ctrl = ndfc_hwcontrol; chip->legacy.dev_ready = ndfc_ready; - chip->select_chip = ndfc_select_chip; + chip->legacy.select_chip = ndfc_select_chip; chip->legacy.chip_delay = 50; chip->controller = &ndfc->ndfc_control; chip->legacy.read_buf = ndfc_read_buf; diff --git a/drivers/mtd/nand/raw/plat_nand.c b/drivers/mtd/nand/raw/plat_nand.c index 86c536ddaf24..a994b76daa50 100644 --- a/drivers/mtd/nand/raw/plat_nand.c +++ b/drivers/mtd/nand/raw/plat_nand.c @@ -63,7 +63,7 @@ static int plat_nand_probe(struct platform_device *pdev) data->chip.legacy.IO_ADDR_W = data->io_base; data->chip.legacy.cmd_ctrl = pdata->ctrl.cmd_ctrl; data->chip.legacy.dev_ready = pdata->ctrl.dev_ready; - data->chip.select_chip = pdata->ctrl.select_chip; + data->chip.legacy.select_chip = pdata->ctrl.select_chip; data->chip.legacy.write_buf = pdata->ctrl.write_buf; data->chip.legacy.read_buf = pdata->ctrl.read_buf; data->chip.legacy.chip_delay = pdata->chip.chip_delay; diff --git a/drivers/mtd/nand/raw/qcom_nandc.c b/drivers/mtd/nand/raw/qcom_nandc.c index 699d3cf49c6d..46c62a31fa46 100644 --- a/drivers/mtd/nand/raw/qcom_nandc.c +++ b/drivers/mtd/nand/raw/qcom_nandc.c @@ -2804,7 +2804,7 @@ static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, mtd->dev.parent = dev; chip->legacy.cmdfunc = qcom_nandc_command; - chip->select_chip = qcom_nandc_select_chip; + chip->legacy.select_chip = qcom_nandc_select_chip; chip->legacy.read_byte = qcom_nandc_read_byte; chip->legacy.read_buf = qcom_nandc_read_buf; chip->legacy.write_buf = qcom_nandc_write_buf; diff --git a/drivers/mtd/nand/raw/r852.c b/drivers/mtd/nand/raw/r852.c index 39be65b35ac2..c01422d953dd 100644 --- a/drivers/mtd/nand/raw/r852.c +++ b/drivers/mtd/nand/raw/r852.c @@ -151,8 +151,9 @@ static void r852_dma_done(struct r852_device *dev, int error) dev->dma_stage = 0; if (dev->phys_dma_addr && dev->phys_dma_addr != dev->phys_bounce_buffer) - pci_unmap_single(dev->pci_dev, dev->phys_dma_addr, R852_DMA_LEN, - dev->dma_dir ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + dma_unmap_single(&dev->pci_dev->dev, dev->phys_dma_addr, + R852_DMA_LEN, + dev->dma_dir ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } /* @@ -197,11 +198,10 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read) bounce = 1; if (!bounce) { - dev->phys_dma_addr = pci_map_single(dev->pci_dev, (void *)buf, + dev->phys_dma_addr = dma_map_single(&dev->pci_dev->dev, buf, R852_DMA_LEN, - (do_read ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE)); - - if (pci_dma_mapping_error(dev->pci_dev, dev->phys_dma_addr)) + do_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + if (dma_mapping_error(&dev->pci_dev->dev, dev->phys_dma_addr)) bounce = 1; } @@ -835,7 +835,7 @@ static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) pci_set_master(pci_dev); - error = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + error = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (error) goto error2; @@ -885,8 +885,8 @@ static int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) dev->pci_dev = pci_dev; pci_set_drvdata(pci_dev, dev); - dev->bounce_buffer = pci_alloc_consistent(pci_dev, R852_DMA_LEN, - &dev->phys_bounce_buffer); + dev->bounce_buffer = dma_alloc_coherent(&pci_dev->dev, R852_DMA_LEN, + &dev->phys_bounce_buffer, GFP_KERNEL); if (!dev->bounce_buffer) goto error6; @@ -946,8 +946,8 @@ error9: error8: pci_iounmap(pci_dev, dev->mmio); error7: - pci_free_consistent(pci_dev, R852_DMA_LEN, - dev->bounce_buffer, dev->phys_bounce_buffer); + dma_free_coherent(&pci_dev->dev, R852_DMA_LEN, dev->bounce_buffer, + dev->phys_bounce_buffer); error6: kfree(dev); error5: @@ -980,8 +980,8 @@ static void r852_remove(struct pci_dev *pci_dev) /* Cleanup */ kfree(dev->tmp_buffer); pci_iounmap(pci_dev, dev->mmio); - pci_free_consistent(pci_dev, R852_DMA_LEN, - dev->bounce_buffer, dev->phys_bounce_buffer); + dma_free_coherent(&pci_dev->dev, R852_DMA_LEN, dev->bounce_buffer, + dev->phys_bounce_buffer); kfree(dev->chip); kfree(dev); @@ -1045,9 +1045,9 @@ static int r852_resume(struct device *device) /* Otherwise, initialize the card */ if (dev->card_registered) { r852_engine_enable(dev); - dev->chip->select_chip(dev->chip, 0); + nand_select_target(dev->chip, 0); nand_reset_op(dev->chip); - dev->chip->select_chip(dev->chip, -1); + nand_deselect_target(dev->chip); } /* Program card detection IRQ */ diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c index d2e42e9d0e8c..adc7a196e383 100644 --- a/drivers/mtd/nand/raw/s3c2410.c +++ b/drivers/mtd/nand/raw/s3c2410.c @@ -866,7 +866,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, chip->legacy.write_buf = s3c2410_nand_write_buf; chip->legacy.read_buf = s3c2410_nand_read_buf; - chip->select_chip = s3c2410_nand_select_chip; + chip->legacy.select_chip = s3c2410_nand_select_chip; chip->legacy.chip_delay = 50; nand_set_controller_data(chip, nmtd); chip->options = set->options; @@ -876,8 +876,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, * let's keep behavior unchanged for legacy boards booting via pdata and * auto-detect timings only when booting with a device tree. */ - if (np) - chip->setup_data_interface = s3c2410_nand_setup_data_interface; + if (!np) + chip->options |= NAND_KEEP_TIMINGS; switch (info->cpu_type) { case TYPE_S3C2410: @@ -1011,6 +1011,7 @@ static int s3c2410_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops s3c24xx_nand_controller_ops = { .attach_chip = s3c2410_nand_attach_chip, + .setup_data_interface = s3c2410_nand_setup_data_interface, }; static const struct of_device_id s3c24xx_nand_dt_ids[] = { diff --git a/drivers/mtd/nand/raw/sh_flctl.c b/drivers/mtd/nand/raw/sh_flctl.c index 4d20d033de7b..7ab50bc6ad3a 100644 --- a/drivers/mtd/nand/raw/sh_flctl.c +++ b/drivers/mtd/nand/raw/sh_flctl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH FLCTL nand controller * @@ -5,20 +6,6 @@ * Copyright (c) 2008 Atom Create Engineering Co., Ltd. * * Based on fsl_elbc_nand.c, Copyright (c) 2006-2007 Freescale Semiconductor - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/module.h> @@ -1183,7 +1170,7 @@ static int flctl_probe(struct platform_device *pdev) nand->legacy.read_byte = flctl_read_byte; nand->legacy.write_buf = flctl_write_buf; nand->legacy.read_buf = flctl_read_buf; - nand->select_chip = flctl_select_chip; + nand->legacy.select_chip = flctl_select_chip; nand->legacy.cmdfunc = flctl_cmdfunc; nand->legacy.set_features = nand_get_set_features_notsupp; nand->legacy.get_features = nand_get_set_features_notsupp; @@ -1236,7 +1223,7 @@ static struct platform_driver flctl_driver = { module_platform_driver_probe(flctl_driver, flctl_probe); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Yoshihiro Shimoda"); MODULE_DESCRIPTION("SuperH FLCTL driver"); MODULE_ALIAS("platform:sh_flctl"); diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 51b1a548064b..a5c83cbe4897 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1847,6 +1847,7 @@ static int sunxi_nand_attach_chip(struct nand_chip *nand) static const struct nand_controller_ops sunxi_nand_controller_ops = { .attach_chip = sunxi_nand_attach_chip, + .setup_data_interface = sunxi_nfc_setup_data_interface, }; static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, @@ -1922,12 +1923,11 @@ static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc, */ nand->ecc.mode = NAND_ECC_HW; nand_set_flash_node(nand, np); - nand->select_chip = sunxi_nfc_select_chip; + nand->legacy.select_chip = sunxi_nfc_select_chip; nand->legacy.cmd_ctrl = sunxi_nfc_cmd_ctrl; nand->legacy.read_buf = sunxi_nfc_read_buf; nand->legacy.write_buf = sunxi_nfc_write_buf; nand->legacy.read_byte = sunxi_nfc_read_byte; - nand->setup_data_interface = sunxi_nfc_setup_data_interface; mtd = nand_to_mtd(nand); mtd->dev.parent = dev; diff --git a/drivers/mtd/nand/raw/tango_nand.c b/drivers/mtd/nand/raw/tango_nand.c index 8818f893f300..cb3beda88789 100644 --- a/drivers/mtd/nand/raw/tango_nand.c +++ b/drivers/mtd/nand/raw/tango_nand.c @@ -530,6 +530,7 @@ static int tango_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops tango_controller_ops = { .attach_chip = tango_attach_chip, + .setup_data_interface = tango_set_timings, }; static int chip_init(struct device *dev, struct device_node *np) @@ -567,10 +568,9 @@ static int chip_init(struct device *dev, struct device_node *np) chip->legacy.read_byte = tango_read_byte; chip->legacy.write_buf = tango_write_buf; chip->legacy.read_buf = tango_read_buf; - chip->select_chip = tango_select_chip; + chip->legacy.select_chip = tango_select_chip; chip->legacy.cmd_ctrl = tango_cmd_ctrl; chip->legacy.dev_ready = tango_dev_ready; - chip->setup_data_interface = tango_set_timings; chip->options = NAND_USE_BOUNCE_BUFFER | NAND_NO_SUBPAGE_WRITE | NAND_WAIT_TCCS; diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c index 9767e29d74e2..13be32c38194 100644 --- a/drivers/mtd/nand/raw/tegra_nand.c +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -454,29 +454,24 @@ static const struct nand_op_parser tegra_nand_op_parser = NAND_OP_PARSER( NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, 4)), ); +static void tegra_nand_select_target(struct nand_chip *chip, + unsigned int die_nr) +{ + struct tegra_nand_chip *nand = to_tegra_chip(chip); + struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); + + ctrl->cur_cs = nand->cs[die_nr]; +} + static int tegra_nand_exec_op(struct nand_chip *chip, const struct nand_operation *op, bool check_only) { + tegra_nand_select_target(chip, op->cs); return nand_op_parser_exec_op(chip, &tegra_nand_op_parser, op, check_only); } -static void tegra_nand_select_chip(struct nand_chip *chip, int die_nr) -{ - struct tegra_nand_chip *nand = to_tegra_chip(chip); - struct tegra_nand_controller *ctrl = to_tegra_ctrl(chip->controller); - - WARN_ON(die_nr >= (int)ARRAY_SIZE(nand->cs)); - - if (die_nr < 0 || die_nr > 0) { - ctrl->cur_cs = -1; - return; - } - - ctrl->cur_cs = nand->cs[die_nr]; -} - static void tegra_nand_hw_ecc(struct tegra_nand_controller *ctrl, struct nand_chip *chip, bool enable) { @@ -503,6 +498,8 @@ static int tegra_nand_page_xfer(struct mtd_info *mtd, struct nand_chip *chip, u32 addr1, cmd, dma_ctrl; int ret; + tegra_nand_select_target(chip, chip->cur_cs); + if (read) { writel_relaxed(NAND_CMD_READ0, ctrl->regs + CMD_REG1); writel_relaxed(NAND_CMD_READSTART, ctrl->regs + CMD_REG2); @@ -1053,6 +1050,8 @@ static int tegra_nand_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops tegra_nand_controller_ops = { .attach_chip = &tegra_nand_attach_chip, + .exec_op = tegra_nand_exec_op, + .setup_data_interface = tegra_nand_setup_data_interface, }; static int tegra_nand_chips_init(struct device *dev, @@ -1115,9 +1114,6 @@ static int tegra_nand_chips_init(struct device *dev, mtd->name = "tegra_nand"; chip->options = NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER; - chip->exec_op = tegra_nand_exec_op; - chip->select_chip = tegra_nand_select_chip; - chip->setup_data_interface = tegra_nand_setup_data_interface; ret = nand_scan(chip, 1); if (ret) diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index 9814fd4a84cf..0fa7cac4ce14 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -487,36 +487,35 @@ static const struct nand_op_parser vf610_nfc_op_parser = NAND_OP_PARSER( NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, PAGE_2K + OOB_MAX)), ); -static int vf610_nfc_exec_op(struct nand_chip *chip, - const struct nand_operation *op, - bool check_only) -{ - return nand_op_parser_exec_op(chip, &vf610_nfc_op_parser, op, - check_only); -} - /* * This function supports Vybrid only (MPC5125 would have full RB and four CS) */ -static void vf610_nfc_select_chip(struct nand_chip *chip, int cs) +static void vf610_nfc_select_target(struct nand_chip *chip, unsigned int cs) { struct vf610_nfc *nfc = mtd_to_nfc(nand_to_mtd(chip)); - u32 tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR); + u32 tmp; /* Vybrid only (MPC5125 would have full RB and four CS) */ if (nfc->variant != NFC_VFC610) return; + tmp = vf610_nfc_read(nfc, NFC_ROW_ADDR); tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK); - - if (cs >= 0) { - tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT; - tmp |= BIT(cs) << ROW_ADDR_CHIP_SEL_SHIFT; - } + tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT; + tmp |= BIT(cs) << ROW_ADDR_CHIP_SEL_SHIFT; vf610_nfc_write(nfc, NFC_ROW_ADDR, tmp); } +static int vf610_nfc_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) +{ + vf610_nfc_select_target(chip, op->cs); + return nand_op_parser_exec_op(chip, &vf610_nfc_op_parser, op, + check_only); +} + static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat, uint8_t *oob, int page) { @@ -566,6 +565,8 @@ static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf, u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0; int stat; + vf610_nfc_select_target(chip, chip->cur_cs); + cmd2 |= NAND_CMD_READ0 << CMD_BYTE1_SHIFT; code |= COMMAND_CMD_BYTE1 | COMMAND_CAR_BYTE1 | COMMAND_CAR_BYTE2; @@ -613,6 +614,8 @@ static int vf610_nfc_write_page(struct nand_chip *chip, const uint8_t *buf, u8 status; int ret; + vf610_nfc_select_target(chip, chip->cur_cs); + cmd2 |= NAND_CMD_SEQIN << CMD_BYTE1_SHIFT; code |= COMMAND_CMD_BYTE1 | COMMAND_CAR_BYTE1 | COMMAND_CAR_BYTE2; @@ -809,6 +812,8 @@ static int vf610_nfc_attach_chip(struct nand_chip *chip) static const struct nand_controller_ops vf610_nfc_controller_ops = { .attach_chip = vf610_nfc_attach_chip, + .exec_op = vf610_nfc_exec_op, + }; static int vf610_nfc_probe(struct platform_device *pdev) @@ -876,9 +881,6 @@ static int vf610_nfc_probe(struct platform_device *pdev) goto err_disable_clk; } - chip->exec_op = vf610_nfc_exec_op; - chip->select_chip = vf610_nfc_select_chip; - chip->options |= NAND_NO_SUBPAGE_WRITE; init_completion(&nfc->cmd_done); diff --git a/drivers/mtd/nand/raw/xway_nand.c b/drivers/mtd/nand/raw/xway_nand.c index a234a5cb4868..4cb78106af14 100644 --- a/drivers/mtd/nand/raw/xway_nand.c +++ b/drivers/mtd/nand/raw/xway_nand.c @@ -176,7 +176,7 @@ static int xway_nand_probe(struct platform_device *pdev) data->chip.legacy.cmd_ctrl = xway_cmd_ctrl; data->chip.legacy.dev_ready = xway_dev_ready; - data->chip.select_chip = xway_select_chip; + data->chip.legacy.select_chip = xway_select_chip; data->chip.legacy.write_buf = xway_write_buf; data->chip.legacy.read_buf = xway_read_buf; data->chip.legacy.read_byte = xway_read_byte; diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index b74e074b363a..be5f73512ece 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -spinand-objs := core.o macronix.o micron.o winbond.o +spinand-objs := core.o macronix.o micron.o toshiba.o winbond.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 30f83649c481..87bdf2a7b724 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -766,6 +766,7 @@ static const struct nand_ops spinand_ops = { static const struct spinand_manufacturer *spinand_manufacturers[] = { ¯onix_spinand_manufacturer, µn_spinand_manufacturer, + &toshiba_spinand_manufacturer, &winbond_spinand_manufacturer, }; diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c new file mode 100644 index 000000000000..294bcf625326 --- /dev/null +++ b/drivers/mtd/nand/spi/toshiba.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 exceet electronics GmbH + * Copyright (c) 2018 Kontron Electronics GmbH + * + * Author: Frieder Schrempf <frieder.schrempf@kontron.de> + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/mtd/spinand.h> + +#define SPINAND_MFR_TOSHIBA 0x98 + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD(false, 0, NULL, 0)); + +static int tc58cvg2s0h_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 7) + return -ERANGE; + + region->offset = 128 + 16 * section; + region->length = 16; + + + return 0; +} + +static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 7) + return -ERANGE; + + region->offset = 2 + 16 * section; + region->length = 14; + + + return 0; +} + +static const struct mtd_ooblayout_ops tc58cvg2s0h_ooblayout = { + .ecc = tc58cvg2s0h_ooblayout_ecc, + .free = tc58cvg2s0h_ooblayout_free, +}; + +static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + struct nand_device *nand = spinand_to_nand(spinand); + u8 mbf = 0; + struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); + + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + + case STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + + case STATUS_ECC_HAS_BITFLIPS: + /* + * Let's try to retrieve the real maximum number of bitflips + * in order to avoid forcing the wear-leveling layer to move + * data around if it's not necessary. + */ + if (spi_mem_exec_op(spinand->spimem, &op)) + return nand->eccreq.strength; + + mbf >>= 4; + + if (WARN_ON(mbf > nand->eccreq.strength || !mbf)) + return nand->eccreq.strength; + + return mbf; + + default: + break; + } + + return -EINVAL; +} + +static const struct spinand_info toshiba_spinand_table[] = { + SPINAND_INFO("TC58CVG2S0H", 0xCD, + NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&tc58cvg2s0h_ooblayout, + tc58cvg2s0h_ecc_get_status)), +}; + +static int toshiba_spinand_detect(struct spinand_device *spinand) +{ + u8 *id = spinand->id.data; + int ret; + + /* + * Toshiba SPI NAND read ID needs a dummy byte, + * so the first byte in id is garbage. + */ + if (id[1] != SPINAND_MFR_TOSHIBA) + return 0; + + ret = spinand_match_and_init(spinand, toshiba_spinand_table, + ARRAY_SIZE(toshiba_spinand_table), + id[2]); + if (ret) + return ret; + + return 1; +} + +static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = { + .detect = toshiba_spinand_detect, +}; + +const struct spinand_manufacturer toshiba_spinand_manufacturer = { + .id = SPINAND_MFR_TOSHIBA, + .name = "Toshiba", + .ops = &toshiba_spinand_manuf_ops, +}; diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index 67baa1b32c00..5d944580b898 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -84,6 +84,14 @@ static const struct spinand_info winbond_spinand_table[] = { 0, SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), SPINAND_SELECT_TARGET(w25m02gv_select_target)), + SPINAND_INFO("W25N01GV", 0xAA, + NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), }; /** diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 7c015536360d..e4f608815c05 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -78,8 +78,6 @@ source "drivers/staging/goldfish/Kconfig" source "drivers/staging/netlogic/Kconfig" -source "drivers/staging/mt29f_spinand/Kconfig" - source "drivers/staging/gs_fpgaboot/Kconfig" source "drivers/staging/unisys/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index a79b3fe20cf0..5868631e8f1b 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -29,7 +29,6 @@ obj-$(CONFIG_STAGING_BOARD) += board/ obj-$(CONFIG_LTE_GDM724X) += gdm724x/ obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ obj-$(CONFIG_GOLDFISH) += goldfish/ -obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ obj-$(CONFIG_UNISYSSPAR) += unisys/ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ diff --git a/drivers/staging/mt29f_spinand/Kconfig b/drivers/staging/mt29f_spinand/Kconfig deleted file mode 100644 index f3f9cb3b5c35..000000000000 --- a/drivers/staging/mt29f_spinand/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config MTD_SPINAND_MT29F - tristate "SPINAND Device Support for Micron" - depends on MTD_NAND && SPI - help - This enables support for accessing Micron SPI NAND flash - devices. - If you have Micron SPI NAND chip say yes. - - If unsure, say no here. - -config MTD_SPINAND_ONDIEECC - bool "Use SPINAND internal ECC" - depends on MTD_SPINAND_MT29F - help - Internal ECC. - Enables Hardware ECC support for Micron SPI NAND. diff --git a/drivers/staging/mt29f_spinand/Makefile b/drivers/staging/mt29f_spinand/Makefile deleted file mode 100644 index e47af0f7fda9..000000000000 --- a/drivers/staging/mt29f_spinand/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand.o diff --git a/drivers/staging/mt29f_spinand/TODO b/drivers/staging/mt29f_spinand/TODO deleted file mode 100644 index a2209b72d371..000000000000 --- a/drivers/staging/mt29f_spinand/TODO +++ /dev/null @@ -1,13 +0,0 @@ -TODO: - - Tested on XLP platform, needs to be tested on other platforms. - - Checkpatch.pl cleanups - - Sparce fixes. - - Clean up coding style to meet kernel standard. - -Please send patches -To: -Kamlakant Patel <kamlakant.patel@broadcom.com> -Cc: -Greg Kroah-Hartman <gregkh@linuxfoundation.org> -Mona Anonuevo <manonuevo@micron.com> -linux-mtd@lists.infradead.org diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c deleted file mode 100644 index def8a1f57d1c..000000000000 --- a/drivers/staging/mt29f_spinand/mt29f_spinand.c +++ /dev/null @@ -1,980 +0,0 @@ -/* - * Copyright (c) 2003-2013 Broadcom Corporation - * - * Copyright (c) 2009-2010 Micron Technology, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/rawnand.h> -#include <linux/spi/spi.h> - -#include "mt29f_spinand.h" - -#define BUFSIZE (10 * 64 * 2048) -#define CACHE_BUF 2112 -/* - * OOB area specification layout: Total 32 available free bytes. - */ - -static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct spinand_info *info = nand_get_controller_data(chip); - struct spinand_state *state = info->priv; - - return state; -} - -#ifdef CONFIG_MTD_SPINAND_ONDIEECC -static int enable_hw_ecc; -static int enable_read_hw_ecc; - -static int spinand_ooblayout_64_ecc(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - if (section > 3) - return -ERANGE; - - oobregion->offset = (section * 16) + 1; - oobregion->length = 6; - - return 0; -} - -static int spinand_ooblayout_64_free(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - if (section > 3) - return -ERANGE; - - oobregion->offset = (section * 16) + 8; - oobregion->length = 8; - - return 0; -} - -static const struct mtd_ooblayout_ops spinand_oob_64_ops = { - .ecc = spinand_ooblayout_64_ecc, - .free = spinand_ooblayout_64_free, -}; -#endif - -/** - * spinand_cmd - process a command to send to the SPI Nand - * Description: - * Set up the command buffer to send to the SPI controller. - * The command buffer has to initialized to 0. - */ - -static int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd) -{ - struct spi_message message; - struct spi_transfer x[4]; - u8 dummy = 0xff; - - spi_message_init(&message); - memset(x, 0, sizeof(x)); - - x[0].len = 1; - x[0].tx_buf = &cmd->cmd; - spi_message_add_tail(&x[0], &message); - - if (cmd->n_addr) { - x[1].len = cmd->n_addr; - x[1].tx_buf = cmd->addr; - spi_message_add_tail(&x[1], &message); - } - - if (cmd->n_dummy) { - x[2].len = cmd->n_dummy; - x[2].tx_buf = &dummy; - spi_message_add_tail(&x[2], &message); - } - - if (cmd->n_tx) { - x[3].len = cmd->n_tx; - x[3].tx_buf = cmd->tx_buf; - spi_message_add_tail(&x[3], &message); - } - - if (cmd->n_rx) { - x[3].len = cmd->n_rx; - x[3].rx_buf = cmd->rx_buf; - spi_message_add_tail(&x[3], &message); - } - - return spi_sync(spi, &message); -} - -/** - * spinand_read_id - Read SPI Nand ID - * Description: - * read two ID bytes from the SPI Nand device - */ -static int spinand_read_id(struct spi_device *spi_nand, u8 *id) -{ - int retval; - u8 nand_id[3]; - struct spinand_cmd cmd = {0}; - - cmd.cmd = CMD_READ_ID; - cmd.n_rx = 3; - cmd.rx_buf = &nand_id[0]; - - retval = spinand_cmd(spi_nand, &cmd); - if (retval < 0) { - dev_err(&spi_nand->dev, "error %d reading id\n", retval); - return retval; - } - id[0] = nand_id[1]; - id[1] = nand_id[2]; - return retval; -} - -/** - * spinand_read_status - send command 0xf to the SPI Nand status register - * Description: - * After read, write, or erase, the Nand device is expected to set the - * busy status. - * This function is to allow reading the status of the command: read, - * write, and erase. - * Once the status turns to be ready, the other status bits also are - * valid status bits. - */ -static int spinand_read_status(struct spi_device *spi_nand, u8 *status) -{ - struct spinand_cmd cmd = {0}; - int ret; - - cmd.cmd = CMD_READ_REG; - cmd.n_addr = 1; - cmd.addr[0] = REG_STATUS; - cmd.n_rx = 1; - cmd.rx_buf = status; - - ret = spinand_cmd(spi_nand, &cmd); - if (ret < 0) - dev_err(&spi_nand->dev, "err: %d read status register\n", ret); - - return ret; -} - -#define MAX_WAIT_JIFFIES (40 * HZ) -static int wait_till_ready(struct spi_device *spi_nand) -{ - unsigned long deadline; - int retval; - u8 stat = 0; - - deadline = jiffies + MAX_WAIT_JIFFIES; - do { - retval = spinand_read_status(spi_nand, &stat); - if (retval < 0) - return -1; - if (!(stat & 0x1)) - break; - - cond_resched(); - } while (!time_after_eq(jiffies, deadline)); - - if ((stat & 0x1) == 0) - return 0; - - return -1; -} - -/** - * spinand_get_otp - send command 0xf to read the SPI Nand OTP register - * Description: - * There is one bit( bit 0x10 ) to set or to clear the internal ECC. - * Enable chip internal ECC, set the bit to 1 - * Disable chip internal ECC, clear the bit to 0 - */ -static int spinand_get_otp(struct spi_device *spi_nand, u8 *otp) -{ - struct spinand_cmd cmd = {0}; - int retval; - - cmd.cmd = CMD_READ_REG; - cmd.n_addr = 1; - cmd.addr[0] = REG_OTP; - cmd.n_rx = 1; - cmd.rx_buf = otp; - - retval = spinand_cmd(spi_nand, &cmd); - if (retval < 0) - dev_err(&spi_nand->dev, "error %d get otp\n", retval); - return retval; -} - -/** - * spinand_set_otp - send command 0x1f to write the SPI Nand OTP register - * Description: - * There is one bit( bit 0x10 ) to set or to clear the internal ECC. - * Enable chip internal ECC, set the bit to 1 - * Disable chip internal ECC, clear the bit to 0 - */ -static int spinand_set_otp(struct spi_device *spi_nand, u8 *otp) -{ - int retval; - struct spinand_cmd cmd = {0}; - - cmd.cmd = CMD_WRITE_REG; - cmd.n_addr = 1; - cmd.addr[0] = REG_OTP; - cmd.n_tx = 1; - cmd.tx_buf = otp; - - retval = spinand_cmd(spi_nand, &cmd); - if (retval < 0) - dev_err(&spi_nand->dev, "error %d set otp\n", retval); - - return retval; -} - -#ifdef CONFIG_MTD_SPINAND_ONDIEECC -/** - * spinand_enable_ecc - send command 0x1f to write the SPI Nand OTP register - * Description: - * There is one bit( bit 0x10 ) to set or to clear the internal ECC. - * Enable chip internal ECC, set the bit to 1 - * Disable chip internal ECC, clear the bit to 0 - */ -static int spinand_enable_ecc(struct spi_device *spi_nand) -{ - int retval; - u8 otp = 0; - - retval = spinand_get_otp(spi_nand, &otp); - if (retval < 0) - return retval; - - if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) - return 0; - otp |= OTP_ECC_MASK; - retval = spinand_set_otp(spi_nand, &otp); - if (retval < 0) - return retval; - return spinand_get_otp(spi_nand, &otp); -} -#endif - -static int spinand_disable_ecc(struct spi_device *spi_nand) -{ - int retval; - u8 otp = 0; - - retval = spinand_get_otp(spi_nand, &otp); - if (retval < 0) - return retval; - - if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) { - otp &= ~OTP_ECC_MASK; - retval = spinand_set_otp(spi_nand, &otp); - if (retval < 0) - return retval; - return spinand_get_otp(spi_nand, &otp); - } - return 0; -} - -/** - * spinand_write_enable - send command 0x06 to enable write or erase the - * Nand cells - * Description: - * Before write and erase the Nand cells, the write enable has to be set. - * After the write or erase, the write enable bit is automatically - * cleared (status register bit 2) - * Set the bit 2 of the status register has the same effect - */ -static int spinand_write_enable(struct spi_device *spi_nand) -{ - struct spinand_cmd cmd = {0}; - - cmd.cmd = CMD_WR_ENABLE; - return spinand_cmd(spi_nand, &cmd); -} - -static int spinand_read_page_to_cache(struct spi_device *spi_nand, u16 page_id) -{ - struct spinand_cmd cmd = {0}; - u16 row; - - row = page_id; - cmd.cmd = CMD_READ; - cmd.n_addr = 3; - cmd.addr[0] = (u8)((row & 0xff0000) >> 16); - cmd.addr[1] = (u8)((row & 0xff00) >> 8); - cmd.addr[2] = (u8)(row & 0x00ff); - - return spinand_cmd(spi_nand, &cmd); -} - -/** - * spinand_read_from_cache - send command 0x03 to read out the data from the - * cache register (2112 bytes max) - * Description: - * The read can specify 1 to 2112 bytes of data read at the corresponding - * locations. - * No tRd delay. - */ -static int spinand_read_from_cache(struct spi_device *spi_nand, u16 page_id, - u16 byte_id, u16 len, u8 *rbuf) -{ - struct spinand_cmd cmd = {0}; - u16 column; - - column = byte_id; - cmd.cmd = CMD_READ_RDM; - cmd.n_addr = 3; - cmd.addr[0] = (u8)((column & 0xff00) >> 8); - cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4); - cmd.addr[1] = (u8)(column & 0x00ff); - cmd.addr[2] = (u8)(0xff); - cmd.n_dummy = 0; - cmd.n_rx = len; - cmd.rx_buf = rbuf; - - return spinand_cmd(spi_nand, &cmd); -} - -/** - * spinand_read_page - read a page - * @page_id: the physical page number - * @offset: the location from 0 to 2111 - * @len: number of bytes to read - * @rbuf: read buffer to hold @len bytes - * - * Description: - * The read includes two commands to the Nand - 0x13 and 0x03 commands - * Poll to read status to wait for tRD time. - */ -static int spinand_read_page(struct spi_device *spi_nand, u16 page_id, - u16 offset, u16 len, u8 *rbuf) -{ - int ret; - u8 status = 0; - -#ifdef CONFIG_MTD_SPINAND_ONDIEECC - if (enable_read_hw_ecc) { - if (spinand_enable_ecc(spi_nand) < 0) - dev_err(&spi_nand->dev, "enable HW ECC failed!"); - } -#endif - ret = spinand_read_page_to_cache(spi_nand, page_id); - if (ret < 0) - return ret; - - if (wait_till_ready(spi_nand)) - dev_err(&spi_nand->dev, "WAIT timedout!!!\n"); - - while (1) { - ret = spinand_read_status(spi_nand, &status); - if (ret < 0) { - dev_err(&spi_nand->dev, - "err %d read status register\n", ret); - return ret; - } - - if ((status & STATUS_OIP_MASK) == STATUS_READY) { - if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) { - dev_err(&spi_nand->dev, "ecc error, page=%d\n", - page_id); - return 0; - } - break; - } - } - - ret = spinand_read_from_cache(spi_nand, page_id, offset, len, rbuf); - if (ret < 0) { - dev_err(&spi_nand->dev, "read from cache failed!!\n"); - return ret; - } - -#ifdef CONFIG_MTD_SPINAND_ONDIEECC - if (enable_read_hw_ecc) { - ret = spinand_disable_ecc(spi_nand); - if (ret < 0) { - dev_err(&spi_nand->dev, "disable ecc failed!!\n"); - return ret; - } - enable_read_hw_ecc = 0; - } -#endif - return ret; -} - -/** - * spinand_program_data_to_cache - write a page to cache - * @byte_id: the location to write to the cache - * @len: number of bytes to write - * @wbuf: write buffer holding @len bytes - * - * Description: - * The write command used here is 0x84--indicating that the cache is - * not cleared first. - * Since it is writing the data to cache, there is no tPROG time. - */ -static int spinand_program_data_to_cache(struct spi_device *spi_nand, - u16 page_id, u16 byte_id, - u16 len, u8 *wbuf) -{ - struct spinand_cmd cmd = {0}; - u16 column; - - column = byte_id; - cmd.cmd = CMD_PROG_PAGE_CLRCACHE; - cmd.n_addr = 2; - cmd.addr[0] = (u8)((column & 0xff00) >> 8); - cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4); - cmd.addr[1] = (u8)(column & 0x00ff); - cmd.n_tx = len; - cmd.tx_buf = wbuf; - - return spinand_cmd(spi_nand, &cmd); -} - -/** - * spinand_program_execute - write a page from cache to the Nand array - * @page_id: the physical page location to write the page. - * - * Description: - * The write command used here is 0x10--indicating the cache is writing to - * the Nand array. - * Need to wait for tPROG time to finish the transaction. - */ -static int spinand_program_execute(struct spi_device *spi_nand, u16 page_id) -{ - struct spinand_cmd cmd = {0}; - u16 row; - - row = page_id; - cmd.cmd = CMD_PROG_PAGE_EXC; - cmd.n_addr = 3; - cmd.addr[0] = (u8)((row & 0xff0000) >> 16); - cmd.addr[1] = (u8)((row & 0xff00) >> 8); - cmd.addr[2] = (u8)(row & 0x00ff); - - return spinand_cmd(spi_nand, &cmd); -} - -/** - * spinand_program_page - write a page - * @page_id: the physical page location to write the page. - * @offset: the location from the cache starting from 0 to 2111 - * @len: the number of bytes to write - * @buf: the buffer holding @len bytes - * - * Description: - * The commands used here are 0x06, 0x84, and 0x10--indicating that - * the write enable is first sent, the write cache command, and the - * write execute command. - * Poll to wait for the tPROG time to finish the transaction. - */ -static int spinand_program_page(struct spi_device *spi_nand, - u16 page_id, u16 offset, u16 len, u8 *buf) -{ - int retval; - u8 status = 0; - u8 *wbuf; -#ifdef CONFIG_MTD_SPINAND_ONDIEECC - unsigned int i, j; - - wbuf = devm_kzalloc(&spi_nand->dev, CACHE_BUF, GFP_KERNEL); - if (!wbuf) - return -ENOMEM; - - enable_read_hw_ecc = 1; - retval = spinand_read_page(spi_nand, page_id, 0, CACHE_BUF, wbuf); - if (retval < 0) { - dev_err(&spi_nand->dev, "ecc error on read page!!!\n"); - return retval; - } - - for (i = offset, j = 0; i < len; i++, j++) - wbuf[i] &= buf[j]; - - if (enable_hw_ecc) { - retval = spinand_enable_ecc(spi_nand); - if (retval < 0) { - dev_err(&spi_nand->dev, "enable ecc failed!!\n"); - return retval; - } - } -#else - wbuf = buf; -#endif - retval = spinand_write_enable(spi_nand); - if (retval < 0) { - dev_err(&spi_nand->dev, "write enable failed!!\n"); - return retval; - } - if (wait_till_ready(spi_nand)) - dev_err(&spi_nand->dev, "wait timedout!!!\n"); - - retval = spinand_program_data_to_cache(spi_nand, page_id, - offset, len, wbuf); - if (retval < 0) - return retval; - retval = spinand_program_execute(spi_nand, page_id); - if (retval < 0) - return retval; - while (1) { - retval = spinand_read_status(spi_nand, &status); - if (retval < 0) { - dev_err(&spi_nand->dev, - "error %d reading status register\n", retval); - return retval; - } - - if ((status & STATUS_OIP_MASK) == STATUS_READY) { - if ((status & STATUS_P_FAIL_MASK) == STATUS_P_FAIL) { - dev_err(&spi_nand->dev, - "program error, page %d\n", page_id); - return -1; - } - break; - } - } -#ifdef CONFIG_MTD_SPINAND_ONDIEECC - if (enable_hw_ecc) { - retval = spinand_disable_ecc(spi_nand); - if (retval < 0) { - dev_err(&spi_nand->dev, "disable ecc failed!!\n"); - return retval; - } - enable_hw_ecc = 0; - } -#endif - - return 0; -} - -/** - * spinand_erase_block_erase - erase a page - * @block_id: the physical block location to erase. - * - * Description: - * The command used here is 0xd8--indicating an erase command to erase - * one block--64 pages - * Need to wait for tERS. - */ -static int spinand_erase_block_erase(struct spi_device *spi_nand, u16 block_id) -{ - struct spinand_cmd cmd = {0}; - u16 row; - - row = block_id; - cmd.cmd = CMD_ERASE_BLK; - cmd.n_addr = 3; - cmd.addr[0] = (u8)((row & 0xff0000) >> 16); - cmd.addr[1] = (u8)((row & 0xff00) >> 8); - cmd.addr[2] = (u8)(row & 0x00ff); - - return spinand_cmd(spi_nand, &cmd); -} - -/** - * spinand_erase_block - erase a page - * @block_id: the physical block location to erase. - * - * Description: - * The commands used here are 0x06 and 0xd8--indicating an erase - * command to erase one block--64 pages - * It will first to enable the write enable bit (0x06 command), - * and then send the 0xd8 erase command - * Poll to wait for the tERS time to complete the tranaction. - */ -static int spinand_erase_block(struct spi_device *spi_nand, u16 block_id) -{ - int retval; - u8 status = 0; - - retval = spinand_write_enable(spi_nand); - if (wait_till_ready(spi_nand)) - dev_err(&spi_nand->dev, "wait timedout!!!\n"); - - retval = spinand_erase_block_erase(spi_nand, block_id); - while (1) { - retval = spinand_read_status(spi_nand, &status); - if (retval < 0) { - dev_err(&spi_nand->dev, - "error %d reading status register\n", retval); - return retval; - } - - if ((status & STATUS_OIP_MASK) == STATUS_READY) { - if ((status & STATUS_E_FAIL_MASK) == STATUS_E_FAIL) { - dev_err(&spi_nand->dev, - "erase error, block %d\n", block_id); - return -1; - } - break; - } - } - return 0; -} - -#ifdef CONFIG_MTD_SPINAND_ONDIEECC -static int spinand_write_page_hwecc(struct nand_chip *chip, - const u8 *buf, int oob_required, - int page) -{ - const u8 *p = buf; - int eccsize = chip->ecc.size; - int eccsteps = chip->ecc.steps; - - enable_hw_ecc = 1; - return nand_prog_page_op(chip, page, 0, p, eccsize * eccsteps); -} - -static int spinand_read_page_hwecc(struct nand_chip *chip, u8 *buf, - int oob_required, int page) -{ - int retval; - u8 status; - u8 *p = buf; - int eccsize = chip->ecc.size; - int eccsteps = chip->ecc.steps; - struct mtd_info *mtd = nand_to_mtd(chip); - struct spinand_info *info = nand_get_controller_data(chip); - - enable_read_hw_ecc = 1; - - nand_read_page_op(chip, page, 0, p, eccsize * eccsteps); - if (oob_required) - chip->legacy.read_buf(chip, chip->oob_poi, mtd->oobsize); - - while (1) { - retval = spinand_read_status(info->spi, &status); - if (retval < 0) { - dev_err(&mtd->dev, - "error %d reading status register\n", retval); - return retval; - } - - if ((status & STATUS_OIP_MASK) == STATUS_READY) { - if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) { - pr_info("spinand: ECC error\n"); - mtd->ecc_stats.failed++; - } else if ((status & STATUS_ECC_MASK) == - STATUS_ECC_1BIT_CORRECTED) - mtd->ecc_stats.corrected++; - break; - } - } - return 0; -} -#endif - -static void spinand_select_chip(struct nand_chip *chip, int dev) -{ -} - -static u8 spinand_read_byte(struct nand_chip *chip) -{ - struct spinand_state *state = mtd_to_state(nand_to_mtd(chip)); - u8 data; - - data = state->buf[state->buf_ptr]; - state->buf_ptr++; - return data; -} - -static int spinand_wait(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct spinand_info *info = nand_get_controller_data(chip); - - unsigned long timeo = jiffies; - int retval, state = chip->state; - u8 status; - - if (state == FL_ERASING) - timeo += (HZ * 400) / 1000; - else - timeo += (HZ * 20) / 1000; - - while (time_before(jiffies, timeo)) { - retval = spinand_read_status(info->spi, &status); - if (retval < 0) { - dev_err(&mtd->dev, - "error %d reading status register\n", retval); - return retval; - } - - if ((status & STATUS_OIP_MASK) == STATUS_READY) - return 0; - - cond_resched(); - } - return 0; -} - -static void spinand_write_buf(struct nand_chip *chip, const u8 *buf, int len) -{ - struct spinand_state *state = mtd_to_state(nand_to_mtd(chip)); - - memcpy(state->buf + state->buf_ptr, buf, len); - state->buf_ptr += len; -} - -static void spinand_read_buf(struct nand_chip *chip, u8 *buf, int len) -{ - struct spinand_state *state = mtd_to_state(nand_to_mtd(chip)); - - memcpy(buf, state->buf + state->buf_ptr, len); - state->buf_ptr += len; -} - -/* - * spinand_reset- send RESET command "0xff" to the Nand device. - */ -static void spinand_reset(struct spi_device *spi_nand) -{ - struct spinand_cmd cmd = {0}; - - cmd.cmd = CMD_RESET; - - if (spinand_cmd(spi_nand, &cmd) < 0) - pr_info("spinand reset failed!\n"); - - /* elapse 1ms before issuing any other command */ - usleep_range(1000, 2000); - - if (wait_till_ready(spi_nand)) - dev_err(&spi_nand->dev, "wait timedout!\n"); -} - -static void spinand_cmdfunc(struct nand_chip *chip, unsigned int command, - int column, int page) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct spinand_info *info = nand_get_controller_data(chip); - struct spinand_state *state = info->priv; - - switch (command) { - /* - * READ0 - read in first 0x800 bytes - */ - case NAND_CMD_READ1: - case NAND_CMD_READ0: - state->buf_ptr = 0; - spinand_read_page(info->spi, page, 0x0, 0x840, state->buf); - break; - /* READOOB reads only the OOB because no ECC is performed. */ - case NAND_CMD_READOOB: - state->buf_ptr = 0; - spinand_read_page(info->spi, page, 0x800, 0x40, state->buf); - break; - case NAND_CMD_RNDOUT: - state->buf_ptr = column; - break; - case NAND_CMD_READID: - state->buf_ptr = 0; - spinand_read_id(info->spi, state->buf); - break; - case NAND_CMD_PARAM: - state->buf_ptr = 0; - break; - /* ERASE1 stores the block and page address */ - case NAND_CMD_ERASE1: - spinand_erase_block(info->spi, page); - break; - /* ERASE2 uses the block and page address from ERASE1 */ - case NAND_CMD_ERASE2: - break; - /* SEQIN sets up the addr buffer and all registers except the length */ - case NAND_CMD_SEQIN: - state->col = column; - state->row = page; - state->buf_ptr = 0; - break; - /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ - case NAND_CMD_PAGEPROG: - spinand_program_page(info->spi, state->row, state->col, - state->buf_ptr, state->buf); - break; - case NAND_CMD_STATUS: - spinand_get_otp(info->spi, state->buf); - if (!(state->buf[0] & 0x80)) - state->buf[0] = 0x80; - state->buf_ptr = 0; - break; - /* RESET command */ - case NAND_CMD_RESET: - if (wait_till_ready(info->spi)) - dev_err(&info->spi->dev, "WAIT timedout!!!\n"); - /* a minimum of 250us must elapse before issuing RESET cmd*/ - usleep_range(250, 1000); - spinand_reset(info->spi); - break; - default: - dev_err(&mtd->dev, "Unknown CMD: 0x%x\n", command); - } -} - -/** - * spinand_lock_block - send write register 0x1f command to the Nand device - * - * Description: - * After power up, all the Nand blocks are locked. This function allows - * one to unlock the blocks, and so it can be written or erased. - */ -static int spinand_lock_block(struct spi_device *spi_nand, u8 lock) -{ - struct spinand_cmd cmd = {0}; - int ret; - u8 otp = 0; - - ret = spinand_get_otp(spi_nand, &otp); - - cmd.cmd = CMD_WRITE_REG; - cmd.n_addr = 1; - cmd.addr[0] = REG_BLOCK_LOCK; - cmd.n_tx = 1; - cmd.tx_buf = &lock; - - ret = spinand_cmd(spi_nand, &cmd); - if (ret < 0) - dev_err(&spi_nand->dev, "error %d lock block\n", ret); - - return ret; -} - -/** - * spinand_probe - [spinand Interface] - * @spi_nand: registered device driver. - * - * Description: - * Set up the device driver parameters to make the device available. - */ -static int spinand_probe(struct spi_device *spi_nand) -{ - struct mtd_info *mtd; - struct nand_chip *chip; - struct spinand_info *info; - struct spinand_state *state; - - info = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_info), - GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->spi = spi_nand; - - spinand_lock_block(spi_nand, BL_ALL_UNLOCKED); - - state = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_state), - GFP_KERNEL); - if (!state) - return -ENOMEM; - - info->priv = state; - state->buf_ptr = 0; - state->buf = devm_kzalloc(&spi_nand->dev, BUFSIZE, GFP_KERNEL); - if (!state->buf) - return -ENOMEM; - - chip = devm_kzalloc(&spi_nand->dev, sizeof(struct nand_chip), - GFP_KERNEL); - if (!chip) - return -ENOMEM; - -#ifdef CONFIG_MTD_SPINAND_ONDIEECC - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = 0x200; - chip->ecc.bytes = 0x6; - chip->ecc.steps = 0x4; - - chip->ecc.strength = 1; - chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; - chip->ecc.read_page = spinand_read_page_hwecc; - chip->ecc.write_page = spinand_write_page_hwecc; -#else - chip->ecc.mode = NAND_ECC_SOFT; - chip->ecc.algo = NAND_ECC_HAMMING; - if (spinand_disable_ecc(spi_nand) < 0) - dev_info(&spi_nand->dev, "%s: disable ecc failed!\n", - __func__); -#endif - - nand_set_flash_node(chip, spi_nand->dev.of_node); - nand_set_controller_data(chip, info); - chip->legacy.read_buf = spinand_read_buf; - chip->legacy.write_buf = spinand_write_buf; - chip->legacy.read_byte = spinand_read_byte; - chip->legacy.cmdfunc = spinand_cmdfunc; - chip->legacy.waitfunc = spinand_wait; - chip->options |= NAND_CACHEPRG; - chip->select_chip = spinand_select_chip; - chip->legacy.set_features = nand_get_set_features_notsupp; - chip->legacy.get_features = nand_get_set_features_notsupp; - - mtd = nand_to_mtd(chip); - - dev_set_drvdata(&spi_nand->dev, mtd); - - mtd->dev.parent = &spi_nand->dev; - mtd->oobsize = 64; -#ifdef CONFIG_MTD_SPINAND_ONDIEECC - mtd_set_ooblayout(mtd, &spinand_oob_64_ops); -#endif - - if (nand_scan(chip, 1)) - return -ENXIO; - - return mtd_device_register(mtd, NULL, 0); -} - -/** - * spinand_remove - remove the device driver - * @spi: the spi device. - * - * Description: - * Remove the device driver parameters and free up allocated memories. - */ -static int spinand_remove(struct spi_device *spi) -{ - mtd_device_unregister(dev_get_drvdata(&spi->dev)); - - return 0; -} - -static const struct of_device_id spinand_dt[] = { - { .compatible = "spinand,mt29f", }, - {} -}; -MODULE_DEVICE_TABLE(of, spinand_dt); - -/* - * Device name structure description - */ -static struct spi_driver spinand_driver = { - .driver = { - .name = "mt29f", - .of_match_table = spinand_dt, - }, - .probe = spinand_probe, - .remove = spinand_remove, -}; - -module_spi_driver(spinand_driver); - -MODULE_DESCRIPTION("SPI NAND driver for Micron"); -MODULE_AUTHOR("Henry Pan <hspan@micron.com>, Kamlakant Patel <kamlakant.patel@broadcom.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.h b/drivers/staging/mt29f_spinand/mt29f_spinand.h deleted file mode 100644 index 457dc7ffdaf1..000000000000 --- a/drivers/staging/mt29f_spinand/mt29f_spinand.h +++ /dev/null @@ -1,106 +0,0 @@ -/*- - * Copyright 2013 Broadcom Corporation - * - * Copyright (c) 2009-2010 Micron Technology, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Henry Pan <hspan@micron.com> - * - * based on nand.h - */ -#ifndef __LINUX_MTD_SPI_NAND_H -#define __LINUX_MTD_SPI_NAND_H - -#include <linux/wait.h> -#include <linux/spinlock.h> -#include <linux/mtd/mtd.h> - -/* cmd */ -#define CMD_READ 0x13 -#define CMD_READ_RDM 0x03 -#define CMD_PROG_PAGE_CLRCACHE 0x02 -#define CMD_PROG_PAGE 0x84 -#define CMD_PROG_PAGE_EXC 0x10 -#define CMD_ERASE_BLK 0xd8 -#define CMD_WR_ENABLE 0x06 -#define CMD_WR_DISABLE 0x04 -#define CMD_READ_ID 0x9f -#define CMD_RESET 0xff -#define CMD_READ_REG 0x0f -#define CMD_WRITE_REG 0x1f - -/* feature/ status reg */ -#define REG_BLOCK_LOCK 0xa0 -#define REG_OTP 0xb0 -#define REG_STATUS 0xc0/* timing */ - -/* status */ -#define STATUS_OIP_MASK 0x01 -#define STATUS_READY 0 -#define STATUS_BUSY BIT(0) - -#define STATUS_E_FAIL_MASK 0x04 -#define STATUS_E_FAIL BIT(2) - -#define STATUS_P_FAIL_MASK 0x08 -#define STATUS_P_FAIL BIT(3) - -#define STATUS_ECC_MASK 0x30 -#define STATUS_ECC_1BIT_CORRECTED BIT(4) -#define STATUS_ECC_ERROR BIT(5) -#define STATUS_ECC_RESERVED (BIT(5) | BIT(4)) - -/*ECC enable defines*/ -#define OTP_ECC_MASK 0x10 -#define OTP_ECC_OFF 0 -#define OTP_ECC_ON 1 - -#define ECC_DISABLED -#define ECC_IN_NAND -#define ECC_SOFT - -/* block lock */ -#define BL_ALL_LOCKED 0x38 -#define BL_1_2_LOCKED 0x30 -#define BL_1_4_LOCKED 0x28 -#define BL_1_8_LOCKED 0x20 -#define BL_1_16_LOCKED 0x18 -#define BL_1_32_LOCKED 0x10 -#define BL_1_64_LOCKED 0x08 -#define BL_ALL_UNLOCKED 0 - -struct spinand_info { - struct spi_device *spi; - void *priv; -}; - -struct spinand_state { - u32 col; - u32 row; - int buf_ptr; - u8 *buf; -}; - -struct spinand_cmd { - u8 cmd; - u32 n_addr; /* Number of address */ - u8 addr[3]; /* Reg Offset */ - u32 n_dummy; /* Dummy use */ - u32 n_tx; /* Number of tx bytes */ - u8 *tx_buf; /* Tx buf */ - u32 n_rx; /* Number of rx bytes */ - u8 *rx_buf; /* Rx buf */ -}; - -int spinand_mtd(struct mtd_info *mtd); -void spinand_mtd_release(struct mtd_info *mtd); - -#endif /* __LINUX_MTD_SPI_NAND_H */ |