Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
This commit is contained in:
@@ -58,6 +58,7 @@ obj-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o
|
||||
obj-$(CONFIG_NAND_SPEAR) += spr_nand.o
|
||||
obj-$(CONFIG_TEGRA_NAND) += tegra_nand.o
|
||||
obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
|
||||
obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o
|
||||
obj-$(CONFIG_NAND_PLAT) += nand_plat.o
|
||||
obj-$(CONFIG_NAND_DOCG4) += docg4.o
|
||||
|
||||
|
||||
@@ -412,7 +412,7 @@ static int pmecc_err_location(struct mtd_info *mtd)
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
printk(KERN_ERR "atmel_nand : Timeout to calculate PMECC error location\n");
|
||||
dev_err(host->dev, "atmel_nand : Timeout to calculate PMECC error location\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
|
||||
*(buf + byte_pos) ^= (1 << bit_pos);
|
||||
|
||||
pos = sector_num * host->pmecc_sector_size + byte_pos;
|
||||
printk(KERN_INFO "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
|
||||
dev_dbg(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
|
||||
pos, bit_pos, err_byte, *(buf + byte_pos));
|
||||
} else {
|
||||
/* Bit flip in OOB area */
|
||||
@@ -462,7 +462,7 @@ static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
|
||||
ecc[tmp] ^= (1 << bit_pos);
|
||||
|
||||
pos = tmp + nand_chip->ecc.layout->eccpos[0];
|
||||
printk(KERN_INFO "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
|
||||
dev_dbg(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
|
||||
pos, bit_pos, err_byte, ecc[tmp]);
|
||||
}
|
||||
|
||||
@@ -500,7 +500,7 @@ normal_check:
|
||||
|
||||
err_nbr = pmecc_err_location(mtd);
|
||||
if (err_nbr == -1) {
|
||||
printk(KERN_ERR "PMECC: Too many errors\n");
|
||||
dev_err(host->dev, "PMECC: Too many errors\n");
|
||||
mtd->ecc_stats.failed++;
|
||||
return -EIO;
|
||||
} else {
|
||||
@@ -544,7 +544,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
printk(KERN_ERR "atmel_nand : Timeout to read PMECC page\n");
|
||||
dev_err(host->dev, "atmel_nand : Timeout to read PMECC page\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -584,7 +584,7 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
printk(KERN_ERR "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n");
|
||||
dev_err(host->dev, "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -827,6 +827,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
|
||||
switch (mtd->writesize) {
|
||||
case 2048:
|
||||
case 4096:
|
||||
case 8192:
|
||||
host->pmecc_degree = (sector_size == 512) ?
|
||||
PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14;
|
||||
host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
|
||||
@@ -840,8 +841,15 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
|
||||
nand->ecc.steps = 1;
|
||||
nand->ecc.bytes = host->pmecc_bytes_per_sector *
|
||||
host->pmecc_sector_number;
|
||||
|
||||
if (nand->ecc.bytes > MTD_MAX_ECCPOS_ENTRIES_LARGE) {
|
||||
dev_err(host->dev, "too large eccpos entries. max support ecc.bytes is %d\n",
|
||||
MTD_MAX_ECCPOS_ENTRIES_LARGE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (nand->ecc.bytes > mtd->oobsize - 2) {
|
||||
printk(KERN_ERR "No room for ECC bytes\n");
|
||||
dev_err(host->dev, "No room for ECC bytes\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
|
||||
@@ -852,7 +860,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand,
|
||||
case 512:
|
||||
case 1024:
|
||||
/* TODO */
|
||||
printk(KERN_ERR "Unsupported page size for PMECC, use Software ECC\n");
|
||||
dev_err(host->dev, "Unsupported page size for PMECC, use Software ECC\n");
|
||||
default:
|
||||
/* page size not handled by HW ECC */
|
||||
/* switching back to soft ECC */
|
||||
@@ -1035,7 +1043,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
|
||||
/* it doesn't seems to be a freshly
|
||||
* erased block.
|
||||
* We can't correct so many errors */
|
||||
printk(KERN_WARNING "atmel_nand : multiple errors detected."
|
||||
dev_warn(host->dev, "atmel_nand : multiple errors detected."
|
||||
" Unable to correct.\n");
|
||||
return -EIO;
|
||||
}
|
||||
@@ -1045,12 +1053,12 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
|
||||
/* there's nothing much to do here.
|
||||
* the bit error is on the ECC itself.
|
||||
*/
|
||||
printk(KERN_WARNING "atmel_nand : one bit error on ECC code."
|
||||
dev_warn(host->dev, "atmel_nand : one bit error on ECC code."
|
||||
" Nothing to correct\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk(KERN_WARNING "atmel_nand : one bit error on data."
|
||||
dev_warn(host->dev, "atmel_nand : one bit error on data."
|
||||
" (word offset in the page :"
|
||||
" 0x%x bit offset : 0x%x)\n",
|
||||
ecc_word, ecc_bit);
|
||||
@@ -1062,7 +1070,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
|
||||
/* 8 bits words */
|
||||
dat[ecc_word] ^= (1 << ecc_bit);
|
||||
}
|
||||
printk(KERN_WARNING "atmel_nand : error corrected\n");
|
||||
dev_warn(host->dev, "atmel_nand : error corrected\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1178,7 +1186,11 @@ int atmel_nand_chip_init(int devnum, ulong base_addr)
|
||||
mtd->priv = nand;
|
||||
nand->IO_ADDR_R = nand->IO_ADDR_W = (void __iomem *)base_addr;
|
||||
|
||||
#ifdef CONFIG_NAND_ECC_BCH
|
||||
nand->ecc.mode = NAND_ECC_SOFT_BCH;
|
||||
#else
|
||||
nand->ecc.mode = NAND_ECC_SOFT;
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NAND_DBW_16
|
||||
nand->options = NAND_BUSWIDTH_16;
|
||||
#endif
|
||||
@@ -1186,7 +1198,7 @@ int atmel_nand_chip_init(int devnum, ulong base_addr)
|
||||
#ifdef CONFIG_SYS_NAND_READY_PIN
|
||||
nand->dev_ready = at91_nand_ready;
|
||||
#endif
|
||||
nand->chip_delay = 20;
|
||||
nand->chip_delay = 75;
|
||||
|
||||
ret = nand_scan_ident(mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL);
|
||||
if (ret)
|
||||
@@ -1214,6 +1226,6 @@ void board_nand_init(void)
|
||||
int i;
|
||||
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
|
||||
if (atmel_nand_chip_init(i, base_addr[i]))
|
||||
printk(KERN_ERR "atmel_nand: Fail to initialize #%d chip",
|
||||
dev_err(host->dev, "atmel_nand: Fail to initialize #%d chip",
|
||||
i);
|
||||
}
|
||||
|
||||
@@ -125,6 +125,69 @@ static struct nand_ecclayout oob_4096_ecc8 = {
|
||||
.oobfree = { {2, 6}, {136, 82} },
|
||||
};
|
||||
|
||||
/* 8192-byte page size with 4-bit ECC */
|
||||
static struct nand_ecclayout oob_8192_ecc4 = {
|
||||
.eccbytes = 128,
|
||||
.eccpos = {
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99, 100, 101, 102, 103,
|
||||
104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127,
|
||||
128, 129, 130, 131, 132, 133, 134, 135,
|
||||
},
|
||||
.oobfree = { {2, 6}, {136, 208} },
|
||||
};
|
||||
|
||||
/* 8192-byte page size with 8-bit ECC -- requires 218-byte OOB */
|
||||
static struct nand_ecclayout oob_8192_ecc8 = {
|
||||
.eccbytes = 256,
|
||||
.eccpos = {
|
||||
8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71,
|
||||
72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99, 100, 101, 102, 103,
|
||||
104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 117, 118, 119,
|
||||
120, 121, 122, 123, 124, 125, 126, 127,
|
||||
128, 129, 130, 131, 132, 133, 134, 135,
|
||||
136, 137, 138, 139, 140, 141, 142, 143,
|
||||
144, 145, 146, 147, 148, 149, 150, 151,
|
||||
152, 153, 154, 155, 156, 157, 158, 159,
|
||||
160, 161, 162, 163, 164, 165, 166, 167,
|
||||
168, 169, 170, 171, 172, 173, 174, 175,
|
||||
176, 177, 178, 179, 180, 181, 182, 183,
|
||||
184, 185, 186, 187, 188, 189, 190, 191,
|
||||
192, 193, 194, 195, 196, 197, 198, 199,
|
||||
200, 201, 202, 203, 204, 205, 206, 207,
|
||||
208, 209, 210, 211, 212, 213, 214, 215,
|
||||
216, 217, 218, 219, 220, 221, 222, 223,
|
||||
224, 225, 226, 227, 228, 229, 230, 231,
|
||||
232, 233, 234, 235, 236, 237, 238, 239,
|
||||
240, 241, 242, 243, 244, 245, 246, 247,
|
||||
248, 249, 250, 251, 252, 253, 254, 255,
|
||||
256, 257, 258, 259, 260, 261, 262, 263,
|
||||
},
|
||||
.oobfree = { {2, 6}, {264, 80} },
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic flash bbt descriptors
|
||||
@@ -428,20 +491,27 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
if (mtd->writesize > 512) {
|
||||
nand_fcr0 =
|
||||
(NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) |
|
||||
(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT);
|
||||
(NAND_CMD_STATUS << IFC_NAND_FCR0_CMD1_SHIFT) |
|
||||
(NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD2_SHIFT);
|
||||
|
||||
out_be32(&ifc->ifc_nand.nand_fir0,
|
||||
(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
|
||||
(IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) |
|
||||
(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) |
|
||||
(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) |
|
||||
(IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT));
|
||||
out_be32(&ifc->ifc_nand.nand_fir1, 0);
|
||||
(IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP4_SHIFT));
|
||||
out_be32(&ifc->ifc_nand.nand_fir1,
|
||||
(IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT) |
|
||||
(IFC_FIR_OP_RDSTAT <<
|
||||
IFC_NAND_FIR1_OP6_SHIFT) |
|
||||
(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP7_SHIFT));
|
||||
} else {
|
||||
nand_fcr0 = ((NAND_CMD_PAGEPROG <<
|
||||
IFC_NAND_FCR0_CMD1_SHIFT) |
|
||||
(NAND_CMD_SEQIN <<
|
||||
IFC_NAND_FCR0_CMD2_SHIFT));
|
||||
IFC_NAND_FCR0_CMD2_SHIFT) |
|
||||
(NAND_CMD_STATUS <<
|
||||
IFC_NAND_FCR0_CMD3_SHIFT));
|
||||
|
||||
out_be32(&ifc->ifc_nand.nand_fir0,
|
||||
(IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
|
||||
@@ -450,7 +520,11 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command,
|
||||
(IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) |
|
||||
(IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT));
|
||||
out_be32(&ifc->ifc_nand.nand_fir1,
|
||||
(IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT));
|
||||
(IFC_FIR_OP_CMD1 << IFC_NAND_FIR1_OP5_SHIFT) |
|
||||
(IFC_FIR_OP_CW3 << IFC_NAND_FIR1_OP6_SHIFT) |
|
||||
(IFC_FIR_OP_RDSTAT <<
|
||||
IFC_NAND_FIR1_OP7_SHIFT) |
|
||||
(IFC_FIR_OP_NOP << IFC_NAND_FIR1_OP8_SHIFT));
|
||||
|
||||
if (column >= mtd->writesize)
|
||||
nand_fcr0 |=
|
||||
@@ -902,6 +976,21 @@ static int fsl_ifc_chip_init(int devnum, u8 *addr)
|
||||
priv->bufnum_mask = 1;
|
||||
break;
|
||||
|
||||
case CSOR_NAND_PGS_8K:
|
||||
if ((csor & CSOR_NAND_ECC_MODE_MASK) ==
|
||||
CSOR_NAND_ECC_MODE_4) {
|
||||
layout = &oob_8192_ecc4;
|
||||
nand->ecc.strength = 4;
|
||||
} else {
|
||||
layout = &oob_8192_ecc8;
|
||||
nand->ecc.strength = 8;
|
||||
nand->ecc.bytes = 16;
|
||||
}
|
||||
|
||||
priv->bufnum_mask = 0;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
printf("ifc nand: bad csor %#x: bad page size\n", csor);
|
||||
return -ENODEV;
|
||||
|
||||
@@ -112,10 +112,13 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst)
|
||||
|
||||
port_size = (cspr & CSPR_PORT_SIZE_16) ? 16 : 8;
|
||||
|
||||
if (csor & CSOR_NAND_PGS_4K) {
|
||||
if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_8K) {
|
||||
page_size = 8192;
|
||||
bufnum_mask = 0x0;
|
||||
} else if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_4K) {
|
||||
page_size = 4096;
|
||||
bufnum_mask = 0x1;
|
||||
} else if (csor & CSOR_NAND_PGS_2K) {
|
||||
} else if ((csor & CSOR_NAND_PGS_MASK) == CSOR_NAND_PGS_2K) {
|
||||
page_size = 2048;
|
||||
bufnum_mask = 0x3;
|
||||
} else {
|
||||
|
||||
196
drivers/mtd/nand/omap_elm.c
Normal file
196
drivers/mtd/nand/omap_elm.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* (C) Copyright 2010-2011 Texas Instruments, <www.ti.com>
|
||||
* Mansoor Ahamed <mansoor.ahamed@ti.com>
|
||||
*
|
||||
* BCH Error Location Module (ELM) support.
|
||||
*
|
||||
* NOTE:
|
||||
* 1. Supports only continuous mode. Dont see need for page mode in uboot
|
||||
* 2. Supports only syndrome polynomial 0. i.e. poly local variable is
|
||||
* always set to ELM_DEFAULT_POLY. Dont see need for other polynomial
|
||||
* sets in uboot
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/omap_gpmc.h>
|
||||
#include <asm/omap_elm.h>
|
||||
|
||||
#define ELM_DEFAULT_POLY (0)
|
||||
|
||||
struct elm *elm_cfg;
|
||||
|
||||
/**
|
||||
* elm_load_syndromes - Load BCH syndromes based on nibble selection
|
||||
* @syndrome: BCH syndrome
|
||||
* @nibbles:
|
||||
* @poly: Syndrome Polynomial set to use
|
||||
*
|
||||
* Load BCH syndromes based on nibble selection
|
||||
*/
|
||||
static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly)
|
||||
{
|
||||
u32 *ptr;
|
||||
u32 val;
|
||||
|
||||
/* reg 0 */
|
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[0];
|
||||
val = syndrome[0] | (syndrome[1] << 8) | (syndrome[2] << 16) |
|
||||
(syndrome[3] << 24);
|
||||
writel(val, ptr);
|
||||
/* reg 1 */
|
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[1];
|
||||
val = syndrome[4] | (syndrome[5] << 8) | (syndrome[6] << 16) |
|
||||
(syndrome[7] << 24);
|
||||
writel(val, ptr);
|
||||
|
||||
/* BCH 8-bit with 26 nibbles (4*8=32) */
|
||||
if (nibbles > 13) {
|
||||
/* reg 2 */
|
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2];
|
||||
val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) |
|
||||
(syndrome[11] << 24);
|
||||
writel(val, ptr);
|
||||
/* reg 3 */
|
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[3];
|
||||
val = syndrome[12] | (syndrome[13] << 8) |
|
||||
(syndrome[14] << 16) | (syndrome[15] << 24);
|
||||
writel(val, ptr);
|
||||
}
|
||||
|
||||
/* BCH 16-bit with 52 nibbles (7*8=56) */
|
||||
if (nibbles > 26) {
|
||||
/* reg 4 */
|
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[4];
|
||||
val = syndrome[16] | (syndrome[17] << 8) |
|
||||
(syndrome[18] << 16) | (syndrome[19] << 24);
|
||||
writel(val, ptr);
|
||||
|
||||
/* reg 5 */
|
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[5];
|
||||
val = syndrome[20] | (syndrome[21] << 8) |
|
||||
(syndrome[22] << 16) | (syndrome[23] << 24);
|
||||
writel(val, ptr);
|
||||
|
||||
/* reg 6 */
|
||||
ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6];
|
||||
val = syndrome[24] | (syndrome[25] << 8) |
|
||||
(syndrome[26] << 16) | (syndrome[27] << 24);
|
||||
writel(val, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* elm_check_errors - Check for BCH errors and return error locations
|
||||
* @syndrome: BCH syndrome
|
||||
* @nibbles:
|
||||
* @error_count: Returns number of errrors in the syndrome
|
||||
* @error_locations: Returns error locations (in decimal) in this array
|
||||
*
|
||||
* Check the provided syndrome for BCH errors and return error count
|
||||
* and locations in the array passed. Returns -1 if error is not correctable,
|
||||
* else returns 0
|
||||
*/
|
||||
int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count,
|
||||
u32 *error_locations)
|
||||
{
|
||||
u8 poly = ELM_DEFAULT_POLY;
|
||||
s8 i;
|
||||
u32 location_status;
|
||||
|
||||
elm_load_syndromes(syndrome, nibbles, poly);
|
||||
|
||||
/* start processing */
|
||||
writel((readl(&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6])
|
||||
| ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID),
|
||||
&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]);
|
||||
|
||||
/* wait for processing to complete */
|
||||
while ((readl(&elm_cfg->irqstatus) & (0x1 << poly)) != 0x1)
|
||||
;
|
||||
/* clear status */
|
||||
writel((readl(&elm_cfg->irqstatus) | (0x1 << poly)),
|
||||
&elm_cfg->irqstatus);
|
||||
|
||||
/* check if correctable */
|
||||
location_status = readl(&elm_cfg->error_location[poly].location_status);
|
||||
if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK))
|
||||
return -1;
|
||||
|
||||
/* get error count */
|
||||
*error_count = readl(&elm_cfg->error_location[poly].location_status) &
|
||||
ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK;
|
||||
|
||||
for (i = 0; i < *error_count; i++) {
|
||||
error_locations[i] =
|
||||
readl(&elm_cfg->error_location[poly].error_location_x[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* elm_config - Configure ELM module
|
||||
* @level: 4 / 8 / 16 bit BCH
|
||||
*
|
||||
* Configure ELM module based on BCH level.
|
||||
* Set mode as continuous mode.
|
||||
* Currently we are using only syndrome 0 and syndromes 1 to 6 are not used.
|
||||
* Also, the mode is set only for syndrome 0
|
||||
*/
|
||||
int elm_config(enum bch_level level)
|
||||
{
|
||||
u32 val;
|
||||
u8 poly = ELM_DEFAULT_POLY;
|
||||
u32 buffer_size = 0x7FF;
|
||||
|
||||
/* config size and level */
|
||||
val = (u32)(level) & ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK;
|
||||
val |= ((buffer_size << ELM_LOCATION_CONFIG_ECC_SIZE_POS) &
|
||||
ELM_LOCATION_CONFIG_ECC_SIZE_MASK);
|
||||
writel(val, &elm_cfg->location_config);
|
||||
|
||||
/* config continous mode */
|
||||
/* enable interrupt generation for syndrome polynomial set */
|
||||
writel((readl(&elm_cfg->irqenable) | (0x1 << poly)),
|
||||
&elm_cfg->irqenable);
|
||||
/* set continuous mode for the syndrome polynomial set */
|
||||
writel((readl(&elm_cfg->page_ctrl) & ~(0x1 << poly)),
|
||||
&elm_cfg->page_ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* elm_reset - Do a soft reset of ELM
|
||||
*
|
||||
* Perform a soft reset of ELM and return after reset is done.
|
||||
*/
|
||||
void elm_reset(void)
|
||||
{
|
||||
/* initiate reset */
|
||||
writel((readl(&elm_cfg->sysconfig) | ELM_SYSCONFIG_SOFTRESET),
|
||||
&elm_cfg->sysconfig);
|
||||
|
||||
/* wait for reset complete and normal operation */
|
||||
while ((readl(&elm_cfg->sysstatus) & ELM_SYSSTATUS_RESETDONE) !=
|
||||
ELM_SYSSTATUS_RESETDONE)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* elm_init - Initialize ELM module
|
||||
*
|
||||
* Initialize ELM support. Currently it does only base address init
|
||||
* and ELM reset.
|
||||
*/
|
||||
void elm_init(void)
|
||||
{
|
||||
elm_cfg = (struct elm *)ELM_BASE;
|
||||
elm_reset();
|
||||
}
|
||||
@@ -15,15 +15,13 @@
|
||||
#include <linux/bch.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <nand.h>
|
||||
#ifdef CONFIG_AM33XX
|
||||
#include <asm/arch/elm.h>
|
||||
#endif
|
||||
#include <asm/omap_elm.h>
|
||||
|
||||
#define BADBLOCK_MARKER_LENGTH 2
|
||||
#define SECTOR_BYTES 512
|
||||
|
||||
static uint8_t cs;
|
||||
static __maybe_unused struct nand_ecclayout hw_nand_oob =
|
||||
GPMC_NAND_HW_ECC_LAYOUT;
|
||||
static __maybe_unused struct nand_ecclayout hw_bch8_nand_oob =
|
||||
GPMC_NAND_HW_BCH8_ECC_LAYOUT;
|
||||
static __maybe_unused struct nand_ecclayout omap_ecclayout;
|
||||
|
||||
/*
|
||||
* omap_nand_hwcontrol - Set the address pointers corretly for the
|
||||
@@ -233,6 +231,7 @@ struct nand_bch_priv {
|
||||
uint8_t type;
|
||||
uint8_t nibbles;
|
||||
struct bch_control *control;
|
||||
enum omap_ecc ecc_scheme;
|
||||
};
|
||||
|
||||
/* bch types */
|
||||
@@ -274,17 +273,15 @@ static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
|
||||
{
|
||||
uint32_t val;
|
||||
uint32_t dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
|
||||
#ifdef CONFIG_AM33XX
|
||||
uint32_t unused_length = 0;
|
||||
#endif
|
||||
uint32_t wr_mode = BCH_WRAPMODE_6;
|
||||
struct nand_bch_priv *bch = chip->priv;
|
||||
|
||||
/* Clear the ecc result registers, select ecc reg as 1 */
|
||||
writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
|
||||
|
||||
#ifdef CONFIG_AM33XX
|
||||
wr_mode = BCH_WRAPMODE_1;
|
||||
if (bch->ecc_scheme == OMAP_ECC_BCH8_CODE_HW) {
|
||||
wr_mode = BCH_WRAPMODE_1;
|
||||
|
||||
switch (bch->nibbles) {
|
||||
case ECC_BCH4_NIBBLES:
|
||||
@@ -320,7 +317,7 @@ static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
|
||||
val |= (unused_length << 22);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
} else {
|
||||
/*
|
||||
* This ecc_size_config setting is for BCH sw library.
|
||||
*
|
||||
@@ -333,7 +330,7 @@ static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
|
||||
* size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
|
||||
*/
|
||||
val = (32 << 22) | (0 << 12);
|
||||
#endif
|
||||
}
|
||||
/* ecc size configuration */
|
||||
writel(val, &gpmc_cfg->ecc_size_config);
|
||||
|
||||
@@ -376,9 +373,9 @@ static void __maybe_unused omap_ecc_disable(struct mtd_info *mtd)
|
||||
}
|
||||
|
||||
/*
|
||||
* BCH8 support (needs ELM and thus AM33xx-only)
|
||||
* BCH support using ELM module
|
||||
*/
|
||||
#ifdef CONFIG_AM33XX
|
||||
#ifdef CONFIG_NAND_OMAP_ELM
|
||||
/*
|
||||
* omap_read_bch8_result - Read BCH result for BCH8 level
|
||||
*
|
||||
@@ -631,20 +628,20 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_AM33XX */
|
||||
#endif /* CONFIG_NAND_OMAP_ELM */
|
||||
|
||||
/*
|
||||
* OMAP3 BCH8 support (with BCH library)
|
||||
*/
|
||||
#ifdef CONFIG_NAND_OMAP_BCH8
|
||||
#ifdef CONFIG_BCH
|
||||
/*
|
||||
* omap_calculate_ecc_bch - Read BCH ECC result
|
||||
* omap_calculate_ecc_bch_sw - Read BCH ECC result
|
||||
*
|
||||
* @mtd: MTD device structure
|
||||
* @dat: The pointer to data on which ecc is computed (unused here)
|
||||
* @ecc: The ECC output buffer
|
||||
*/
|
||||
static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
|
||||
static int omap_calculate_ecc_bch_sw(struct mtd_info *mtd, const uint8_t *dat,
|
||||
uint8_t *ecc)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -689,13 +686,13 @@ static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
|
||||
}
|
||||
|
||||
/**
|
||||
* omap_correct_data_bch - Decode received data and correct errors
|
||||
* omap_correct_data_bch_sw - Decode received data and correct errors
|
||||
* @mtd: MTD device structure
|
||||
* @data: page data
|
||||
* @read_ecc: ecc read from nand flash
|
||||
* @calc_ecc: ecc read from HW ECC registers
|
||||
*/
|
||||
static int omap_correct_data_bch(struct mtd_info *mtd, u_char *data,
|
||||
static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data,
|
||||
u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
int i, count;
|
||||
@@ -752,7 +749,150 @@ static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
|
||||
chip_priv->control = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_NAND_OMAP_BCH8 */
|
||||
#endif /* CONFIG_BCH */
|
||||
|
||||
/**
|
||||
* omap_select_ecc_scheme - configures driver for particular ecc-scheme
|
||||
* @nand: NAND chip device structure
|
||||
* @ecc_scheme: ecc scheme to configure
|
||||
* @pagesize: number of main-area bytes per page of NAND device
|
||||
* @oobsize: number of OOB/spare bytes per page of NAND device
|
||||
*/
|
||||
static int omap_select_ecc_scheme(struct nand_chip *nand,
|
||||
enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) {
|
||||
struct nand_bch_priv *bch = nand->priv;
|
||||
struct nand_ecclayout *ecclayout = nand->ecc.layout;
|
||||
int eccsteps = pagesize / SECTOR_BYTES;
|
||||
int i;
|
||||
|
||||
switch (ecc_scheme) {
|
||||
case OMAP_ECC_HAM1_CODE_SW:
|
||||
debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n");
|
||||
/* For this ecc-scheme, ecc.bytes, ecc.layout, ... are
|
||||
* initialized in nand_scan_tail(), so just set ecc.mode */
|
||||
bch_priv.control = NULL;
|
||||
bch_priv.type = 0;
|
||||
nand->ecc.mode = NAND_ECC_SOFT;
|
||||
nand->ecc.layout = NULL;
|
||||
nand->ecc.size = pagesize;
|
||||
bch->ecc_scheme = OMAP_ECC_HAM1_CODE_SW;
|
||||
break;
|
||||
|
||||
case OMAP_ECC_HAM1_CODE_HW:
|
||||
debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n");
|
||||
/* check ecc-scheme requirements before updating ecc info */
|
||||
if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
|
||||
printf("nand: error: insufficient OOB: require=%d\n", (
|
||||
(3 * eccsteps) + BADBLOCK_MARKER_LENGTH));
|
||||
return -EINVAL;
|
||||
}
|
||||
bch_priv.control = NULL;
|
||||
bch_priv.type = 0;
|
||||
/* populate ecc specific fields */
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.strength = 1;
|
||||
nand->ecc.size = SECTOR_BYTES;
|
||||
nand->ecc.bytes = 3;
|
||||
nand->ecc.hwctl = omap_enable_hwecc;
|
||||
nand->ecc.correct = omap_correct_data;
|
||||
nand->ecc.calculate = omap_calculate_ecc;
|
||||
/* define ecc-layout */
|
||||
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
|
||||
for (i = 0; i < ecclayout->eccbytes; i++)
|
||||
ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
|
||||
ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
|
||||
ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
|
||||
BADBLOCK_MARKER_LENGTH;
|
||||
bch->ecc_scheme = OMAP_ECC_HAM1_CODE_HW;
|
||||
break;
|
||||
|
||||
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
|
||||
#ifdef CONFIG_BCH
|
||||
debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
|
||||
/* check ecc-scheme requirements before updating ecc info */
|
||||
if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
|
||||
printf("nand: error: insufficient OOB: require=%d\n", (
|
||||
(13 * eccsteps) + BADBLOCK_MARKER_LENGTH));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* check if BCH S/W library can be used for error detection */
|
||||
bch_priv.control = init_bch(13, 8, 0x201b);
|
||||
if (!bch_priv.control) {
|
||||
printf("nand: error: could not init_bch()\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
bch_priv.type = ECC_BCH8;
|
||||
/* populate ecc specific fields */
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.strength = 8;
|
||||
nand->ecc.size = SECTOR_BYTES;
|
||||
nand->ecc.bytes = 13;
|
||||
nand->ecc.hwctl = omap_enable_ecc_bch;
|
||||
nand->ecc.correct = omap_correct_data_bch_sw;
|
||||
nand->ecc.calculate = omap_calculate_ecc_bch_sw;
|
||||
/* define ecc-layout */
|
||||
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
|
||||
ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
|
||||
for (i = 1; i < ecclayout->eccbytes; i++) {
|
||||
if (i % nand->ecc.bytes)
|
||||
ecclayout->eccpos[i] =
|
||||
ecclayout->eccpos[i - 1] + 1;
|
||||
else
|
||||
ecclayout->eccpos[i] =
|
||||
ecclayout->eccpos[i - 1] + 2;
|
||||
}
|
||||
ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
|
||||
ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
|
||||
BADBLOCK_MARKER_LENGTH;
|
||||
omap_hwecc_init_bch(nand, NAND_ECC_READ);
|
||||
bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW;
|
||||
break;
|
||||
#else
|
||||
printf("nand: error: CONFIG_BCH required for ECC\n");
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
case OMAP_ECC_BCH8_CODE_HW:
|
||||
#ifdef CONFIG_NAND_OMAP_ELM
|
||||
debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n");
|
||||
/* check ecc-scheme requirements before updating ecc info */
|
||||
if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
|
||||
printf("nand: error: insufficient OOB: require=%d\n", (
|
||||
(14 * eccsteps) + BADBLOCK_MARKER_LENGTH));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* intialize ELM for ECC error detection */
|
||||
elm_init();
|
||||
bch_priv.type = ECC_BCH8;
|
||||
/* populate ecc specific fields */
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.strength = 8;
|
||||
nand->ecc.size = SECTOR_BYTES;
|
||||
nand->ecc.bytes = 14;
|
||||
nand->ecc.hwctl = omap_enable_ecc_bch;
|
||||
nand->ecc.correct = omap_correct_data_bch;
|
||||
nand->ecc.calculate = omap_calculate_ecc_bch;
|
||||
nand->ecc.read_page = omap_read_page_bch;
|
||||
/* define ecc-layout */
|
||||
ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
|
||||
for (i = 0; i < ecclayout->eccbytes; i++)
|
||||
ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
|
||||
ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
|
||||
ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
|
||||
BADBLOCK_MARKER_LENGTH;
|
||||
bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW;
|
||||
break;
|
||||
#else
|
||||
printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
default:
|
||||
debug("nand: error: ecc scheme not enabled or supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
/*
|
||||
@@ -763,77 +903,45 @@ static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
|
||||
* @eccstrength - the number of bits that could be corrected
|
||||
* (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16)
|
||||
*/
|
||||
void omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
|
||||
int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
|
||||
{
|
||||
struct nand_chip *nand;
|
||||
struct mtd_info *mtd;
|
||||
int err = 0;
|
||||
|
||||
if (nand_curr_device < 0 ||
|
||||
nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
|
||||
!nand_info[nand_curr_device].name) {
|
||||
printf("Error: Can't switch ecc, no devices available\n");
|
||||
return;
|
||||
printf("nand: error: no NAND devices found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mtd = &nand_info[nand_curr_device];
|
||||
nand = mtd->priv;
|
||||
|
||||
nand->options |= NAND_OWN_BUFFERS;
|
||||
|
||||
/* Reset ecc interface */
|
||||
nand->ecc.mode = NAND_ECC_NONE;
|
||||
nand->ecc.read_page = NULL;
|
||||
nand->ecc.write_page = NULL;
|
||||
nand->ecc.read_oob = NULL;
|
||||
nand->ecc.write_oob = NULL;
|
||||
nand->ecc.hwctl = NULL;
|
||||
nand->ecc.correct = NULL;
|
||||
nand->ecc.calculate = NULL;
|
||||
nand->ecc.strength = eccstrength;
|
||||
|
||||
/* Setup the ecc configurations again */
|
||||
if (hardware) {
|
||||
if (eccstrength == 1) {
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.layout = &hw_nand_oob;
|
||||
nand->ecc.size = 512;
|
||||
nand->ecc.bytes = 3;
|
||||
nand->ecc.hwctl = omap_enable_hwecc;
|
||||
nand->ecc.correct = omap_correct_data;
|
||||
nand->ecc.calculate = omap_calculate_ecc;
|
||||
omap_hwecc_init(nand);
|
||||
printf("1-bit hamming HW ECC selected\n");
|
||||
err = omap_select_ecc_scheme(nand,
|
||||
OMAP_ECC_HAM1_CODE_HW,
|
||||
mtd->writesize, mtd->oobsize);
|
||||
} else if (eccstrength == 8) {
|
||||
err = omap_select_ecc_scheme(nand,
|
||||
OMAP_ECC_BCH8_CODE_HW,
|
||||
mtd->writesize, mtd->oobsize);
|
||||
} else {
|
||||
printf("nand: error: unsupported ECC scheme\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#if defined(CONFIG_AM33XX) || defined(CONFIG_NAND_OMAP_BCH8)
|
||||
else if (eccstrength == 8) {
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.layout = &hw_bch8_nand_oob;
|
||||
nand->ecc.size = 512;
|
||||
#ifdef CONFIG_AM33XX
|
||||
nand->ecc.bytes = 14;
|
||||
nand->ecc.read_page = omap_read_page_bch;
|
||||
#else
|
||||
nand->ecc.bytes = 13;
|
||||
#endif
|
||||
nand->ecc.hwctl = omap_enable_ecc_bch;
|
||||
nand->ecc.correct = omap_correct_data_bch;
|
||||
nand->ecc.calculate = omap_calculate_ecc_bch;
|
||||
omap_hwecc_init_bch(nand, NAND_ECC_READ);
|
||||
printf("8-bit BCH HW ECC selected\n");
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
nand->ecc.mode = NAND_ECC_SOFT;
|
||||
/* Use mtd default settings */
|
||||
nand->ecc.layout = NULL;
|
||||
nand->ecc.size = 0;
|
||||
printf("SW ECC selected\n");
|
||||
err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
|
||||
mtd->writesize, mtd->oobsize);
|
||||
}
|
||||
|
||||
/* Update NAND handling after ECC mode switch */
|
||||
nand_scan_tail(mtd);
|
||||
|
||||
nand->options &= ~NAND_OWN_BUFFERS;
|
||||
if (!err)
|
||||
err = nand_scan_tail(mtd);
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_SPL_BUILD */
|
||||
|
||||
@@ -856,7 +964,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
{
|
||||
int32_t gpmc_config = 0;
|
||||
cs = 0;
|
||||
|
||||
int err = 0;
|
||||
/*
|
||||
* xloader/Uboot's gpmc configuration would have configured GPMC for
|
||||
* nand type of memory. The following logic scans and latches on to the
|
||||
@@ -873,7 +981,7 @@ int board_nand_init(struct nand_chip *nand)
|
||||
cs++;
|
||||
}
|
||||
if (cs >= GPMC_MAX_CS) {
|
||||
printf("NAND: Unable to find NAND settings in "
|
||||
printf("nand: error: Unable to find NAND settings in "
|
||||
"GPMC Configuration - quitting\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -885,64 +993,27 @@ int board_nand_init(struct nand_chip *nand)
|
||||
|
||||
nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
|
||||
nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
|
||||
|
||||
nand->cmd_ctrl = omap_nand_hwcontrol;
|
||||
nand->options = NAND_NO_PADDING | NAND_CACHEPRG;
|
||||
nand->priv = &bch_priv;
|
||||
nand->cmd_ctrl = omap_nand_hwcontrol;
|
||||
nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
|
||||
/* If we are 16 bit dev, our gpmc config tells us that */
|
||||
if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
|
||||
nand->options |= NAND_BUSWIDTH_16;
|
||||
|
||||
nand->chip_delay = 100;
|
||||
nand->ecc.layout = &omap_ecclayout;
|
||||
|
||||
#if defined(CONFIG_AM33XX) || defined(CONFIG_NAND_OMAP_BCH8)
|
||||
#ifdef CONFIG_AM33XX
|
||||
/* AM33xx uses the ELM */
|
||||
/* required in case of BCH */
|
||||
elm_init();
|
||||
/* select ECC scheme */
|
||||
#if defined(CONFIG_NAND_OMAP_ECCSCHEME)
|
||||
err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME,
|
||||
CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);
|
||||
#else
|
||||
/*
|
||||
* Whereas other OMAP based SoC do not have the ELM, they use the BCH
|
||||
* SW library.
|
||||
*/
|
||||
bch_priv.control = init_bch(13, 8, 0x201b /* hw polynominal */);
|
||||
if (!bch_priv.control) {
|
||||
puts("Could not init_bch()\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
/* BCH info that will be correct for SPL or overridden otherwise. */
|
||||
nand->priv = &bch_priv;
|
||||
#endif
|
||||
|
||||
/* Default ECC mode */
|
||||
#if defined(CONFIG_AM33XX) || defined(CONFIG_NAND_OMAP_BCH8)
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.layout = &hw_bch8_nand_oob;
|
||||
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
|
||||
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
|
||||
nand->ecc.strength = 8;
|
||||
nand->ecc.hwctl = omap_enable_ecc_bch;
|
||||
nand->ecc.correct = omap_correct_data_bch;
|
||||
nand->ecc.calculate = omap_calculate_ecc_bch;
|
||||
#ifdef CONFIG_AM33XX
|
||||
nand->ecc.read_page = omap_read_page_bch;
|
||||
#endif
|
||||
omap_hwecc_init_bch(nand, NAND_ECC_READ);
|
||||
#else
|
||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC)
|
||||
nand->ecc.mode = NAND_ECC_SOFT;
|
||||
#else
|
||||
nand->ecc.mode = NAND_ECC_HW;
|
||||
nand->ecc.layout = &hw_nand_oob;
|
||||
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
|
||||
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
|
||||
nand->ecc.hwctl = omap_enable_hwecc;
|
||||
nand->ecc.correct = omap_correct_data;
|
||||
nand->ecc.calculate = omap_calculate_ecc;
|
||||
nand->ecc.strength = 1;
|
||||
omap_hwecc_init(nand);
|
||||
#endif
|
||||
/* pagesize and oobsize are not required to configure sw ecc-scheme */
|
||||
err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
|
||||
0, 0);
|
||||
#endif
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
if (nand->options & NAND_BUSWIDTH_16)
|
||||
|
||||
@@ -761,7 +761,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
|
||||
uint8_t *oob_buf = this->oob_buf;
|
||||
|
||||
free = this->ecclayout->oobfree;
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && free->length;
|
||||
i++, free++) {
|
||||
if (readcol >= lastgap)
|
||||
readcol += free->offset - lastgap;
|
||||
if (readend >= lastgap)
|
||||
@@ -770,7 +771,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
|
||||
}
|
||||
this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
|
||||
free = this->ecclayout->oobfree;
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && free->length;
|
||||
i++, free++) {
|
||||
int free_end = free->offset + free->length;
|
||||
if (free->offset < readend && free_end > readcol) {
|
||||
int st = max_t(int,free->offset,readcol);
|
||||
@@ -1356,7 +1358,8 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
|
||||
unsigned int i;
|
||||
|
||||
free = this->ecclayout->oobfree;
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && free->length;
|
||||
i++, free++) {
|
||||
if (writecol >= lastgap)
|
||||
writecol += free->offset - lastgap;
|
||||
if (writeend >= lastgap)
|
||||
@@ -1364,7 +1367,8 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
|
||||
lastgap = free->offset + free->length;
|
||||
}
|
||||
free = this->ecclayout->oobfree;
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE && free->length;
|
||||
i++, free++) {
|
||||
int free_end = free->offset + free->length;
|
||||
if (free->offset < writeend && free_end > writecol) {
|
||||
int st = max_t(int,free->offset,writecol);
|
||||
@@ -2750,7 +2754,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
|
||||
* the out of band area
|
||||
*/
|
||||
this->ecclayout->oobavail = 0;
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES &&
|
||||
|
||||
for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE &&
|
||||
this->ecclayout->oobfree[i].length; i++)
|
||||
this->ecclayout->oobavail +=
|
||||
this->ecclayout->oobfree[i].length;
|
||||
|
||||
Reference in New Issue
Block a user