[PATCH 4/6] pxa3xx_nand: unify prepare command

Lei Wen leiwen at marvell.com
Fri Jul 8 13:50:58 EDT 2011


Make the interface simpler which could make both debug
and enhancement easier.

Signed-off-by: Lei Wen <leiwen at marvell.com>
Signed-off-by: Haojian Zhuang <haojian.zhuang at marvell.com>
Cc: Eric Miao <eric.y.miao at gmail.com>
Cc: David Woodhouse <dwmw2 at infradead.org>
---
 drivers/mtd/nand/pxa3xx_nand.c |  286 ++++++++++++++++++++++------------------
 1 files changed, 157 insertions(+), 129 deletions(-)

diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 04aeea9..0895cf8 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -28,6 +28,7 @@
 
 #define	CHIP_DELAY_TIMEOUT	(2 * HZ/10)
 #define NAND_STOP_DELAY		(2 * HZ/50)
+#define PAGE_CHUNK_SIZE		(2048)
 
 /* registers and bit definitions */
 #define NDCR		(0x00) /* Control register */
@@ -77,6 +78,7 @@
 #define NDSR_RDDREQ		(0x1 << 1)
 #define NDSR_WRCMDREQ		(0x1)
 
+#define NDCB0_ST_ROW_EN         (0x1 << 26)
 #define NDCB0_AUTO_RS		(0x1 << 25)
 #define NDCB0_CSEL		(0x1 << 24)
 #define NDCB0_CMD_TYPE_MASK	(0x7 << 21)
@@ -319,66 +321,6 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
 	nand_writel(info, NDSR, NDSR_MASK);
 }
 
-static void prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
-		uint16_t cmd, int column, int page_addr)
-{
-	const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
-	pxa3xx_set_datasize(info);
-
-	/* generate values for NDCBx registers */
-	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
-	info->ndcb1 = 0;
-	info->ndcb2 = 0;
-	info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles);
-
-	if (info->col_addr_cycles == 2) {
-		/* large block, 2 cycles for column address
-		 * row address starts from 3rd cycle
-		 */
-		info->ndcb1 |= page_addr << 16;
-		if (info->row_addr_cycles == 3)
-			info->ndcb2 = (page_addr >> 16) & 0xff;
-	} else
-		/* small block, 1 cycles for column address
-		 * row address starts from 2nd cycle
-		 */
-		info->ndcb1 = page_addr << 8;
-
-	if (cmd == cmdset->program)
-		info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
-}
-
-static void prepare_erase_cmd(struct pxa3xx_nand_info *info,
-			uint16_t cmd, int page_addr)
-{
-	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
-	info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3);
-	info->ndcb1 = page_addr;
-	info->ndcb2 = 0;
-}
-
-static void prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd)
-{
-	const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
-
-	info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0);
-	info->ndcb1 = 0;
-	info->ndcb2 = 0;
-
-	info->oob_size = 0;
-	if (cmd == cmdset->read_id) {
-		info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1);
-		info->data_size = 8;
-	} else if (cmd == cmdset->read_status) {
-		info->ndcb0 |= NDCB0_CMD_TYPE(4);
-		info->data_size = 8;
-	} else if (cmd == cmdset->reset || cmd == cmdset->lock ||
-		   cmd == cmdset->unlock) {
-		info->ndcb0 |= NDCB0_CMD_TYPE(5);
-	} else
-		BUG();
-}
-
 static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
 {
 	uint32_t ndcr;
@@ -529,81 +471,166 @@ static inline int is_buf_blank(uint8_t *buf, size_t len)
 	return 1;
 }
 
