Skip to contentSkip to conversation

at91: 9x5: Enable PMECC(Programmable Multibit ECC controller) support

PATCH Superseded Josh Wu 3 participants 14 messages Aug 23, 2012 – Sep 1, 2012

Subsystems (3)
lore
Share & tools
lore

Josh Wu

author
#0 lore raw

v3 cover at91: 9x5: Enable PMECC(Programmable Multibit ECC controller) support

This patch series will add PMECC support for atmel at91sam9x5ek in u-boot.

The NAND flash driver patch is ported from kernel patch. The main different from kernel patch is the modification about registers access part. in this version it via a register structure to access.

It is tested in atmel AT919G25EK board.

Changes since v2:
adapt atmel nand driver to CONFIG_SYS_NAND_SELF_INIT. It use a new
board_nand_init(void) function.
Add README doc for Atmel PMECC.
Add timeout for PMECC read hw status.
refine code according to Andreas and Scott's comments.

Josh Wu (5):
at91: atmel_nand: extract HWECC initialization code into one
function: atmel_hw_nand_init_param().
at91: atmel_nand: remove unused variables.
at91: atmel_nand: Update driver to support Programmable Multibit ECC
controller
at91: 9x5: change SMC config timing that both works for PMECC &
non-PMECC.
at91: 9x5: Enable PMECC for 5series ek board.

 board/atmel/at91sam9x5ek/at91sam9x5ek.c |   12 +-
 doc/README.atmel_pmecc                  |   44 ++
 drivers/mtd/nand/atmel_nand.c           |  828 ++++++++++++++++++++++++++++---
 drivers/mtd/nand/atmel_nand_ecc.h       |  113 +++++
 include/configs/at91sam9x5ek.h          |    7 +
 include/nand.h                          |    2 +-
 6 files changed, 938 insertions(+), 68 deletions(-)
 create mode 100644 doc/README.atmel_pmecc
Signature · 1 line
1.7.9.5
author
#1 lore raw

PATCH v3 1/5 at91: atmel_nand: extract HWECC initialization code into one function: atmel_hw_nand_init_param().

This patch
1. extract the hwecc initialization code into one function. It is a preparation for adding atmel PMECC support.
2. enable CONFIG_SYS_NAND_SELF_INIT. Which make us can configurate the ecc parameters between nand_scan_ident() and nand_scan_tail().

---
Changes since v2:
adapt to CONFIG_SYS_NAND_SELF_INIT.

 drivers/mtd/nand/atmel_nand.c |  145 ++++++++++++++++++++++++-----------------
 include/nand.h                |    2 +-
 2 files changed, 88 insertions(+), 59 deletions(-)
drivers/mtd/nand/atmel_nand.c +87 -58
index de66382..21dc4f5 100644
@@ -232,6 +232,60 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
 static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 {
 }
+
+int atmel_hwecc_nand_init_param(struct nand_chip *nand, struct mtd_info *mtd)
+{
+	nand->ecc.mode = NAND_ECC_HW;
+	nand->ecc.calculate = atmel_nand_calculate;
+	nand->ecc.correct = atmel_nand_correct;
+	nand->ecc.hwctl = atmel_nand_hwctl;
+	nand->ecc.read_page = atmel_nand_read_page;
+	nand->ecc.bytes = 4;
+
+	if (nand->ecc.mode == NAND_ECC_HW) {
+		/* ECC is calculated for the whole page (1 step) */
+		nand->ecc.size = mtd->writesize;
+
+		/* set ECC page size and oob layout */
+		switch (mtd->writesize) {
+		case 512:
+			nand->ecc.layout = &atmel_oobinfo_small;
+			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR,
+					ATMEL_ECC_PAGESIZE_528);
+			break;
+		case 1024:
+			nand->ecc.layout = &atmel_oobinfo_large;
+			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR,
+					ATMEL_ECC_PAGESIZE_1056);
+			break;
+		case 2048:
+			nand->ecc.layout = &atmel_oobinfo_large;
+			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR,
+					ATMEL_ECC_PAGESIZE_2112);
+			break;
+		case 4096:
+			nand->ecc.layout = &atmel_oobinfo_large;
+			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR,
+					ATMEL_ECC_PAGESIZE_4224);
+			break;
+		default:
+			/* page size not handled by HW ECC */
+			/* switching back to soft ECC */
+			nand->ecc.mode = NAND_ECC_SOFT;
+			nand->ecc.calculate = NULL;
+			nand->ecc.correct = NULL;
+			nand->ecc.hwctl = NULL;
+			nand->ecc.read_page = NULL;
+			nand->ecc.postpad = 0;
+			nand->ecc.prepad = 0;
+			nand->ecc.bytes = 0;
+			break;
+		}
+	}
+
+	return 0;
+}
+
 #endif
 
 static void at91_nand_hwcontrol(struct mtd_info *mtd,
@@ -267,12 +321,20 @@ static int at91_nand_ready(struct mtd_info *mtd)
 }
 #endif
 
-int board_nand_init(struct nand_chip *nand)
-{
-#ifdef CONFIG_ATMEL_NAND_HWECC
-	static int chip_nr = 0;
-	struct mtd_info *mtd;
+#ifndef CONFIG_SYS_NAND_BASE_LIST
+#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
 #endif
+static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
+static ulong base_addr[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
+
+int atmel_nand_chip_init(int devnum, ulong base_addr)
+{
+	int ret;
+	struct mtd_info *mtd = &nand_info[devnum];
+	struct nand_chip *nand = &nand_chip[devnum];
+
+	mtd->priv = nand;
+	nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;
 
 	nand->ecc.mode = NAND_ECC_SOFT;
 #ifdef CONFIG_SYS_NAND_DBW_16
@@ -284,62 +346,29 @@ int board_nand_init(struct nand_chip *nand)
 #endif
 	nand->chip_delay = 20;
 
-#ifdef CONFIG_ATMEL_NAND_HWECC
-	nand->ecc.mode = NAND_ECC_HW;
-	nand->ecc.calculate = atmel_nand_calculate;
-	nand->ecc.correct = atmel_nand_correct;
-	nand->ecc.hwctl = atmel_nand_hwctl;
-	nand->ecc.read_page = atmel_nand_read_page;
-	nand->ecc.bytes = 4;
-#endif
+	ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL);
+	if (ret)
+		return ret;
 
 #ifdef CONFIG_ATMEL_NAND_HWECC
-	mtd = &nand_info[chip_nr++];
-	mtd->priv = nand;
+	ret = atmel_hwecc_nand_init_param(nand, mtd);
+#endif
+	if (ret)
+		return ret;
 
-	/* Detect NAND chips */
-	if (nand_scan_ident(mtd, 1, NULL)) {
-		printk(KERN_WARNING "NAND Flash not found !\n");
-		return -ENXIO;
-	}
+	ret = nand_scan_tail(mtd);
+	if (!ret)
+		nand_register(devnum);
 
-	if (nand->ecc.mode == NAND_ECC_HW) {
-		/* ECC is calculated for the whole page (1 step) */
-		nand->ecc.size = mtd->writesize;
-
-		/* set ECC page size and oob layout */
-		switch (mtd->writesize) {
-		case 512:
-			nand->ecc.layout = &atmel_oobinfo_small;
-			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_528);
-			break;
-		case 1024:
-			nand->ecc.layout = &atmel_oobinfo_large;
-			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_1056);
-			break;
-		case 2048:
-			nand->ecc.layout = &atmel_oobinfo_large;
-			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_2112);
-			break;
-		case 4096:
-			nand->ecc.layout = &atmel_oobinfo_large;
-			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_4224);
-			break;
-		default:
-			/* page size not handled by HW ECC */
-			/* switching back to soft ECC */
-			nand->ecc.mode = NAND_ECC_SOFT;
-			nand->ecc.calculate = NULL;
-			nand->ecc.correct = NULL;
-			nand->ecc.hwctl = NULL;
-			nand->ecc.read_page = NULL;
-			nand->ecc.postpad = 0;
-			nand->ecc.prepad = 0;
-			nand->ecc.bytes = 0;
-			break;
-		}
-	}
-#endif
+	return ret;
+}
 
