1
0
Fork 0

NAND core changes:

- Fourth batch of fixes/cleanup to the raw NAND core impacting various
   controller drivers (Sunxi, Marvell, MTK, TMIO, OMAP2).
 - Checking the return code of nand_reset() and nand_readid_op().
 - Removing ->legacy.erase and single_erase().
 - Simplifying the locking.
 - Several implicit fall through annotations.
 
 Raw NAND controllers drivers changes:
 - Fixing various possible object reference leaks (MTK, JZ4780, Atmel).
 - ST:
   * Adding support for STM32 FMC2 NAND flash controller.
 - Meson:
   * Adding support for Amlogic NAND flash controller.
 - Denali:
   * Several cleanup patches.
 - Sunxi:
   * Several cleanup patches.
 - FSMC:
   * Disabling NAND on remove().
   * Resetting NAND timings on resume().
 
 SPI-NAND drivers changes:
 - Toshiba:
   * Adding support for all Toshiba products.
 - Macronix:
   * Fixing ECC status read.
 - Gigadevice:
   * Adding support for GD5F1GQ4UExxG.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEE9HuaYnbmDhq/XIDIJWrqGEe9VoQFAlxwE4kACgkQJWrqGEe9
 VoRQVQf+OOkScM6ZbsO2GbMRe0ybMOCOyBXfojPEGtVv80gHHrAPRocLqWMB1Xdb
 MSfm7j+lyZU1I8eYVvdYXby7s5FlVWbrh8NSnnwox1QusdmyBm7vcxc6st15Poy/
 /WtjE+Cry49eIx5L/pmmNH3AIqMdvSRTJD7NgOYjo/SIq4GLR+KQEgt1VLp/KyO0
 TGeMDIT3Q3+MXVwvUh3YlHUwNJ2jOpjpPW94QxD0mef/b9doUlkvrOdHs3JeGQzX
 aiiqWI1nRBmjNs34wp7Dyf3G/feplKyi+IS/ghTiijAgwbWdRI7KxrPtyCUYiint
 3XqVgZAF/sfFaKFMIiJBMzoLQB15dQ==
 =VbaE
 -----END PGP SIGNATURE-----

Merge tag 'nand/for-5.1' of git://git.infradead.org/linux-mtd into mtd/next

NAND core changes:
- Fourth batch of fixes/cleanup to the raw NAND core impacting various
  controller drivers (Sunxi, Marvell, MTK, TMIO, OMAP2).
- Checking the return code of nand_reset() and nand_readid_op().
- Removing ->legacy.erase and single_erase().
- Simplifying the locking.
- Several implicit fall through annotations.

Raw NAND controllers drivers changes:
- Fixing various possible object reference leaks (MTK, JZ4780, Atmel).
- ST:
  * Adding support for STM32 FMC2 NAND flash controller.
- Meson:
  * Adding support for Amlogic NAND flash controller.
- Denali:
  * Several cleanup patches.
- Sunxi:
  * Several cleanup patches.
- FSMC:
  * Disabling NAND on remove().
  * Resetting NAND timings on resume().

SPI-NAND drivers changes:
- Toshiba:
  * Adding support for all Toshiba products.
- Macronix:
  * Fixing ECC status read.
- Gigadevice:
  * Adding support for GD5F1GQ4UExxG.
hifive-unleashed-5.1
Boris Brezillon 2019-02-25 09:28:54 +01:00
commit 9220d7befc
26 changed files with 4380 additions and 570 deletions

View File

@ -0,0 +1,60 @@
Amlogic NAND Flash Controller (NFC) for GXBB/GXL/AXG family SoCs
This file documents the properties in addition to those available in
the MTD NAND bindings.
Required properties:
- compatible : contains one of:
- "amlogic,meson-gxl-nfc"
- "amlogic,meson-axg-nfc"
- clocks :
A list of phandle + clock-specifier pairs for the clocks listed
in clock-names.
- clock-names: Should contain the following:
"core" - NFC module gate clock
"device" - device clock from eMMC sub clock controller
"rx" - rx clock phase
"tx" - tx clock phase
- amlogic,mmc-syscon : Required for NAND clocks, it's shared with SD/eMMC
controller port C
Optional children nodes:
Children nodes represent the available nand chips.
Other properties:
see Documentation/devicetree/bindings/mtd/nand.txt for generic bindings.
Example demonstrate on AXG SoC:
sd_emmc_c_clkc: mmc@7000 {
compatible = "amlogic,meson-axg-mmc-clkc", "syscon";
reg = <0x0 0x7000 0x0 0x800>;
};
nand-controller@7800 {
compatible = "amlogic,meson-axg-nfc";
reg = <0x0 0x7800 0x0 0x100>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>;
clocks = <&clkc CLKID_SD_EMMC_C>,
<&sd_emmc_c_clkc CLKID_MMC_DIV>,
<&sd_emmc_c_clkc CLKID_MMC_PHASE_RX>,
<&sd_emmc_c_clkc CLKID_MMC_PHASE_TX>;
clock-names = "core", "device", "rx", "tx";
amlogic,mmc-syscon = <&sd_emmc_c_clkc>;
pinctrl-names = "default";
pinctrl-0 = <&nand_pins>;
nand@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-on-flash-bbt;
};
};