+static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
+		uint16_t column, int page_addr)
+{
+	 uint16_t cmd;
+	 int addr_cycle, exec_cmd, ndcb0;
+	 struct mtd_info *mtd = info->mtd;
+
+	 ndcb0 = 0;
+	 addr_cycle = 0;
+	 exec_cmd = 1;
+
+	 /* reset data and oob column point to handle data */
+	 info->buf_start	= 0;
+	 info->buf_count	= 0;
+	 info->oob_size		= 0;
+	 info->use_ecc		= 0;
+	 info->retcode		= ERR_NONE;
+
+	 switch (command) {
+	 case NAND_CMD_READ0:
+	 case NAND_CMD_PAGEPROG:
+		 info->use_ecc = 1;
+	 case NAND_CMD_READOOB:
+		 pxa3xx_set_datasize(info);
+		 break;
+	 case NAND_CMD_SEQIN:
+		 exec_cmd = 0;
+		 break;
+	 default:
+		 info->ndcb1 = 0;
+		 info->ndcb2 = 0;
+		 break;
+	 }
+
+	 info->ndcb0 = ndcb0;
+	 addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles
+			 + info->col_addr_cycles);
+
+	 switch (command) {
+	 case NAND_CMD_READOOB:
+	 case NAND_CMD_READ0:
+		 cmd  = info->cmdset->read1;
+		 if (command == NAND_CMD_READOOB)
+			 info->buf_start = mtd->writesize + column;
+		 else
+			 info->buf_start = column;
+
+		 if (unlikely(info->page_size < PAGE_CHUNK_SIZE))
+			 info->ndcb0 |= NDCB0_CMD_TYPE(0)
+					 | addr_cycle
+					 | (cmd & NDCB0_CMD1_MASK);
+		 else
+			 info->ndcb0 |= NDCB0_CMD_TYPE(0)
+					 | NDCB0_DBC
+					 | addr_cycle
+					 | cmd;
+
+	 case NAND_CMD_SEQIN:
+		 /* small page addr setting */
+		 if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) {
+			 info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
+					 | (column & 0xFF);
+
+			 info->ndcb2 = 0;
+		 }
+		 else {
+			 info->ndcb1 = ((page_addr & 0xFFFF) << 16)
+					 | (column & 0xFFFF);
+
+			 if (page_addr & 0xFF0000)
+				 info->ndcb2 = (page_addr & 0xFF0000) >> 16;
+			 else
+				 info->ndcb2 = 0;
+		 }
+
+		 info->buf_count = mtd->writesize + mtd->oobsize;
+		 memset(info->data_buff, 0xFF, info->buf_count);
+
+		 break;
+
+	 case NAND_CMD_PAGEPROG:
+		 if (is_buf_blank(info->data_buff, (mtd->writesize + mtd->oobsize))) {
+			 exec_cmd = 0;
+			 break;
+		 }
+
+		 cmd = info->cmdset->program;
+		 info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+				 | NDCB0_AUTO_RS
+				 | NDCB0_ST_ROW_EN
+				 | NDCB0_DBC
+				 | cmd
+				 | addr_cycle;
+		 break;
+
+	 case NAND_CMD_READID:
+		 cmd = info->cmdset->read_id;
+		 info->buf_count = info->read_id_bytes;
+		 info->ndcb0 |= NDCB0_CMD_TYPE(3)
+				 | NDCB0_ADDR_CYC(1)
+				 | cmd;
+
+		 info->data_size = 8;
+		 break;
+	 case NAND_CMD_STATUS:
+		 cmd = info->cmdset->read_status;
+		 info->buf_count = 1;
+		 info->ndcb0 |= NDCB0_CMD_TYPE(4)
+				 | NDCB0_ADDR_CYC(1)
+				 | cmd;
+
+		 info->data_size = 8;
+		 break;
+
+	 case NAND_CMD_ERASE1:
+		 cmd = info->cmdset->erase;
+		 info->ndcb0 |= NDCB0_CMD_TYPE(2)
+				 | NDCB0_AUTO_RS
+				 | NDCB0_ADDR_CYC(3)
+				 | NDCB0_DBC
+				 | cmd;
+		 info->ndcb1 = page_addr;
+		 info->ndcb2 = 0;
+
+		 break;
+	 case NAND_CMD_RESET:
+		 cmd = info->cmdset->reset;
+		 info->ndcb0 |= NDCB0_CMD_TYPE(5)
+				 | cmd;
+
+		 break;
+
+	 case NAND_CMD_ERASE2:
+		 exec_cmd = 0;
+		 break;
+
+	 default:
+		 exec_cmd = 0;
+		 printk(KERN_ERR "pxa3xx-nand: non-supported command %x\n", command);
+		 break;
+	 }
+
+	 return exec_cmd;
+}
+
 static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
 				int column, int page_addr)
 {
 	struct pxa3xx_nand_info *info = mtd->priv;
-	const struct pxa3xx_nand_cmdset *cmdset = info->cmdset;
-	int ret, exec_cmd = 0;
-
-	info->use_dma = (use_dma) ? 1 : 0;
-	info->use_ecc = 0;
-	info->data_size = 0;
-	info->state = 0;
-	info->retcode = ERR_NONE;
-
-	switch (command) {
-	case NAND_CMD_READOOB:
-		/* disable HW ECC to get all the OOB data */
-		info->buf_count = mtd->writesize + mtd->oobsize;
-		info->buf_start = mtd->writesize + column;
-		memset(info->data_buff, 0xFF, info->buf_count);
-
-		prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
-		exec_cmd = 1;
-		break;
-
-	case NAND_CMD_READ0:
-		info->use_ecc = 1;
-		info->buf_start = column;
-		info->buf_count = mtd->writesize + mtd->oobsize;
-		memset(info->data_buff, 0xFF, info->buf_count);
+	int ret, exec_cmd;
 
-		prepare_read_prog_cmd(info, cmdset->read1, column, page_addr);
-		exec_cmd = 1;
-		break;
-	case NAND_CMD_SEQIN:
-		info->buf_start = column;
-		info->buf_count = mtd->writesize + mtd->oobsize;
-		memset(info->data_buff, 0xff, info->buf_count);
-
-		/* save column/page_addr for next CMD_PAGEPROG */
-		info->seqin_column = column;
-		info->seqin_page_addr = page_addr;
-		break;
-	case NAND_CMD_PAGEPROG:
-		info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1;
-
-		prepare_read_prog_cmd(info, cmdset->program,
-				info->seqin_column, info->seqin_page_addr);
-		exec_cmd = 1;
-		break;
-	case NAND_CMD_ERASE1:
-		prepare_erase_cmd(info, cmdset->erase, page_addr);
-		exec_cmd = 1;
-		break;
-	case NAND_CMD_ERASE2:
-		break;
-	case NAND_CMD_READID:
-	case NAND_CMD_STATUS:
-		info->use_dma = 0;	/* force PIO read */
-		info->buf_start = 0;
-		info->buf_count = (command == NAND_CMD_READID) ?
-				info->read_id_bytes : 1;
-
-		prepare_other_cmd(info, (command == NAND_CMD_READID) ?
-				cmdset->read_id : cmdset->read_status);
-		exec_cmd = 1;
-		break;
-	case NAND_CMD_RESET:
-		prepare_other_cmd(info, cmdset->reset);
-		exec_cmd = 1;
-		break;
-	default:
-		printk(KERN_ERR "non-supported command.\n");
-		break;
-	}
+	/*
+	 * if this is a x16 device ,then convert the input
+	 * "byte" address into a "word" address appropriate
+	 * for indexing a word-oriented device
+	 */
+	if (info->reg_ndcr & NDCR_DWIDTH_M)
+		column /= 2;
 
+	exec_cmd = prepare_command_pool(info, command, column, page_addr);
 	if (exec_cmd) {
 		init_completion(&info->cmd_complete);
 		pxa3xx_nand_start(info);
@@ -920,6 +947,7 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd,
 	struct nand_chip *this = &info->nand_chip;
 
 	this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0;
+	this->options |= NAND_NO_AUTOINCR;
 
 	this->waitfunc		= pxa3xx_nand_waitfunc;
 	this->select_chip	= pxa3xx_nand_select_chip;
-- 
1.7.0.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel



More information about the linux-mtd mailing list