From 9449252787861fa476a8586067436eaa54d81d69 Mon Sep 17 00:00:00 2001
From: Holger Freyther <ich@tamarin.(none)>
Date: Sat, 26 Jul 2008 22:49:23 +0200
Subject: [PATCH] [s3c2440] Enable hardware ECC for large page NAND devices
     Enable hardware ECC for the s3c2442 CPU and large page (2K) NAND pages as
     used by the freerunner (gta02). NAND_ECC_HW3_256 was picked to be
     compatible with the Linux kernel. The values of ECC have not been verified.

    This way we can flash the kernel and rootfs from uboot and be able to use
    that from the kernel.
---
 cpu/arm920t/s3c24x0/nand.c      |   54 ++++++++++++++++++++++++++++++++++----
 include/configs/neo1973_gta02.h |    4 +-
 2 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/cpu/arm920t/s3c24x0/nand.c b/cpu/arm920t/s3c24x0/nand.c
index 2d76798..73a9f6b 100644
--- a/cpu/arm920t/s3c24x0/nand.c
+++ b/cpu/arm920t/s3c24x0/nand.c
@@ -1,6 +1,7 @@
 /*
  * (C) Copyright 2006 OpenMoko, Inc.
  * Author: Harald Welte <laforge@openmoko.org>
+ *         Holger Freyther <zecke@openmoko.org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -200,18 +201,50 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
 	return 0;
 }
 
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
-				     u_char *read_ecc, u_char *calc_ecc)
+#endif
+
+#ifdef CONFIG_S3C2440_NAND_HWECC
+static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+	DEBUGN("%s(%p, %d)\n", __func__, mtd, mode);
+
+	/* 
+	 * In software mode, ECC module generates ECC parity code for all
+	 * read / write data. So you have to reset ECC value by writing the
+	 * InitECC(NFCONT[4]) bit as ‘1’ and have to clear theMainECCLock(
+	 * NFCONT[5]) bit to ‘0’(Unlock) before read or write data.
+	 */
+	NFCONT |= S3C2440_NFCONF_INITECC;
+	NFCONT &= ~S3C2440_NFCONF_MAINECCLOCK;
+}
+
+static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+                                      u_char *ecc_code)
+{
+	unsigned long ecc = NFMECC0;
+
+	ecc_code[0] = ecc;
+	ecc_code[1] = ecc >> 8;
+	ecc_code[2] = ecc >> 16;
+
+	DEBUGN("%s(%p,): 0x%02x 0x%02x 0x%02x\n",
+		__func__, mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
+
+	return 0;
+}
+#endif
+
+static int s3c24xx_nand_correct_data_noop(struct mtd_info *mtd, u_char *dat,
+				          u_char *read_ecc, u_char *calc_ecc)
 {
 	if (read_ecc[0] == calc_ecc[0] &&
 	    read_ecc[1] == calc_ecc[1] &&
 	    read_ecc[2] == calc_ecc[2])
 		return 0;
 
-	printf("s3c2410_nand_correct_data: not implemented\n");
+	printf("%s: not implemented\n", __func__);
 	return -1;
 }
-#endif
 
 int board_nand_init(void) __attribute__((weak, alias("__board_nand_init")));
 
@@ -252,11 +285,20 @@ int __board_nand_init(struct nand_chip *nand)
 
 	nand->dev_ready = s3c2410_dev_ready;
 
-#ifdef CONFIG_S3C2410_NAND_HWECC
+#if defined(CONFIG_S3C2410_NAND_HWECC)
 	nand->enable_hwecc = s3c2410_nand_enable_hwecc;
 	nand->calculate_ecc = s3c2410_nand_calculate_ecc;
-	nand->correct_data = s3c2410_nand_correct_data;
+	nand->correct_data = s3c24xx_nand_correct_data_noop;
 	nand->eccmode = NAND_ECC_HW3_512;
+#elif defined(CONFIG_S3C2440_NAND_HWECC)
+	/*
+	 * Assume we have a large page flash and set the eccmode so that it 
+	 * will be compatible with the linux kernel.
+         */
+	nand->enable_hwecc = s3c2440_nand_enable_hwecc;
+	nand->calculate_ecc = s3c2440_nand_calculate_ecc;
+	nand->correct_data = s3c24xx_nand_correct_data_noop;
+	nand->eccmode = NAND_ECC_HW3_256;
 #else
 	nand->eccmode = NAND_ECC_SOFT;
 #endif
diff --git a/include/configs/neo1973_gta02.h b/include/configs/neo1973_gta02.h
index d69d348..9133545 100644
--- a/include/configs/neo1973_gta02.h
+++ b/include/configs/neo1973_gta02.h
@@ -194,7 +194,7 @@ extern char __cfg_prompt[20];
 #define CONFIG_EXTRA_ENV_SETTINGS 					\
 	"usbtty=cdc_acm\0"						\
 	"stderr=usbtty\0stdout=usbtty\0stdin=usbtty\0"			\
-	"bootargs_base=rootfstype=jffs2 root=/dev/mtdblock6 console=ttySAC2,115200 console=tty0 loglevel=8\0" \
+	"bootargs_base=rootfstype=jffs2 root=/dev/mtdblock6 console=ttySAC2,115200 console=tty0 loglevel=8 hardware_ecc=1\0" \
 	""
 #define CONFIG_CMD_LOADENV
 #define CONFIG_CMD_DEFAULTENV
@@ -281,7 +281,7 @@ extern char __cfg_prompt[20];
 #endif
 
 #define CONFIG_S3C2410_NAND_BBT                1
-//#define CONFIG_S3C2410_NAND_HWECC              1
+#define CONFIG_S3C2440_NAND_HWECC              1
 
 #define CONFIG_DRIVER_PCF50633		1
 #define	CONFIG_RTC_PCF50633		1
-- 
1.5.4.3