-	return 0;
+void board_nand_init(void)
+{
+	int i;
+	for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
+		if (atmel_nand_chip_init(i, base_addr[i]))
+			printk(KERN_ERR "atmel_nand: Fail to initialize #%d chip",
+				i);
 }
+
include/nand.h +1 -1
index a48b1b8..c554c55 100644
@@ -31,7 +31,7 @@
  *@the same time, so do it here.  When all drivers are
  * converted, this will go away.
  */
-#if defined(CONFIG_NAND_FSL_ELBC)
+#if defined(CONFIG_NAND_FSL_ELBC) || defined(CONFIG_NAND_ATMEL)
 #define CONFIG_SYS_NAND_SELF_INIT
 #endif
 
Signature · 1 line
1.7.9.5
#2 lore raw

PATCH v3 1/5 at91: atmel_nand: extract HWECC initialization code into one function: atmel_hw_nand_init_param().

Dear Josh Wu,

Quoted 6 lines · Josh Wu

This patch
1. extract the hwecc initialization code into one function. It is a preparation for adding atmel PMECC support.
2. enable CONFIG_SYS_NAND_SELF_INIT. Which make us can configurate the ecc parameters between nand_scan_ident() and nand_scan_tail().

---

applied to u-boot-atmel/master with two minor changes (read on).

Quoted 111 lines

Changes since v2:
adapt to CONFIG_SYS_NAND_SELF_INIT.

  drivers/mtd/nand/atmel_nand.c |  145 ++++++++++++++++++++++++-----------------
  include/nand.h                |    2 +-
  2 files changed, 88 insertions(+), 59 deletions(-)
drivers/mtd/nand/atmel_nand.c +68 -13
index de66382..21dc4f5 100644
@@ -232,6 +232,60 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
  static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
  {
  }
+
+int atmel_hwecc_nand_init_param(struct nand_chip *nand, struct mtd_info *mtd)
+{
+	nand->ecc.mode = NAND_ECC_HW;
+	nand->ecc.calculate = atmel_nand_calculate;
+	nand->ecc.correct = atmel_nand_correct;
+	nand->ecc.hwctl = atmel_nand_hwctl;
+	nand->ecc.read_page = atmel_nand_read_page;
+	nand->ecc.bytes = 4;
+
+	if (nand->ecc.mode == NAND_ECC_HW) {
+		/* ECC is calculated for the whole page (1 step) */
+		nand->ecc.size = mtd->writesize;
+
+		/* set ECC page size and oob layout */
+		switch (mtd->writesize) {
+		case 512:
+			nand->ecc.layout = &atmel_oobinfo_small;
+			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR,
+					ATMEL_ECC_PAGESIZE_528);
+			break;
+		case 1024:
+			nand->ecc.layout = &atmel_oobinfo_large;
+			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR,
+					ATMEL_ECC_PAGESIZE_1056);
+			break;
+		case 2048:
+			nand->ecc.layout = &atmel_oobinfo_large;
+			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR,
+					ATMEL_ECC_PAGESIZE_2112);
+			break;
+		case 4096:
+			nand->ecc.layout = &atmel_oobinfo_large;
+			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR,
+					ATMEL_ECC_PAGESIZE_4224);
+			break;
+		default:
+			/* page size not handled by HW ECC */
+			/* switching back to soft ECC */
+			nand->ecc.mode = NAND_ECC_SOFT;
+			nand->ecc.calculate = NULL;
+			nand->ecc.correct = NULL;
+			nand->ecc.hwctl = NULL;
+			nand->ecc.read_page = NULL;
+			nand->ecc.postpad = 0;
+			nand->ecc.prepad = 0;
+			nand->ecc.bytes = 0;
+			break;
+		}
+	}
+
+	return 0;
+}
+
  #endif
 
  static void at91_nand_hwcontrol(struct mtd_info *mtd,
@@ -267,12 +321,20 @@ static int at91_nand_ready(struct mtd_info *mtd)
  }
  #endif
 
