summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/brcmnand/brcmnand.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-05-11 10:44:22 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-11 10:44:22 -0700
commit9786e34e0a6055dbd1b46e16dfa791ac2b3da289 (patch)
tree0151608bdb134bec3a59748f40c67324798a224e /drivers/mtd/nand/brcmnand/brcmnand.c
parent791a9a666d1afe2603bcb2c6a4852d684e879252 (diff)
parenta9402889f41cc2db7a9b162990bef271be098ff0 (diff)
downloadblackbird-op-linux-9786e34e0a6055dbd1b46e16dfa791ac2b3da289.tar.gz
blackbird-op-linux-9786e34e0a6055dbd1b46e16dfa791ac2b3da289.zip
Merge tag 'for-linus-20170510' of git://git.infradead.org/linux-mtd
Pull MTD updates from Brian Norris: "NAND, from Boris: - some minor fixes/improvements on existing drivers (fsmc, gpio, ifc, davinci, brcmnand, omap) - a huge cleanup/rework of the denali driver accompanied with core fixes/improvements to simplify the driver code - a complete rewrite of the atmel driver to support new DT bindings make future evolution easier - the addition of per-vendor detection/initialization steps to avoid extending the nand_ids table with more extended-id entries SPI NOR, from Cyrille: - fixes in the hisi, intel and Mediatek SPI controller drivers - fixes to some SPI flash memories not supporting the Chip Erase command. - add support to some new memory parts (Winbond, Macronix, Micron, ESMT). - add new driver for the STM32 QSPI controller And a few fixes for Gemini and Versatile platforms on physmap-of" * tag 'for-linus-20170510' of git://git.infradead.org/linux-mtd: (100 commits) MAINTAINERS: Update NAND subsystem git repositories mtd: nand: gpio: update binding mtd: nand: add ooblayout for old hamming layout mtd: oxnas_nand: Allocating more than necessary in probe() dt-bindings: mtd: Document the STM32 QSPI bindings mtd: mtk-nor: set controller's address width according to nor flash mtd: spi-nor: add driver for STM32 quad spi flash controller mtd: nand: brcmnand: Check flash #WP pin status before nand erase/program mtd: nand: davinci: add comment on NAND subpage write status on keystone mtd: nand: omap2: Fix partition creation via cmdline mtdparts mtd: nand: NULL terminate a of_device_id table mtd: nand: Fix a couple error codes mtd: nand: allow drivers to request minimum alignment for passed buffer mtd: nand: allocate aligned buffers if NAND_OWN_BUFFERS is unset mtd: nand: denali: allow to override revision number mtd: nand: denali_dt: use pdev instead of ofdev for platform_device mtd: nand: denali_dt: remove dma-mask DT property mtd: nand: denali: support 64bit capable DMA engine mtd: nand: denali_dt: enable HW_ECC_FIXUP for Altera SOCFPGA variant mtd: nand: denali: support HW_ECC_FIXUP capability ...
Diffstat (limited to 'drivers/mtd/nand/brcmnand/brcmnand.c')
-rw-r--r--drivers/mtd/nand/brcmnand/brcmnand.c61
1 files changed, 58 insertions, 3 deletions
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index 42ebd73f821d..7419c5ce63f8 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -101,6 +101,9 @@ struct brcm_nand_dma_desc {
#define BRCMNAND_MIN_BLOCKSIZE (8 * 1024)
#define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024)
+#define NAND_CTRL_RDY (INTFC_CTLR_READY | INTFC_FLASH_READY)
+#define NAND_POLL_STATUS_TIMEOUT_MS 100
+
/* Controller feature flags */
enum {
BRCMNAND_HAS_1K_SECTORS = BIT(0),
@@ -765,6 +768,31 @@ enum {
CS_SELECT_AUTO_DEVICE_ID_CFG = BIT(30),
};
+static int bcmnand_ctrl_poll_status(struct brcmnand_controller *ctrl,
+ u32 mask, u32 expected_val,
+ unsigned long timeout_ms)
+{
+ unsigned long limit;
+ u32 val;
+
+ if (!timeout_ms)
+ timeout_ms = NAND_POLL_STATUS_TIMEOUT_MS;
+
+ limit = jiffies + msecs_to_jiffies(timeout_ms);
+ do {
+ val = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
+ if ((val & mask) == expected_val)
+ return 0;
+
+ cpu_relax();
+ } while (time_after(limit, jiffies));
+
+ dev_warn(ctrl->dev, "timeout on status poll (expected %x got %x)\n",
+ expected_val, val & mask);
+
+ return -ETIMEDOUT;
+}
+
static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
{
u32 val = en ? CS_SELECT_NAND_WP : 0;
@@ -1024,12 +1052,39 @@ static void brcmnand_wp(struct mtd_info *mtd, int wp)
if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
static int old_wp = -1;
+ int ret;
if (old_wp != wp) {
dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
old_wp = wp;
}
+
+ /*
+ * make sure ctrl/flash ready before and after
+ * changing state of #WP pin
+ */
+ ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY |
+ NAND_STATUS_READY,
+ NAND_CTRL_RDY |
+ NAND_STATUS_READY, 0);
+ if (ret)
+ return;
+
brcmnand_set_wp(ctrl, wp);
+ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+ /* NAND_STATUS_WP 0x00 = protected, 0x80 = not protected */
+ ret = bcmnand_ctrl_poll_status(ctrl,
+ NAND_CTRL_RDY |
+ NAND_STATUS_READY |
+ NAND_STATUS_WP,
+ NAND_CTRL_RDY |
+ NAND_STATUS_READY |
+ (wp ? 0 : NAND_STATUS_WP), 0);
+
+ if (ret)
+ dev_err_ratelimited(&host->pdev->dev,
+ "nand #WP expected %s\n",
+ wp ? "on" : "off");
}
}
@@ -1157,15 +1212,15 @@ static irqreturn_t brcmnand_dma_irq(int irq, void *data)
static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
{
struct brcmnand_controller *ctrl = host->ctrl;
- u32 intfc;
+ int ret;
dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
BUG_ON(ctrl->cmd_pending != 0);
ctrl->cmd_pending = cmd;
- intfc = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
- WARN_ON(!(intfc & INTFC_CTLR_READY));
+ ret = bcmnand_ctrl_poll_status(ctrl, NAND_CTRL_RDY, NAND_CTRL_RDY, 0);
+ WARN_ON(ret);
mb(); /* flush previous writes */
brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,
OpenPOWER on IntegriCloud