Commit c3c1acaf authored by Richard Weinberger's avatar Richard Weinberger

Merge tag 'nand/for-5.4' of...

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

NAND core
* Fixing typos
* Adding missing of_node_put() in various drivers

Raw NAND controller drivers:
* Macronix: new controller driver
* Omap2: Fixing the number of bitflips returned
* Brcmnand: Fix a pointer not iterating over all the page chunks
* W90x900: Driver removed
* Onenand: Fix a memory leak
* Sharpsl: Missing include guard
* STM32: Avoid warnings when building with W=1
* Ingenic: Fix a coccinelle warning
* r852: Call a helper to simplify the code
parents 089cf7f6 f480b969
Macronix Raw NAND Controller Device Tree Bindings
-------------------------------------------------
Required properties:
- compatible: should be "mxic,multi-itfc-v009-nand-controller"
- reg: should contain 1 entry for the registers
- #address-cells: should be set to 1
- #size-cells: should be set to 0
- interrupts: interrupt line connected to this raw NAND controller
- clock-names: should contain "ps", "send" and "send_dly"
- clocks: should contain 3 phandles for the "ps", "send" and
"send_dly" clocks
Children nodes:
- children nodes represent the available NAND chips.
See Documentation/devicetree/bindings/mtd/nand-controller.yaml
for more details on generic bindings.
Example:
nand: nand-controller@43c30000 {
compatible = "mxic,multi-itfc-v009-nand-controller";
reg = <0x43c30000 0x10000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <GIC_SPI 0x1d IRQ_TYPE_EDGE_RISING>;
clocks = <&clkwizard 0>, <&clkwizard 1>, <&clkc 15>;
clock-names = "send", "send_dly", "ps";
nand@0 {
reg = <0>;
nand-ecc-mode = "soft";
nand-ecc-algo = "bch";
};
};
...@@ -3880,6 +3880,9 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) ...@@ -3880,6 +3880,9 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
if (!this->oob_buf) { if (!this->oob_buf) {
if (this->options & ONENAND_PAGEBUF_ALLOC) { if (this->options & ONENAND_PAGEBUF_ALLOC) {
this->options &= ~ONENAND_PAGEBUF_ALLOC; this->options &= ~ONENAND_PAGEBUF_ALLOC;
#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
kfree(this->verify_buf);
#endif
kfree(this->page_buf); kfree(this->page_buf);
} }
return -ENOMEM; return -ENOMEM;
......
...@@ -351,14 +351,6 @@ config MTD_NAND_SOCRATES ...@@ -351,14 +351,6 @@ config MTD_NAND_SOCRATES
help help
Enables support for NAND Flash chips wired onto Socrates board. Enables support for NAND Flash chips wired onto Socrates board.
config MTD_NAND_NUC900
tristate "Nuvoton NUC9xx/w90p910 NAND controller"
depends on ARCH_W90X900 || COMPILE_TEST
depends on HAS_IOMEM
help
This enables the driver for the NAND Flash on evaluation board based
on w90p910 / NUC9xx.
source "drivers/mtd/nand/raw/ingenic/Kconfig" source "drivers/mtd/nand/raw/ingenic/Kconfig"
config MTD_NAND_FSMC config MTD_NAND_FSMC
...@@ -407,6 +399,12 @@ config MTD_NAND_MTK ...@@ -407,6 +399,12 @@ config MTD_NAND_MTK
Enables support for NAND controller on MTK SoCs. Enables support for NAND controller on MTK SoCs.
This controller is found on mt27xx, mt81xx, mt65xx SoCs. This controller is found on mt27xx, mt81xx, mt65xx SoCs.
config MTD_NAND_MXIC
tristate "Macronix raw NAND controller"
depends on HAS_IOMEM || COMPILE_TEST
help
This selects the Macronix raw NAND controller driver.
config MTD_NAND_TEGRA config MTD_NAND_TEGRA
tristate "NVIDIA Tegra NAND controller" tristate "NVIDIA Tegra NAND controller"
depends on ARCH_TEGRA || COMPILE_TEST depends on ARCH_TEGRA || COMPILE_TEST
......
...@@ -41,7 +41,6 @@ obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o ...@@ -41,7 +41,6 @@ obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
obj-$(CONFIG_MTD_NAND_NUC900) += nuc900_nand.o
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o
obj-$(CONFIG_MTD_NAND_RICOH) += r852.o obj-$(CONFIG_MTD_NAND_RICOH) += r852.o
...@@ -54,6 +53,7 @@ obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o ...@@ -54,6 +53,7 @@ obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand/ 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_MXIC) += mxic_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_STM32_FMC2) += stm32_fmc2_nand.o
obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o obj-$(CONFIG_MTD_NAND_MESON) += meson_nand.o
......
...@@ -1792,6 +1792,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, ...@@ -1792,6 +1792,7 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
int bitflips = 0; int bitflips = 0;
int page = addr >> chip->page_shift; int page = addr >> chip->page_shift;
int ret; int ret;
void *ecc_chunk;
if (!buf) if (!buf)
buf = nand_get_data_buf(chip); buf = nand_get_data_buf(chip);
...@@ -1804,7 +1805,9 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd, ...@@ -1804,7 +1805,9 @@ static int brcmstb_nand_verify_erased_page(struct mtd_info *mtd,
return ret; return ret;
for (i = 0; i < chip->ecc.steps; i++, oob += sas) { for (i = 0; i < chip->ecc.steps; i++, oob += sas) {
ret = nand_check_erased_ecc_chunk(buf, chip->ecc.size, ecc_chunk = buf + chip->ecc.size * i;
ret = nand_check_erased_ecc_chunk(ecc_chunk,
chip->ecc.size,
oob, sas, NULL, 0, oob, sas, NULL, 0,
chip->ecc.strength); chip->ecc.strength);
if (ret < 0) if (ret < 0)
......
...@@ -310,7 +310,6 @@ static int ingenic_nand_init_chip(struct platform_device *pdev, ...@@ -310,7 +310,6 @@ static int ingenic_nand_init_chip(struct platform_device *pdev,
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct ingenic_nand *nand; struct ingenic_nand *nand;
struct ingenic_nand_cs *cs; struct ingenic_nand_cs *cs;
struct resource *res;
struct nand_chip *chip; struct nand_chip *chip;
struct mtd_info *mtd; struct mtd_info *mtd;
const __be32 *reg; const __be32 *reg;
...@@ -326,8 +325,7 @@ static int ingenic_nand_init_chip(struct platform_device *pdev, ...@@ -326,8 +325,7 @@ static int ingenic_nand_init_chip(struct platform_device *pdev,
jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND); jz4780_nemc_set_type(nfc->dev, cs->bank, JZ4780_NEMC_BANK_NAND);
res = platform_get_resource(pdev, IORESOURCE_MEM, chipnr); cs->base = devm_platform_ioremap_resource(pdev, chipnr);
cs->base = devm_ioremap_resource(dev, res);
if (IS_ERR(cs->base)) if (IS_ERR(cs->base))
return PTR_ERR(cs->base); return PTR_ERR(cs->base);
...@@ -418,6 +416,7 @@ static int ingenic_nand_init_chips(struct ingenic_nfc *nfc, ...@@ -418,6 +416,7 @@ static int ingenic_nand_init_chips(struct ingenic_nfc *nfc,
ret = ingenic_nand_init_chip(pdev, nfc, np, i); ret = ingenic_nand_init_chip(pdev, nfc, np, i);
if (ret) { if (ret) {
ingenic_nand_cleanup_chips(nfc); ingenic_nand_cleanup_chips(nfc);
of_node_put(np);
return ret; return ret;
} }
......
...@@ -1320,6 +1320,7 @@ static int meson_nfc_nand_chips_init(struct device *dev, ...@@ -1320,6 +1320,7 @@ static int meson_nfc_nand_chips_init(struct device *dev,
ret = meson_nfc_nand_chip_init(dev, nfc, nand_np); ret = meson_nfc_nand_chip_init(dev, nfc, nand_np);
if (ret) { if (ret) {
meson_nfc_nand_chip_cleanup(nfc); meson_nfc_nand_chip_cleanup(nfc);
of_node_put(nand_np);
return ret; return ret;
} }
} }
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Macronix International Co., Ltd.
*
* Author:
* Mason Yang <masonccyang@mxic.com.tw>
*/
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/platform_device.h>
#include "internals.h"
#define HC_CFG 0x0
#define HC_CFG_IF_CFG(x) ((x) << 27)
#define HC_CFG_DUAL_SLAVE BIT(31)
#define HC_CFG_INDIVIDUAL BIT(30)
#define HC_CFG_NIO(x) (((x) / 4) << 27)
#define HC_CFG_TYPE(s, t) ((t) << (23 + ((s) * 2)))
#define HC_CFG_TYPE_SPI_NOR 0
#define HC_CFG_TYPE_SPI_NAND 1
#define HC_CFG_TYPE_SPI_RAM 2
#define HC_CFG_TYPE_RAW_NAND 3
#define HC_CFG_SLV_ACT(x) ((x) << 21)
#define HC_CFG_CLK_PH_EN BIT(20)
#define HC_CFG_CLK_POL_INV BIT(19)
#define HC_CFG_BIG_ENDIAN BIT(18)
#define HC_CFG_DATA_PASS BIT(17)
#define HC_CFG_IDLE_SIO_LVL(x) ((x) << 16)
#define HC_CFG_MAN_START_EN BIT(3)
#define HC_CFG_MAN_START BIT(2)
#define HC_CFG_MAN_CS_EN BIT(1)
#define HC_CFG_MAN_CS_ASSERT BIT(0)
#define INT_STS 0x4
#define INT_STS_EN 0x8
#define INT_SIG_EN 0xc
#define INT_STS_ALL GENMASK(31, 0)
#define INT_RDY_PIN BIT(26)
#define INT_RDY_SR BIT(25)
#define INT_LNR_SUSP BIT(24)
#define INT_ECC_ERR BIT(17)
#define INT_CRC_ERR BIT(16)
#define INT_LWR_DIS BIT(12)
#define INT_LRD_DIS BIT(11)
#define INT_SDMA_INT BIT(10)
#define INT_DMA_FINISH BIT(9)
#define INT_RX_NOT_FULL BIT(3)
#define INT_RX_NOT_EMPTY BIT(2)
#define INT_TX_NOT_FULL BIT(1)
#define INT_TX_EMPTY BIT(0)
#define HC_EN 0x10
#define HC_EN_BIT BIT(0)
#define TXD(x) (0x14 + ((x) * 4))
#define RXD 0x24
#define SS_CTRL(s) (0x30 + ((s) * 4))
#define LRD_CFG 0x44
#define LWR_CFG 0x80
#define RWW_CFG 0x70
#define OP_READ BIT(23)
#define OP_DUMMY_CYC(x) ((x) << 17)
#define OP_ADDR_BYTES(x) ((x) << 14)
#define OP_CMD_BYTES(x) (((x) - 1) << 13)
#define OP_OCTA_CRC_EN BIT(12)
#define OP_DQS_EN BIT(11)
#define OP_ENHC_EN BIT(10)
#define OP_PREAMBLE_EN BIT(9)
#define OP_DATA_DDR BIT(8)
#define OP_DATA_BUSW(x) ((x) << 6)
#define OP_ADDR_DDR BIT(5)
#define OP_ADDR_BUSW(x) ((x) << 3)
#define OP_CMD_DDR BIT(2)
#define OP_CMD_BUSW(x) (x)
#define OP_BUSW_1 0
#define OP_BUSW_2 1
#define OP_BUSW_4 2
#define OP_BUSW_8 3
#define OCTA_CRC 0x38
#define OCTA_CRC_IN_EN(s) BIT(3 + ((s) * 16))
#define OCTA_CRC_CHUNK(s, x) ((fls((x) / 32)) << (1 + ((s) * 16)))
#define OCTA_CRC_OUT_EN(s) BIT(0 + ((s) * 16))
#define ONFI_DIN_CNT(s) (0x3c + (s))
#define LRD_CTRL 0x48
#define RWW_CTRL 0x74
#define LWR_CTRL 0x84
#define LMODE_EN BIT(31)
#define LMODE_SLV_ACT(x) ((x) << 21)
#define LMODE_CMD1(x) ((x) << 8)
#define LMODE_CMD0(x) (x)
#define LRD_ADDR 0x4c
#define LWR_ADDR 0x88
#define LRD_RANGE 0x50
#define LWR_RANGE 0x8c
#define AXI_SLV_ADDR 0x54
#define DMAC_RD_CFG 0x58
#define DMAC_WR_CFG 0x94
#define DMAC_CFG_PERIPH_EN BIT(31)
#define DMAC_CFG_ALLFLUSH_EN BIT(30)
#define DMAC_CFG_LASTFLUSH_EN BIT(29)
#define DMAC_CFG_QE(x) (((x) + 1) << 16)
#define DMAC_CFG_BURST_LEN(x) (((x) + 1) << 12)
#define DMAC_CFG_BURST_SZ(x) ((x) << 8)
#define DMAC_CFG_DIR_READ BIT(1)
#define DMAC_CFG_START BIT(0)
#define DMAC_RD_CNT 0x5c
#define DMAC_WR_CNT 0x98
#define SDMA_ADDR 0x60
#define DMAM_CFG 0x64
#define DMAM_CFG_START BIT(31)
#define DMAM_CFG_CONT BIT(30)
#define DMAM_CFG_SDMA_GAP(x) (fls((x) / 8192) << 2)
#define DMAM_CFG_DIR_READ BIT(1)
#define DMAM_CFG_EN BIT(0)
#define DMAM_CNT 0x68
#define LNR_TIMER_TH 0x6c
#define RDM_CFG0 0x78
#define RDM_CFG0_POLY(x) (x)
#define RDM_CFG1 0x7c
#define RDM_CFG1_RDM_EN BIT(31)
#define RDM_CFG1_SEED(x) (x)
#define LWR_SUSP_CTRL 0x90
#define LWR_SUSP_CTRL_EN BIT(31)
#define DMAS_CTRL 0x9c
#define DMAS_CTRL_EN BIT(31)
#define DMAS_CTRL_DIR_READ BIT(30)
#define DATA_STROB 0xa0
#define DATA_STROB_EDO_EN BIT(2)
#define DATA_STROB_INV_POL BIT(1)
#define DATA_STROB_DELAY_2CYC BIT(0)
#define IDLY_CODE(x) (0xa4 + ((x) * 4))
#define IDLY_CODE_VAL(x, v) ((v) << (((x) % 4) * 8))
#define GPIO 0xc4
#define GPIO_PT(x) BIT(3 + ((x) * 16))
#define GPIO_RESET(x) BIT(2 + ((x) * 16))
#define GPIO_HOLDB(x) BIT(1 + ((x) * 16))
#define GPIO_WPB(x) BIT((x) * 16)
#define HC_VER 0xd0
#define HW_TEST(x) (0xe0 + ((x) * 4))
#define MXIC_NFC_MAX_CLK_HZ 50000000
#define IRQ_TIMEOUT 1000
struct mxic_nand_ctlr {
struct clk *ps_clk;
struct clk *send_clk;
struct clk *send_dly_clk;
struct completion complete;
void __iomem *regs;
struct nand_controller controller;
struct device *dev;
struct nand_chip chip;
};
static int mxic_nfc_clk_enable(struct mxic_nand_ctlr *nfc)
{
int ret;
ret = clk_prepare_enable(nfc->ps_clk);
if (ret)
return ret;
ret = clk_prepare_enable(nfc->send_clk);
if (ret)
goto err_ps_clk;
ret = clk_prepare_enable(nfc->send_dly_clk);
if (ret)
goto err_send_dly_clk;
return ret;
err_send_dly_clk:
clk_disable_unprepare(nfc->send_clk);
err_ps_clk:
clk_disable_unprepare(nfc->ps_clk);
return ret;
}
static void mxic_nfc_clk_disable(struct mxic_nand_ctlr *nfc)
{
clk_disable_unprepare(nfc->send_clk);
clk_disable_unprepare(nfc->send_dly_clk);
clk_disable_unprepare(nfc->ps_clk);
}
static void mxic_nfc_set_input_delay(struct mxic_nand_ctlr *nfc, u8 idly_code)
{
writel(IDLY_CODE_VAL(0, idly_code) |
IDLY_CODE_VAL(1, idly_code) |
IDLY_CODE_VAL(2, idly_code) |
IDLY_CODE_VAL(3, idly_code),
nfc->regs + IDLY_CODE(0));
writel(IDLY_CODE_VAL(4, idly_code) |
IDLY_CODE_VAL(5, idly_code) |
IDLY_CODE_VAL(6, idly_code) |
IDLY_CODE_VAL(7, idly_code),
nfc->regs + IDLY_CODE(1));
}
static int mxic_nfc_clk_setup(struct mxic_nand_ctlr *nfc, unsigned long freq)
{
int ret;
ret = clk_set_rate(nfc->send_clk, freq);
if (ret)
return ret;
ret = clk_set_rate(nfc->send_dly_clk, freq);
if (ret)
return ret;
/*
* A constant delay range from 0x0 ~ 0x1F for input delay,
* the unit is 78 ps, the max input delay is 2.418 ns.
*/
mxic_nfc_set_input_delay(nfc, 0xf);
/*
* Phase degree = 360 * freq * output-delay
* where output-delay is a constant value 1 ns in FPGA.
*
* Get Phase degree = 360 * freq * 1 ns
* = 360 * freq * 1 sec / 1000000000
* = 9 * freq / 25000000
*/
ret = clk_set_phase(nfc->send_dly_clk, 9 * freq / 25000000);
if (ret)
return ret;
return 0;
}
static int mxic_nfc_set_freq(struct mxic_nand_ctlr *nfc, unsigned long freq)
{
int ret;
if (freq > MXIC_NFC_MAX_CLK_HZ)
freq = MXIC_NFC_MAX_CLK_HZ;
mxic_nfc_clk_disable(nfc);
ret = mxic_nfc_clk_setup(nfc, freq);
if (ret)
return ret;
ret = mxic_nfc_clk_enable(nfc);
if (ret)
return ret;
return 0;
}
static irqreturn_t mxic_nfc_isr(int irq, void *dev_id)
{
struct mxic_nand_ctlr *nfc = dev_id;
u32 sts;
sts = readl(nfc->regs + INT_STS);
if (sts & INT_RDY_PIN)
complete(&nfc->complete);
else
return IRQ_NONE;
return IRQ_HANDLED;
}
static void mxic_nfc_hw_init(struct mxic_nand_ctlr *nfc)
{
writel(HC_CFG_NIO(8) | HC_CFG_TYPE(1, HC_CFG_TYPE_RAW_NAND) |
HC_CFG_SLV_ACT(0) | HC_CFG_MAN_CS_EN |
HC_CFG_IDLE_SIO_LVL(1), nfc->regs + HC_CFG);
writel(INT_STS_ALL, nfc->regs + INT_STS_EN);
writel(INT_RDY_PIN, nfc->regs + INT_SIG_EN);
writel(0x0, nfc->regs + ONFI_DIN_CNT(0));
writel(0, nfc->regs + LRD_CFG);
writel(0, nfc->regs + LRD_CTRL);
writel(0x0, nfc->regs + HC_EN);
}
static void mxic_nfc_cs_enable(struct mxic_nand_ctlr *nfc)
{
writel(readl(nfc->regs + HC_CFG) | HC_CFG_MAN_CS_EN,
nfc->regs + HC_CFG);
writel(HC_CFG_MAN_CS_ASSERT | readl(nfc->regs + HC_CFG),
nfc->regs + HC_CFG);
}
static void mxic_nfc_cs_disable(struct mxic_nand_ctlr *nfc)
{
writel(~HC_CFG_MAN_CS_ASSERT & readl(nfc->regs + HC_CFG),
nfc->regs + HC_CFG);
}
static int mxic_nfc_wait_ready(struct nand_chip *chip)
{
struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
int ret;
ret = wait_for_completion_timeout(&nfc->complete,
msecs_to_jiffies(IRQ_TIMEOUT));
if (!ret) {
dev_err(nfc->dev, "nand device timeout\n");
return -ETIMEDOUT;
}
return 0;
}
static int mxic_nfc_data_xfer(struct mxic_nand_ctlr *nfc, const void *txbuf,
void *rxbuf, unsigned int len)
{
unsigned int pos = 0;
while (pos < len) {
unsigned int nbytes = len - pos;
u32 data = 0xffffffff;
u32 sts;
int ret;
if (nbytes > 4)
nbytes = 4;
if (txbuf)
memcpy(&data, txbuf + pos, nbytes);
ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
sts & INT_TX_EMPTY, 0, USEC_PER_SEC);
if (ret)
return ret;
writel(data, nfc->regs + TXD(nbytes % 4));
ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
sts & INT_TX_EMPTY, 0, USEC_PER_SEC);
if (ret)
return ret;
ret = readl_poll_timeout(nfc->regs + INT_STS, sts,
sts & INT_RX_NOT_EMPTY, 0,
USEC_PER_SEC);
if (ret)
return ret;
data = readl(nfc->regs + RXD);
if (rxbuf) {
data >>= (8 * (4 - nbytes));
memcpy(rxbuf + pos, &data, nbytes);
}
if (readl(nfc->regs + INT_STS) & INT_RX_NOT_EMPTY)
dev_warn(nfc->dev, "RX FIFO not empty\n");
pos += nbytes;
}
return 0;
}
static int mxic_nfc_exec_op(struct nand_chip *chip,
const struct nand_operation *op, bool check_only)
{
struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
const struct nand_op_instr *instr = NULL;
int ret = 0;
unsigned int op_id;
mxic_nfc_cs_enable(nfc);
init_completion(&nfc->complete);
for (op_id = 0; op_id < op->ninstrs; op_id++) {
instr = &op->instrs[op_id];
switch (instr->type) {
case NAND_OP_CMD_INSTR:
writel(0, nfc->regs + HC_EN);
writel(HC_EN_BIT, nfc->regs + HC_EN);
writel(OP_CMD_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
OP_CMD_BYTES(0), nfc->regs + SS_CTRL(0));
ret = mxic_nfc_data_xfer(nfc,
&instr->ctx.cmd.opcode,
NULL, 1);
break;
case NAND_OP_ADDR_INSTR:
writel(OP_ADDR_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
OP_ADDR_BYTES(instr->ctx.addr.naddrs),
nfc->regs + SS_CTRL(0));
ret = mxic_nfc_data_xfer(nfc,
instr->ctx.addr.addrs, NULL,
instr->ctx.addr.naddrs);
break;
case NAND_OP_DATA_IN_INSTR:
writel(0x0, nfc->regs + ONFI_DIN_CNT(0));
writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) |
OP_READ, nfc->regs + SS_CTRL(0));
ret = mxic_nfc_data_xfer(nfc, NULL,
instr->ctx.data.buf.in,
instr->ctx.data.len);
break;
case NAND_OP_DATA_OUT_INSTR:
writel(instr->ctx.data.len,
nfc->regs + ONFI_DIN_CNT(0));
writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F),
nfc->regs + SS_CTRL(0));
ret = mxic_nfc_data_xfer(nfc,
instr->ctx.data.buf.out, NULL,
instr->ctx.data.len);
break;
case NAND_OP_WAITRDY_INSTR:
ret = mxic_nfc_wait_ready(chip);
break;
}
}
mxic_nfc_cs_disable(nfc);
return ret;
}
static int mxic_nfc_setup_data_interface(struct nand_chip *chip, int chipnr,
const struct nand_data_interface *conf)
{
struct mxic_nand_ctlr *nfc = nand_get_controller_data(chip);
const struct nand_sdr_timings *sdr;
unsigned long freq;
int ret;
sdr = nand_get_sdr_timings(conf);
if (IS_ERR(sdr))
return PTR_ERR(sdr);
if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
return 0;
freq = NSEC_PER_SEC / (sdr->tRC_min / 1000);
ret = mxic_nfc_set_freq(nfc, freq);
if (ret)
dev_err(nfc->dev, "set freq:%ld failed\n", freq);
if (sdr->tRC_min < 30000)
writel(DATA_STROB_EDO_EN, nfc->regs + DATA_STROB);
return 0;
}
static const struct nand_controller_ops mxic_nand_controller_ops = {
.exec_op = mxic_nfc_exec_op,
.setup_data_interface = mxic_nfc_setup_data_interface,
};
static int mxic_nfc_probe(struct platform_device *pdev)
{
struct device_node *nand_np, *np = pdev->dev.of_node;
struct mtd_info *mtd;
struct mxic_nand_ctlr *nfc;
struct nand_chip *nand_chip;
int err;
int irq;
nfc = devm_kzalloc(&pdev->dev, sizeof(struct mxic_nand_ctlr),
GFP_KERNEL);
if (!nfc)
return -ENOMEM;
nfc->ps_clk = devm_clk_get(&pdev->dev, "ps");
if (IS_ERR(nfc->ps_clk))
return PTR_ERR(nfc->ps_clk);
nfc->send_clk = devm_clk_get(&pdev->dev, "send");
if (IS_ERR(nfc->send_clk))
return PTR_ERR(nfc->send_clk);
nfc->send_dly_clk = devm_clk_get(&pdev->dev, "send_dly");
if (IS_ERR(nfc->send_dly_clk))
return PTR_ERR(nfc->send_dly_clk);
nfc->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(nfc->regs))
return PTR_ERR(nfc->regs);
nand_chip = &nfc->chip;
mtd = nand_to_mtd(nand_chip);
mtd->dev.parent = &pdev->dev;
for_each_child_of_node(np, nand_np)
nand_set_flash_node(nand_chip, nand_np);
nand_chip->priv = nfc;
nfc->dev = &pdev->dev;
nfc->controller.ops = &mxic_nand_controller_ops;
nand_controller_init(&nfc->controller);
nand_chip->controller = &nfc->controller;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to retrieve irq\n");
return irq;
}
mxic_nfc_hw_init(nfc);
err = devm_request_irq(&pdev->dev, irq, mxic_nfc_isr,
0, "mxic-nfc", nfc);
if (err)
goto fail;
err = nand_scan(nand_chip, 1);
if (err)
goto fail;
err = mtd_device_register(mtd, NULL, 0);
if (err)
goto fail;
platform_set_drvdata(pdev, nfc);
return 0;
fail:
mxic_nfc_clk_disable(nfc);
return err;
}
static int mxic_nfc_remove(struct platform_device *pdev)
{
struct mxic_nand_ctlr *nfc = platform_get_drvdata(pdev);
nand_release(&nfc->chip);
mxic_nfc_clk_disable(nfc);
return 0;
}
static const struct of_device_id mxic_nfc_of_ids[] = {
{ .compatible = "mxic,multi-itfc-v009-nand-controller", },
{},
};
MODULE_DEVICE_TABLE(of, mxic_nfc_of_ids);
static struct platform_driver mxic_nfc_driver = {
.probe = mxic_nfc_probe,
.remove = mxic_nfc_remove,
.driver = {
.name = "mxic-nfc",
.of_match_table = mxic_nfc_of_ids,
},
};
module_platform_driver(mxic_nfc_driver);
MODULE_AUTHOR("Mason Yang <masonccyang@mxic.com.tw>");
MODULE_DESCRIPTION("Macronix raw NAND controller driver");
MODULE_LICENSE("GPL v2");
...@@ -4112,7 +4112,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, ...@@ -4112,7 +4112,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops) struct mtd_oob_ops *ops)
{ {
struct nand_chip *chip = mtd_to_nand(mtd); struct nand_chip *chip = mtd_to_nand(mtd);
int ret = -ENOTSUPP; int ret;
ops->retlen = 0; ops->retlen = 0;
......
...@@ -1232,7 +1232,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd) ...@@ -1232,7 +1232,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
if (!td) { if (!td) {
if ((res = nand_memory_bbt(this, bd))) { if ((res = nand_memory_bbt(this, bd))) {
pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
goto err; goto err_free_bbt;
} }
return 0; return 0;
} }
...@@ -1245,7 +1245,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd) ...@@ -1245,7 +1245,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
buf = vmalloc(len); buf = vmalloc(len);
if (!buf) { if (!buf) {
res = -ENOMEM; res = -ENOMEM;
goto err; goto err_free_bbt;
} }
/* Is the bbt at a given page? */ /* Is the bbt at a given page? */
...@@ -1258,7 +1258,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd) ...@@ -1258,7 +1258,7 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
res = check_create(this, buf, bd); res = check_create(this, buf, bd);
if (res) if (res)
goto err; goto err_free_buf;
/* Prevent the bbt regions from erasing / writing */ /* Prevent the bbt regions from erasing / writing */
mark_bbt_region(this, td); mark_bbt_region(this, td);
...@@ -1268,7 +1268,9 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd) ...@@ -1268,7 +1268,9 @@ static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
vfree(buf); vfree(buf);
return 0; return 0;
err: err_free_buf:
vfree(buf);
err_free_bbt:
kfree(this->bbt); kfree(this->bbt);
this->bbt = NULL; this->bbt = NULL;
return res; return res;
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright © 2009 Nuvoton technology corporation.
*
* Wan ZongShun <mcuos.com@gmail.com>
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#define REG_FMICSR 0x00
#define REG_SMCSR 0xa0
#define REG_SMISR 0xac
#define REG_SMCMD 0xb0
#define REG_SMADDR 0xb4
#define REG_SMDATA 0xb8
#define RESET_FMI 0x01
#define NAND_EN 0x08
#define READYBUSY (0x01 << 18)
#define SWRST 0x01
#define PSIZE (0x01 << 3)
#define DMARWEN (0x03 << 1)
#define BUSWID (0x01 << 4)
#define ECC4EN (0x01 << 5)
#define WP (0x01 << 24)
#define NANDCS (0x01 << 25)
#define ENDADDR (0x01 << 31)
#define read_data_reg(dev) \
__raw_readl((dev)->reg + REG_SMDATA)
#define write_data_reg(dev, val) \
__raw_writel((val), (dev)->reg + REG_SMDATA)
#define write_cmd_reg(dev, val) \
__raw_writel((val), (dev)->reg + REG_SMCMD)
#define write_addr_reg(dev, val) \
__raw_writel((val), (dev)->reg + REG_SMADDR)
struct nuc900_nand {
struct nand_chip chip;
void __iomem *reg;
struct clk *clk;
spinlock_t lock;
};
static inline struct nuc900_nand *mtd_to_nuc900(struct mtd_info *mtd)
{
return container_of(mtd_to_nand(mtd), struct nuc900_nand, chip);
}
static const struct mtd_partition partitions[] = {
{
.name = "NAND FS 0",
.offset = 0,
.size = 8 * 1024 * 1024
},
{
.name = "NAND FS 1",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL
}
};
static unsigned char nuc900_nand_read_byte(struct nand_chip *chip)
{
unsigned char ret;
struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
ret = (unsigned char)read_data_reg(nand);
return ret;
}
static void nuc900_nand_read_buf(struct nand_chip *chip,
unsigned char *buf, int len)
{
int i;
struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
for (i = 0; i < len; i++)
buf[i] = (unsigned char)read_data_reg(nand);
}
static void nuc900_nand_write_buf(struct nand_chip *chip,
const unsigned char *buf, int len)
{
int i;
struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
for (i = 0; i < len; i++)
write_data_reg(nand, buf[i]);
}
static int nuc900_check_rb(struct nuc900_nand *nand)
{
unsigned int val;
spin_lock(&nand->lock);
val = __raw_readl(nand->reg + REG_SMISR);
val &= READYBUSY;
spin_unlock(&nand->lock);
return val;
}
static int nuc900_nand_devready(struct nand_chip *chip)
{
struct nuc900_nand *nand = mtd_to_nuc900(nand_to_mtd(chip));
int ready;
ready = (nuc900_check_rb(nand)) ? 1 : 0;
return ready;
}
static void nuc900_nand_command_lp(struct nand_chip *chip,
unsigned int command,
int column, int page_addr)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nuc900_nand *nand = mtd_to_nuc900(mtd);
if (command == NAND_CMD_READOOB) {
column += mtd->writesize;
command = NAND_CMD_READ0;
}
write_cmd_reg(nand, command & 0xff);
if (column != -1 || page_addr != -1) {
if (column != -1) {
if (chip->options & NAND_BUSWIDTH_16 &&
!nand_opcode_8bits(command))
column >>= 1;
write_addr_reg(nand, column);
write_addr_reg(nand, column >> 8 | ENDADDR);
}
if (page_addr != -1) {
write_addr_reg(nand, page_addr);
if (chip->options & NAND_ROW_ADDR_3) {
write_addr_reg(nand, page_addr >> 8);
write_addr_reg(nand, page_addr >> 16 | ENDADDR);
} else {
write_addr_reg(nand, page_addr >> 8 | ENDADDR);
}
}
}
switch (command) {
case NAND_CMD_CACHEDPROG:
case NAND_CMD_PAGEPROG:
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_RNDIN:
case NAND_CMD_STATUS:
return;
case NAND_CMD_RESET:
if (chip->legacy.dev_ready)
break;
udelay(chip->legacy.chip_delay);
write_cmd_reg(nand, NAND_CMD_STATUS);
write_cmd_reg(nand, command);
while (!nuc900_check_rb(nand))
;
return;
case NAND_CMD_RNDOUT:
write_cmd_reg(nand, NAND_CMD_RNDOUTSTART);
return;
case NAND_CMD_READ0:
write_cmd_reg(nand, NAND_CMD_READSTART);
/* fall through */
default:
if (!chip->legacy.dev_ready) {
udelay(chip->legacy.chip_delay);
return;
}
}
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
ndelay(100);
while (!chip->legacy.dev_ready(chip))
;
}
static void nuc900_nand_enable(struct nuc900_nand *nand)
{
unsigned int val;
spin_lock(&nand->lock);
__raw_writel(RESET_FMI, (nand->reg + REG_FMICSR));
val = __raw_readl(nand->reg + REG_FMICSR);
if (!(val & NAND_EN))
__raw_writel(val | NAND_EN, nand->reg + REG_FMICSR);
val = __raw_readl(nand->reg + REG_SMCSR);
val &= ~(SWRST|PSIZE|DMARWEN|BUSWID|ECC4EN|NANDCS);
val |= WP;
__raw_writel(val, nand->reg + REG_SMCSR);
spin_unlock(&nand->lock);
}
static int nuc900_nand_probe(struct platform_device *pdev)
{
struct nuc900_nand *nuc900_nand;
struct nand_chip *chip;
struct mtd_info *mtd;
struct resource *res;
nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand),
GFP_KERNEL);
if (!nuc900_nand)
return -ENOMEM;
chip = &(nuc900_nand->chip);
mtd = nand_to_mtd(chip);
mtd->dev.parent = &pdev->dev;
spin_lock_init(&nuc900_nand->lock);
nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(nuc900_nand->clk))
return -ENOENT;
clk_enable(nuc900_nand->clk);
chip->legacy.cmdfunc = nuc900_nand_command_lp;
chip->legacy.dev_ready = nuc900_nand_devready;
chip->legacy.read_byte = nuc900_nand_read_byte;
chip->legacy.write_buf = nuc900_nand_write_buf;
chip->legacy.read_buf = nuc900_nand_read_buf;
chip->legacy.chip_delay = 50;
chip->options = 0;
chip->ecc.mode = NAND_ECC_SOFT;
chip->ecc.algo = NAND_ECC_HAMMING;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(nuc900_nand->reg))
return PTR_ERR(nuc900_nand->reg);
nuc900_nand_enable(nuc900_nand);
if (nand_scan(chip, 1))
return -ENXIO;
mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions));
platform_set_drvdata(pdev, nuc900_nand);
return 0;
}
static int nuc900_nand_remove(struct platform_device *pdev)
{
struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
nand_release(&nuc900_nand->chip);
clk_disable(nuc900_nand->clk);
return 0;
}
static struct platform_driver nuc900_nand_driver = {
.probe = nuc900_nand_probe,
.remove = nuc900_nand_remove,
.driver = {
.name = "nuc900-fmi",
},
};
module_platform_driver(nuc900_nand_driver);
MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("w90p910/NUC9xx nand driver!");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:nuc900-fmi");
...@@ -1501,7 +1501,7 @@ static int omap_elm_correct_data(struct nand_chip *chip, u_char *data, ...@@ -1501,7 +1501,7 @@ static int omap_elm_correct_data(struct nand_chip *chip, u_char *data,
} }
/* Update number of correctable errors */ /* Update number of correctable errors */
stat += err_vec[i].error_count; stat = max_t(unsigned int, stat, err_vec[i].error_count);
/* Update page data with sector size */ /* Update page data with sector size */
data += ecc->size; data += ecc->size;
......
...@@ -116,7 +116,7 @@ static int oxnas_nand_probe(struct platform_device *pdev) ...@@ -116,7 +116,7 @@ static int oxnas_nand_probe(struct platform_device *pdev)
GFP_KERNEL); GFP_KERNEL);
if (!chip) { if (!chip) {
err = -ENOMEM; err = -ENOMEM;
goto err_clk_unprepare; goto err_release_child;
} }
chip->controller = &oxnas->base; chip->controller = &oxnas->base;
...@@ -137,12 +137,12 @@ static int oxnas_nand_probe(struct platform_device *pdev) ...@@ -137,12 +137,12 @@ static int oxnas_nand_probe(struct platform_device *pdev)
/* Scan to find existence of the device */ /* Scan to find existence of the device */
err = nand_scan(chip, 1); err = nand_scan(chip, 1);
if (err) if (err)
goto err_clk_unprepare; goto err_release_child;
err = mtd_device_register(mtd, NULL, 0); err = mtd_device_register(mtd, NULL, 0);
if (err) { if (err) {
nand_release(chip); nand_release(chip);
goto err_clk_unprepare; goto err_release_child;
} }
oxnas->chips[nchips] = chip; oxnas->chips[nchips] = chip;
...@@ -159,6 +159,8 @@ static int oxnas_nand_probe(struct platform_device *pdev) ...@@ -159,6 +159,8 @@ static int oxnas_nand_probe(struct platform_device *pdev)
return 0; return 0;
err_release_child:
of_node_put(nand_np);
err_clk_unprepare: err_clk_unprepare:
clk_disable_unprepare(oxnas->clk); clk_disable_unprepare(oxnas->clk);
return err; return err;
......
...@@ -998,7 +998,7 @@ static void r852_shutdown(struct pci_dev *pci_dev) ...@@ -998,7 +998,7 @@ static void r852_shutdown(struct pci_dev *pci_dev)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int r852_suspend(struct device *device) static int r852_suspend(struct device *device)
{ {
struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); struct r852_device *dev = dev_get_drvdata(device);
if (dev->ctlreg & R852_CTL_CARDENABLE) if (dev->ctlreg & R852_CTL_CARDENABLE)
return -EBUSY; return -EBUSY;
...@@ -1019,7 +1019,7 @@ static int r852_suspend(struct device *device) ...@@ -1019,7 +1019,7 @@ static int r852_suspend(struct device *device)
static int r852_resume(struct device *device) static int r852_resume(struct device *device)
{ {
struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); struct r852_device *dev = dev_get_drvdata(device);
r852_disable_irqs(dev); r852_disable_irqs(dev);
r852_card_update_present(dev); r852_card_update_present(dev);
......
...@@ -1427,21 +1427,16 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, ...@@ -1427,21 +1427,16 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
struct stm32_fmc2_timings *tims = &nand->timings; struct stm32_fmc2_timings *tims = &nand->timings;
unsigned long hclk = clk_get_rate(fmc2->clk); unsigned long hclk = clk_get_rate(fmc2->clk);
unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000); unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000);
int tar, tclr, thiz, twait, tset_mem, tset_att, thold_mem, thold_att; unsigned long timing, tar, tclr, thiz, twait;
unsigned long tset_mem, tset_att, thold_mem, thold_att;
tar = hclkp;
if (tar < sdrt->tAR_min) tar = max_t(unsigned long, hclkp, sdrt->tAR_min);
tar = sdrt->tAR_min; timing = DIV_ROUND_UP(tar, hclkp) - 1;
tims->tar = DIV_ROUND_UP(tar, hclkp) - 1; tims->tar = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK);
if (tims->tar > FMC2_PCR_TIMING_MASK)
tims->tar = FMC2_PCR_TIMING_MASK; tclr = max_t(unsigned long, hclkp, sdrt->tCLR_min);
timing = DIV_ROUND_UP(tclr, hclkp) - 1;
tclr = hclkp; tims->tclr = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK);
if (tclr < sdrt->tCLR_min)
tclr = sdrt->tCLR_min;
tims->tclr = DIV_ROUND_UP(tclr, hclkp) - 1;
if (tims->tclr > FMC2_PCR_TIMING_MASK)
tims->tclr = FMC2_PCR_TIMING_MASK;
tims->thiz = FMC2_THIZ; tims->thiz = FMC2_THIZ;
thiz = (tims->thiz + 1) * hclkp; thiz = (tims->thiz + 1) * hclkp;
...@@ -1451,18 +1446,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, ...@@ -1451,18 +1446,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
* tWAIT > tWP * tWAIT > tWP
* tWAIT > tREA + tIO * tWAIT > tREA + tIO
*/ */
twait = hclkp; twait = max_t(unsigned long, hclkp, sdrt->tRP_min);
if (twait < sdrt->tRP_min) twait = max_t(unsigned long, twait, sdrt->tWP_min);
twait = sdrt->tRP_min; twait = max_t(unsigned long, twait, sdrt->tREA_max + FMC2_TIO);
if (twait < sdrt->tWP_min) timing = DIV_ROUND_UP(twait, hclkp);
twait = sdrt->tWP_min; tims->twait = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
if (twait < sdrt->tREA_max + FMC2_TIO)
twait = sdrt->tREA_max + FMC2_TIO;
tims->twait = DIV_ROUND_UP(twait, hclkp);
if (tims->twait == 0)
tims->twait = 1;
else if (tims->twait > FMC2_PMEM_PATT_TIMING_MASK)
tims->twait = FMC2_PMEM_PATT_TIMING_MASK;
/* /*
* tSETUP_MEM > tCS - tWAIT * tSETUP_MEM > tCS - tWAIT
...@@ -1477,20 +1465,15 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, ...@@ -1477,20 +1465,15 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
if (twait > thiz && (sdrt->tDS_min > twait - thiz) && if (twait > thiz && (sdrt->tDS_min > twait - thiz) &&
(tset_mem < sdrt->tDS_min - (twait - thiz))) (tset_mem < sdrt->tDS_min - (twait - thiz)))
tset_mem = sdrt->tDS_min - (twait - thiz); tset_mem = sdrt->tDS_min - (twait - thiz);
tims->tset_mem = DIV_ROUND_UP(tset_mem, hclkp); timing = DIV_ROUND_UP(tset_mem, hclkp);
if (tims->tset_mem == 0) tims->tset_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
tims->tset_mem = 1;
else if (tims->tset_mem > FMC2_PMEM_PATT_TIMING_MASK)
tims->tset_mem = FMC2_PMEM_PATT_TIMING_MASK;
/* /*
* tHOLD_MEM > tCH * tHOLD_MEM > tCH
* tHOLD_MEM > tREH - tSETUP_MEM * tHOLD_MEM > tREH - tSETUP_MEM
* tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT) * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT)
*/ */
thold_mem = hclkp; thold_mem = max_t(unsigned long, hclkp, sdrt->tCH_min);
if (thold_mem < sdrt->tCH_min)
thold_mem = sdrt->tCH_min;
if (sdrt->tREH_min > tset_mem && if (sdrt->tREH_min > tset_mem &&
(thold_mem < sdrt->tREH_min - tset_mem)) (thold_mem < sdrt->tREH_min - tset_mem))
thold_mem = sdrt->tREH_min - tset_mem; thold_mem = sdrt->tREH_min - tset_mem;
...@@ -1500,11 +1483,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, ...@@ -1500,11 +1483,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
if ((sdrt->tWC_min > tset_mem + twait) && if ((sdrt->tWC_min > tset_mem + twait) &&
(thold_mem < sdrt->tWC_min - (tset_mem + twait))) (thold_mem < sdrt->tWC_min - (tset_mem + twait)))
thold_mem = sdrt->tWC_min - (tset_mem + twait); thold_mem = sdrt->tWC_min - (tset_mem + twait);
tims->thold_mem = DIV_ROUND_UP(thold_mem, hclkp); timing = DIV_ROUND_UP(thold_mem, hclkp);
if (tims->thold_mem == 0) tims->thold_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
tims->thold_mem = 1;
else if (tims->thold_mem > FMC2_PMEM_PATT_TIMING_MASK)
tims->thold_mem = FMC2_PMEM_PATT_TIMING_MASK;
/* /*
* tSETUP_ATT > tCS - tWAIT * tSETUP_ATT > tCS - tWAIT
...@@ -1526,11 +1506,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, ...@@ -1526,11 +1506,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
if (twait > thiz && (sdrt->tDS_min > twait - thiz) && if (twait > thiz && (sdrt->tDS_min > twait - thiz) &&
(tset_att < sdrt->tDS_min - (twait - thiz))) (tset_att < sdrt->tDS_min - (twait - thiz)))
tset_att = sdrt->tDS_min - (twait - thiz); tset_att = sdrt->tDS_min - (twait - thiz);
tims->tset_att = DIV_ROUND_UP(tset_att, hclkp); timing = DIV_ROUND_UP(tset_att, hclkp);
if (tims->tset_att == 0) tims->tset_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
tims->tset_att = 1;
else if (tims->tset_att > FMC2_PMEM_PATT_TIMING_MASK)
tims->tset_att = FMC2_PMEM_PATT_TIMING_MASK;
/* /*
* tHOLD_ATT > tALH * tHOLD_ATT > tALH
...@@ -1545,17 +1522,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, ...@@ -1545,17 +1522,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
* tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT) * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT)
* tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT) * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT)
*/ */
thold_att = hclkp; thold_att = max_t(unsigned long, hclkp, sdrt->tALH_min);
if (thold_att < sdrt->tALH_min) thold_att = max_t(unsigned long, thold_att, sdrt->tCH_min);
thold_att = sdrt->tALH_min; thold_att = max_t(unsigned long, thold_att, sdrt->tCLH_min);
if (thold_att < sdrt->tCH_min) thold_att = max_t(unsigned long, thold_att, sdrt->tCOH_min);
thold_att = sdrt->tCH_min; thold_att = max_t(unsigned long, thold_att, sdrt->tDH_min);
if (thold_att < sdrt->tCLH_min)
thold_att = sdrt->tCLH_min;
if (thold_att < sdrt->tCOH_min)
thold_att = sdrt->tCOH_min;
if (thold_att < sdrt->tDH_min)
thold_att = sdrt->tDH_min;
if ((sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC > tset_mem) && if ((sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC > tset_mem) &&
(thold_att < sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem)) (thold_att < sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem))
thold_att = sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem; thold_att = sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem;
...@@ -1574,11 +1545,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, ...@@ -1574,11 +1545,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip,
if ((sdrt->tWC_min > tset_att + twait) && if ((sdrt->tWC_min > tset_att + twait) &&
(thold_att < sdrt->tWC_min - (tset_att + twait))) (thold_att < sdrt->tWC_min - (tset_att + twait)))
thold_att = sdrt->tWC_min - (tset_att + twait); thold_att = sdrt->tWC_min - (tset_att + twait);
tims->thold_att = DIV_ROUND_UP(thold_att, hclkp); timing = DIV_ROUND_UP(thold_att, hclkp);
if (tims->thold_att == 0) tims->thold_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK);
tims->thold_att = 1;
else if (tims->thold_att > FMC2_PMEM_PATT_TIMING_MASK)
tims->thold_att = FMC2_PMEM_PATT_TIMING_MASK;
} }
static int stm32_fmc2_setup_interface(struct nand_chip *chip, int chipnr, static int stm32_fmc2_setup_interface(struct nand_chip *chip, int chipnr,
......
...@@ -659,6 +659,7 @@ static int tango_nand_probe(struct platform_device *pdev) ...@@ -659,6 +659,7 @@ static int tango_nand_probe(struct platform_device *pdev)
err = chip_init(&pdev->dev, np); err = chip_init(&pdev->dev, np);
if (err) { if (err) {
tango_nand_remove(pdev); tango_nand_remove(pdev);
of_node_put(np);
return err; return err;
} }
} }
......
...@@ -862,6 +862,7 @@ static int vf610_nfc_probe(struct platform_device *pdev) ...@@ -862,6 +862,7 @@ static int vf610_nfc_probe(struct platform_device *pdev)
dev_err(nfc->dev, dev_err(nfc->dev,
"Only one NAND chip supported!\n"); "Only one NAND chip supported!\n");
err = -EINVAL; err = -EINVAL;
of_node_put(child);
goto err_disable_clk; goto err_disable_clk;
} }
......
...@@ -346,7 +346,7 @@ static inline unsigned int nanddev_ntargets(const struct nand_device *nand) ...@@ -346,7 +346,7 @@ static inline unsigned int nanddev_ntargets(const struct nand_device *nand)
} }
/** /**
* nanddev_neraseblocks() - Get the total number of erasablocks * nanddev_neraseblocks() - Get the total number of eraseblocks
* @nand: NAND device * @nand: NAND device
* *
* Return: the total number of eraseblocks exposed by @nand. * Return: the total number of eraseblocks exposed by @nand.
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
* Copyright (C) 2008 Dmitry Baryshkov * Copyright (C) 2008 Dmitry Baryshkov
*/ */
#ifndef _MTD_SHARPSL_H
#define _MTD_SHARPSL_H
#include <linux/mtd/rawnand.h> #include <linux/mtd/rawnand.h>
#include <linux/mtd/nand_ecc.h> #include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
...@@ -16,3 +19,5 @@ struct sharpsl_nand_platform_data { ...@@ -16,3 +19,5 @@ struct sharpsl_nand_platform_data {
unsigned int nr_partitions; unsigned int nr_partitions;
const char *const *part_parsers; const char *const *part_parsers;
}; };
#endif /* _MTD_SHARPSL_H */
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