[PATCH 22/29] pxa3xx_nand: support ecc requirement higher

Lei Wen leiwen at marvell.com
Tue Jun 22 11:06:01 EDT 2010


than 4bit per 512 bytes

Signed-off-by: Lei Wen <leiwen at marvell.com>
---
 arch/arm/plat-pxa/include/plat/pxa3xx_nand.h |    2 +-
 drivers/mtd/nand/pxa3xx_nand.c               |  117 +++++++++++++++----------
 2 files changed, 71 insertions(+), 48 deletions(-)

diff --git a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
index c20ac35..2f1a1cf 100644
--- a/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
+++ b/arch/arm/plat-pxa/include/plat/pxa3xx_nand.h
@@ -43,7 +43,7 @@ struct pxa3xx_nand_flash {
 	uint16_t 	page_size;	/* Page size in bytes */
 	uint8_t		flash_width;	/* Width of Flash memory (DWIDTH_M) */
 	uint8_t 	dfc_width;	/* Width of flash controller(DWIDTH_C) */
-	uint8_t		ecc_type;	/* Which ECC is applied */
+	uint8_t		ecc_strength;	/* How strong a ecc should be applied */
 	uint32_t	num_blocks;	/* Number of physical blocks in Flash */
 	struct pxa3xx_nand_cmdset *cmdset;	/* NAND command set */
 	struct pxa3xx_nand_timing *timing;	/* NAND Flash timing */
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index b0a0ccf..8f7ab2d 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -33,6 +33,8 @@
 #define BCH_THRESHOLD           (8)
 #define CMD_POOL_SIZE           (5)
 #define READ_ID_BYTES		(4)
+#define BCH_STRENGTH		(4)
+#define HAMMING_STRENGTH	(1)

 /* registers and bit definitions */
 #define NDCR		(0x00) /* Control register */
@@ -84,9 +86,9 @@
 #define NDCR_RDDREQM            (0x1 << 1)
 #define NDCR_WRCMDREQM          (0x1)

+#define NDSR_MASK		(0xffffffff)
 #define NDSR_ERR_CNT_MASK       (0x1F << 16)
 #define NDSR_ERR_CNT(x)         (((x) << 16) & NDSR_ERR_CNT_MASK)
-#define NDSR_MASK		(0xfff)
 #define NDSR_RDY                (0x1 << 12)
 #define NDSR_FLASH_RDY          (0x1 << 11)
 #define NDSR_CS0_PAGED		(0x1 << 10)
@@ -103,6 +105,7 @@

 #define NDCB0_CMD_XTYPE_MASK    (0x7 << 29)
 #define NDCB0_CMD_XTYPE(x)      (((x) << 29) & NDCB0_CMD_XTYPE_MASK)
+#define NDCB0_LEN_OVRD		(0x1 << 28)
 #define NDCB0_ST_ROW_EN         (0x1 << 26)
 #define NDCB0_AUTO_RS		(0x1 << 25)
 #define NDCB0_CSEL		(0x1 << 24)
@@ -161,7 +164,7 @@ struct pxa3xx_nand_info {
 	int			page_addr;
 	uint16_t		page_size;
 	uint8_t			chip_select;
-	uint8_t			use_ecc;
+	uint8_t			ecc_strength;

 	/* calculated from pxa3xx_nand_flash data */
 	uint8_t			col_addr_cycles;
@@ -206,8 +209,8 @@ struct pxa3xx_nand {

 	/* relate to the command */
 	uint8_t			chip_select;
+	uint8_t			ecc_strength;
 	unsigned int		state;
-	int			use_ecc;	/* use HW ECC ? */
 	int			use_dma;	/* use DMA ? */
 	int 			retcode;

@@ -218,6 +221,7 @@ struct pxa3xx_nand {
 	uint32_t		ndcb0[CMD_POOL_SIZE];
 	uint32_t		ndcb1;
 	uint32_t		ndcb2;
+	uint32_t		ndcb3[CMD_POOL_SIZE];
 };

 static int use_dma = 1;
@@ -253,17 +257,17 @@ static struct pxa3xx_nand_timing __devinitdata
timing[] = {
 #define NAND_SETTING_MICRON      &default_cmdset, &timing[2]
 #define NAND_SETTING_ST          &default_cmdset, &timing[3]
 static struct pxa3xx_nand_flash __devinitdata builtin_flash_types[] = {
-{ "DEFAULT FLASH",      0,       0,  0, 2048,  8,  8, ECC_NONE,
0, NAND_SETTING_DEFAULT, },
-{ "64MiB 16-bit",  0x46ec, 0xffff,  32,  512, 16, 16, ECC_HAMMIN,
4096, NAND_SETTING_SAMSUNG, },
-{ "256MiB 8-bit",  0xdaec, 0xffff,  64, 2048,  8,  8, ECC_HAMMIN,
2048, NAND_SETTING_SAMSUNG, },
-{ "1GiB 8-bit",    0xd3ec, 0xffff, 128, 2048,  8,  8, ECC_BCH,
4096, NAND_SETTING_SAMSUNG, },
-{ "4GiB 8-bit",    0xd7ec, 0x29d5, 128, 4096,  8,  8, ECC_BCH,
8192, NAND_SETTING_SAMSUNG, },
-{ "128MiB 8-bit",  0xa12c, 0xffff,  64, 2048,  8,  8, ECC_HAMMIN,
1024, NAND_SETTING_MICRON, },
-{ "128MiB 16-bit", 0xb12c, 0xffff,  64, 2048, 16, 16, ECC_HAMMIN,
1024, NAND_SETTING_MICRON, },
-{ "512MiB 8-bit",  0xdc2c, 0xffff,  64, 2048,  8,  8, ECC_HAMMIN,
4096, NAND_SETTING_MICRON, },
-{ "512MiB 16-bit", 0xcc2c, 0xffff,  64, 2048, 16, 16, ECC_HAMMIN,
4096, NAND_SETTING_MICRON, },
-{ "1GiB 8-bit",    0x382c, 0xffff, 128, 4096,  8,  8, ECC_BCH,
2048, NAND_SETTING_MICRON },
-{ "256MiB 16-bit", 0xba20, 0xffff,  64, 2048, 16, 16, ECC_HAMMIN,
2048, NAND_SETTING_ST, },
+{ "DEFAULT FLASH",      0,       0,  0, 2048,  8,  8, 0,    0,
NAND_SETTING_DEFAULT, },
+{ "64MiB 16-bit",  0x46ec, 0xffff,  32,  512, 16, 16, 1, 4096,
NAND_SETTING_SAMSUNG, },
+{ "256MiB 8-bit",  0xdaec, 0xffff,  64, 2048,  8,  8, 1, 2048,
NAND_SETTING_SAMSUNG, },
+{ "1GiB 8-bit",    0xd3ec, 0xffff, 128, 2048,  8,  8, 4, 4096,
NAND_SETTING_SAMSUNG, },
+{ "4GiB 8-bit",    0xd7ec, 0x29d5, 128, 4096,  8,  8, 8, 8192,
NAND_SETTING_SAMSUNG, },
+{ "128MiB 8-bit",  0xa12c, 0xffff,  64, 2048,  8,  8, 1, 1024,
NAND_SETTING_MICRON, },
+{ "128MiB 16-bit", 0xb12c, 0xffff,  64, 2048, 16, 16, 1, 1024,
NAND_SETTING_MICRON, },
+{ "512MiB 8-bit",  0xdc2c, 0xffff,  64, 2048,  8,  8, 1, 4096,
NAND_SETTING_MICRON, },
+{ "512MiB 16-bit", 0xcc2c, 0xffff,  64, 2048, 16, 16, 1, 4096,
NAND_SETTING_MICRON, },
+{ "1GiB 8-bit",    0x382c, 0xffff, 128, 4096,  8,  8, 4, 2048,
NAND_SETTING_MICRON },
+{ "256MiB 16-bit", 0xba20, 0xffff,  64, 2048, 16, 16, 1, 2048,
NAND_SETTING_ST, },
 };

 static const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL};
@@ -319,16 +323,15 @@ static void pxa3xx_set_datasize(struct
pxa3xx_nand_info *info)
 			return;
 		}

-		switch (nand->use_ecc) {
-		case ECC_HAMMIN:
-			nand->oob_size = 40;
+		switch (nand->ecc_strength) {
+		case 0:
+			nand->oob_size = 64;
 			break;
-		case ECC_BCH:
-			nand->oob_size = 32;
+		case HAMMING_STRENGTH:
+			nand->oob_size = 40;
 			break;
 		default:
-			nand->oob_size = 64;
-			break;
+			nand->oob_size = 32;
 		}
 	} else {
 		nand->data_size = 512;
@@ -337,17 +340,16 @@ static void pxa3xx_set_datasize(struct
pxa3xx_nand_info *info)
 			return;
 		}

-		switch (nand->use_ecc) {
-		case ECC_HAMMIN:
+		switch (nand->ecc_strength) {
+		case 0:
+			nand->oob_size = 16;
+			break;
+		case HAMMING_STRENGTH:
 			nand->oob_size = 8;
 			break;
-		case ECC_BCH:
+		default:
 			printk("Don't support BCH on small page device!!!\n");
 			BUG();
-			break;
-		default:
-			nand->oob_size = 16;
-			break;
 		}
 	}
 }
@@ -365,16 +367,16 @@ 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 |= NDCR_ND_RUN;

-	switch (nand->use_ecc) {
-	case ECC_BCH:
+	switch (nand->ecc_strength) {
+	default:
 		ndeccctrl |= NDECCCTRL_BCH_EN;
 		ndeccctrl |= NDECCCTRL_ECC_THRESH(BCH_THRESHOLD);
-	case ECC_HAMMIN:
+	case HAMMING_STRENGTH:
 		ndcr |= NDCR_ECC_EN;
-	default:
+	case 0:
 		break;
 	}

@@ -610,6 +612,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 			nand_writel(nand, NDCB0, nand->ndcb0[cmd_seqs]);
 			nand_writel(nand, NDCB0, ndcb1);
 			nand_writel(nand, NDCB0, ndcb2);
+			if (nand->ndcb3[cmd_seqs])
+				nand_writel(nand, NDCB0, nand->ndcb3[cmd_seqs]);
 		}
 		else
 			is_completed = 1;
@@ -654,7 +658,6 @@ static int prepare_command_pool(struct pxa3xx_nand
*nand, int command,
 	nand->cmd_seqs		= 0;
 	nand->data_size		= 0;
 	nand->oob_size		= 0;
-	nand->use_ecc		= 0;
 	nand->use_dma		= 0;
 	nand->state		= 0;
 	nand->bad_count		= 0;
@@ -667,11 +670,23 @@ static int prepare_command_pool(struct
pxa3xx_nand *nand, int command,
 		pxa3xx_set_datasize(info);
 		nand->use_dma = use_dma;
 		chunks = info->page_size / nand->data_size;
+		if (info->ecc_strength > BCH_STRENGTH) {
+			i = info->ecc_strength / BCH_STRENGTH;
+			nand->data_size /= i;
+			ndcb0 |= NDCB0_LEN_OVRD;
+			chunks *= i;
+		}
 		break;
+	case NAND_CMD_READOOB:
+		if (info->ecc_strength > BCH_STRENGTH) {
+			printk(KERN_ERR "we don't support oob command if use"
+				     " 8bit per 512bytes ecc feature!!\n");
+			BUG();
+		}
 	default:
 		nand->ndcb1 = 0;
 		nand->ndcb2 = 0;
-		nand->use_ecc = ECC_NONE;
+		nand->ecc_strength = 0;
 		break;
 	}
 	if (nand->use_dma) {
@@ -683,6 +698,7 @@ static int prepare_command_pool(struct pxa3xx_nand
*nand, int command,
 	for (i = 0; i < CMD_POOL_SIZE; i ++) {
 		nand->ndcb0[i] = ndcb0;
 		nand->wait_ready[i] = 0;
+		nand->ndcb3[i] = (ndcb0 & NDCB0_LEN_OVRD)? nand->data_size : 0;
 	}
 	addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles
 			+ info->col_addr_cycles);
@@ -690,7 +706,7 @@ static int prepare_command_pool(struct pxa3xx_nand
*nand, int command,
 	switch (command) {
 	case NAND_CMD_READ0:
 	case NAND_CMD_SEQIN:
-		nand->use_ecc = info->use_ecc;
+		nand->ecc_strength = info->ecc_strength;
 	case NAND_CMD_READOOB:
 		memset(nand->data_buff, 0xff, column);
 		nand->buf_count = mtd->writesize + mtd->oobsize;
@@ -737,7 +753,8 @@ static int prepare_command_pool(struct pxa3xx_nand
*nand, int command,
 				| NDCB0_NC
 				| addr_cycle
 				| cmd;
-
+		nand->ndcb0[0] &= ~NDCB0_LEN_OVRD;
+		nand->ndcb3[0] = 0;
 		nand->ndcb0[1] |= NDCB0_CMD_XTYPE(0x5)
 				| NDCB0_NC
 				| addr_cycle;
@@ -792,6 +809,8 @@ static int prepare_command_pool(struct pxa3xx_nand
*nand, int command,
 				| (cmd & NDCB0_CMD2_MASK)
 				| NDCB0_CMD1_MASK
 				| addr_cycle;
+		nand->ndcb0[chunks] &= ~NDCB0_LEN_OVRD;
+		nand->ndcb3[chunks] = 0;
 		/* we should wait for RnB goes high which
 		 * indicate the data has been written succesfully*/
 		nand->wait_ready[nand->total_cmds] = 1;
@@ -988,7 +1007,12 @@ static int pxa3xx_nand_config_flash(struct
pxa3xx_nand_info *info,
 		return -EINVAL;
 	}
 	/* calculate flash information */
-	info->use_ecc = f->ecc_type;
+	if (f->ecc_strength != 0 && f->ecc_strength != HAMMING_STRENGTH
+	    && (f->ecc_strength % BCH_STRENGTH != 0)) {
+		printk(KERN_ERR "ECC strength definition error, please recheck!!\n");
+		return -EINVAL;
+	}
+	info->ecc_strength = f->ecc_strength;
 	info->cmdset = f->cmdset;
 	info->page_size = f->page_size;

@@ -1032,7 +1056,9 @@ static int pxa3xx_nand_config_flash(struct
pxa3xx_nand_info *info,
 	}

 	ndcr |= NDCR_RD_ID_CNT(READ_ID_BYTES);
-	ndcr |= NDCR_SPARE_EN; /* enable spare by default */
+	/* only enable spare area when ecc is lower than 8bits per 512 bytes */
+	if (f->ecc_strength <= BCH_STRENGTH)
+		ndcr |= NDCR_SPARE_EN;

 	info->reg_ndcr = ndcr;
 	pxa3xx_nand_set_timing(info, f->timing);
@@ -1055,7 +1081,7 @@ static int pxa3xx_nand_detect_config(struct
pxa3xx_nand *nand)

 	info->ndtr0cs0 = nand_readl(nand, NDTR0CS0);
 	info->ndtr1cs0 = nand_readl(nand, NDTR1CS0);
-	info->use_ecc = (ndeccctrl & NDECCCTRL_BCH_EN) ? ECC_BCH : ECC_HAMMIN;
+	info->ecc_strength = (ndeccctrl & NDECCCTRL_BCH_EN) ? BCH_STRENGTH :
HAMMING_STRENGTH;
 	info->cmdset = &default_cmdset;

 	return 0;
@@ -1091,19 +1117,16 @@ static void pxa3xx_read_page(struct mtd_info
*mtd, uint8_t *buf)
 	pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RNDOUT, 0, info->page_addr);
 	switch (nand->retcode) {
 	case ERR_SBERR:
-		switch (nand->use_ecc) {
-		case ECC_BCH:
+		switch (nand->ecc_strength) {
+		default:
 			if (nand->bad_count > BCH_THRESHOLD)
 				mtd->ecc_stats.corrected +=
 					(nand->bad_count - BCH_THRESHOLD);
 			break;

-		case ECC_HAMMIN:
+		case HAMMING_STRENGTH:
 			mtd->ecc_stats.corrected ++;
-			break;
-
-		case ECC_NONE:
-		default:
+		case 0:
 			break;
 		}
 		break;
-- 
1.7.0.4



More information about the linux-arm-kernel mailing list