Commit 9220d7be authored by Boris Brezillon's avatar Boris Brezillon

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.
parents dfbd3995 53bcbb83
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;
};
};
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>;
};
};
...@@ -9849,6 +9849,13 @@ F: drivers/media/platform/meson/ao-cec.c ...@@ -9849,6 +9849,13 @@ F: drivers/media/platform/meson/ao-cec.c
F: Documentation/devicetree/bindings/media/meson-ao-cec.txt F: Documentation/devicetree/bindings/media/meson-ao-cec.txt
T: git git://linuxtv.org/media_tree.git 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 MICROBLAZE ARCHITECTURE
M: Michal Simek <monstr@monstr.eu> M: Michal Simek <monstr@monstr.eu>
W: http://www.monstr.eu/fdt/ W: http://www.monstr.eu/fdt/
......
...@@ -541,4 +541,21 @@ config MTD_NAND_TEGRA ...@@ -541,4 +541,21 @@ config MTD_NAND_TEGRA
is supported. Extra OOB bytes when using HW ECC are currently is supported. Extra OOB bytes when using HW ECC are currently
not supported. 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 endif # MTD_NAND
...@@ -56,6 +56,8 @@ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ ...@@ -56,6 +56,8 @@ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/
obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o obj-$(CONFIG_MTD_NAND_MTK) += mtk_ecc.o mtk_nand.o
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_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_base.o nand_legacy.o nand_bbt.o nand_timings.o nand_ids.o
nand-objs += nand_onfi.o nand-objs += nand_onfi.o
......
...@@ -876,23 +876,32 @@ static struct atmel_pmecc *atmel_pmecc_get_by_node(struct device *userdev, ...@@ -876,23 +876,32 @@ static struct atmel_pmecc *atmel_pmecc_get_by_node(struct device *userdev,
{ {
struct platform_device *pdev; struct platform_device *pdev;
struct atmel_pmecc *pmecc, **ptr; struct atmel_pmecc *pmecc, **ptr;
int ret;
pdev = of_find_device_by_node(np); pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev)) if (!pdev)
return ERR_PTR(-EPROBE_DEFER); 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); ptr = devres_alloc(devm_atmel_pmecc_put, sizeof(*ptr), GFP_KERNEL);
if (!ptr) if (!ptr) {
return ERR_PTR(-ENOMEM); ret = -ENOMEM;
goto err_put_device;
get_device(&pdev->dev); }
pmecc = platform_get_drvdata(pdev);
*ptr = pmecc; *ptr = pmecc;
devres_add(userdev, ptr); devres_add(userdev, ptr);
return pmecc; 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 }; static const int atmel_pmecc_strengths[] = { 2, 4, 8, 12, 24, 32 };
......
...@@ -37,9 +37,6 @@ ...@@ -37,9 +37,6 @@
#define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) /* address cycle */ #define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) /* address cycle */
#define DENALI_MAP11_DATA ((DENALI_MAP11) | 2) /* data 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_BANK(denali) ((denali)->active_bank << 24)
#define DENALI_INVALID_BANK -1 #define DENALI_INVALID_BANK -1
...@@ -476,7 +473,7 @@ static void denali_setup_dma32(struct denali_nand_info *denali, ...@@ -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, 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; u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
uint32_t *buf32 = (uint32_t *)buf; uint32_t *buf32 = (uint32_t *)buf;
...@@ -504,7 +501,7 @@ static int denali_pio_read(struct denali_nand_info *denali, void *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, 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; u32 addr = DENALI_MAP01 | DENALI_BANK(denali) | page;
const uint32_t *buf32 = (uint32_t *)buf; const uint32_t *buf32 = (uint32_t *)buf;
...@@ -525,16 +522,16 @@ static int denali_pio_write(struct denali_nand_info *denali, ...@@ -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, 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) if (write)
return denali_pio_write(denali, buf, size, page, raw); return denali_pio_write(denali, buf, size, page);
else 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, 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; dma_addr_t dma_addr;
uint32_t irq_mask, irq_status, ecc_err_mask; 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, ...@@ -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); dma_addr = dma_map_single(denali->dev, buf, size, dir);
if (dma_mapping_error(denali->dev, dma_addr)) { if (dma_mapping_error(denali->dev, dma_addr)) {
dev_dbg(denali->dev, "Failed to DMA-map buffer. Trying PIO.\n"); 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) { if (write) {
...@@ -598,9 +595,9 @@ static int denali_data_xfer(struct denali_nand_info *denali, void *buf, ...@@ -598,9 +595,9 @@ static int denali_data_xfer(struct denali_nand_info *denali, void *buf,
denali->reg + TRANSFER_SPARE_REG); denali->reg + TRANSFER_SPARE_REG);
if (denali->dma_avail) if (denali->dma_avail)
return denali_dma_xfer(denali, buf, size, page, raw, write); return denali_dma_xfer(denali, buf, size, page, write);
else 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, 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) ...@@ -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) static int denali_write_oob(struct nand_chip *chip, int page)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); 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); denali_oob_xfer(mtd, chip, page, 1);
...@@ -903,23 +897,6 @@ static int denali_waitfunc(struct nand_chip *chip) ...@@ -903,23 +897,6 @@ static int denali_waitfunc(struct nand_chip *chip)
return irq_status & INTR__INT_ACT ? 0 : NAND_STATUS_FAIL; 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, static int denali_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf) const struct nand_data_interface *conf)
{ {
...@@ -1244,7 +1221,6 @@ static int denali_attach_chip(struct nand_chip *chip) ...@@ -1244,7 +1221,6 @@ static int denali_attach_chip(struct nand_chip *chip)
chip->ecc.write_page_raw = denali_write_page_raw; chip->ecc.write_page_raw = denali_write_page_raw;
chip->ecc.read_oob = denali_read_oob; chip->ecc.read_oob = denali_read_oob;
chip->ecc.write_oob = denali_write_oob; chip->ecc.write_oob = denali_write_oob;
chip->legacy.erase = denali_erase;
ret = denali_multidev_fixup(denali); ret = denali_multidev_fixup(denali);
if (ret) if (ret)
......
...@@ -304,7 +304,6 @@ struct denali_nand_info { ...@@ -304,7 +304,6 @@ struct denali_nand_info {
u32 irq_status; /* interrupts that have happened */ u32 irq_status; /* interrupts that have happened */
int irq; int irq;
void *buf; /* for syndrome layout conversion */ void *buf; /* for syndrome layout conversion */
dma_addr_t dma_addr;
int dma_avail; /* can support DMA? */ int dma_avail; /* can support DMA? */
int devs_per_cs; /* devices connected in parallel */ int devs_per_cs; /* devices connected in parallel */
int oob_skip_bytes; /* number of bytes reserved for BBM */ int oob_skip_bytes; /* number of bytes reserved for BBM */
......
...@@ -109,25 +109,17 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -109,25 +109,17 @@ static int denali_dt_probe(struct platform_device *pdev)
if (IS_ERR(denali->host)) if (IS_ERR(denali->host))
return PTR_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"); dt->clk = devm_clk_get(dev, "nand");
if (IS_ERR(dt->clk)) 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); return PTR_ERR(dt->clk);
}
dt->clk_x = devm_clk_get(dev, "nand_x"); dt->clk_x = devm_clk_get(dev, "nand_x");
if (IS_ERR(dt->clk_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"); dt->clk_ecc = devm_clk_get(dev, "ecc");
if (IS_ERR(dt->clk_ecc)) if (IS_ERR(dt->clk_ecc))
dt->clk_ecc = NULL; return PTR_ERR(dt->clk_ecc);
ret = clk_prepare_enable(dt->clk); ret = clk_prepare_enable(dt->clk);
if (ret) if (ret)
...@@ -141,19 +133,8 @@ static int denali_dt_probe(struct platform_device *pdev) ...@@ -141,19 +133,8 @@ static int denali_dt_probe(struct platform_device *pdev)
if (ret) if (ret)
goto out_disable_clk_x; goto out_disable_clk_x;
if (dt->clk_x) { denali->clk_rate = clk_get_rate(dt->clk);
denali->clk_rate = clk_get_rate(dt->clk); denali->clk_x_rate = clk_get_rate(dt->clk_x);
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;
}
ret = denali_init(denali); ret = denali_init(denali);
if (ret) if (ret)
......
...@@ -986,6 +986,19 @@ static const struct nand_controller_ops fsmc_nand_controller_ops = { ...@@ -986,6 +986,19 @@ static const struct nand_controller_ops fsmc_nand_controller_ops = {
.setup_data_interface = fsmc_setup_data_interface, .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 * fsmc_nand_probe - Probe function
* @pdev: platform device structure * @pdev: platform device structure
...@@ -1141,6 +1154,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) ...@@ -1141,6 +1154,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
if (host->mode == USE_DMA_ACCESS) if (host->mode == USE_DMA_ACCESS)
dma_release_channel(host->read_dma_chan); dma_release_channel(host->read_dma_chan);
disable_clk: disable_clk:
fsmc_nand_disable(host);
clk_disable_unprepare(host->clk); clk_disable_unprepare(host->clk);
return ret; return ret;
...@@ -1155,6 +1169,7 @@ static int fsmc_nand_remove(struct platform_device *pdev) ...@@ -1155,6 +1169,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
if (host) { if (host) {
nand_release(&host->nand); nand_release(&host->nand);
fsmc_nand_disable(host);
if (host->mode == USE_DMA_ACCESS) { if (host->mode == USE_DMA_ACCESS) {
dma_release_channel(host->write_dma_chan); dma_release_channel(host->write_dma_chan);
...@@ -1185,6 +1200,7 @@ static int fsmc_nand_resume(struct device *dev) ...@@ -1185,6 +1200,7 @@ static int fsmc_nand_resume(struct device *dev)
clk_prepare_enable(host->clk); clk_prepare_enable(host->clk);
if (host->dev_timings) if (host->dev_timings)
fsmc_nand_setup(host, host->dev_timings); fsmc_nand_setup(host, host->dev_timings);
nand_reset(&host->nand, 0);
} }
return 0; return 0;
......
...@@ -281,12 +281,15 @@ static struct jz4780_bch *jz4780_bch_get(struct device_node *np) ...@@ -281,12 +281,15 @@ static struct jz4780_bch *jz4780_bch_get(struct device_node *np)
struct jz4780_bch *bch; struct jz4780_bch *bch;
pdev = of_find_device_by_node(np); pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev)) if (!pdev)
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
get_device(&pdev->dev);
bch = platform_get_drvdata(pdev); bch = platform_get_drvdata(pdev);
if (!bch) {
put_device(&pdev->dev);
return ERR_PTR(-EPROBE_DEFER);
}
clk_prepare_enable(bch->clk); clk_prepare_enable(bch->clk);
return bch; return bch;
......
...@@ -2550,9 +2550,8 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc, ...@@ -2550,9 +2550,8 @@ static int marvell_nand_chip_init(struct device *dev, struct marvell_nfc *nfc,
} }
/* Alloc the nand chip structure */ /* Alloc the nand chip structure */
marvell_nand = devm_kzalloc(dev, sizeof(*marvell_nand) + marvell_nand = devm_kzalloc(dev,
(nsels * struct_size(marvell_nand, sels, nsels),
sizeof(struct marvell_nand_chip_sel)),
GFP_KERNEL); GFP_KERNEL);
if (!marvell_nand) { if (!marvell_nand) {
dev_err(dev, "could not allocate chip structure\n"); dev_err(dev, "could not allocate chip structure\n");
......
This diff is collapsed.
...@@ -267,11 +267,15 @@ static struct mtk_ecc *mtk_ecc_get(struct device_node *np) ...@@ -267,11 +267,15 @@ static struct mtk_ecc *mtk_ecc_get(struct device_node *np)
struct mtk_ecc *ecc; struct mtk_ecc *ecc;
pdev = of_find_device_by_node(np); pdev = of_find_device_by_node(np);
if (!pdev || !platform_get_drvdata(pdev)) if (!pdev)
return ERR_PTR(-EPROBE_DEFER); return ERR_PTR(-EPROBE_DEFER);
get_device(&pdev->dev);
ecc = platform_get_drvdata(pdev); ecc = platform_get_drvdata(pdev);
if (!ecc) {
put_device(&pdev->dev);
return ERR_PTR(-EPROBE_DEFER);
}
clk_prepare_enable(ecc->clk); clk_prepare_enable(ecc->clk);
mtk_ecc_hw_init(ecc); mtk_ecc_hw_init(ecc);
......
...@@ -1451,8 +1451,7 @@ static int mtk_nfc_probe(struct platform_device *pdev) ...@@ -1451,8 +1451,7 @@ static int mtk_nfc_probe(struct platform_device *pdev)
if (!nfc) if (!nfc)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&nfc->controller.lock); nand_controller_init(&nfc->controller);
init_waitqueue_head(&nfc->controller.wq);
INIT_LIST_HEAD(&nfc->chips); INIT_LIST_HEAD(&nfc->chips);
nfc->controller.ops = &mtk_nfc_controller_ops; nfc->controller.ops = &mtk_nfc_controller_ops;
......
...@@ -278,11 +278,8 @@ EXPORT_SYMBOL_GPL(nand_deselect_target); ...@@ -278,11 +278,8 @@ EXPORT_SYMBOL_GPL(nand_deselect_target);
static void nand_release_device(struct nand_chip *chip) static void nand_release_device(struct nand_chip *chip)
{ {
/* Release the controller and the chip */ /* Release the controller and the chip */
spin_lock(&chip->controller->lock); mutex_unlock(&chip->controller->lock);
chip->controller->active = NULL; mutex_unlock(&chip->lock);
chip->state = FL_READY;
wake_up(&chip->controller->wq);
spin_unlock(&chip->controller->lock);
} }
/** /**
...@@ -330,58 +327,24 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs) ...@@ -330,58 +327,24 @@ static int nand_isbad_bbm(struct nand_chip *chip, loff_t ofs)
return nand_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 * nand_get_device - [GENERIC] Get chip for selected access
* @chip: NAND chip structure * @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 static int nand_get_device(struct nand_chip *chip)
nand_get_device(struct nand_chip *chip, int new_state)
{ {
spinlock_t *lock = &chip->controller->lock; mutex_lock(&chip->lock);
wait_queue_head_t *wq = &chip->controller->wq; if (chip->suspended) {
DECLARE_WAITQUEUE(wait, current); mutex_unlock(&chip->lock);
retry: return -EBUSY;
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); mutex_lock(&chip->controller->lock);
add_wait_queue(wq, &wait);
spin_unlock(lock); return 0;
schedule();
remove_wait_queue(wq, &wait);
goto retry;
} }
/** /**
...@@ -457,7 +420,7 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to, ...@@ -457,7 +420,7 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to,
struct mtd_oob_ops *ops) struct mtd_oob_ops *ops)
{ {
struct mtd_info *mtd = nand_to_mtd(chip); 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", pr_debug("%s: to = 0x%08x, len = %i\n",
__func__, (unsigned int)to, (int)ops->ooblen); __func__, (unsigned int)to, (int)ops->ooblen);
...@@ -479,7 +442,9 @@ static int nand_do_write_oob(struct nand_chip *chip, loff_t to, ...@@ -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' * 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. * 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); nand_select_target(chip, chipnr);
...@@ -602,7 +567,10 @@ static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs) ...@@ -602,7 +567,10 @@ static int nand_block_markbad_lowlevel(struct nand_chip *chip, loff_t ofs)
nand_erase_nand(chip, &einfo, 0); nand_erase_nand(chip, &einfo, 0);
/* Write bad block marker to OOB */ /* 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); ret = nand_markbad_bbm(chip, ofs);
nand_release_device(chip); nand_release_device(chip);
} }
...@@ -3580,7 +3548,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, ...@@ -3580,7 +3548,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
ops->mode != MTD_OPS_RAW) ops->mode != MTD_OPS_RAW)
return -ENOTSUPP; return -ENOTSUPP;
nand_get_device(chip, FL_READING); ret = nand_get_device(chip);
if (ret)
return ret;
if (!ops->datbuf) if (!ops->datbuf)
ret = nand_do_read_oob(chip, from, ops); 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, ...@@ -4099,9 +4069,6 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
struct mtd_oob_ops ops; struct mtd_oob_ops ops;
int ret; int ret;
/* Grab the device */
panic_nand_get_device(chip, FL_WRITING);
nand_select_target(chip, chipnr); nand_select_target(chip, chipnr);
/* Wait for the device to get ready */ /* Wait for the device to get ready */
...@@ -4132,7 +4099,9 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, ...@@ -4132,7 +4099,9 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
ops->retlen = 0; ops->retlen = 0;
nand_get_device(chip, FL_WRITING); ret = nand_get_device(chip);
if (ret)
return ret;
switch (ops->mode) { switch (ops->mode) {
case MTD_OPS_PLACE_OOB: case MTD_OPS_PLACE_OOB:
...@@ -4154,23 +4123,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, ...@@ -4154,23 +4123,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
return ret; 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) * nand_erase - [MTD Interface] erase block(s)
* @mtd: MTD device structure * @mtd: MTD device structure
...@@ -4194,7 +4146,7 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) ...@@ -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 nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
int allowbbt) int allowbbt)
{ {
int page, status, pages_per_block, ret, chipnr; int page, pages_per_block, ret, chipnr;
loff_t len; loff_t len;
pr_debug("%s: start = 0x%012llx, len = %llu\n", 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, ...@@ -4205,7 +4157,9 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
return -EINVAL; return -EINVAL;
/* Grab the lock and see if the device is available */ /* 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 */ /* Shift to get first page */
page = (int)(instr->addr >> chip->page_shift); page = (int)(instr->addr >> chip->page_shift);
...@@ -4246,17 +4200,11 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr, ...@@ -4246,17 +4200,11 @@ int nand_erase_nand(struct nand_chip *chip, struct erase_info *instr,
(page + pages_per_block)) (page + pages_per_block))
chip->pagebuf = -1; chip->pagebuf = -1;
if (chip->legacy.erase) ret = nand_erase_op(chip, (page & chip->pagemask) >>
status = chip->legacy.erase(chip, (chip->phys_erase_shift - chip->page_shift));
page & chip->pagemask); if (ret) {
else
status = single_erase(chip, page & chip->pagemask);
/* See if block erase succeeded */
if (status) {
pr_debug("%s: failed erase, page 0x%08x\n", pr_debug("%s: failed erase, page 0x%08x\n",
__func__, page); __func__, page);
ret = -EIO;
instr->fail_addr = instr->fail_addr =
((loff_t)page << chip->page_shift); ((loff_t)page << chip->page_shift);
goto erase_exit; goto erase_exit;
...@@ -4298,7 +4246,7 @@ static void nand_sync(struct mtd_info *mtd) ...@@ -4298,7 +4246,7 @@ static void nand_sync(struct mtd_info *mtd)
pr_debug("%s: called\n", __func__); pr_debug("%s: called\n", __func__);
/* Grab the lock and see if the device is available */ /* 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 */ /* Release it and go back */
nand_release_device(chip); nand_release_device(chip);
} }
...@@ -4315,7 +4263,10 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) ...@@ -4315,7 +4263,10 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
int ret; int ret;
/* Select the NAND device */ /* Select the NAND device */
nand_get_device(chip, FL_READING); ret = nand_get_device(chip);
if (ret)
return ret;
nand_select_target(chip, chipnr); nand_select_target(chip, chipnr);
ret = nand_block_checkbad(chip, offs, 0); 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) ...@@ -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) 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) ...@@ -4399,11 +4356,13 @@ static void nand_resume(struct mtd_info *mtd)
{ {
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
if (chip->state == FL_PM_SUSPENDED) mutex_lock(&chip->lock);
nand_release_device(chip); if (chip->suspended)
chip->suspended = 0;
else else
pr_err("%s called for a chip which is not in suspended state\n", pr_err("%s called for a chip which is not in suspended state\n",
__func__); __func__);
mutex_unlock(&chip->lock);
} }
/** /**
...@@ -4413,7 +4372,7 @@ static void nand_resume(struct mtd_info *mtd) ...@@ -4413,7 +4372,7 @@ static void nand_resume(struct mtd_info *mtd)
*/ */
static void nand_shutdown(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 */ /* Set default functions */
...@@ -5018,6 +4977,8 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, ...@@ -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(). */ /* Assume all dies are deselected when we enter nand_scan_ident(). */
chip->cur_cs = -1; chip->cur_cs = -1;
mutex_init(&chip->lock);
/* Enforce the right timings for reset/detection */ /* Enforce the right timings for reset/detection */
onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0); 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, ...@@ -5060,11 +5021,15 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
u8 id[2]; u8 id[2];
/* See comment in nand_get_flash_type for reset */ /* 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); nand_select_target(chip, i);
/* Send the command for reading device ID */ /* 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 */ /* Read manufacturer and device IDs */
if (nand_maf_id != id[0] || nand_dev_id != id[1]) { if (nand_maf_id != id[0] || nand_dev_id != id[1]) {
nand_deselect_target(chip); nand_deselect_target(chip);
...@@ -5555,6 +5520,7 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5555,6 +5520,7 @@ static int nand_scan_tail(struct nand_chip *chip)
} }
if (!ecc->read_page) if (!ecc->read_page)
ecc->read_page = nand_read_page_hwecc_oob_first; ecc->read_page = nand_read_page_hwecc_oob_first;
/* fall through */
case NAND_ECC_HW: case NAND_ECC_HW:
/* Use standard hwecc read page function? */ /* Use standard hwecc read page function? */
...@@ -5574,6 +5540,7 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5574,6 +5540,7 @@ static int nand_scan_tail(struct nand_chip *chip)
ecc->read_subpage = nand_read_subpage; ecc->read_subpage = nand_read_subpage;
if (!ecc->write_subpage && ecc->hwctl && ecc->calculate) if (!ecc->write_subpage && ecc->hwctl && ecc->calculate)
ecc->write_subpage = nand_write_subpage_hwecc; ecc->write_subpage = nand_write_subpage_hwecc;
/* fall through */
case NAND_ECC_HW_SYNDROME: case NAND_ECC_HW_SYNDROME:
if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) && if ((!ecc->calculate || !ecc->correct || !ecc->hwctl) &&
...@@ -5611,6 +5578,7 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5611,6 +5578,7 @@ static int nand_scan_tail(struct nand_chip *chip)
ecc->size, mtd->writesize); ecc->size, mtd->writesize);
ecc->mode = NAND_ECC_SOFT; ecc->mode = NAND_ECC_SOFT;
ecc->algo = NAND_ECC_HAMMING; ecc->algo = NAND_ECC_HAMMING;
/* fall through */
case NAND_ECC_SOFT: case NAND_ECC_SOFT:
ret = nand_set_ecc_soft_ops(chip); ret = nand_set_ecc_soft_ops(chip);
...@@ -5717,9 +5685,6 @@ static int nand_scan_tail(struct nand_chip *chip) ...@@ -5717,9 +5685,6 @@ static int nand_scan_tail(struct nand_chip *chip)
} }
chip->subpagesize = mtd->writesize >> mtd->subpage_sft; chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
/* Initialize state */
chip->state = FL_READY;
/* Invalidate the pagebuffer reference */ /* Invalidate the pagebuffer reference */
chip->pagebuf = -1; chip->pagebuf = -1;
......
...@@ -331,6 +331,7 @@ static void nand_command(struct nand_chip *chip, unsigned int command, ...@@ -331,6 +331,7 @@ static void nand_command(struct nand_chip *chip, unsigned int command,
*/ */
if (column == -1 && page_addr == -1) if (column == -1 && page_addr == -1)
return; return;
/* fall through */
default: default:
/* /*
...@@ -483,7 +484,7 @@ static void nand_command_lp(struct nand_chip *chip, unsigned int command, ...@@ -483,7 +484,7 @@ static void nand_command_lp(struct nand_chip *chip, unsigned int command,
chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE, chip->legacy.cmd_ctrl(chip, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE); NAND_NCE | NAND_CTRL_CHANGE);
/* This applies to read commands */ /* fall through - This applies to read commands */
default: default:
/* /*
* If we don't have access to the busy pin, we apply the given * If we don't have access to the busy pin, we apply the given
......
...@@ -994,12 +994,9 @@ static int omap_wait(struct nand_chip *this) ...@@ -994,12 +994,9 @@ static int omap_wait(struct nand_chip *this)
{ {
struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this)); struct omap_nand_info *info = mtd_to_omap(nand_to_mtd(this));
unsigned long timeo = jiffies; unsigned long timeo = jiffies;
int status, state = this->state; int status;
if (state == FL_ERASING) timeo += msecs_to_jiffies(400);
timeo += msecs_to_jiffies(400);
else
timeo += msecs_to_jiffies(20);
writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command); writeb(NAND_CMD_STATUS & 0xFF, info->reg.gpmc_nand_command);
while (time_before(jiffies, timeo)) { while (time_before(jiffies, timeo)) {
...@@ -2173,11 +2170,8 @@ static const struct nand_controller_ops omap_nand_controller_ops = { ...@@ -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 */ /* Shared among all NAND instances to synchronize access to the ECC Engine */
static struct nand_controller omap_gpmc_controller = { static struct nand_controller omap_gpmc_controller;
.lock = __SPIN_LOCK_UNLOCKED(omap_gpmc_controller.lock), static bool omap_gpmc_controller_initialized;
.wq = __WAIT_QUEUE_HEAD_INITIALIZER(omap_gpmc_controller.wq),
.ops = &omap_nand_controller_ops,
};
static int omap_nand_probe(struct platform_device *pdev) static int omap_nand_probe(struct platform_device *pdev)
{ {
...@@ -2227,6 +2221,12 @@ 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; 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->controller = &omap_gpmc_controller;
nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R; nand_chip->legacy.IO_ADDR_W = nand_chip->legacy.IO_ADDR_R;
......
...@@ -369,8 +369,7 @@ static int r852_wait(struct nand_chip *chip) ...@@ -369,8 +369,7 @@ static int r852_wait(struct nand_chip *chip)
unsigned long timeout; unsigned long timeout;
u8 status; u8 status;
timeout = jiffies + (chip->state == FL_ERASING ? timeout = jiffies + msecs_to_jiffies(400);
msecs_to_jiffies(400) : msecs_to_jiffies(20));
while (time_before(jiffies, timeout)) while (time_before(jiffies, timeout))
if (chip->legacy.dev_ready(chip)) if (chip->legacy.dev_ready(chip))
......
This diff is collapsed.
This diff is collapsed.
...@@ -104,6 +104,7 @@ ...@@ -104,6 +104,7 @@
struct tmio_nand { struct tmio_nand {
struct nand_chip chip; struct nand_chip chip;
struct completion comp;
struct platform_device *dev; struct platform_device *dev;
...@@ -168,15 +169,11 @@ static int tmio_nand_dev_ready(struct nand_chip *chip) ...@@ -168,15 +169,11 @@ static int tmio_nand_dev_ready(struct nand_chip *chip)
static irqreturn_t tmio_irq(int irq, void *__tmio) static irqreturn_t tmio_irq(int irq, void *__tmio)
{ {
struct tmio_nand *tmio = __tmio; struct tmio_nand *tmio = __tmio;
struct nand_chip *nand_chip = &tmio->chip;
/* disable RDYREQ interrupt */ /* disable RDYREQ interrupt */
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); 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; return IRQ_HANDLED;
} }
...@@ -193,18 +190,18 @@ static int tmio_nand_wait(struct nand_chip *nand_chip) ...@@ -193,18 +190,18 @@ static int tmio_nand_wait(struct nand_chip *nand_chip)
u8 status; u8 status;
/* enable RDYREQ interrupt */ /* enable RDYREQ interrupt */
tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR); tmio_iowrite8(0x0f, tmio->fcr + FCR_ISR);
reinit_completion(&tmio->comp);
tmio_iowrite8(0x81, tmio->fcr + FCR_IMR); tmio_iowrite8(0x81, tmio->fcr + FCR_IMR);
timeout = wait_event_timeout(nand_chip->controller->wq, timeout = 400;
tmio_nand_dev_ready(nand_chip), timeout = wait_for_completion_timeout(&tmio->comp,
msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20)); msecs_to_jiffies(timeout));
if (unlikely(!tmio_nand_dev_ready(nand_chip))) { if (unlikely(!tmio_nand_dev_ready(nand_chip))) {
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n", dev_warn(&tmio->dev->dev, "still busy after 400 ms\n");
nand_chip->state == FL_ERASING ? "erase" : "program",
nand_chip->state == FL_ERASING ? 400 : 20);
} else if (unlikely(!timeout)) { } else if (unlikely(!timeout)) {
tmio_iowrite8(0x00, tmio->fcr + FCR_IMR); tmio_iowrite8(0x00, tmio->fcr + FCR_IMR);
...@@ -378,6 +375,8 @@ static int tmio_probe(struct platform_device *dev) ...@@ -378,6 +375,8 @@ static int tmio_probe(struct platform_device *dev)
if (!tmio) if (!tmio)
return -ENOMEM; return -ENOMEM;
init_completion(&tmio->comp);
tmio->dev = dev; tmio->dev = dev;
platform_set_drvdata(dev, tmio); platform_set_drvdata(dev, tmio);
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4) #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4) #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
#define GD5FXGQ4UEXXG_REG_STATUS2 0xf0
static SPINAND_OP_VARIANTS(read_cache_variants, static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, 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, ...@@ -81,11 +83,83 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
return -EINVAL; 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 = { static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
.ecc = gd5fxgq4xa_ooblayout_ecc, .ecc = gd5fxgq4xa_ooblayout_ecc,
.free = gd5fxgq4xa_ooblayout_free, .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[] = { static const struct spinand_info gigadevice_spinand_table[] = {
SPINAND_INFO("GD5F1GQ4xA", 0xF1, SPINAND_INFO("GD5F1GQ4xA", 0xF1,
NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1), NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
...@@ -114,6 +188,15 @@ static const struct spinand_info gigadevice_spinand_table[] = { ...@@ -114,6 +188,15 @@ static const struct spinand_info gigadevice_spinand_table[] = {
0, 0,
SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
gd5fxgq4xa_ecc_get_status)), 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) static int gigadevice_spinand_detect(struct spinand_device *spinand)
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/mtd/spinand.h> #include <linux/mtd/spinand.h>
#define SPINAND_MFR_MACRONIX 0xC2 #define SPINAND_MFR_MACRONIX 0xC2
#define MACRONIX_ECCSR_MASK 0x0F
static SPINAND_OP_VARIANTS(read_cache_variants, static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), 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) ...@@ -55,7 +56,12 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr)
SPI_MEM_OP_DUMMY(1, 1), SPI_MEM_OP_DUMMY(1, 1),
SPI_MEM_OP_DATA_IN(1, eccsr, 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, static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
......
...@@ -25,19 +25,19 @@ static SPINAND_OP_VARIANTS(write_cache_variants, ...@@ -25,19 +25,19 @@ static SPINAND_OP_VARIANTS(write_cache_variants,
static SPINAND_OP_VARIANTS(update_cache_variants, static SPINAND_OP_VARIANTS(update_cache_variants,
SPINAND_PROG_LOAD(false, 0, NULL, 0)); 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) struct mtd_oob_region *region)
{ {
if (section > 7) if (section > 0)
return -ERANGE; return -ERANGE;
region->offset = 128 + 16 * section; region->offset = mtd->oobsize / 2;
region->length = 16; region->length = mtd->oobsize / 2;
return 0; 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) struct mtd_oob_region *region)
{ {
if (section > 0) if (section > 0)
...@@ -45,17 +45,17 @@ static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section, ...@@ -45,17 +45,17 @@ static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
/* 2 bytes reserved for BBM */ /* 2 bytes reserved for BBM */
region->offset = 2; region->offset = 2;
region->length = 126; region->length = (mtd->oobsize / 2) - 2;
return 0; return 0;
} }
static const struct mtd_ooblayout_ops tc58cvg2s0h_ooblayout = { static const struct mtd_ooblayout_ops tc58cxgxsx_ooblayout = {
.ecc = tc58cvg2s0h_ooblayout_ecc, .ecc = tc58cxgxsx_ooblayout_ecc,
.free = tc58cvg2s0h_ooblayout_free, .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) u8 status)
{ {
struct nand_device *nand = spinand_to_nand(spinand); struct nand_device *nand = spinand_to_nand(spinand);
...@@ -94,15 +94,66 @@ static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand, ...@@ -94,15 +94,66 @@ static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
} }
static const struct spinand_info toshiba_spinand_table[] = { 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),
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_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
NAND_ECCREQ(8, 512), NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants, SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants, &write_cache_variants,
&update_cache_variants), &update_cache_variants),
SPINAND_HAS_QE_BIT, 0,
SPINAND_ECCINFO(&tc58cvg2s0h_ooblayout, SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
tc58cvg2s0h_ecc_get_status)), tc58cxgxsx_ecc_get_status)),
}; };
static int toshiba_spinand_detect(struct spinand_device *spinand) static int toshiba_spinand_detect(struct spinand_device *spinand)
......
...@@ -16,13 +16,12 @@ ...@@ -16,13 +16,12 @@
#ifndef __LINUX_MTD_RAWNAND_H #ifndef __LINUX_MTD_RAWNAND_H
#define __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/mtd.h>
#include <linux/mtd/flashchip.h> #include <linux/mtd/flashchip.h>
#include <linux/mtd/bbm.h> #include <linux/mtd/bbm.h>
#include <linux/mtd/jedec.h> #include <linux/mtd/jedec.h>
#include <linux/mtd/onfi.h> #include <linux/mtd/onfi.h>
#include <linux/mutex.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -897,25 +896,17 @@ struct nand_controller_ops { ...@@ -897,25 +896,17 @@ struct nand_controller_ops {
/** /**
* struct nand_controller - Structure used to describe a NAND controller * struct nand_controller - Structure used to describe a NAND controller
* *
* @lock: protection lock * @lock: lock used to serialize accesses to the NAND controller
* @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.
* @ops: NAND controller operations. * @ops: NAND controller operations.
*/ */
struct nand_controller { struct nand_controller {
spinlock_t lock; struct mutex lock;
struct nand_chip *active;
wait_queue_head_t wq;
const struct nand_controller_ops *ops; const struct nand_controller_ops *ops;
}; };
static inline void nand_controller_init(struct nand_controller *nfc) static inline void nand_controller_init(struct nand_controller *nfc)
{ {
nfc->active = NULL; mutex_init(&nfc->lock);
spin_lock_init(&nfc->lock);
init_waitqueue_head(&nfc->wq);
} }
/** /**
...@@ -936,7 +927,6 @@ static inline void nand_controller_init(struct nand_controller *nfc) ...@@ -936,7 +927,6 @@ static inline void nand_controller_init(struct nand_controller *nfc)
* @waitfunc: hardware specific function for wait on ready. * @waitfunc: hardware specific function for wait on ready.
* @block_bad: check if a block is bad, using OOB markers * @block_bad: check if a block is bad, using OOB markers
* @block_markbad: mark a block bad * @block_markbad: mark a block bad
* @erase: erase function
* @set_features: set the NAND chip features * @set_features: set the NAND chip features
* @get_features: get the NAND chip features * @get_features: get the NAND chip features
* @chip_delay: chip dependent delay for transferring data from array to read * @chip_delay: chip dependent delay for transferring data from array to read
...@@ -962,7 +952,6 @@ struct nand_legacy { ...@@ -962,7 +952,6 @@ struct nand_legacy {
int (*waitfunc)(struct nand_chip *chip); int (*waitfunc)(struct nand_chip *chip);
int (*block_bad)(struct nand_chip *chip, loff_t ofs); int (*block_bad)(struct nand_chip *chip, loff_t ofs);
int (*block_markbad)(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, int (*set_features)(struct nand_chip *chip, int feature_addr,
u8 *subfeature_para); u8 *subfeature_para);
int (*get_features)(struct nand_chip *chip, int feature_addr, int (*get_features)(struct nand_chip *chip, int feature_addr,
...@@ -983,7 +972,6 @@ struct nand_legacy { ...@@ -983,7 +972,6 @@ struct nand_legacy {
* setting the read-retry mode. Mostly needed for MLC NAND. * setting the read-retry mode. Mostly needed for MLC NAND.
* @ecc: [BOARDSPECIFIC] ECC control structure * @ecc: [BOARDSPECIFIC] ECC control structure
* @buf_align: minimum buffer alignment required by a platform * @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 * @oob_poi: "poison value buffer," used for laying out OOB data
* before writing * before writing
* @page_shift: [INTERN] number of address bits in a page (column * @page_shift: [INTERN] number of address bits in a page (column
...@@ -1034,6 +1022,9 @@ struct nand_legacy { ...@@ -1034,6 +1022,9 @@ struct nand_legacy {
* cur_cs < numchips. NAND Controller drivers should not * cur_cs < numchips. NAND Controller drivers should not
* modify this value, but they're allowed to read it. * modify this value, but they're allowed to read it.
* @read_retries: [INTERN] the number of read retry modes supported * @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: [INTERN] bad block table pointer
* @bbt_td: [REPLACEABLE] bad block table descriptor for flash * @bbt_td: [REPLACEABLE] bad block table descriptor for flash
* lookup. * lookup.
...@@ -1088,7 +1079,8 @@ struct nand_chip { ...@@ -1088,7 +1079,8 @@ struct nand_chip {
int read_retries; int read_retries;
flstate_t state; struct mutex lock;
unsigned int suspended : 1;
uint8_t *oob_poi; uint8_t *oob_poi;
struct nand_controller *controller; struct nand_controller *controller;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment