* [PATCH] OMAP gpmc nand
@ 2011-11-08 13:01 Sascha Hauer
2011-11-08 13:01 ` [PATCH 01/10] mtd nand omap: use blocknum calculation to where it's used Sascha Hauer
` (9 more replies)
0 siblings, 10 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
The following series contains several improvements to the OMAP gpmc
nand driver. The goal was to implement the reading of data in the
omap4 romcode ecc mode, but this series also contains some general
fixes to the driver found along the way.
Sascha
Sascha Hauer (10):
mtd nand omap: use blocknum calculation to where it's used
mtd nand omap: factor out bch correct function
mtd nand omap: factor out hamming correct function
mtd nand omap: call ecc calculate function outside omap_correct_bch
mtd nand omap: fail on bch decode failure
mtd nand omap: use register defines for ecc registers
mtd nand omap: make debugging output more useful
mtd nand omap: factor out an internal __omap_calculate_ecc function
mtd nand omap: add read function for the OMAP4 romcode ecc mode
mtd nand omap: use NAND_OWN_BUFFERS option
drivers/mtd/nand/nand_omap_gpmc.c | 396 +++++++++++++++++++++++++------------
1 files changed, 267 insertions(+), 129 deletions(-)
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 01/10] mtd nand omap: use blocknum calculation to where it's used
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
@ 2011-11-08 13:01 ` Sascha Hauer
2011-11-08 13:01 ` [PATCH 02/10] mtd nand omap: factor out bch correct function Sascha Hauer
` (8 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
Just some refactoring to make the next patches better readable.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_omap_gpmc.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index a012c03..f1074bb 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -362,19 +362,13 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
int ecc_type = OMAP_ECC_BCH8_CODE_HW;
int i, j, eccsize, eccflag, count;
unsigned int err_loc[8];
- int blockCnt = 0;
+ int blocks = 0;
int select_4_8;
debug("mtd=%x dat=%x read_ecc=%x calc_ecc=%x", (unsigned int)mtd,
(unsigned int)dat, (unsigned int)read_ecc,
(unsigned int)calc_ecc);
- if ((nand->ecc.mode == NAND_ECC_HW) &&
- (nand->ecc.size == 2048))
- blockCnt = 4;
- else
- blockCnt = 1;
-
switch (oinfo->ecc_mode) {
case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
if (read_ecc[0] == 0xff && read_ecc[1] == 0xff &&
@@ -415,6 +409,12 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
select_4_8 = 1;
/* fall through */
case OMAP_ECC_BCH4_CODE_HW:
+
+ if (nand->ecc.size == 2048)
+ blocks = 4;
+ else
+ blocks = 1;
+
if (ecc_type == OMAP_ECC_BCH4_CODE_HW) {
eccsize = 7;
select_4_8 = 0;
--
1.7.7
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 02/10] mtd nand omap: factor out bch correct function
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
2011-11-08 13:01 ` [PATCH 01/10] mtd nand omap: use blocknum calculation to where it's used Sascha Hauer
@ 2011-11-08 13:01 ` Sascha Hauer
2011-11-08 13:01 ` [PATCH 03/10] mtd nand omap: factor out hamming " Sascha Hauer
` (7 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
We need the bch correct algorithm in the next patches, so
factor out a seperate function for this and also safe an
indention level.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_omap_gpmc.c | 114 ++++++++++++++++++++-----------------
1 files changed, 62 insertions(+), 52 deletions(-)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index f1074bb..1b5bfaf 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -337,6 +337,66 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
return 0;
}
+static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
+ uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+ struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
+ struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
+ int i, j, eccsize, eccflag, count;
+ unsigned int err_loc[8];
+ int blocks = 0;
+ int select_4_8;
+
+ if (oinfo->ecc_mode == OMAP_ECC_BCH4_CODE_HW) {
+ eccsize = 7;
+ select_4_8 = 0;
+ } else {
+ eccsize = 13;
+ select_4_8 = 1;
+ }
+
+ if (nand->ecc.size == 2048)
+ blocks = 4;
+ else
+ blocks = 1;
+
+ omap_calculate_ecc(mtd, dat, calc_ecc);
+
+ for (i = 0; i < blocks; i++) {
+ /* check if any ecc error */
+ eccflag = 0;
+ for (j = 0; (j < eccsize) && (eccflag == 0); j++) {
+ if (calc_ecc[j] != 0)
+ eccflag = 1;
+ }
+
+ if (eccflag == 1) {
+ eccflag = 0;
+ for (j = 0; (j < eccsize) &&
+ (eccflag == 0); j++)
+ if (read_ecc[j] != 0xFF)
+ eccflag = 1;
+ }
+
+ count = 0;
+ if (eccflag == 1)
+ count = decode_bch(select_4_8, calc_ecc, err_loc);
+
+ for (j = 0; j < count; j++) {
+ if (err_loc[j] < 4096)
+ dat[err_loc[j] >> 3] ^=
+ 1 << (err_loc[j] & 7);
+ /* else, not interested to correct ecc */
+ }
+
+ calc_ecc = calc_ecc + eccsize;
+ read_ecc = read_ecc + eccsize;
+ dat += 512;
+ }
+
+ return 0;
+}
+
/**
* @brief Compares the ecc read from nand spare area with ECC
* registers values and corrects one bit error if it has occured
@@ -359,11 +419,6 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
unsigned char bit;
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
- int ecc_type = OMAP_ECC_BCH8_CODE_HW;
- int i, j, eccsize, eccflag, count;
- unsigned int err_loc[8];
- int blocks = 0;
- int select_4_8;
debug("mtd=%x dat=%x read_ecc=%x calc_ecc=%x", (unsigned int)mtd,
(unsigned int)dat, (unsigned int)read_ecc,
@@ -403,55 +458,10 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
}
}
break;
+ case OMAP_ECC_BCH4_CODE_HW:
case OMAP_ECC_BCH8_CODE_HW:
case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
- eccsize = 13;
- select_4_8 = 1;
- /* fall through */
- case OMAP_ECC_BCH4_CODE_HW:
-
- if (nand->ecc.size == 2048)
- blocks = 4;
- else
- blocks = 1;
-
- if (ecc_type == OMAP_ECC_BCH4_CODE_HW) {
- eccsize = 7;
- select_4_8 = 0;
- }
-
- omap_calculate_ecc(mtd, dat, calc_ecc);
- for (i = 0; i < blockCnt; i++) {
- /* check if any ecc error */
- eccflag = 0;
- for (j = 0; (j < eccsize) && (eccflag == 0); j++)
- if (calc_ecc[j] != 0)
- eccflag = 1;
-
- if (eccflag == 1) {
- eccflag = 0;
- for (j = 0; (j < eccsize) &&
- (eccflag == 0); j++)
- if (read_ecc[j] != 0xFF)
- eccflag = 1;
- }
-
- count = 0;
- if (eccflag == 1)
- count = decode_bch(select_4_8, calc_ecc, err_loc);
-
- for (j = 0; j < count; j++) {
- if (err_loc[j] < 4096)
- dat[err_loc[j] >> 3] ^=
- 1 << (err_loc[j] & 7);
- /* else, not interested to correct ecc */
- }
-
- calc_ecc = calc_ecc + eccsize;
- read_ecc = read_ecc + eccsize;
- dat += 512;
- }
- break;
+ return omap_correct_bch(mtd, dat, read_ecc, calc_ecc);
default:
return -EINVAL;
}
--
1.7.7
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 03/10] mtd nand omap: factor out hamming correct function
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
2011-11-08 13:01 ` [PATCH 01/10] mtd nand omap: use blocknum calculation to where it's used Sascha Hauer
2011-11-08 13:01 ` [PATCH 02/10] mtd nand omap: factor out bch correct function Sascha Hauer
@ 2011-11-08 13:01 ` Sascha Hauer
2011-11-08 13:01 ` [PATCH 04/10] mtd nand omap: call ecc calculate function outside omap_correct_bch Sascha Hauer
` (6 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
To be consistent also factor out the hamming correct function
and also safe an indention level.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_omap_gpmc.c | 80 +++++++++++++++++++++----------------
1 files changed, 45 insertions(+), 35 deletions(-)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 1b5bfaf..0713b64 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -397,6 +397,50 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
return 0;
}
+static int omap_correct_hamming(struct mtd_info *mtd, uint8_t *dat,
+ uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+ unsigned int orig_ecc, new_ecc, res, hm;
+ unsigned short parity_bits, byte;
+ unsigned char bit;
+ struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
+ struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
+
+ if (read_ecc[0] == 0xff && read_ecc[1] == 0xff &&
+ read_ecc[2] == 0xff && calc_ecc[0] == 0x0 &&
+ calc_ecc[1] == 0x0 && calc_ecc[0] == 0x0)
+ return 0;
+
+ /* Regenerate the orginal ECC */
+ orig_ecc = gen_true_ecc(read_ecc);
+ new_ecc = gen_true_ecc(calc_ecc);
+ /* Get the XOR of real ecc */
+ res = orig_ecc ^ new_ecc;
+ if (res) {
+ /* Get the hamming width */
+ hm = hweight32(res);
+ /* Single bit errors can be corrected! */
+ if (hm == oinfo->ecc_parity_pairs) {
+ /* Correctable data! */
+ parity_bits = res >> 16;
+ bit = (parity_bits & 0x7);
+ byte = (parity_bits >> 3) & 0x1FF;
+ /* Flip the bit to correct */
+ dat[byte] ^= (0x1 << bit);
+ } else if (hm == 1) {
+ printf("Ecc is wrong\n");
+ /* ECC itself is corrupted */
+ return 2;
+ } else {
+ printf("bad compare! failed\n");
+ /* detected 2 bit error */
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
/**
* @brief Compares the ecc read from nand spare area with ECC
* registers values and corrects one bit error if it has occured
@@ -414,9 +458,6 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
uint8_t *read_ecc, uint8_t *calc_ecc)
{
- unsigned int orig_ecc, new_ecc, res, hm;
- unsigned short parity_bits, byte;
- unsigned char bit;
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
@@ -426,38 +467,7 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
switch (oinfo->ecc_mode) {
case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
- if (read_ecc[0] == 0xff && read_ecc[1] == 0xff &&
- read_ecc[2] == 0xff && calc_ecc[0] == 0x0 &&
- calc_ecc[1] == 0x0 && calc_ecc[0] == 0x0)
- break;
-
- /* Regenerate the orginal ECC */
- orig_ecc = gen_true_ecc(read_ecc);
- new_ecc = gen_true_ecc(calc_ecc);
- /* Get the XOR of real ecc */
- res = orig_ecc ^ new_ecc;
- if (res) {
- /* Get the hamming width */
- hm = hweight32(res);
- /* Single bit errors can be corrected! */
- if (hm == oinfo->ecc_parity_pairs) {
- /* Correctable data! */
- parity_bits = res >> 16;
- bit = (parity_bits & 0x7);
- byte = (parity_bits >> 3) & 0x1FF;
- /* Flip the bit to correct */
- dat[byte] ^= (0x1 << bit);
- } else if (hm == 1) {
- printf("Ecc is wrong\n");
- /* ECC itself is corrupted */
- return 2;
- } else {
- printf("bad compare! failed\n");
- /* detected 2 bit error */
- return -1;
- }
- }
- break;
+ return omap_correct_hamming(mtd, dat, read_ecc, calc_ecc);
case OMAP_ECC_BCH4_CODE_HW:
case OMAP_ECC_BCH8_CODE_HW:
case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
--
1.7.7
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 04/10] mtd nand omap: call ecc calculate function outside omap_correct_bch
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
` (2 preceding siblings ...)
2011-11-08 13:01 ` [PATCH 03/10] mtd nand omap: factor out hamming " Sascha Hauer
@ 2011-11-08 13:01 ` Sascha Hauer
2011-11-08 13:01 ` [PATCH 05/10] mtd nand omap: fail on bch decode failure Sascha Hauer
` (5 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
Move omap_calculate_ecc outside omap_correct_bch. When implementing
the romcode bch read page we have to call omap_calculate_ecc with
different arguments than in the standard case.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_omap_gpmc.c | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 0713b64..8dd6b8c 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -360,8 +360,6 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
else
blocks = 1;
- omap_calculate_ecc(mtd, dat, calc_ecc);
-
for (i = 0; i < blocks; i++) {
/* check if any ecc error */
eccflag = 0;
@@ -471,6 +469,12 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
case OMAP_ECC_BCH4_CODE_HW:
case OMAP_ECC_BCH8_CODE_HW:
case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
+ /*
+ * The nand layer already called omap_calculate_ecc,
+ * but before it has read the oob data. Do it again,
+ * this time with oob data.
+ */
+ omap_calculate_ecc(mtd, dat, calc_ecc);
return omap_correct_bch(mtd, dat, read_ecc, calc_ecc);
default:
return -EINVAL;
--
1.7.7
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 05/10] mtd nand omap: fail on bch decode failure
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
` (3 preceding siblings ...)
2011-11-08 13:01 ` [PATCH 04/10] mtd nand omap: call ecc calculate function outside omap_correct_bch Sascha Hauer
@ 2011-11-08 13:01 ` Sascha Hauer
2011-11-08 13:01 ` [PATCH 06/10] mtd nand omap: use register defines for ecc registers Sascha Hauer
` (4 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
The driver used to print an error when bch decoing failed, but
did not actually throw an error. Fix this.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_omap_gpmc.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 8dd6b8c..9097dde 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -377,8 +377,11 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
}
count = 0;
- if (eccflag == 1)
+ if (eccflag == 1) {
count = decode_bch(select_4_8, calc_ecc, err_loc);
+ if (count < 0)
+ return count;
+ }
for (j = 0; j < count; j++) {
if (err_loc[j] < 4096)
--
1.7.7
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 06/10] mtd nand omap: use register defines for ecc registers
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
` (4 preceding siblings ...)
2011-11-08 13:01 ` [PATCH 05/10] mtd nand omap: fail on bch decode failure Sascha Hauer
@ 2011-11-08 13:01 ` Sascha Hauer
2011-11-08 13:01 ` [PATCH 07/10] mtd nand omap: make debugging output more useful Sascha Hauer
` (3 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
We need this register bits later in another function, so
use register bit defines now.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_omap_gpmc.c | 51 +++++++++++++++++++++++++++++--------
1 files changed, 40 insertions(+), 11 deletions(-)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 9097dde..50e0544 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -76,6 +76,20 @@
#include <mach/gpmc.h>
#include <mach/gpmc_nand.h>
+#define GPMC_ECC_CONFIG_ECCENABLE (1 << 0)
+#define GPMC_ECC_CONFIG_ECCCS(x) (((x) & 0x7) << 1)
+#define GPMC_ECC_CONFIG_ECCTOPSECTOR(x) (((x) & 0x7) << 4)
+#define GPMC_ECC_CONFIG_ECC16B (1 << 7)
+#define GPMC_ECC_CONFIG_ECCWRAPMODE(x) (((x) & 0xf) << 8)
+#define GPMC_ECC_CONFIG_ECCBCHTSEL(x) (((x) & 0x3) << 12)
+#define GPMC_ECC_CONFIG_ECCALGORITHM (1 << 16)
+
+#define GPMC_ECC_CONTROL_ECCPOINTER(x) ((x) & 0xf)
+#define GPMC_ECC_CONTROL_ECCCLEAR (1 << 8)
+
+#define GPMC_ECC_SIZE_CONFIG_ECCSIZE0(x) ((x) << 12)
+#define GPMC_ECC_SIZE_CONFIG_ECCSIZE1(x) ((x) << 22)
+
int decode_bch(int select_4_8, unsigned char *ecc, unsigned int *err_loc);
static char *ecc_mode_strings[] = {
@@ -492,7 +506,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
unsigned int bch_mod = 0, bch_wrapmode = 0, eccsize1 = 0, eccsize0 = 0;
unsigned int ecc_conf_val = 0, ecc_size_conf_val = 0;
- int dev_width = nand->options & NAND_BUSWIDTH_16 ? 1 : 0;
+ int dev_width = nand->options & NAND_BUSWIDTH_16 ? GPMC_ECC_CONFIG_ECC16B : 0;
int ecc_size = nand->ecc.size;
int cs = 0;
@@ -529,24 +543,39 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
/* clear ecc and enable bits */
if (oinfo->ecc_mode == OMAP_ECC_HAMMING_CODE_HW_ROMCODE) {
- writel(0x00000101, oinfo->gpmc_base + GPMC_ECC_CONTROL);
- /* Size 0 = 0xFF, Size1 is 0xFF - both are 512 bytes
+ writel(GPMC_ECC_CONTROL_ECCCLEAR |
+ GPMC_ECC_CONTROL_ECCPOINTER(1),
+ oinfo->gpmc_base + GPMC_ECC_CONTROL);
+
+ /*
+ * Size 0 = 0xFF, Size1 is 0xFF - both are 512 bytes
* tell all regs to generate size0 sized regs
* we just have a single ECC engine for all CS
*/
- ecc_size_conf_val = 0x3FCFF000;
- ecc_conf_val = (dev_width << 7) | (cs << 1) | (0x1);
+ ecc_size_conf_val = GPMC_ECC_SIZE_CONFIG_ECCSIZE1(0xff) |
+ GPMC_ECC_SIZE_CONFIG_ECCSIZE0(0xff);
+ ecc_conf_val = dev_width | GPMC_ECC_CONFIG_ECCCS(cs) |
+ GPMC_ECC_CONFIG_ECCENABLE;
} else {
- writel(0x1, oinfo->gpmc_base + GPMC_ECC_CONTROL);
- ecc_size_conf_val = (eccsize1 << 22) | (eccsize0 << 12);
- ecc_conf_val = ((0x01 << 16) | (bch_mod << 12)
- | (bch_wrapmode << 8) | (dev_width << 7)
- | (0x03 << 4) | (cs << 1) | (0x1));
+ writel(GPMC_ECC_CONTROL_ECCPOINTER(1),
+ oinfo->gpmc_base + GPMC_ECC_CONTROL);
+
+ ecc_size_conf_val = GPMC_ECC_SIZE_CONFIG_ECCSIZE1(eccsize1) |
+ GPMC_ECC_SIZE_CONFIG_ECCSIZE0(eccsize0);
+
+ ecc_conf_val = (GPMC_ECC_CONFIG_ECCALGORITHM |
+ GPMC_ECC_CONFIG_ECCBCHTSEL(bch_mod) |
+ GPMC_ECC_CONFIG_ECCWRAPMODE(bch_wrapmode) |
+ dev_width |
+ GPMC_ECC_CONFIG_ECCTOPSECTOR(3) |
+ GPMC_ECC_CONFIG_ECCCS(cs) |
+ GPMC_ECC_CONFIG_ECCENABLE);
}
writel(ecc_size_conf_val, oinfo->gpmc_base + GPMC_ECC_SIZE_CONFIG);
writel(ecc_conf_val, oinfo->gpmc_base + GPMC_ECC_CONFIG);
- writel(0x00000101, oinfo->gpmc_base + GPMC_ECC_CONTROL);
+ writel(GPMC_ECC_CONTROL_ECCCLEAR | GPMC_ECC_CONTROL_ECCPOINTER(1),
+ oinfo->gpmc_base + GPMC_ECC_CONTROL);
}
static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
--
1.7.7
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 07/10] mtd nand omap: make debugging output more useful
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
` (5 preceding siblings ...)
2011-11-08 13:01 ` [PATCH 06/10] mtd nand omap: use register defines for ecc registers Sascha Hauer
@ 2011-11-08 13:01 ` Sascha Hauer
2011-11-08 13:01 ` [PATCH 08/10] mtd nand omap: factor out an internal __omap_calculate_ecc function Sascha Hauer
` (2 subsequent siblings)
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
- add missing '\n' at line ends
- fix wrong argument type warnings
- remove too noisy debug in omap_hwcontrol
- add function names to debug printfs
- add 0x prefixes to hex values
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_omap_gpmc.c | 27 ++++++++++-----------------
1 files changed, 10 insertions(+), 17 deletions(-)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 50e0544..e3c77ec 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -194,14 +194,13 @@ static int omap_dev_ready(struct mtd_info *mtd)
uint64_t start = get_time_ns();
unsigned long comp;
- debug("mtd=%x", (unsigned int)mtd);
/* What do we mean by assert and de-assert? */
comp = (oinfo->wait_pol == NAND_WAITPOL_HIGH) ?
oinfo->wait_mon_mask : 0x0;
while (1) {
/* Breakout condition */
if (is_timeout(start, oinfo->timeout)) {
- debug("timedout\n");
+ debug("%s timedout\n", __func__);
return -ETIMEDOUT;
}
/* if the wait is released, we are good to go */
@@ -226,7 +225,8 @@ static void gpmc_nand_wp(struct gpmc_nand_info *oinfo, int mode)
{
unsigned long config = readl(oinfo->gpmc_base + GPMC_CFG);
- debug("mode=%x", mode);
+ debug("%s: mode=%x\n", __func__, mode);
+
if (mode)
config &= ~(NAND_WP_BIT); /* WP is ON */
else
@@ -251,8 +251,7 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
- debug("mtd=%x nand=%x cmd=%x ctrl = %x", (unsigned int)mtd, nand,
- cmd, ctrl);
+
switch (ctrl) {
case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
nand->IO_ADDR_W = oinfo->gpmc_command;
@@ -285,8 +284,9 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
*/
static unsigned int gen_true_ecc(u8 *ecc_buf)
{
- debug("ecc_buf=%x 1, 2 3 = %x %x %x", (unsigned int)ecc_buf,
+ debug("%s: eccbuf: 0x%02x 0x%02x 0x%02x\n", __func__,
ecc_buf[0], ecc_buf[1], ecc_buf[2]);
+
return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
((ecc_buf[2] & 0x0F) << 8);
}
@@ -476,9 +476,7 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
- debug("mtd=%x dat=%x read_ecc=%x calc_ecc=%x", (unsigned int)mtd,
- (unsigned int)dat, (unsigned int)read_ecc,
- (unsigned int)calc_ecc);
+ debug("%s\n", __func__);
switch (oinfo->ecc_mode) {
case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
@@ -766,14 +764,9 @@ static int gpmc_nand_probe(struct device_d *pdev)
oinfo->gpmc_address = (void *)(cs_base + GPMC_CS_NAND_ADDRESS);
oinfo->gpmc_data = (void *)(cs_base + GPMC_CS_NAND_DATA);
oinfo->timeout = pdata->max_timeout;
- debug("GPMC Details:\n"
- "GPMC BASE=%x\n"
- "CMD=%x\n"
- "ADDRESS=%x\n"
- "DATA=%x\n"
- "CS_BASE=%x\n",
- oinfo->gpmc_base, oinfo->gpmc_command,
- oinfo->gpmc_address, oinfo->gpmc_data, cs_base);
+ dev_dbg(pdev, "GPMC base=0x%p cmd=0x%p address=0x%p data=0x%p cs_base=0x%p\n",
+ oinfo->gpmc_base, oinfo->gpmc_command, oinfo->gpmc_address,
+ oinfo->gpmc_data, cs_base);
/* If we are 16 bit dev, our gpmc config tells us that */
if ((readl(cs_base) & 0x3000) == 0x1000) {
--
1.7.7
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 08/10] mtd nand omap: factor out an internal __omap_calculate_ecc function
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
` (6 preceding siblings ...)
2011-11-08 13:01 ` [PATCH 07/10] mtd nand omap: make debugging output more useful Sascha Hauer
@ 2011-11-08 13:01 ` Sascha Hauer
2011-11-08 13:01 ` [PATCH 09/10] mtd nand omap: add read function for the OMAP4 romcode ecc mode Sascha Hauer
2011-11-08 13:01 ` [PATCH 10/10] mtd nand omap: use NAND_OWN_BUFFERS option Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
We can't use the ECC_RESULTx_0 register set for manual mode which
we'll need in the next patch. So factor out an internal function
which makes the register set to use configurable.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_omap_gpmc.c | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index e3c77ec..e6555bb 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -291,8 +291,8 @@ static unsigned int gen_true_ecc(u8 *ecc_buf)
((ecc_buf[2] & 0x0F) << 8);
}
-static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
- uint8_t *ecc_code)
+static int __omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
+ uint8_t *ecc_code, int sblock)
{
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
@@ -313,7 +313,7 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
* Reading HW ECC_BCH_Results
* 0x240-0x24C, 0x250-0x25C, 0x260-0x26C, 0x270-0x27C
*/
- reg = GPMC_ECC_BCH_RESULT_0 + (0x10 * i);
+ reg = GPMC_ECC_BCH_RESULT_0 + (0x10 * (i + sblock));
val1 = readl(oinfo->gpmc_base + reg);
val2 = readl(oinfo->gpmc_base + reg + 4);
if (ecc_size == 8) {
@@ -351,6 +351,12 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
return 0;
}
+static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
+ uint8_t *ecc_code)
+{
+ return __omap_calculate_ecc(mtd, dat, ecc_code, 0);
+}
+
static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
uint8_t *read_ecc, uint8_t *calc_ecc)
{
@@ -489,7 +495,7 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
* but before it has read the oob data. Do it again,
* this time with oob data.
*/
- omap_calculate_ecc(mtd, dat, calc_ecc);
+ __omap_calculate_ecc(mtd, dat, calc_ecc, 0);
return omap_correct_bch(mtd, dat, read_ecc, calc_ecc);
default:
return -EINVAL;
--
1.7.7
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 09/10] mtd nand omap: add read function for the OMAP4 romcode ecc mode
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
` (7 preceding siblings ...)
2011-11-08 13:01 ` [PATCH 08/10] mtd nand omap: factor out an internal __omap_calculate_ecc function Sascha Hauer
@ 2011-11-08 13:01 ` Sascha Hauer
2011-11-08 13:01 ` [PATCH 10/10] mtd nand omap: use NAND_OWN_BUFFERS option Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
The OMAP4 romcode expects some unusual ecc layout which we could
write but not read. This patch adds a function which uses the
manual mode to read a page written with this ecc layout.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_omap_gpmc.c | 99 ++++++++++++++++++++++++++++++++++---
1 files changed, 91 insertions(+), 8 deletions(-)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index e6555bb..765a0d6 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -582,6 +582,96 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
oinfo->gpmc_base + GPMC_ECC_CONTROL);
}
+static int omap_gpmc_read_buf_manual(struct mtd_info *mtd, struct nand_chip *chip,
+ void *buf, int bytes, int result_reg)
+{
+ struct gpmc_nand_info *oinfo = chip->priv;
+
+ writel(GPMC_ECC_SIZE_CONFIG_ECCSIZE1(0) |
+ GPMC_ECC_SIZE_CONFIG_ECCSIZE0(bytes * 2),
+ oinfo->gpmc_base + GPMC_ECC_SIZE_CONFIG);
+
+ writel(GPMC_ECC_CONTROL_ECCPOINTER(result_reg),
+ oinfo->gpmc_base + GPMC_ECC_CONTROL);
+
+ chip->read_buf(mtd, buf, bytes);
+
+ return bytes;
+}
+
+/*
+ * read a page with the ecc layout used by the OMAP4 romcode. The
+ * romcode expects an unusual ecc layout (f = free, e = ecc):
+ *
+ * 2f, 13e, 1f, 13e, 1f, 13e, 1f, 13e, 7f
+ *
+ * This can't be accomplished with the predefined ecc modes, so
+ * we have to use the manual mode here.
+ *
+ * For the manual mode we can't use the ECC_RESULTx_0 register set
+ * because it would disable ecc generation completeley. Also, the
+ * hardware seems to ignore eccsize1 (which should bypass ecc
+ * generation), so we use the otherwise unused ECC_RESULTx_5 to
+ * generate dummy eccs for the unprotected oob area.
+ */
+static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf)
+{
+ struct gpmc_nand_info *oinfo = chip->priv;
+ int dev_width = chip->options & NAND_BUSWIDTH_16 ? GPMC_ECC_CONFIG_ECC16B : 0;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+ int stat, i;
+
+ writel(GPMC_ECC_SIZE_CONFIG_ECCSIZE1(0) |
+ GPMC_ECC_SIZE_CONFIG_ECCSIZE0(64),
+ oinfo->gpmc_base + GPMC_ECC_SIZE_CONFIG);
+
+ writel(GPMC_ECC_CONTROL_ECCPOINTER(1),
+ oinfo->gpmc_base + GPMC_ECC_CONTROL);
+
+ writel(GPMC_ECC_CONFIG_ECCALGORITHM |
+ GPMC_ECC_CONFIG_ECCBCHTSEL(1) |
+ GPMC_ECC_CONFIG_ECCWRAPMODE(0) |
+ dev_width | GPMC_ECC_CONFIG_ECCTOPSECTOR(3) |
+ GPMC_ECC_CONFIG_ECCCS(0) |
+ GPMC_ECC_CONFIG_ECCENABLE,
+ oinfo->gpmc_base + GPMC_ECC_CONFIG);
+
+ writel(GPMC_ECC_CONTROL_ECCCLEAR |
+ GPMC_ECC_CONTROL_ECCPOINTER(1),
+ oinfo->gpmc_base + GPMC_ECC_CONTROL);
+
+ for (i = 0; i < 32; i++)
+ p += omap_gpmc_read_buf_manual(mtd, chip, p, 64, (i >> 3) + 1);
+
+ p = chip->oob_poi;
+
+ p += omap_gpmc_read_buf_manual(mtd, chip, p, 2, 5);
+
+ for (i = 0; i < 4; i++) {
+ p += omap_gpmc_read_buf_manual(mtd, chip, p, 13, i + 1);
+ p += omap_gpmc_read_buf_manual(mtd, chip, p, 1, 5);
+ }
+
+ p += omap_gpmc_read_buf_manual(mtd, chip, p, 6, 5);
+
+ for (i = 0; i < chip->ecc.total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+
+ __omap_calculate_ecc(mtd, buf, ecc_calc, 1);
+
+ stat = omap_correct_bch(mtd, buf, ecc_code, ecc_calc);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+
+ return 0;
+}
+
static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
enum gpmc_ecc_mode mode)
{
@@ -651,16 +741,9 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
omap_oobinfo.eccpos[i] = i + offset;
break;
case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
- /*
- * Contradicting the datasheet the ecc checksum has to start
- * at byte 2 in oob. I have no idea how the rom code can
- * read this but it does.
- */
- dev_warn(oinfo->pdev, "using rom loader ecc mode. "
- "You can write properly but not read it back\n");
-
oinfo->nand.ecc.bytes = 4 * 13;
oinfo->nand.ecc.size = 4 * 512;
+ nand->ecc.read_page = omap_gpmc_read_page_bch_rom_mode;
omap_oobinfo.oobfree->length = 0;
j = 0;
for (i = 2; i < 15; i++)
--
1.7.7
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 10/10] mtd nand omap: use NAND_OWN_BUFFERS option
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
` (8 preceding siblings ...)
2011-11-08 13:01 ` [PATCH 09/10] mtd nand omap: add read function for the OMAP4 romcode ecc mode Sascha Hauer
@ 2011-11-08 13:01 ` Sascha Hauer
9 siblings, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2011-11-08 13:01 UTC (permalink / raw)
To: barebox
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_omap_gpmc.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 765a0d6..d5e642a 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -765,9 +765,6 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
oinfo->ecc_mode = mode;
- if (nand->buffers)
- kfree(nand->buffers);
-
/* second phase scan */
if (nand_scan_tail(minfo))
return -ENXIO;
@@ -897,6 +894,9 @@ static int gpmc_nand_probe(struct device_d *pdev)
/* Dont do a bbt scan at the start */
nand->options |= NAND_SKIP_BBTSCAN;
+ nand->options |= NAND_OWN_BUFFERS;
+ nand->buffers = xzalloc(sizeof(*nand->buffers));
+
/* State my controller */
nand->controller = &oinfo->controller;
--
1.7.7
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2011-11-08 13:02 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-08 13:01 [PATCH] OMAP gpmc nand Sascha Hauer
2011-11-08 13:01 ` [PATCH 01/10] mtd nand omap: use blocknum calculation to where it's used Sascha Hauer
2011-11-08 13:01 ` [PATCH 02/10] mtd nand omap: factor out bch correct function Sascha Hauer
2011-11-08 13:01 ` [PATCH 03/10] mtd nand omap: factor out hamming " Sascha Hauer
2011-11-08 13:01 ` [PATCH 04/10] mtd nand omap: call ecc calculate function outside omap_correct_bch Sascha Hauer
2011-11-08 13:01 ` [PATCH 05/10] mtd nand omap: fail on bch decode failure Sascha Hauer
2011-11-08 13:01 ` [PATCH 06/10] mtd nand omap: use register defines for ecc registers Sascha Hauer
2011-11-08 13:01 ` [PATCH 07/10] mtd nand omap: make debugging output more useful Sascha Hauer
2011-11-08 13:01 ` [PATCH 08/10] mtd nand omap: factor out an internal __omap_calculate_ecc function Sascha Hauer
2011-11-08 13:01 ` [PATCH 09/10] mtd nand omap: add read function for the OMAP4 romcode ecc mode Sascha Hauer
2011-11-08 13:01 ` [PATCH 10/10] mtd nand omap: use NAND_OWN_BUFFERS option Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox