aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c86
1 files changed, 69 insertions, 17 deletions
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 84a6c649100c..5062eddad834 100644
--- 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 */
@@ -335,19 +339,12 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
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;
}
/**
@@ -362,10 +359,15 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
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;
@@ -1067,6 +1069,41 @@ static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
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;
@@ -1137,13 +1174,13 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
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;
@@ -1158,6 +1195,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;