View File

@ -0,0 +1,61 @@
STMicroelectronics Flexible Memory Controller 2 (FMC2)
NAND Interface
Required properties:
- compatible: Should be one of:
* st,stm32mp15-fmc2
- reg: NAND flash controller memory areas.
First region contains the register location.
Regions 2 to 4 respectively contain the data, command,
and address space for CS0.
Regions 5 to 7 contain the same areas for CS1.
- interrupts: The interrupt number
- pinctrl-0: Standard Pinctrl phandle (see: pinctrl/pinctrl-bindings.txt)
- clocks: The clock needed by the NAND flash controller
Optional properties:
- resets: Reference to a reset controller asserting the FMC controller
- dmas: DMA specifiers (see: dma/stm32-mdma.txt)
- dma-names: Must be "tx", "rx" and "ecc"
* NAND device bindings:
Required properties:
- reg: describes the CS lines assigned to the NAND device.
Optional properties:
- nand-on-flash-bbt: see nand.txt
- nand-ecc-strength: see nand.txt
- nand-ecc-step-size: see nand.txt
The following ECC strength and step size are currently supported:
- nand-ecc-strength = <1>, nand-ecc-step-size = <512> (Hamming)
- nand-ecc-strength = <4>, nand-ecc-step-size = <512> (BCH4)
- nand-ecc-strength = <8>, nand-ecc-step-size = <512> (BCH8) (default)
Example:
fmc: nand-controller@58002000 {
compatible = "st,stm32mp15-fmc2";
reg = <0x58002000 0x1000>,
<0x80000000 0x1000>,
<0x88010000 0x1000>,
<0x88020000 0x1000>,
<0x81000000 0x1000>,
<0x89010000 0x1000>,
<0x89020000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&rcc FMC_K>;
resets = <&rcc FMC_R>;
pinctrl-names = "default";
pinctrl-0 = <&fmc_pins_a>;
#address-cells = <1>;
#size-cells = <0>;
nand@0 {
reg = <0>;
nand-on-flash-bbt;
#address-cells = <1>;
#size-cells = <1>;
};
};

View File

@ -9849,6 +9849,13 @@ F: drivers/media/platform/meson/ao-cec.c
F: Documentation/devicetree/bindings/media/meson-ao-cec.txt
T: git git://linuxtv.org/media_tree.git
MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS
M: Liang Yang <liang.yang@amlogic.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/raw/meson_*
F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt
MICROBLAZE ARCHITECTURE
M: Michal Simek <monstr@monstr.eu>
W: http://www.monstr.eu/fdt/

View File

@ -541,4 +541,21 @@ config MTD_NAND_TEGRA
is supported. Extra OOB bytes when using HW ECC are currently
not supported.
config MTD_NAND_STM32_FMC2
tristate "Support for NAND controller on STM32MP SoCs"
depends on MACH_STM32MP157 || COMPILE_TEST
help
Enables support for NAND Flash chips on SoCs containing the FMC2
NAND controller. This controller is found on STM32MP SoCs.
The controller supports a maximum 8k page size and supports
a maximum 8-bit correction error per sector of 512 bytes.
config MTD_NAND_MESON
tristate "Support for NAND controller on Amlogic's Meson SoCs"
depends on ARCH_MESON || COMPILE_TEST
select MFD_SYSCON
help
Enables support for NAND controller on Amlogic's Meson SoCs.
This controller is found on Meson SoCs.
endif # MTD_NAND

View File

@ -56,6 +56,8 @@ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
obj-$(CONFIG_MTD_NAND_STM32_FMC2) += stm32_fmc2_nand.o
obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o
nand-objs := nand_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_onfi.o

View File

@ -876,23 +876,32 @@ static struct atmel_pmecc *atmel_pmecc_get_by_node(struct device *userdev,
{
struct platform_device *pdev;
struct atmel_pmecc *pmecc, **ptr;
int ret;
pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev))
if (!pdev)
return ERR_PTR(-EPROBE_DEFER);
pmecc = platform_get_drvdata(pdev);
if (!pmecc) {
ret = -EPROBE_DEFER;
goto err_put_device;
}
ptr = devres_alloc(devm_atmel_pmecc_put, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
get_device(&pdev->dev);
pmecc = platform_get_drvdata(pdev);
if (!ptr) {
ret = -ENOMEM;
goto err_put_device;
}
*ptr = pmecc;
devres_add(userdev, ptr);
return pmecc;
err_put_device:
put_device(&pdev->dev);
return ERR_PTR(ret);
}
static const int atmel_pmecc_strengths[] = { 2, 4, 8, 12, 24, 32 };

View File

@ -37,9 +37,6 @@
#define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) /* address cycle */
#define DENALI_MAP11_DATA ((DENALI_MAP11) | 2) /* data cycle */
/* MAP10 commands */
#define DENALI_ERASE 0x01
#define DENALI_BANK(denali) ((denali)->active_bank << 24)
#define DENALI_INVALID_BANK -1
@ -476,7 +473,7 @@ static void denali_setup_dma32(struct denali_nand_info *denali,
}
static int denali_pio_read(struct denali_nand_info *denali, void *buf,
size_t size, int page, int raw)
size_t size, int page)
{
u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
uint32_t *buf32 = (uint32_t *)buf;
@ -504,7 +501,7 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf,
}
static int denali_pio_write(struct denali_nand_info *denali,
const void *buf, size_t size, int page, int raw)
const void *buf, size_t size, int page)
{
u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
const uint32_t *buf32 = (uint32_t *)buf;
@ -525,16 +522,16 @@ static int denali_pio_write(struct denali_nand_info *denali,
}
static int denali_pio_xfer(struct denali_nand_info *denali, void *buf,
size_t size, int page, int raw, int write)
size_t size, int page, int write)
{
if (write)
return denali_pio_write(denali, buf, size, page, raw);
return denali_pio_write(denali, buf, size, page);
else
return denali_pio_read(denali, buf, size, page, raw);
return denali_pio_read(denali, buf, size, page);
}
static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
size_t size, int page, int raw, int write)
size_t size, int page, int write)
{
dma_addr_t dma_addr;
uint32_t irq_mask, irq_status, ecc_err_mask;
@ -544,7 +541,7 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
dma_addr = dma_map_single(denali->dev, buf, size, dir);
if (dma_mapping_error(denali->dev, dma_addr)) {
dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n");
return denali_pio_xfer(denali, buf, size, page, raw, write);
return denali_pio_xfer(denali, buf, size, page, write);
}
if (write) {
@ -598,9 +595,9 @@ static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
denali->reg + TRANSFER_SPARE_REG);
if (denali->dma_avail)
return denali_dma_xfer(denali, buf, size, page, raw, write);
return denali_dma_xfer(denali, buf, size, page, write);
else
return denali_pio_xfer(denali, buf, size, page, raw, write);
return denali_pio_xfer(denali, buf, size, page, write);
}
static void denali_oob_xfer(struct mtd_info *mtd, struct nand_chip *chip,
@ -754,9 +751,6 @@ static int denali_read_oob(struct nand_chip *chip, int page)
static int denali_write_oob(struct nand_chip *chip, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct denali_nand_info *denali = mtd_to_denali(mtd);
denali_reset_irq(denali);
denali_oob_xfer(mtd, chip, page, 1);
@ -903,23 +897,6 @@ static int denali_waitfunc(struct nand_chip *chip)
return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL;
}
static int denali_erase(struct nand_chip *chip, int page)
{
struct denali_nand_info *denali = mtd_to_denali(nand_to_mtd(chip));
uint32_t irq_status;
denali_reset_irq(denali);
denali->host_write(denali, DENALI_MAP10 | DENALI_BANK(denali) | page,
DENALI_ERASE);
/* wait for erase to complete or failure to occur */
irq_status = denali_wait_for_irq(denali,
INTR__ERASE_COMP | INTR__ERASE_FAIL);
return irq_status & INTR__ERASE_COMP ? 0 : -EIO;
}
static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
{
@ -1244,7 +1221,6 @@ static int denali_attach_chip(struct nand_chip *chip)
chip->ecc.write_page_raw = denali_write_page_raw;
chip->ecc.read_oob = denali_read_oob;
chip->ecc.write_oob = denali_write_oob;
chip->legacy.erase = denali_erase;
ret = denali_multidev_fixup(denali);
if (ret)

View File

@ -304,7 +304,6 @@ struct denali_nand_info {
u32 irq_status; /* interrupts that have happened */
int irq;
void *buf; /* for syndrome layout conversion */
dma_addr_t dma_addr;
int dma_avail; /* can support DMA? */
int devs_per_cs; /* devices connected in parallel */
int oob_skip_bytes; /* number of bytes reserved for BBM */

View File

@ -109,25 +109,17 @@ static int denali_dt_probe(struct platform_device *pdev)
if (IS_ERR(denali->host))
return PTR_ERR(denali->host);
/*
* A single anonymous clock is supported for the backward compatibility.
* New platforms should support all the named clocks.
*/
dt->clk = devm_clk_get(dev, "nand");
if (IS_ERR(dt->clk))
dt->clk = devm_clk_get(dev, NULL);
if (IS_ERR(dt->clk)) {
dev_err(dev, "no clk available\n");
return PTR_ERR(dt->clk);
}
dt->clk_x = devm_clk_get(dev, "nand_x");
if (IS_ERR(dt->clk_x))
dt->clk_x = NULL;
return PTR_ERR(dt->clk_x);
dt->clk_ecc = devm_clk_get(dev, "ecc");
if (IS_ERR(dt->clk_ecc))
dt->clk_ecc = NULL;
return PTR_ERR(dt->clk_ecc);
ret = clk_prepare_enable(dt->clk);
if (ret)
@ -141,19 +133,8 @@ static int denali_dt_probe(struct platform_device *pdev)
if (ret)
goto out_disable_clk_x;
if (dt->clk_x) {
denali->clk_rate = clk_get_rate(dt->clk);
denali->clk_x_rate = clk_get_rate(dt->clk_x);
} else {
/*
* Hardcode the clock rates for the backward compatibility.
* This works for both SOCFPGA and UniPhier.
*/
dev_notice(dev,
"necessary clock is missing. default clock rates are used.\n");
denali->clk_rate = 50000000;
denali->clk_x_rate = 200000000;
}
denali->clk_rate = clk_get_rate(dt->clk);
denali->clk_x_rate = clk_get_rate(dt->clk_x);
ret = denali_init(denali);
if (ret)

View File

@ -986,6 +986,19 @@ static const struct nand_controller_ops fsmc_nand_controller_ops = {
.setup_data_interface = fsmc_setup_data_interface,
};
/**
* fsmc_nand_disable() - Disables the NAND bank
* @host: The instance to disable
*/
static void fsmc_nand_disable(struct fsmc_nand_data *host)
{
u32 val;
val = readl(host->regs_va + FSMC_PC);
val &= ~FSMC_ENABLE;
writel(val, host->regs_va + FSMC_PC);
}
/*
* fsmc_nand_probe - Probe function
* @pdev: platform device structure
@ -1141,6 +1154,7 @@ release_dma_read_chan:
if (host->mode == USE_DMA_ACCESS)
dma_release_channel(host->read_dma_chan);
disable_clk:
fsmc_nand_disable(host);
clk_disable_unprepare(host->clk);
return ret;
@ -1155,6 +1169,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
if (host) {
nand_release(&host->nand);
fsmc_nand_disable(host);
if (host->mode == USE_DMA_ACCESS) {
dma_release_channel(host->write_dma_chan);
@ -1185,6 +1200,7 @@ static int fsmc_nand_resume(struct device *dev)
clk_prepare_enable(host->clk);
if (host->dev_timings)
fsmc_nand_setup(host, host->dev_timings);
nand_reset(&host->nand, 0);
}
return 0;

View File

@ -281,12 +281,15 @@ static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
struct jz4780_bch *bch;
pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev))
if (!pdev)
return ERR_PTR(-EPROBE_DEFER);
get_device(&pdev->dev);
bch = platform_get_drvdata(pdev);
if (!bch) {
put_device(&pdev->dev);
return ERR_PTR(-EPROBE_DEFER);
}
clk_prepare_enable(bch->clk);
return bch;

View File

@ -2550,9 +2550,8 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
}
/* Alloc the nand chip structure */
marvell_nand = devm_kzalloc(dev, sizeof(*marvell_nand) +
(nsels *
sizeof(struct marvell_nand_chip_sel)),
marvell_nand = devm_kzalloc(dev,
struct_size(marvell_nand, sels, nsels),
GFP_KERNEL);
if (!marvell_nand) {
dev_err(dev, "could not allocate chip structure\n");

File diff suppressed because it is too large Load Diff

View File

@ -267,11 +267,15 @@ static struct mtk_ecc *mtk_ecc_get(struct device_node *np)
struct mtk_ecc *ecc;
pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev))
if (!pdev)
return ERR_PTR(-EPROBE_DEFER);
get_device(&pdev->dev);
ecc = platform_get_drvdata(pdev);
if (!ecc) {
put_device(&pdev->dev);
return ERR_PTR(-EPROBE_DEFER);
}
clk_prepare_enable(ecc->clk);
mtk_ecc_hw_init(ecc);

View File

@ -1451,8 +1451,7 @@ static int mtk_nfc_probe(struct platform_device *pdev)
if (!nfc)
return -ENOMEM;
spin_lock_init(&nfc->controller.lock);
init_waitqueue_head(&nfc->controller.wq);
nand_controller_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
nfc->controller.ops = &mtk_nfc_controller_ops;

View File

@ -278,11 +278,8 @@ EXPORT_SYMBOL_GPL(nand_deselect_target);
static void nand_release_device(struct nand_chip *chip)
{
/* Release the controller and the chip */
spin_lock(&chip->controller->lock);
chip->controller->active = NULL;
chip->state = FL_READY;
wake_up(&chip->controller->wq);
spin_unlock(&chip->controller->lock);
mutex_unlock(&chip->controller->lock);
mutex_unlock(&chip->lock);
}
/**
@ -330,58 +327,24 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t 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
* Lock the device and its controller for exclusive access
*
* Return: -EBUSY if the chip has been suspended, 0 otherwise
*/
static int
nand_get_device(struct nand_chip *chip, int new_state)
static int nand_get_device(struct nand_chip *chip)
{
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;
mutex_lock(&chip->lock);
if (chip->suspended) {
mutex_unlock(&chip->lock);
return -EBUSY;
}
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;
mutex_lock(&chip->controller->lock);
return 0;
}
/**
@ -457,7 +420,7 @@ 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;
int chipnr, page, status, len, ret;
pr_debug("%s: to = 0x%08x, len = %i\n",
__func__, (unsigned int)to, (int)ops->ooblen);
@ -479,7 +442,9 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to,
* 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);
ret = nand_reset(chip, chipnr);
if (ret)
return ret;
nand_select_target(chip, chipnr);
@ -602,7 +567,10 @@ static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs)
nand_erase_nand(chip, &einfo, 0);
/* Write bad block marker to OOB */
nand_get_device(chip, FL_WRITING);
ret = nand_get_device(chip);
if (ret)
return ret;
ret = nand_markbad_bbm(chip, ofs);
nand_release_device(chip);
}
@ -3580,7 +3548,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
ops->mode != MTD_OPS_RAW)
return -ENOTSUPP;
nand_get_device(chip, FL_READING);
ret = nand_get_device(chip);
if (ret)
return ret;
if (!ops->datbuf)
ret = nand_do_read_oob(chip, from, ops);
@ -4099,9 +4069,6 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
struct mtd_oob_ops ops;
int ret;
/* Grab the device */
panic_nand_get_device(chip, FL_WRITING);
nand_select_target(chip, chipnr);
/* Wait for the device to get ready */
@ -4132,7 +4099,9 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
ops->retlen = 0;
nand_get_device(chip, FL_WRITING);
ret = nand_get_device(chip);
if (ret)
return ret;
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
@ -4154,23 +4123,6 @@ out:
return ret;
}
/**
* single_erase - [GENERIC] NAND standard block erase command function
* @chip: NAND chip object
* @page: the page address of the block which will be erased
*
* Standard erase command for NAND chips. Returns NAND status.
*/
static int single_erase(struct nand_chip *chip, int page)
{
unsigned int eraseblock;
/* Send commands to erase a block */
eraseblock = page >> (chip->phys_erase_shift - chip->page_shift);
return nand_erase_op(chip, eraseblock);
}
/**
* nand_erase - [MTD Interface] erase block(s)
* @mtd: MTD device structure
@ -4194,7 +4146,7 @@ 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)
{
int page, status, pages_per_block, ret, chipnr;
int page, pages_per_block, ret, chipnr;
loff_t len;
pr_debug("%s: start = 0x%012llx, len = %llu\n",
@ -4205,7 +4157,9 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
return -EINVAL;
/* Grab the lock and see if the device is available */
nand_get_device(chip, FL_ERASING);
ret = nand_get_device(chip);
if (ret)
return ret;
/* Shift to get first page */
page = (int)(instr->addr >> chip->page_shift);
@ -4246,17 +4200,11 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
(page + pages_per_block))
chip->pagebuf = -1;
if (chip->legacy.erase)
status = chip->legacy.erase(chip,
page & chip->pagemask);
else
status = single_erase(chip, page & chip->pagemask);
/* See if block erase succeeded */
if (status) {
ret = nand_erase_op(chip, (page & chip->pagemask) >>
(chip->phys_erase_shift - chip->page_shift));
if (ret) {
pr_debug("%s: failed erase, page 0x%08x\n",
__func__, page);
ret = -EIO;
instr->fail_addr =
((loff_t)page << chip->page_shift);
goto erase_exit;
@ -4298,7 +4246,7 @@ static void nand_sync(struct mtd_info *mtd)
pr_debug("%s: called\n", __func__);
/* Grab the lock and see if the device is available */
nand_get_device(chip, FL_SYNCING);
WARN_ON(nand_get_device(chip));
/* Release it and go back */
nand_release_device(chip);
}
@ -4315,7 +4263,10 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
int ret;
/* Select the NAND device */
nand_get_device(chip, FL_READING);
ret = nand_get_device(chip);
if (ret)
return ret;
nand_select_target(chip, chipnr);
ret = nand_block_checkbad(chip, offs, 0);
@ -4388,7 +4339,13 @@ 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_to_nand(mtd), FL_PM_SUSPENDED);
struct nand_chip *chip = mtd_to_nand(mtd);
mutex_lock(&chip->lock);
chip->suspended = 1;
mutex_unlock(&chip->lock);
return 0;
}
/**
@ -4399,11 +4356,13 @@ 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(chip);
mutex_lock(&chip->lock);
if (chip->suspended)
chip->suspended = 0;
else
pr_err("%s called for a chip which is not in suspended state\n",
__func__);
mutex_unlock(&chip->lock);
}
/**
@ -4413,7 +4372,7 @@ static void nand_resume(struct mtd_info *mtd)
*/
static void nand_shutdown(struct mtd_info *mtd)
{
nand_get_device(mtd_to_nand(mtd), FL_PM_SUSPENDED);
nand_suspend(mtd);
}
/* Set default functions */
@ -5018,6 +4977,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
/* Assume all dies are deselected when we enter nand_scan_ident(). */
chip->cur_cs = -1;
mutex_init(&chip->lock);
/* Enforce the right timings for reset/detection */
onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0);
@ -5060,11 +5021,15 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
u8 id[2];
/* See comment in nand_get_flash_type for reset */
nand_reset(chip, i);
ret = nand_reset(chip, i);
if (ret)
break;
nand_select_target(chip, i);
/* Send the command for reading device ID */
nand_readid_op(chip, 0, id, sizeof(id));
ret = nand_readid_op(chip, 0, id, sizeof(id));
if (ret)
break;
/* Read manufacturer and device IDs */
if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
nand_deselect_target(chip);
@ -5555,6 +5520,7 @@ static int nand_scan_tail(struct nand_chip *chip)
}
if (!ecc->read_page)
ecc->read_page = nand_read_page_hwecc_oob_first;
/* fall through */
case NAND_ECC_HW:
/* Use standard hwecc read page function? */
@ -5574,6 +5540,7 @@ static int nand_scan_tail(struct nand_chip *chip)
ecc->read_subpage = nand_read_subpage;
if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
ecc->write_subpage = nand_write_subpage_hwecc;
/* fall through */
case NAND_ECC_HW_SYNDROME:
if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
@ -5611,6 +5578,7 @@ static int nand_scan_tail(struct nand_chip *chip)
ecc->size, mtd->writesize);
ecc->mode = NAND_ECC_SOFT;
ecc->algo = NAND_ECC_HAMMING;
/* fall through */
case NAND_ECC_SOFT:
ret = nand_set_ecc_soft_ops(chip);
@ -5717,9 +5685,6 @@ static int nand_scan_tail(struct nand_chip *chip)
}
chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
/* Initialize state */
chip->state = FL_READY;
/* Invalidate the pagebuffer reference */
chip->pagebuf = -1;

