mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: barebox@lists.infradead.org
Subject: [PATCH 09/10] mtd nand omap: add read function for the OMAP4 romcode ecc mode
Date: Tue,  8 Nov 2011 14:01:52 +0100	[thread overview]
Message-ID: <1320757313-12568-10-git-send-email-s.hauer@pengutronix.de> (raw)
In-Reply-To: <1320757313-12568-1-git-send-email-s.hauer@pengutronix.de>

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

  parent reply	other threads:[~2011-11-08 13:02 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Sascha Hauer [this message]
2011-11-08 13:01 ` [PATCH 10/10] mtd nand omap: use NAND_OWN_BUFFERS option Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1320757313-12568-10-git-send-email-s.hauer@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox