Openwrt/target/linux/mvebu/patches-3.10/0143-mtd-nand-pxa3xx-Add-driver-specific-ECC-BCH-support.patch
Luka Perkov c9ae111a20 mvebu: backport mainline patches from kernel 3.13
This is a backport of the patches accepted to the Linux mainline related to
mvebu SoC (Armada XP and Armada 370) between Linux v3.12, and Linux v3.13.
This work mainly covers:

* Finishes work for sharing the pxa nand driver(drivers/mtd/nand/pxa3xx_nand.c)
  between the PXA family, and the Armada family.
* timer initialization update, and access function for the Armada family.
* Generic IRQ handling backporting.
* Some bug fixes.

Signed-off-by: Seif Mazareeb <seif.mazareeb@gmail.com>
CC: Luka Perkov <luka@openwrt.org>

SVN-Revision: 39566
2014-02-11 02:07:44 +00:00

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;