View File

@ -331,6 +331,7 @@ static void nand_command(struct nand_chip *chip, unsigned int command,
*/
if (column == -1 && page_addr == -1)
return;
/* fall through */
default:
/*
@ -483,7 +484,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);
/* This applies to read commands */
/* fall through - This applies to read commands */
default:
/*
* If we don't have access to the busy pin, we apply the given

View File

@ -994,12 +994,9 @@ static int omap_wait(struct nand_chip *this)
{
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this));
unsigned long timeo = jiffies;
int status, state = this->state;
int status;
if (state == FL_ERASING)
timeo += msecs_to_jiffies(400);
else
timeo += msecs_to_jiffies(20);
timeo += msecs_to_jiffies(400);
writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
while (time_before(jiffies, timeo)) {
@ -2173,11 +2170,8 @@ static const struct nand_controller_ops omap_nand_controller_ops = {
};
/* Shared among all NAND instances to synchronize access to the ECC Engine */
static struct nand_controller omap_gpmc_controller = {
.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock),
.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
.ops = &omap_nand_controller_ops,
};
static struct nand_controller omap_gpmc_controller;
static bool omap_gpmc_controller_initialized;
static int omap_nand_probe(struct platform_device *pdev)
{
@ -2227,6 +2221,12 @@ static int omap_nand_probe(struct platform_device *pdev)
info->phys_base = res->start;
if (!omap_gpmc_controller_initialized) {
omap_gpmc_controller.ops = &omap_nand_controller_ops;
nand_controller_init(&omap_gpmc_controller);
omap_gpmc_controller_initialized = true;
}
nand_chip->controller = &omap_gpmc_controller;
nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R;

View File

@ -369,8 +369,7 @@ static int r852_wait(struct nand_chip *chip)
unsigned long timeout;
u8 status;
timeout = jiffies + (chip->state == FL_ERASING ?
msecs_to_jiffies(400) : msecs_to_jiffies(20));
timeout = jiffies + msecs_to_jiffies(400);
while (time_before(jiffies, timeout))
if (chip->legacy.dev_ready(chip))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -104,6 +104,7 @@
struct tmio_nand {
struct nand_chip chip;
struct completion comp;
struct platform_device *dev;
@ -168,15 +169,11 @@ static int tmio_nand_dev_ready(struct nand_chip *chip)
static irqreturn_t tmio_irq(int irq, void *__tmio)
{
struct tmio_nand *tmio = __tmio;
struct nand_chip *nand_chip = &tmio->chip;
/* disable RDYREQ interrupt */
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
complete(&tmio->comp);
if (unlikely(!waitqueue_active(&nand_chip->controller->wq)))
dev_warn(&tmio->dev->dev, "spurious interrupt\n");
wake_up(&nand_chip->controller->wq);
return IRQ_HANDLED;
}
@ -193,18 +190,18 @@ static int tmio_nand_wait(struct nand_chip *nand_chip)
u8 status;
/* enable RDYREQ interrupt */
tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
reinit_completion(&tmio->comp);
tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
timeout = wait_event_timeout(nand_chip->controller->wq,
tmio_nand_dev_ready(nand_chip),
msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20));
timeout = 400;
timeout = wait_for_completion_timeout(&tmio->comp,
msecs_to_jiffies(timeout));
if (unlikely(!tmio_nand_dev_ready(nand_chip))) {
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n",
nand_chip->state == FL_ERASING ? "erase" : "program",
nand_chip->state == FL_ERASING ? 400 : 20);
dev_warn(&tmio->dev->dev, "still busy after 400 ms\n");
} else if (unlikely(!timeout)) {
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
@ -378,6 +375,8 @@ static int tmio_probe(struct platform_device *dev)
if (!tmio)
return -ENOMEM;
init_completion(&tmio->comp);
tmio->dev = dev;
platform_set_drvdata(dev, tmio);

View File

@ -12,6 +12,8 @@
#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
#define GD5FXGQ4UEXXG_REG_STATUS2 0xf0
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
@ -81,11 +83,83 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
return -EINVAL;
}
static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
region->offset = 64;
region->length = 64;
return 0;
}
static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section)
return -ERANGE;
/* Reserve 1 bytes for the BBM. */
region->offset = 1;
region->length = 63;
return 0;
}
static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
u8 status2;
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4UEXXG_REG_STATUS2,
&status2);
int ret;
switch (status & STATUS_ECC_MASK) {
case STATUS_ECC_NO_BITFLIPS:
return 0;
case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
/*
* Read status2 register to determine a more fine grained
* bit error status
*/
ret = spi_mem_exec_op(spinand->spimem, &op);
if (ret)
return ret;
/*
* 4 ... 7 bits are flipped (1..4 can't be detected, so
* report the maximum of 4 in this case
*/
/* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
return ((status & STATUS_ECC_MASK) >> 2) |
((status2 & STATUS_ECC_MASK) >> 4);
case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
return 8;
case STATUS_ECC_UNCOR_ERROR:
return -EBADMSG;
default:
break;
}
return -EINVAL;
}
static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
.ecc = gd5fxgq4xa_ooblayout_ecc,
.free = gd5fxgq4xa_ooblayout_free,
};
static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
.ecc = gd5fxgq4uexxg_ooblayout_ecc,
.free = gd5fxgq4uexxg_ooblayout_free,
};
static const struct spinand_info gigadevice_spinand_table[] = {
SPINAND_INFO("GD5F1GQ4xA", 0xF1,
NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
@ -114,6 +188,15 @@ static const struct spinand_info gigadevice_spinand_table[] = {
0,
SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
gd5fxgq4xa_ecc_get_status)),
SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&gd5fxgq4uexxg_ooblayout,
gd5fxgq4uexxg_ecc_get_status)),
};
static int gigadevice_spinand_detect(struct spinand_device *spinand)

View File

@ -10,6 +10,7 @@
#include <linux/mtd/spinand.h>
#define SPINAND_MFR_MACRONIX 0xC2
#define MACRONIX_ECCSR_MASK 0x0F
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
@ -55,7 +56,12 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
SPI_MEM_OP_DUMMY(1, 1),
SPI_MEM_OP_DATA_IN(1, eccsr, 1));
return spi_mem_exec_op(spinand->spimem, &op);
int ret = spi_mem_exec_op(spinand->spimem, &op);
if (ret)
return ret;
*eccsr &= MACRONIX_ECCSR_MASK;
return 0;
}
static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,

View File

@ -25,19 +25,19 @@ static SPINAND_OP_VARIANTS(write_cache_variants,
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,
static int tc58cxgxsx_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section > 7)
if (section > 0)
return -ERANGE;
region->offset = 128 + 16 * section;
region->length = 16;
region->offset = mtd->oobsize / 2;
region->length = mtd->oobsize / 2;
return 0;
}
static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
static int tc58cxgxsx_ooblayout_free(struct mtd_info *mtd, int section,
struct mtd_oob_region *region)
{
if (section > 0)
@ -45,17 +45,17 @@ static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
/* 2 bytes reserved for BBM */
region->offset = 2;
region->length = 126;
region->length = (mtd->oobsize / 2) - 2;
return 0;
}
static const struct mtd_ooblayout_ops tc58cvg2s0h_ooblayout = {
.ecc = tc58cvg2s0h_ooblayout_ecc,
.free = tc58cvg2s0h_ooblayout_free,
static const struct mtd_ooblayout_ops tc58cxgxsx_ooblayout = {
.ecc = tc58cxgxsx_ooblayout_ecc,
.free = tc58cxgxsx_ooblayout_free,
};
static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand,
u8 status)
{
struct nand_device *nand = spinand_to_nand(spinand);
@ -94,15 +94,66 @@ static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
}
static const struct spinand_info toshiba_spinand_table[] = {
SPINAND_INFO("TC58CVG2S0H", 0xCD,
/* 3.3V 1Gb */
SPINAND_INFO("TC58CVG0S3", 0xC2,
NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
/* 3.3V 2Gb */
SPINAND_INFO("TC58CVG1S3", 0xCB,
NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
/* 3.3V 4Gb */
SPINAND_INFO("TC58CVG2S0", 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)),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
/* 1.8V 1Gb */
SPINAND_INFO("TC58CYG0S3", 0xB2,
NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
/* 1.8V 2Gb */
SPINAND_INFO("TC58CYG1S3", 0xBB,
NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
/* 1.8V 4Gb */
SPINAND_INFO("TC58CYG2S0", 0xBD,
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),
0,
SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cxgxsx_ecc_get_status)),
};
static int toshiba_spinand_detect(struct spinand_device *spinand)

View File

@ -16,13 +16,12 @@
#ifndef __LINUX_MTD_RAWNAND_H
#define __LINUX_MTD_RAWNAND_H
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/flashchip.h>
#include <linux/mtd/bbm.h>
#include <linux/mtd/jedec.h>
#include <linux/mtd/onfi.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/types.h>
@ -897,25 +896,17 @@ struct nand_controller_ops {
/**
* struct nand_controller - Structure used to describe a NAND controller
*
* @lock: protection lock
* @active: the mtd device which holds the controller currently
* @wq: wait queue to sleep on if a NAND operation is in
* progress used instead of the per chip wait queue
* when a hw controller is available.
* @lock: lock used to serialize accesses to the NAND controller
* @ops: NAND controller operations.
*/
struct nand_controller {
spinlock_t lock;
struct nand_chip *active;
wait_queue_head_t wq;
struct mutex lock;
const struct nand_controller_ops *ops;
};
static inline void nand_controller_init(struct nand_controller *nfc)
{
nfc->active = NULL;
spin_lock_init(&nfc->lock);
init_waitqueue_head(&nfc->wq);
mutex_init(&nfc->lock);
}
/**
@ -936,7 +927,6 @@ static inline void nand_controller_init(struct nand_controller *nfc)
* @waitfunc: hardware specific function for wait on ready.
* @block_bad: check if a block is bad, using OOB markers
* @block_markbad: mark a block bad
* @erase: erase function
* @set_features: set the NAND chip features
* @get_features: get the NAND chip features
* @chip_delay: chip dependent delay for transferring data from array to read
@ -962,7 +952,6 @@ struct nand_legacy {
int (*waitfunc)(struct nand_chip *chip);
int (*block_bad)(struct nand_chip *chip, loff_t ofs);
int (*block_markbad)(struct nand_chip *chip, loff_t ofs);
int (*erase)(struct nand_chip *chip, int page);
int (*set_features)(struct nand_chip *chip, int feature_addr,
u8 *subfeature_para);
int (*get_features)(struct nand_chip *chip, int feature_addr,
@ -983,7 +972,6 @@ struct nand_legacy {
* setting the read-retry mode. Mostly needed for MLC NAND.
* @ecc: [BOARDSPECIFIC] ECC control structure
* @buf_align: minimum buffer alignment required by a platform
* @state: [INTERN] the current state of the NAND device
* @oob_poi: "poison value buffer," used for laying out OOB data
* before writing
* @page_shift: [INTERN] number of address bits in a page (column
@ -1034,6 +1022,9 @@ struct nand_legacy {
* cur_cs < numchips. NAND Controller drivers should not
* modify this value, but they're allowed to read it.
* @read_retries: [INTERN] the number of read retry modes supported
* @lock: lock protecting the suspended field. Also used to
* serialize accesses to the NAND device.
* @suspended: set to 1 when the device is suspended, 0 when it's not.
* @bbt: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash
* lookup.
@ -1088,7 +1079,8 @@ struct nand_chip {
int read_retries;
flstate_t state;
struct mutex lock;
unsigned int suspended : 1;
uint8_t *oob_poi;
struct nand_controller *controller;