-int board_nand_init(struct nand_chip *nand)
-{
-#ifdef CONFIG_ATMEL_NAND_HWECC
-	static int chip_nr = 0;
-	struct mtd_info *mtd;
+#ifndef CONFIG_SYS_NAND_BASE_LIST
+#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE }
  #endif
+static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
+static ulong base_addr[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST;
+
+int atmel_nand_chip_init(int devnum, ulong base_addr)
+{
+	int ret;
+	struct mtd_info *mtd = &nand_info[devnum];
+	struct nand_chip *nand = &nand_chip[devnum];
+
+	mtd->priv = nand;
+	nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr;
 
  	nand->ecc.mode = NAND_ECC_SOFT;
  #ifdef CONFIG_SYS_NAND_DBW_16
@@ -284,62 +346,29 @@ int board_nand_init(struct nand_chip *nand)
  #endif
  	nand->chip_delay = 20;
 
-#ifdef CONFIG_ATMEL_NAND_HWECC
-	nand->ecc.mode = NAND_ECC_HW;
-	nand->ecc.calculate = atmel_nand_calculate;
-	nand->ecc.correct = atmel_nand_correct;
-	nand->ecc.hwctl = atmel_nand_hwctl;
-	nand->ecc.read_page = atmel_nand_read_page;
-	nand->ecc.bytes = 4;
-#endif
+	ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL);

drivers/mtd/nand/atmel_nand.c int board_nand_init(struct nand_chip *nand) · line 357

Quoted 10 lines
drivers/mtd/nand/atmel_nand.c +6 -2
+	if (ret)
+		return ret;
 
  #ifdef CONFIG_ATMEL_NAND_HWECC
-	mtd = &nand_info[chip_nr++];
-	mtd->priv = nand;
+	ret = atmel_hwecc_nand_init_param(nand, mtd);
+#endif
+	if (ret)
+		return ret;

put this return value check into the ifdef, run time tested on at91sam9260ek with HWECC enabled in board config.

Quoted 50 lines
drivers/mtd/nand/atmel_nand.c +5 -42
-	/* Detect NAND chips */
-	if (nand_scan_ident(mtd, 1, NULL)) {
-		printk(KERN_WARNING "NAND Flash not found !\n");
-		return -ENXIO;
-	}
+	ret = nand_scan_tail(mtd);
+	if (!ret)
+		nand_register(devnum);
 
-	if (nand->ecc.mode == NAND_ECC_HW) {
-		/* ECC is calculated for the whole page (1 step) */
-		nand->ecc.size = mtd->writesize;
-
-		/* set ECC page size and oob layout */
-		switch (mtd->writesize) {
-		case 512:
-			nand->ecc.layout = &atmel_oobinfo_small;
-			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_528);
-			break;
-		case 1024:
-			nand->ecc.layout = &atmel_oobinfo_large;
-			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_1056);
-			break;
-		case 2048:
-			nand->ecc.layout = &atmel_oobinfo_large;
-			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_2112);
-			break;
-		case 4096:
-			nand->ecc.layout = &atmel_oobinfo_large;
-			ecc_writel(CONFIG_SYS_NAND_ECC_BASE, MR, ATMEL_ECC_PAGESIZE_4224);
-			break;
-		default:
-			/* page size not handled by HW ECC */
-			/* switching back to soft ECC */
-			nand->ecc.mode = NAND_ECC_SOFT;
-			nand->ecc.calculate = NULL;
-			nand->ecc.correct = NULL;
-			nand->ecc.hwctl = NULL;
-			nand->ecc.read_page = NULL;
-			nand->ecc.postpad = 0;
-			nand->ecc.prepad = 0;
-			nand->ecc.bytes = 0;
-			break;
-		}
-	}
-#endif
+	return ret;
+}
 

