mtd: nand: pxa3xx-nand: prevent DFI bus lockup on removal

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Fri Nov 6 10:59:04 PST 2015


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=e971affaf92d530b653122f08aa23e7384de170f
Commit:     e971affaf92d530b653122f08aa23e7384de170f
Parent:     b33c35b11e0049e3adbb58df6c83d6c9496f8210
Author:     Robert Jarzmik <robert.jarzmik at free.fr>
AuthorDate: Mon Sep 28 22:56:51 2015 +0200
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Mon Sep 28 17:32:19 2015 -0700

    mtd: nand: pxa3xx-nand: prevent DFI bus lockup on removal
    
    After the conversion of pxa architecture to common clock framework, the
    NAND clock can be disabled on driver exit.
    
    In this case, it happens that if the driver used the NAND and set the
    DFI arbitration bit, the next access to a static memory controller area,
    such as an ethernet card, will stall the system bus, and the core will
    be stalled forever.
    
    This is especially true on pxa31x SoCs, where the NDCR was augmented
    with a new bit to prevent this lockups by giving full ownership of the
    DFI arbiter to the SMC, in change SCr#6.
    
    Fix this by clearing the DFI arbritration bit in driver exit. This
    effectively prevents a lockup on zylonite when removing pxa3xx-nand
    module, and using ethernet afterwards.
    
    Signed-off-by: Robert Jarzmik <robert.jarzmik at free.fr>
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/nand/pxa3xx_nand.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index da563cd..232c707 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -76,7 +76,8 @@
 #define NDCR_ND_MODE		(0x3 << 21)
 #define NDCR_NAND_MODE   	(0x0)
 #define NDCR_CLR_PG_CNT		(0x1 << 20)
-#define NDCR_STOP_ON_UNCOR	(0x1 << 19)
+#define NFCV1_NDCR_ARB_CNTL	(0x1 << 19)
+#define NFCV2_NDCR_STOP_ON_UNCOR	(0x1 << 19)
 #define NDCR_RD_ID_CNT_MASK	(0x7 << 16)
 #define NDCR_RD_ID_CNT(x)	(((x) << 16) & NDCR_RD_ID_CNT_MASK)
 
@@ -1320,7 +1321,8 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
 
 	/* Set an initial chunk size */
 	info->chunk_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512;
-	info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
+	info->reg_ndcr = ndcr &
+		~(NDCR_INT_MASK | NDCR_ND_ARB_EN | NFCV1_NDCR_ARB_CNTL);
 	info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
 	info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
 	return 0;
@@ -1553,6 +1555,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
 	pxa3xx_flash_ids[1].name = NULL;
 	def = pxa3xx_flash_ids;
 KEEP_CONFIG:
+	info->reg_ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0;
 	if (info->reg_ndcr & NDCR_DWIDTH_M)
 		chip->options |= NAND_BUSWIDTH_16;
 
@@ -1768,6 +1771,16 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
 		free_irq(irq, info);
 	pxa3xx_nand_free_buff(info);
 
+	/*
+	 * In the pxa3xx case, the DFI bus is shared between the SMC and NFC.
+	 * In order to prevent a lockup of the system bus, the DFI bus
+	 * arbitration is granted to SMC upon driver removal. This is done by
+	 * setting the x_ARB_CNTL bit, which also prevents the NAND to have
+	 * access to the bus anymore.
+	 */
+	nand_writel(info, NDCR,
+		    (nand_readl(info, NDCR) & ~NDCR_ND_ARB_EN) |
+		    NFCV1_NDCR_ARB_CNTL);
 	clk_disable_unprepare(info->clk);
 
 	for (cs = 0; cs < pdata->num_cs; cs++)



More information about the linux-mtd-cvs mailing list