173 lines
4.7 KiB
Diff
173 lines
4.7 KiB
Diff
|
From 3677d22ed7e3a631f35e2addc4e2181f6215e4b0 Mon Sep 17 00:00:00 2001
|
||
|
From: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||
|
Date: Thu, 14 Nov 2013 18:25:29 -0300
|
||
|
Subject: [PATCH 143/203] mtd: nand: pxa3xx: Add driver-specific ECC BCH
|
||
|
support
|
||
|
|
||
|
This commit adds the BCH ECC support available in NFCv2 controller.
|
||
|
Depending on the detected required strength the respective ECC layout
|
||
|
is selected.
|
||
|
|
||
|
This commit adds an empty ECC layout, since support to access large
|
||
|
pages is first required. Once that support is added, a proper ECC
|
||
|
layout will be added as well.
|
||
|
|
||
|
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
|
||
|
Tested-by: Daniel Mack <zonque@gmail.com>
|
||
|
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||
|
---
|
||
|
drivers/mtd/nand/pxa3xx_nand.c | 86 +++++++++++++++++++++++++++++++++---------
|
||
|
1 file changed, 69 insertions(+), 17 deletions(-)
|
||
|
|
||
|
--- a/drivers/mtd/nand/pxa3xx_nand.c
|
||
|
+++ b/drivers/mtd/nand/pxa3xx_nand.c
|
||
|
@@ -58,6 +58,7 @@
|
||
|
#define NDPCR (0x18) /* Page Count Register */
|
||
|
#define NDBDR0 (0x1C) /* Bad Block Register 0 */
|
||
|
#define NDBDR1 (0x20) /* Bad Block Register 1 */
|
||
|
+#define NDECCCTRL (0x28) /* ECC control */
|
||
|
#define NDDB (0x40) /* Data Buffer */
|
||
|
#define NDCB0 (0x48) /* Command Buffer0 */
|
||
|
#define NDCB1 (0x4C) /* Command Buffer1 */
|
||
|
@@ -198,6 +199,7 @@ struct pxa3xx_nand_info {
|
||
|
|
||
|
int cs;
|
||
|
int use_ecc; /* use HW ECC ? */
|
||
|
+ int ecc_bch; /* using BCH ECC? */
|
||
|
int use_dma; /* use DMA ? */
|
||
|
int use_spare; /* use spare ? */
|
||
|
int need_wait;
|
||
|
@@ -205,6 +207,8 @@ struct pxa3xx_nand_info {
|
||
|
unsigned int fifo_size; /* max. data size in the FIFO */
|
||
|
unsigned int data_size; /* data to be read from FIFO */
|
||
|
unsigned int oob_size;
|
||
|
+ unsigned int spare_size;
|
||
|
+ unsigned int ecc_size;
|
||
|
int retcode;
|
||
|
|
||
|
/* cached register value */
|
||
|
@@ -339,19 +343,12 @@ static void pxa3xx_set_datasize(struct p
|
||
|
int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
|
||
|
|
||
|
info->data_size = info->fifo_size;
|
||
|
- if (!oob_enable) {
|
||
|
- info->oob_size = 0;
|
||
|
+ if (!oob_enable)
|
||
|
return;
|
||
|
- }
|
||
|
|
||
|
- switch (info->fifo_size) {
|
||
|
- case 2048:
|
||
|
- info->oob_size = (info->use_ecc) ? 40 : 64;
|
||
|
- break;
|
||
|
- case 512:
|
||
|
- info->oob_size = (info->use_ecc) ? 8 : 16;
|
||
|
- break;
|
||
|
- }
|
||
|
+ info->oob_size = info->spare_size;
|
||
|
+ if (!info->use_ecc)
|
||
|
+ info->oob_size += info->ecc_size;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@@ -366,10 +363,15 @@ static void pxa3xx_nand_start(struct pxa
|
||
|
|
||
|
ndcr = info->reg_ndcr;
|
||
|
|
||
|
- if (info->use_ecc)
|
||
|
+ if (info->use_ecc) {
|
||
|
ndcr |= NDCR_ECC_EN;
|
||
|
- else
|
||
|
+ if (info->ecc_bch)
|
||
|
+ nand_writel(info, NDECCCTRL, 0x1);
|
||
|
+ } else {
|
||
|
ndcr &= ~NDCR_ECC_EN;
|
||
|
+ if (info->ecc_bch)
|
||
|
+ nand_writel(info, NDECCCTRL, 0x0);
|
||
|
+ }
|
||
|
|
||
|
if (info->use_dma)
|
||
|
ndcr |= NDCR_DMA_EN;
|
||
|
@@ -1071,6 +1073,41 @@ static int pxa3xx_nand_sensing(struct px
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static int pxa_ecc_init(struct pxa3xx_nand_info *info,
|
||
|
+ struct nand_ecc_ctrl *ecc,
|
||
|
+ int strength, int page_size)
|
||
|
+{
|
||
|
+ /*
|
||
|
+ * We don't use strength here as the PXA variant
|
||
|
+ * is used with non-ONFI compliant devices.
|
||
|
+ */
|
||
|
+ if (page_size == 2048) {
|
||
|
+ info->spare_size = 40;
|
||
|
+ info->ecc_size = 24;
|
||
|
+ ecc->mode = NAND_ECC_HW;
|
||
|
+ ecc->size = 512;
|
||
|
+ ecc->strength = 1;
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ } else if (page_size == 512) {
|
||
|
+ info->spare_size = 8;
|
||
|
+ info->ecc_size = 8;
|
||
|
+ ecc->mode = NAND_ECC_HW;
|
||
|
+ ecc->size = 512;
|
||
|
+ ecc->strength = 1;
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int armada370_ecc_init(struct pxa3xx_nand_info *info,
|
||
|
+ struct nand_ecc_ctrl *ecc,
|
||
|
+ int strength, int page_size)
|
||
|
+{
|
||
|
+ /* Unimplemented yet */
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int pxa3xx_nand_scan(struct mtd_info *mtd)
|
||
|
{
|
||
|
struct pxa3xx_nand_host *host = mtd->priv;
|
||
|
@@ -1141,13 +1178,13 @@ static int pxa3xx_nand_scan(struct mtd_i
|
||
|
pxa3xx_flash_ids[1].name = NULL;
|
||
|
def = pxa3xx_flash_ids;
|
||
|
KEEP_CONFIG:
|
||
|
- chip->ecc.mode = NAND_ECC_HW;
|
||
|
- chip->ecc.size = info->fifo_size;
|
||
|
- chip->ecc.strength = 1;
|
||
|
-
|
||
|
if (info->reg_ndcr & NDCR_DWIDTH_M)
|
||
|
chip->options |= NAND_BUSWIDTH_16;
|
||
|
|
||
|
+ /* Device detection must be done with ECC disabled */
|
||
|
+ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
|
||
|
+ nand_writel(info, NDECCCTRL, 0x0);
|
||
|
+
|
||
|
if (nand_scan_ident(mtd, 1, def))
|
||
|
return -ENODEV;
|
||
|
|
||
|
@@ -1162,6 +1199,21 @@ KEEP_CONFIG:
|
||
|
chip->bbt_md = &bbt_mirror_descr;
|
||
|
}
|
||
|
|
||
|
+ if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
|
||
|
+ ret = armada370_ecc_init(info, &chip->ecc,
|
||
|
+ chip->ecc_strength_ds,
|
||
|
+ mtd->writesize);
|
||
|
+ else
|
||
|
+ ret = pxa_ecc_init(info, &chip->ecc,
|
||
|
+ chip->ecc_strength_ds,
|
||
|
+ mtd->writesize);
|
||
|
+ if (!ret) {
|
||
|
+ dev_err(&info->pdev->dev,
|
||
|
+ "ECC strength %d at page size %d is not supported\n",
|
||
|
+ chip->ecc_strength_ds, mtd->writesize);
|
||
|
+ return -ENODEV;
|
||
|
+ }
|
||
|
+
|
||
|
/* calculate addressing information */
|
||
|
if (mtd->writesize >= 2048)
|
||
|
host->col_addr_cycles = 2;
|