drivers/mtd/nand/atmel_nand.c int board_nand_init(struct nand_chip *nand) · line 374

Quoted 10 lines
drivers/mtd/nand/atmel_nand.c +8 -1
-	return 0;
+void board_nand_init(void)
+{
+	int i;
+	for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
+		if (atmel_nand_chip_init(i, base_addr[i]))
+			printk(KERN_ERR "atmel_nand: Fail to initialize #%d chip",
+				i);
  }
+

removed this empty newline at EOF.

Quoted 6 lines
include/nand.h +0 -0
index a48b1b8..c554c55 100644

include/nand.h line 37

Quoted 8 lines
include/nand.h +1 -1
@@ -31,7 +31,7 @@
   * at the same time, so do it here.  When all drivers are
   * converted, this will go away.
   */
-#if defined(CONFIG_NAND_FSL_ELBC)
+#if defined(CONFIG_NAND_FSL_ELBC) || defined(CONFIG_NAND_ATMEL)
  #define CONFIG_SYS_NAND_SELF_INIT
  #endif
 

Best regards

Andreas Bie?mann

author
#3 lore raw

PATCH v3 2/5 at91: atmel_nand: remove unused variables.

In reply to Josh Wu
---
 drivers/mtd/nand/atmel_nand.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/mtd/nand/atmel_nand.c +1 -2
index 21dc4f5..05a6317 100644
@@ -79,7 +79,6 @@ static struct nand_ecclayout atmel_oobinfo_small = {
 static int atmel_nand_calculate(struct mtd_info *mtd,
 		const u_char *dat, unsigned char *ecc_code)
 {
-	struct nand_chip *nand_chip = mtd->priv;
 	unsigned int ecc_value;
 
 	/* get the first 2 ECC bytes */
@@ -167,7 +166,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
 		u_char *read_ecc, u_char *isnull)
 {
 	struct nand_chip *nand_chip = mtd->priv;
-	unsigned int ecc_status, ecc_parity, ecc_mode;
+	unsigned int ecc_status;
 	unsigned int ecc_word, ecc_bit;
 
 	/* get the status from the Status Register */
Signature · 1 line
1.7.9.5
author
#5 lore raw

PATCH v3 3/5 at91: atmel_nand: Update driver to support Programmable Multibit ECC controller

In reply to Josh Wu

The Programmable Multibit ECC (PMECC) controller is a programmable binary BCH(Bose, Chaudhuri and Hocquenghem) encoder and decoder. This controller can be used to support both SLC and MLC NAND Flash devices. It supports to generate ECC to correct 2, 4, 8, 12 or 24 bits of error per sector of data.

To use PMECC in this driver, the user needs to set the PMECC correction capability, the sector size and ROM lookup table offsets in board config file.

This driver is ported from Linux kernel atmel_nand PMECC patch. The main difference is in this version it uses registers structure access hardware instead of using macros. It is tested in 9x5 serial boards.

---
Changes since v2:
add timeout when read hardware register.
add README document for atmel pmecc.
according to Scott and Andreas' suggestion, refined the pmecc_get_sigma()
function and add more comments for the function.

 doc/README.atmel_pmecc            |   44 +++
 drivers/mtd/nand/atmel_nand.c     |  680 ++++++++++++++++++++++++++++++++++++-
 drivers/mtd/nand/atmel_nand_ecc.h |  113 ++++++
 3 files changed, 836 insertions(+), 1 deletion(-)
 create mode 100644 doc/README.atmel_pmecc
doc/README.atmel_pmecc new file +44 -0
new file mode 100644
index 0000000..b483744
@@ -0,0 +1,44 @@
+How to enable PMECC(Programmable Multibit ECC) for nand on Atmel SoCs
+-----------------------------------------------------------
+2012-08-22 Josh Wu <[email protected]>
+
+The Programmable Multibit ECC (PMECC) controller is a programmable binary
+BCH(Bose, Chaudhuri and Hocquenghem) encoder and decoder. This controller
+can be used to support both SLC and MLC NAND Flash devices. It supports to
+generate ECC to correct 2, 4, 8, 12 or 24 bits of error per sector (512 or
+1024 bytes) of data.
+
+Following Atmel AT91 products support PMECC.
+- AT91SAM9X25, X35, G25, G15, G35 (tested)
+- AT91SAM9N12 (not tested, Should work)
+
+As soon as your nand flash software ECC works, you can enable PMECC.
+
+To use PMECC in this driver, the user needs to set:
+	1. the PMECC correction error bits capability: CONFIG_PMECC_CAP.
+	   It can be 2, 4, 8, 12 or 24.
+	2. The PMECC sector size: CONFIG_PMECC_SECTOR_SIZE.
+	   It only can be 512 or 1024.
+	3. The PMECC index lookup table's offsets in ROM code: CONFIG_PMECC_INDEX_TABLE_OFFSET.
+	   In the chip datasheet section "Boot Stragegies", you can find
+	   two Galois Field Table in the ROM code. One table is for 512-bytes
+	   sector. Another is for 1024-byte sector. Each Galois Field includes
+	   two sub-table: indext table & alpha table.
+	   In the beginning of each Galois Field Table is the index table,
+	   Alpha table is in the following.
+	   So the index table's offset is same as the Galois Field Table.
+
+	   Please set CONFIG_PMECC_INDEX_TABLE_OFFSET correctly according the
+	   Galois Field Table's offset base on the sector size you used.
+
+Take AT91SAM9X5EK as an example, the board definition file likes:
+
+/* PMECC & PMERRLOC */
+#define CONFIG_ATMEL_NAND_HWECC		1
+#define CONFIG_ATMEL_NAND_HW_PMECC	1
+#define CONFIG_PMECC_CAP		2
+#define CONFIG_PMECC_SECTOR_SIZE	512
+#define CONFIG_PMECC_INDEX_TABLE_OFFSET	0x8000
+
+NOTE: If you use 1024 as the sector size, then need set 0x10000 as the
+ CONFIG_PMECC_INDEX_TABLE_OFFSET
drivers/mtd/nand/atmel_nand.c +679 -1

712 lines not on this page · raw message

drivers/mtd/nand/atmel_nand_ecc.h +113 -0

117 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#6 lore raw

PATCH v3 3/5 at91: atmel_nand: Update driver to support Programmable Multibit ECC controller

Dear Josh Wu,

Quoted 8 lines · Josh Wu

The Programmable Multibit ECC (PMECC) controller is a programmable binary BCH(Bose, Chaudhuri and Hocquenghem) encoder and decoder. This controller can be used to support both SLC and MLC NAND Flash devices. It supports to generate ECC to correct 2, 4, 8, 12 or 24 bits of error per sector of data.

To use PMECC in this driver, the user needs to set the PMECC correction capability, the sector size and ROM lookup table offsets in board config file.

Quoted 6 lines

This driver is ported from Linux kernel atmel_nand PMECC patch. The main difference is in this version it uses registers structure access hardware instead of using macros. It is tested in 9x5 serial boards.

---

applied to u-boot-atmel/master (slightly modified due to required rebase cause of change in 1/5), thanks!

Best regards

Andreas Bie?mann

author
#7 lore raw

PATCH v3 4/5 at91: 9x5: change SMC config timing that both works for PMECC & non-PMECC.

In reply to Josh Wu
---
 board/atmel/at91sam9x5ek/at91sam9x5ek.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
board/atmel/at91sam9x5ek/at91sam9x5ek.c +6 -6
index 88b3478..ae408bc 100644
@@ -65,13 +65,13 @@ static void at91sam9x5ek_nand_hw_init(void)
 	writel(csa, &matrix->ebicsa);
 
 	/* Configure SMC CS3 for NAND/SmartMedia */
-	writel(AT91_SMC_SETUP_NWE(2) | AT91_SMC_SETUP_NCS_WR(0) |
-		AT91_SMC_SETUP_NRD(2) | AT91_SMC_SETUP_NCS_RD(0),
+	writel(AT91_SMC_SETUP_NWE(1) | AT91_SMC_SETUP_NCS_WR(0) |
+		AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(0),
 		&smc->cs[3].setup);
-	writel(AT91_SMC_PULSE_NWE(4) | AT91_SMC_PULSE_NCS_WR(4) |
-		AT91_SMC_PULSE_NRD(4) | AT91_SMC_PULSE_NCS_RD(4),
+	writel(AT91_SMC_PULSE_NWE(3) | AT91_SMC_PULSE_NCS_WR(5) |
+		AT91_SMC_PULSE_NRD(4) | AT91_SMC_PULSE_NCS_RD(6),
 		&smc->cs[3].pulse);
-	writel(AT91_SMC_CYCLE_NWE(7) | AT91_SMC_CYCLE_NRD(7),
+	writel(AT91_SMC_CYCLE_NWE(5) | AT91_SMC_CYCLE_NRD(6),
 		&smc->cs[3].cycle);
 	writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE |
 		AT91_SMC_MODE_EXNW_DISABLE |
@@ -80,7 +80,7 @@ static void at91sam9x5ek_nand_hw_init(void)
 #else /* CONFIG_SYS_NAND_DBW_8 */
 		AT91_SMC_MODE_DBW_8 |
 #endif
-		AT91_SMC_MODE_TDF_CYCLE(3),
+		AT91_SMC_MODE_TDF_CYCLE(1),
 		&smc->cs[3].mode);
 
 	writel(1 << ATMEL_ID_PIOCD, &pmc->pcer);
Signature · 1 line
1.7.9.5
#8 lore raw

PATCH v3 4/5 at91: 9x5: change SMC config timing that both works for PMECC & non-PMECC.

Hi Josh,

Quoted 29 lines · Josh Wu
---
  board/atmel/at91sam9x5ek/at91sam9x5ek.c |   12 ++++++------
  1 file changed, 6 insertions(+), 6 deletions(-)
board/atmel/at91sam9x5ek/at91sam9x5ek.c +5 -5
index 88b3478..ae408bc 100644
@@ -65,13 +65,13 @@ static void at91sam9x5ek_nand_hw_init(void)
  	writel(csa, &matrix->ebicsa);
 
  	/* Configure SMC CS3 for NAND/SmartMedia */
-	writel(AT91_SMC_SETUP_NWE(2) | AT91_SMC_SETUP_NCS_WR(0) |
-		AT91_SMC_SETUP_NRD(2) | AT91_SMC_SETUP_NCS_RD(0),
+	writel(AT91_SMC_SETUP_NWE(1) | AT91_SMC_SETUP_NCS_WR(0) |
+		AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(0),
  		&smc->cs[3].setup);
-	writel(AT91_SMC_PULSE_NWE(4) | AT91_SMC_PULSE_NCS_WR(4) |
-		AT91_SMC_PULSE_NRD(4) | AT91_SMC_PULSE_NCS_RD(4),
+	writel(AT91_SMC_PULSE_NWE(3) | AT91_SMC_PULSE_NCS_WR(5) |
+		AT91_SMC_PULSE_NRD(4) | AT91_SMC_PULSE_NCS_RD(6),
  		&smc->cs[3].pulse);
-	writel(AT91_SMC_CYCLE_NWE(7) | AT91_SMC_CYCLE_NRD(7),
+	writel(AT91_SMC_CYCLE_NWE(5) | AT91_SMC_CYCLE_NRD(6),
  		&smc->cs[3].cycle);
  	writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE |
  		AT91_SMC_MODE_EXNW_DISABLE |

board/atmel/at91sam9x5ek/at91sam9x5ek.c static void at91sam9x5ek_nand_hw_init(void) · line 84

Quoted 6 lines
board/atmel/at91sam9x5ek/at91sam9x5ek.c +1 -1
@@ -80,7 +80,7 @@ static void at91sam9x5ek_nand_hw_init(void)
  #else /* CONFIG_SYS_NAND_DBW_8 */
  		AT91_SMC_MODE_DBW_8 |
  #endif
-		AT91_SMC_MODE_TDF_CYCLE(3),
+		AT91_SMC_MODE_TDF_CYCLE(1),
  		&smc->cs[3].mode);

Test these parameters for NAND using software ECC. It works well.

Tested-by voice.shen at atmel.com
Quoted 3 lines
board/atmel/at91sam9x5ek/at91sam9x5ek.c +0 -0
  	writel(1 << ATMEL_ID_PIOCD, &pmc->pcer);
 
author
#10 lore raw

PATCH v3 5/5 at91: 9x5: Enable PMECC for 5series ek board.

In reply to Josh Wu
---
 include/configs/at91sam9x5ek.h |    7 +++++++
 1 file changed, 7 insertions(+)
include/configs/at91sam9x5ek.h +7 -0
index 82f6b48..3a5a7e6 100644
@@ -120,6 +120,13 @@
 #define CONFIG_SYS_NAND_ENABLE_PIN	AT91_PIN_PD4
 #define CONFIG_SYS_NAND_READY_PIN	AT91_PIN_PD5
 
+/* PMECC & PMERRLOC */
+#define CONFIG_ATMEL_NAND_HWECC		1
+#define CONFIG_ATMEL_NAND_HW_PMECC	1
+#define CONFIG_PMECC_CAP		2
+#define CONFIG_PMECC_SECTOR_SIZE	512
+#define CONFIG_PMECC_INDEX_TABLE_OFFSET	0x8000
+
 #define CONFIG_MTD_DEVICE
 #define CONFIG_CMD_MTDPARTS
 #define CONFIG_MTD_PARTITIONS
Signature · 1 line
1.7.9.5
author
#12 lore raw

v3 cover at91: 9x5: Enable PMECC(Programmable Multibit ECC controller) support

In reply to Josh Wu

Hi, All

Is any feedback for this rev3 patch series.

Best Regards,
Josh Wu

Quoted 33 lines · Josh Wu

This patch series will add PMECC support for atmel at91sam9x5ek in u-boot.

The NAND flash driver patch is ported from kernel patch. The main different from kernel patch is the modification about registers access part. in this version it via a register structure to access.

It is tested in atmel AT919G25EK board.

Changes since v2:
adapt atmel nand driver to CONFIG_SYS_NAND_SELF_INIT. It use a new
board_nand_init(void) function.
Add README doc for Atmel PMECC.
Add timeout for PMECC read hw status.
refine code according to Andreas and Scott's comments.

Josh Wu (5):
at91: atmel_nand: extract HWECC initialization code into one
function: atmel_hw_nand_init_param().
at91: atmel_nand: remove unused variables.
at91: atmel_nand: Update driver to support Programmable Multibit ECC
controller
at91: 9x5: change SMC config timing that both works for PMECC &
non-PMECC.
at91: 9x5: Enable PMECC for 5series ek board.

  board/atmel/at91sam9x5ek/at91sam9x5ek.c |   12 +-
  doc/README.atmel_pmecc                  |   44 ++
  drivers/mtd/nand/atmel_nand.c           |  828 ++++++++++++++++++++++++++++---
  drivers/mtd/nand/atmel_nand_ecc.h       |  113 +++++
  include/configs/at91sam9x5ek.h          |    7 +
  include/nand.h                          |    2 +-
  6 files changed, 938 insertions(+), 68 deletions(-)

create mode 100644 doc/README.atmel_pmecc

#13 lore raw

v3 cover at91: 9x5: Enable PMECC(Programmable Multibit ECC controller) support

Dear Josh Wu,

Quoted 3 lines · Josh Wu

Hi, All

Is any feedback for this rev3 patch series.

sorry, had no time yet, I will send feedback this evening (CEST).

Best regards

Andreas Bie?mann