[PATCH] pxa3xx_nand: add polling mode support

Lei Wen leiwen at marvell.com
Sun Mar 28 22:30:26 EDT 2010


Add polling mode to facilitate debugging.

Signed-off-by: Lei Wen <leiwen at marvell.com>
Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
---
 drivers/mtd/nand/pxa3xx_nand.c |  119 +++++++++++++++++++++++++++-------------
 1 files changed, 80 insertions(+), 39 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 56559e1..31ebc78 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -26,9 +26,10 @@
 #include <mach/dma.h>
 #include <plat/pxa3xx_nand.h>

-#define	CHIP_DELAY_TIMEOUT	(2 * HZ/10)
+#define	CHIP_DELAY_TIMEOUT	(100 * HZ/10)
 #define NAND_STOP_DELAY		(2 * HZ/50)
 #define PAGE_CHUNK_SIZE		(2048)
+#define OOB_CHUNK_SIZE		(64)
 #define BCH_THRESHOLD           (8)
 #define CMD_POOL_SIZE           (5)
 #undef PXA3XX_NAND_DEBUG
@@ -298,6 +299,10 @@ static int use_dma = 1;
 module_param(use_dma, bool, 0444);
 MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW");

+static int use_polling = 0;
+module_param(use_polling, bool, 0444);
+MODULE_PARM_DESC(use_polling, "Use full polling mode");
+
 static int naked_cmd_support = 0;
 module_param(naked_cmd_support, bool, 0444);
 MODULE_PARM_DESC(naked_cmd_support, "Whether the controller support
using naked command set");
@@ -329,7 +334,7 @@ static struct pxa3xx_nand_flash __devinitdata
builtin_flash_types[] = {
 { 0xd3ec, 128, 2048, 8, 8, ECC_BCH, 4096, \
 	{ 0, 10, 0, 20, 40, 30, 40, 11123, 0, 110, 10, }, },
 { 0xd7ec, 128, 4096, 8, 8, ECC_BCH, 8192, \
-	{ 0, 10, 0, 20, 40, 30, 40, 11123, 0, 110, 10, }, },
+	{ 0, 10, 0, 20, 40, 30, 40, 25000, 0, 110, 10, }, },
 { 0xa12c, 64, 2048, 8, 8, ECC_HAMMIN, 1024, \
 	{ 0, 10, 25, 15, 25, 15, 30, 25000, 0, 60, 10, }, },
 { 0xb12c, 64, 2048, 16, 16, ECC_HAMMIN, 1024, \
@@ -569,7 +574,8 @@ static void pxa3xx_nand_start(struct pxa3xx_nand *nand)

 	info = nand->info[nand->chip_select];
 	ndcr = info->reg_ndcr;
-	ndcr |= nand->use_dma ? NDCR_DMA_EN : NDCR_STOP_ON_UNCOR;
+	ndcr |= nand->use_dma ? NDCR_DMA_EN : 0;
+	ndcr |= use_polling ? NDCR_INT_MASK : 0;
 	ndcr |= NDCR_ND_RUN;

 	switch (nand->use_ecc) {
@@ -764,9 +770,8 @@ static void pxa3xx_nand_data_dma_irq(int channel,
void *data)
 	nand_writel(nand, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
 }

-static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
+static int pxa3xx_nand_transaction(struct pxa3xx_nand *nand)
 {
-	struct pxa3xx_nand *nand = devid;
 	struct pxa3xx_nand_info *info;
 	unsigned int status, is_completed = 0, cs, cmd_seqs, ndcb1, ndcb2;
 	unsigned int ready, cmd_done, page_done, badblock_detect;
@@ -780,8 +785,10 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 	cmd_seqs	= info->cmd_seqs;

 	status = nand_readl(nand, NDSR);
-	DBG_NAND(if (status != 0)
-		printk("\t\t==cmd seqs %x, status %x, cs %x\n", cmd_seqs, status, cs));
+	if (!status)
+		return 0;
+	DBG_NAND(printk("\t\t==cmd seqs %x, status %x, cs %x\n",
+				cmd_seqs, status, cs));
 	nand->bad_count = (status & NDSR_ERR_CNT_MASK) >> 16;
 	if (status & NDSR_DBERR)
 		nand->retcode = ERR_DBERR;
@@ -791,7 +798,7 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)

 		nand->state |= STATE_DATA_PROCESSING;
 		/* whether use dma to transfer data */
-		if (nand->use_dma) {
+		if (nand->use_dma && !use_polling) {
 			disable_int(nand, NDCR_INT_MASK);
 			start_data_dma(nand, nand->state & STATE_IS_WRITE);
 			goto NORMAL_IRQ_EXIT;
@@ -805,13 +812,20 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 	if (status & ready) {
 		nand->state |= STATE_READY;
 		if (info->wait_ready[cmd_seqs]) {
-			enable_int(nand, NDCR_WRCMDREQM);
+			if (!use_polling)
+				enable_int(nand, NDCR_WRCMDREQM | NDCR_CS0_CMDDM
+						| NDCR_CS1_CMDDM);
 			if (cmd_seqs == info->total_cmds)
 				is_completed = 1;
 		}
 	}
 	if (status & cmd_done) {
 		nand->state |= STATE_CMD_DONE;
+		if (info->wait_ready[cmd_seqs] && !(nand->state & STATE_READY)) {
+			status &= ~cmd_done;
+			if (!use_polling)
+				disable_int(nand, NDCR_CS0_CMDDM | NDCR_CS1_CMDDM);
+		}
 		if (cmd_seqs == info->total_cmds && !info->wait_ready[cmd_seqs])
 			is_completed = 1;
 	}
@@ -819,7 +833,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 	if (status & NDSR_WRCMDREQ) {
 		status &= ~NDSR_WRCMDREQ;
 		if (info->wait_ready[cmd_seqs] && !(nand->state & STATE_READY)) {
-			disable_int(nand, NDCR_WRCMDREQM);
+			if (!use_polling)
+				disable_int(nand, NDCR_WRCMDREQM);
 			goto IRQ_FORCE_EXIT;
 		}

@@ -849,12 +864,36 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 IRQ_FORCE_EXIT:
 	/* clear NDSR to let the controller exit the IRQ */
 	nand_writel(nand, NDSR, status);
+NORMAL_IRQ_EXIT:
+	return is_completed;
+}
+
+static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
+{
+	struct pxa3xx_nand *nand = devid;
+	int is_completed;
+
+	is_completed = pxa3xx_nand_transaction(nand);
 	if (is_completed)
 		complete(&nand->cmd_complete);
-NORMAL_IRQ_EXIT:
+
 	return IRQ_HANDLED;
 }

+static int pxa3xx_nand_polling(struct pxa3xx_nand *nand, unsigned long timeout)
+{
+	int i, ret = 0;
+
+	for (i = 0; i < timeout; i++) {
+		ret = pxa3xx_nand_transaction(nand);
+		if (ret)
+			break;
+		udelay(5);
+	}
+
+	return ret;
+}
+
 static inline int is_buf_blank(uint8_t *buf, size_t len)
 {
 	for (; len > 0; len--)
@@ -1107,8 +1146,11 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info
*mtd, unsigned command,
 		nand->state |= STATE_CMD_PREPARED;
 		pxa3xx_nand_start(nand);

-		ret = wait_for_completion_timeout(&nand->cmd_complete,
-				CHIP_DELAY_TIMEOUT);
+		if (!use_polling)
+			ret = wait_for_completion_timeout(&nand->cmd_complete,
+					CHIP_DELAY_TIMEOUT);
+		else
+			ret = pxa3xx_nand_polling(nand, CHIP_DELAY_TIMEOUT);
 		if (!ret) {
 			printk(KERN_ERR "Wait time out!!!\n");
 			nand_error_dump(nand);
@@ -1229,31 +1271,30 @@ static void pxa3xx_nand_config_flash(struct
pxa3xx_nand_info *info,
 	ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0;

 	switch (f->page_per_block) {
-		case 32:
-			ndcr |= NDCR_PG_PER_BLK(0x0);
-			break;
-		case 128:
-			ndcr |= NDCR_PG_PER_BLK(0x1);
-			break;
-		case 256:
-			ndcr |= NDCR_PG_PER_BLK(0x3);
-			break;
-		case 64:
-		default:
-			ndcr |= NDCR_PG_PER_BLK(0x2);
-			break;
+	case 32:
+		ndcr |= NDCR_PG_PER_BLK(0x0);
+		break;
+	case 128:
+		ndcr |= NDCR_PG_PER_BLK(0x1);
+		break;
+	case 256:
+		ndcr |= NDCR_PG_PER_BLK(0x3);
+		break;
+	case 64:
+	default:
+		ndcr |= NDCR_PG_PER_BLK(0x2);
+		break;
 	}

 	switch (f->page_size) {
-		case 512:
-			ndcr |= NDCR_PAGE_SZ(0x0);
-			break;
-		case 2048:
-		default:
-			ndcr |= NDCR_PAGE_SZ(0x1);
-			ndcr |= NDCR_FORCE_CSX;
-			break;
-
+	case 512:
+		ndcr |= NDCR_PAGE_SZ(0x0);
+		break;
+	case 2048:
+	default:
+		ndcr |= NDCR_PAGE_SZ(0x1);
+		ndcr |= NDCR_FORCE_CSX;
+		break;
 	}

 	ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes);
@@ -1264,11 +1305,11 @@ static void pxa3xx_nand_config_flash(struct
pxa3xx_nand_info *info,
 	pxa3xx_nand_set_timing(info, &f->timing, show_timing);
 }

-/* the maximum possible buffer size for large page with OOB data
- * is: 2048 + 64 = 2112 bytes, allocate a page here for both the
- * data buffer and the DMA descriptor
+/* the max buff size should be large than
+ * the largest size of page of NAND flash
+ * that currently controller support
  */
-#define MAX_BUFF_SIZE	PAGE_SIZE
+#define MAX_BUFF_SIZE	((PAGE_CHUNK_SIZE + OOB_CHUNK_SIZE) * 2) +
sizeof(struct pxa_dma_desc)

 static struct nand_ecclayout hw_smallpage_ecclayout = {
 	.eccbytes = 6,
-- 
1.5.6.5



More information about the linux-arm-kernel mailing list