From 7604a3f920031aa6f3426eedf44494b69ae291e1 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 28 Aug 2013 14:54:26 +0000 Subject: MTD: atmel_nand: support for software BCH ECC Add possible to use software BCH ECC for atmel nand driver Signed-off-by: Bo Shen diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index da83f06..10011c6 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1178,7 +1178,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 -- cgit v0.10.2 From ed5ac34a33821809ddee6307aa6dc80aeb0245a7 Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Thu, 3 Oct 2013 11:35:35 +0530 Subject: driver/mtd/ifc: Read Status while programming NAND flash as per controller description, "While programming a NAND flash, status read should never skipped. Because it may happen that a new command is issued to the NAND Flash, even when the device has not yet finished processing the previous request. This may result in unpredictable behaviour." IFC controller never polls for R/B signal after command send. It just return control to software. This behaviour may not occur with NAND flash access. because new commands are sent after polling R/B signal. But it may happen in scenario where GPCM-ASIC and NAND flash device are working simultaneously. Update the controller driver to take care of this requirement Signed-off-by: Prabhakar Kushwaha diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 98a09c0..1d18815 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -428,20 +428,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 +457,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 |= -- cgit v0.10.2 From 68ec9c85a9d334c7598b4972af037de05c034f8d Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Fri, 4 Oct 2013 13:47:58 +0530 Subject: mtd: move & update nand_ecclayout structure (plus board changes) nand_ecclayout is present in mtd.h at Linux. Move this structure to mtd.h to comply with Linux. Also, increase the ecc placement locations to 640 to suport device having writesize/oobsize of 8KB/640B. This means that the maximum oobsize has gone up to 640 bytes and consequently the maximum ecc placement locations have also gone up to 640. Changes from Prabhabkar's version (squashed into one patch to preserve bisectability): - Added _LARGE to MTD_MAX_*_ENTRIES This makes the names match current Linux source, and resolves a conflict between http://patchwork.ozlabs.org/patch/280488/ and http://patchwork.ozlabs.org/patch/284513/ The former was posted first and is closer to matching Linux, but unlike Linux it does not add _LARGE to the names. The second adds _LARGE to one of the names, and depends on it in a subsequent patch (http://patchwork.ozlabs.org/patch/284512/). - Made max oobfree/eccpos configurable, and used this on tricorder, alpr, ASH405, T4160QDS, and T4240QDS (these boards failed to build for me without doing so, due to a size increase). On tricorder SPL, this saves 2576 bytes (and makes the SPL build again) versus the new default of 640 eccpos and 32 oobfree, and saves 336 bytes versus the old default of 128 eccpos and 8 oobfree. Signed-off-by: Prabhakar Kushwaha CC: Vipin Kumar [scottwood@freescale.com: changes as described above] Signed-off-by: Scott Wood Cc: Thomas Weber Cc: Matthias Fuchs Cc: Stefan Roese Cc: York Sun Cc: Tom Rini Reviewed-by: Stefan Roese diff --git a/doc/README.nand b/doc/README.nand index 913e9b5..3a507b6 100644 --- a/doc/README.nand +++ b/doc/README.nand @@ -104,6 +104,16 @@ Configuration Options: CONFIG_SYS_MAX_NAND_DEVICE The maximum number of NAND devices you want to support. + CONFIG_SYS_NAND_MAX_ECCPOS + If specified, overrides the maximum number of ECC bytes + supported. Useful for reducing image size, especially with SPL. + This must be at least 48 if nand_base.c is used. + + CONFIG_SYS_NAND_MAX_OOBFREE + If specified, overrides the maximum number of free OOB regions + supported. Useful for reducing image size, especially with SPL. + This must be at least 2 if nand_base.c is used. + CONFIG_SYS_NAND_MAX_CHIPS The maximum number of NAND chips per device to be supported. diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 067f8ef..979e4af 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -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; diff --git a/include/configs/ASH405.h b/include/configs/ASH405.h index 9460be3..2f53407 100644 --- a/include/configs/ASH405.h +++ b/include/configs/ASH405.h @@ -143,6 +143,8 @@ #define CONFIG_SYS_NAND_SKIP_BAD_DOT_I 1 /* ".i" read skips bad blocks */ #define CONFIG_SYS_NAND_QUIET 1 +#define CONFIG_SYS_NAND_MAX_OOBFREE 2 +#define CONFIG_SYS_NAND_MAX_ECCPOS 56 /*----------------------------------------------------------------------- * PCI stuff diff --git a/include/configs/MPC8572DS.h b/include/configs/MPC8572DS.h index c751144..9ad9402 100644 --- a/include/configs/MPC8572DS.h +++ b/include/configs/MPC8572DS.h @@ -322,6 +322,8 @@ #define CONFIG_CMD_NAND 1 #define CONFIG_NAND_FSL_ELBC 1 #define CONFIG_SYS_NAND_BLOCK_SIZE (128 * 1024) +#define CONFIG_SYS_NAND_MAX_OOBFREE 5 +#define CONFIG_SYS_NAND_MAX_ECCPOS 56 /* NAND boot: 4K NAND loader config */ #define CONFIG_SYS_NAND_SPL_SIZE 0x1000 diff --git a/include/configs/T4240QDS.h b/include/configs/T4240QDS.h index 3777ccb..c96df54 100644 --- a/include/configs/T4240QDS.h +++ b/include/configs/T4240QDS.h @@ -229,6 +229,8 @@ unsigned long get_board_ddr_clk(void); #define CONFIG_CMD_NAND #define CONFIG_SYS_NAND_BLOCK_SIZE (128 * 1024) +#define CONFIG_SYS_NAND_MAX_OOBFREE 2 +#define CONFIG_SYS_NAND_MAX_ECCPOS 256 #if defined(CONFIG_NAND) #define CONFIG_SYS_CSPR0_EXT CONFIG_SYS_NAND_CSPR_EXT diff --git a/include/configs/alpr.h b/include/configs/alpr.h index 2bf1986..61fdeba 100644 --- a/include/configs/alpr.h +++ b/include/configs/alpr.h @@ -324,6 +324,8 @@ #define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE + 0, CONFIG_SYS_NAND_BASE + 2, \ CONFIG_SYS_NAND_BASE + 4, CONFIG_SYS_NAND_BASE + 6 } #define CONFIG_SYS_NAND_QUIET_TEST 1 /* don't warn upon unknown NAND flash */ +#define CONFIG_SYS_NAND_MAX_OOBFREE 2 +#define CONFIG_SYS_NAND_MAX_ECCPOS 56 /*----------------------------------------------------------------------- * External Bus Controller (EBC) Setup diff --git a/include/configs/tricorder.h b/include/configs/tricorder.h index d57394e..590eab7 100644 --- a/include/configs/tricorder.h +++ b/include/configs/tricorder.h @@ -140,6 +140,8 @@ /* devices */ #define CONFIG_NAND_OMAP_BCH8 #define CONFIG_BCH +#define CONFIG_SYS_NAND_MAX_OOBFREE 2 +#define CONFIG_SYS_NAND_MAX_ECCPOS 56 /* commands to include */ #include diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 6f44abd..a65b681 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -96,6 +96,29 @@ struct mtd_oob_ops { uint8_t *oobbuf; }; +#ifdef CONFIG_SYS_NAND_MAX_OOBFREE +#define MTD_MAX_OOBFREE_ENTRIES_LARGE CONFIG_SYS_NAND_MAX_OOBFREE +#else +#define MTD_MAX_OOBFREE_ENTRIES_LARGE 32 +#endif + +#ifdef CONFIG_SYS_NAND_MAX_ECCPOS +#define MTD_MAX_ECCPOS_ENTRIES_LARGE CONFIG_SYS_NAND_MAX_ECCPOS +#else +#define MTD_MAX_ECCPOS_ENTRIES_LARGE 640 +#endif + +/* + * ECC layout control structure. Exported to userspace for + * diagnosis and to allow creation of raw images + */ +struct nand_ecclayout { + uint32_t eccbytes; + uint32_t eccpos[MTD_MAX_ECCPOS_ENTRIES_LARGE]; + uint32_t oobavail; + struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES_LARGE]; +}; + struct mtd_info { u_char type; u_int32_t flags; diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index d51c1ab..ac3c298 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -155,18 +155,6 @@ struct nand_oobfree { uint32_t length; }; -#define MTD_MAX_OOBFREE_ENTRIES 8 -/* - * ECC layout control structure. Exported to userspace for - * diagnosis and to allow creation of raw images - */ -struct nand_ecclayout { - uint32_t eccbytes; - uint32_t eccpos[128]; - uint32_t oobavail; - struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; -}; - /** * struct mtd_ecc_stats - error correction stats * -- cgit v0.10.2 From 71220f80e7489b7fc1766f573ae89c64db2419ce Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Fri, 4 Oct 2013 10:05:36 +0530 Subject: mtd/ifc: Add support of 8K page size NAND flash Current IFC driver supports till 4K page size NAND flash. Add support of 8K NAND flash - Program Spare region size in csor_ext - Add nand_ecclayout for 4 bit & 8 bit ecc - Defines constants - Add support of 8K NAND boot. Signed-off-by: Prabhakar Kushwaha CC: Liu Po diff --git a/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c b/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c index 2d0fb43..64a5225 100644 --- a/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c +++ b/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c @@ -34,6 +34,9 @@ void init_early_memctl_regs(void) #ifdef CONFIG_SYS_CSPR0_EXT set_ifc_cspr_ext(IFC_CS0, CONFIG_SYS_CSPR0_EXT); #endif +#ifdef CONFIG_SYS_CSOR0_EXT + set_ifc_csor_ext(IFC_CS0, CONFIG_SYS_CSOR0_EXT); +#endif set_ifc_cspr(IFC_CS0, CONFIG_SYS_CSPR0); set_ifc_amask(IFC_CS0, CONFIG_SYS_AMASK0); set_ifc_csor(IFC_CS0, CONFIG_SYS_CSOR0); @@ -43,6 +46,9 @@ void init_early_memctl_regs(void) #ifdef CONFIG_SYS_CSPR1_EXT set_ifc_cspr_ext(IFC_CS1, CONFIG_SYS_CSPR1_EXT); #endif +#ifdef CONFIG_SYS_CSOR1_EXT + set_ifc_csor_ext(IFC_CS1, CONFIG_SYS_CSOR1_EXT); +#endif #if defined(CONFIG_SYS_CSPR1) && defined(CONFIG_SYS_CSOR1) set_ifc_ftim(IFC_CS1, IFC_FTIM0, CONFIG_SYS_CS1_FTIM0); set_ifc_ftim(IFC_CS1, IFC_FTIM1, CONFIG_SYS_CS1_FTIM1); @@ -57,6 +63,9 @@ void init_early_memctl_regs(void) #ifdef CONFIG_SYS_CSPR2_EXT set_ifc_cspr_ext(IFC_CS2, CONFIG_SYS_CSPR2_EXT); #endif +#ifdef CONFIG_SYS_CSOR2_EXT + set_ifc_csor_ext(IFC_CS2, CONFIG_SYS_CSOR2_EXT); +#endif #if defined(CONFIG_SYS_CSPR2) && defined(CONFIG_SYS_CSOR2) set_ifc_ftim(IFC_CS2, IFC_FTIM0, CONFIG_SYS_CS2_FTIM0); set_ifc_ftim(IFC_CS2, IFC_FTIM1, CONFIG_SYS_CS2_FTIM1); @@ -71,6 +80,9 @@ void init_early_memctl_regs(void) #ifdef CONFIG_SYS_CSPR3_EXT set_ifc_cspr_ext(IFC_CS3, CONFIG_SYS_CSPR3_EXT); #endif +#ifdef CONFIG_SYS_CSOR3_EXT + set_ifc_csor_ext(IFC_CS3, CONFIG_SYS_CSOR3_EXT); +#endif #if defined(CONFIG_SYS_CSPR3) && defined(CONFIG_SYS_CSOR3) set_ifc_ftim(IFC_CS3, IFC_FTIM0, CONFIG_SYS_CS3_FTIM0); set_ifc_ftim(IFC_CS3, IFC_FTIM1, CONFIG_SYS_CS3_FTIM1); @@ -85,6 +97,9 @@ void init_early_memctl_regs(void) #ifdef CONFIG_SYS_CSPR4_EXT set_ifc_cspr_ext(IFC_CS4, CONFIG_SYS_CSPR4_EXT); #endif +#ifdef CONFIG_SYS_CSOR4_EXT + set_ifc_csor_ext(IFC_CS4, CONFIG_SYS_CSOR4_EXT); +#endif #if defined(CONFIG_SYS_CSPR4) && defined(CONFIG_SYS_CSOR4) set_ifc_ftim(IFC_CS4, IFC_FTIM0, CONFIG_SYS_CS4_FTIM0); set_ifc_ftim(IFC_CS4, IFC_FTIM1, CONFIG_SYS_CS4_FTIM1); @@ -99,6 +114,9 @@ void init_early_memctl_regs(void) #ifdef CONFIG_SYS_CSPR5_EXT set_ifc_cspr_ext(IFC_CS5, CONFIG_SYS_CSPR5_EXT); #endif +#ifdef CONFIG_SYS_CSOR5_EXT + set_ifc_csor_ext(IFC_CS5, CONFIG_SYS_CSOR5_EXT); +#endif #if defined(CONFIG_SYS_CSPR5) && defined(CONFIG_SYS_CSOR5) set_ifc_ftim(IFC_CS5, IFC_FTIM0, CONFIG_SYS_CS5_FTIM0); set_ifc_ftim(IFC_CS5, IFC_FTIM1, CONFIG_SYS_CS5_FTIM1); @@ -113,6 +131,9 @@ void init_early_memctl_regs(void) #ifdef CONFIG_SYS_CSPR6_EXT set_ifc_cspr_ext(IFC_CS6, CONFIG_SYS_CSPR6_EXT); #endif +#ifdef CONFIG_SYS_CSOR6_EXT + set_ifc_csor_ext(IFC_CS6, CONFIG_SYS_CSOR6_EXT); +#endif #if defined(CONFIG_SYS_CSPR6) && defined(CONFIG_SYS_CSOR6) set_ifc_ftim(IFC_CS6, IFC_FTIM0, CONFIG_SYS_CS6_FTIM0); set_ifc_ftim(IFC_CS6, IFC_FTIM1, CONFIG_SYS_CS6_FTIM1); @@ -127,6 +148,9 @@ void init_early_memctl_regs(void) #ifdef CONFIG_SYS_CSPR7_EXT set_ifc_cspr_ext(IFC_CS7, CONFIG_SYS_CSPR7_EXT); #endif +#ifdef CONFIG_SYS_CSOR7_EXT + set_ifc_csor_ext(IFC_CS7, CONFIG_SYS_CSOR7_EXT); +#endif #if defined(CONFIG_SYS_CSPR7) && defined(CONFIG_SYS_CSOR7) set_ifc_ftim(IFC_CS7, IFC_FTIM0, CONFIG_SYS_CS7_FTIM0); set_ifc_ftim(IFC_CS7, IFC_FTIM1, CONFIG_SYS_CS7_FTIM1); diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/arch/powerpc/include/asm/fsl_ifc.h index a945e4b..182b1a6 100644 --- a/arch/powerpc/include/asm/fsl_ifc.h +++ b/arch/powerpc/include/asm/fsl_ifc.h @@ -77,6 +77,7 @@ #define CSOR_NAND_PGS_512 0x00000000 #define CSOR_NAND_PGS_2K 0x00080000 #define CSOR_NAND_PGS_4K 0x00100000 +#define CSOR_NAND_PGS_8K 0x00180000 /* Spare region Size */ #define CSOR_NAND_SPRZ_MASK 0x0000E000 #define CSOR_NAND_SPRZ_SHIFT 13 @@ -86,6 +87,7 @@ #define CSOR_NAND_SPRZ_210 0x00006000 #define CSOR_NAND_SPRZ_218 0x00008000 #define CSOR_NAND_SPRZ_224 0x0000A000 +#define CSOR_NAND_SPRZ_CSOR_EXT 0x0000C000 /* Pages Per Block */ #define CSOR_NAND_PB_MASK 0x00000700 #define CSOR_NAND_PB_SHIFT 8 diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 1d18815..49b63af 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -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 @@ -913,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; diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/fsl_ifc_spl.c index d462265..9fa5ccb 100644 --- a/drivers/mtd/nand/fsl_ifc_spl.c +++ b/drivers/mtd/nand/fsl_ifc_spl.c @@ -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 { -- cgit v0.10.2 From affd520f8ce506eab96e66ad525c4807871e2981 Mon Sep 17 00:00:00 2001 From: Prabhakar Kushwaha Date: Fri, 4 Oct 2013 10:05:50 +0530 Subject: board/c29xpcie: Add support of 8K page size NAND flash Defines constants required to support 8K page size NAND flash. Signed-off-by: Prabhakar Kushwaha diff --git a/include/configs/C29XPCIE.h b/include/configs/C29XPCIE.h index 08156c5..bb15745 100644 --- a/include/configs/C29XPCIE.h +++ b/include/configs/C29XPCIE.h @@ -191,13 +191,14 @@ | CSPR_MSEL_NAND \ | CSPR_V) #define CONFIG_SYS_NAND_AMASK IFC_AMASK(64*1024) +#define CONFIG_SYS_NAND_OOBSIZE 0x00000280 /* 640b */ #define CONFIG_SYS_NAND_CSOR (CSOR_NAND_ECC_ENC_EN /* ECC on encode */ \ | CSOR_NAND_ECC_DEC_EN /* ECC on decode */ \ | CSOR_NAND_ECC_MODE_4 /* 4-bit ECC */ \ - | CSOR_NAND_RAL_2 /* RAL = 2 Bytes */ \ - | CSOR_NAND_PGS_2K /* Page Size = 2k */ \ - | CSOR_NAND_SPRZ_64 /* Spare size = 64 */ \ - | CSOR_NAND_PB(64)) /* 64 Pages Per Block */ + | CSOR_NAND_RAL_3 /* RAL = 3 Bytes */ \ + | CSOR_NAND_PGS_8K /* Page Size = 8K */ \ + | CSOR_NAND_SPRZ_CSOR_EXT /*oob in csor_ext*/\ + | CSOR_NAND_PB(128)) /*128 Pages Per Block*/ #define CONFIG_SYS_NAND_FTIM0 (FTIM0_NAND_TCCST(0x01) | \ FTIM0_NAND_TWP(0x0c) | \ FTIM0_NAND_TWCHT(0x08) | \ @@ -224,6 +225,7 @@ #define CONFIG_SYS_CSPR1 CONFIG_SYS_NAND_CSPR #define CONFIG_SYS_AMASK1 CONFIG_SYS_NAND_AMASK #define CONFIG_SYS_CSOR1 CONFIG_SYS_NAND_CSOR +#define CONFIG_SYS_CSOR1_EXT CONFIG_SYS_NAND_OOBSIZE #define CONFIG_SYS_CS1_FTIM0 CONFIG_SYS_NAND_FTIM0 #define CONFIG_SYS_CS1_FTIM1 CONFIG_SYS_NAND_FTIM1 #define CONFIG_SYS_CS1_FTIM2 CONFIG_SYS_NAND_FTIM2 -- cgit v0.10.2 From 16dddef6050471f47c84b6c929ae3c4bc9c0fb46 Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Fri, 18 Oct 2013 17:46:31 +0800 Subject: mtd: atmel_nand: enable PMECC support for 8k bytes page NAND flash increase the delay to 75us to support the 8k bytes page nand flash Signed-off-by: Josh Wu diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 10011c6..1d8c860 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -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,6 +841,13 @@ 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"); return -EINVAL; @@ -1190,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) -- cgit v0.10.2 From d02a60a16e40b185a9eb5ad3bc038584fd7264c2 Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Fri, 18 Oct 2013 17:46:32 +0800 Subject: sama5d3xek: support larger than 4G nand flash Signed-off-by: Josh Wu diff --git a/board/atmel/sama5d3xek/sama5d3xek.c b/board/atmel/sama5d3xek/sama5d3xek.c index b0965ef..83fd63f 100644 --- a/board/atmel/sama5d3xek/sama5d3xek.c +++ b/board/atmel/sama5d3xek/sama5d3xek.c @@ -131,7 +131,8 @@ static void sama5d3xek_lcd_hw_init(void) void lcd_show_board_info(void) { - ulong dram_size, nand_size; + ulong dram_size; + uint64_t nand_size; int i; char temp[32]; @@ -150,7 +151,7 @@ void lcd_show_board_info(void) for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) nand_size += nand_info[i].size; #endif - lcd_printf("%ld MB SDRAM, %ld MB NAND\n", + lcd_printf("%ld MB SDRAM, %lld MB NAND\n", dram_size >> 20, nand_size >> 20); } #endif /* CONFIG_LCD_INFO */ -- cgit v0.10.2 From c55cc573eaf1ba7318b1b692c673a28b99f5195c Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Fri, 18 Oct 2013 17:46:33 +0800 Subject: mtd: atmel_nand: don't print bit correction message in driver Since for some MLC nand, bit errors happened too often. Just disable it to avoid noise Signed-off-by: Josh Wu diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 1d8c860..92547432 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -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]); } -- cgit v0.10.2 From c0dc3dec697e930d290145e127a86ff31f7c2dde Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Fri, 18 Oct 2013 17:46:34 +0800 Subject: mtd: atmel_nand: use dev_xxx instead of printk Signed-off-by: Josh Wu diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 92547432..16b7df0 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -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; } @@ -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; } @@ -849,7 +849,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, } 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, @@ -860,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 */ @@ -1043,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; } @@ -1053,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); @@ -1070,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; } @@ -1226,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); } -- cgit v0.10.2 From beba5f04f2215c81016fbfb727257ea6667aca85 Mon Sep 17 00:00:00 2001 From: pekon gupta Date: Mon, 18 Nov 2013 19:02:59 +0530 Subject: mtd: nand: omap: make am33xx/elm.c as common driver for all OMAPx and AMxxxx platforms ELM hardware engine which is used for ECC error detection, is present on all latest OMAP SoC (like OMAP4xxx, OMAP5xxx, DRA7xxx, AM33xx, AM43xx). Thus ELM driver should be moved to common drivers/mtd/nand/ folder so that all SoC having on-chip ELM hardware engine can re-use it. This patch has following changes: - mv arch/arm/include/asm/arch-am33xx/elm.h arch/arm/include/asm/omap_elm.h - mv arch/arm/cpu/armv7/am33xx/elm.c drivers/mtd/nand/omap_elm.c - update Makefiles - update #include - add CONFIG_NAND_OMAP_ELM to compile driver/mtd/nand/omap_elm.c and include in all board configs using AM33xx SoC platform. Signed-off-by: Pekon Gupta diff --git a/arch/arm/cpu/armv7/am33xx/Makefile b/arch/arm/cpu/armv7/am33xx/Makefile index 966fcab..5566310 100644 --- a/arch/arm/cpu/armv7/am33xx/Makefile +++ b/arch/arm/cpu/armv7/am33xx/Makefile @@ -19,4 +19,3 @@ obj-y += ddr.o obj-y += emif4.o obj-y += board.o obj-y += mux.o -obj-$(CONFIG_NAND_OMAP_GPMC) += elm.o diff --git a/arch/arm/cpu/armv7/am33xx/elm.c b/arch/arm/cpu/armv7/am33xx/elm.c deleted file mode 100644 index 8f1d6af..0000000 --- a/arch/arm/cpu/armv7/am33xx/elm.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * (C) Copyright 2010-2011 Texas Instruments, - * Mansoor Ahamed - * - * 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 -#include -#include -#include -#include -#include - -#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(); -} diff --git a/arch/arm/include/asm/arch-am33xx/elm.h b/arch/arm/include/asm/arch-am33xx/elm.h deleted file mode 100644 index 45454ea..0000000 --- a/arch/arm/include/asm/arch-am33xx/elm.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * (C) Copyright 2010-2011 Texas Instruments, - * Mansoor Ahamed - * - * Derived from work done by Rohit Choraria for omap3 - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#ifndef __ASM_ARCH_ELM_H -#define __ASM_ARCH_ELM_H -/* - * ELM Module Registers - */ - -/* ELM registers bit fields */ -#define ELM_SYSCONFIG_SOFTRESET_MASK (0x2) -#define ELM_SYSCONFIG_SOFTRESET (0x2) -#define ELM_SYSSTATUS_RESETDONE_MASK (0x1) -#define ELM_SYSSTATUS_RESETDONE (0x1) -#define ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK (0x3) -#define ELM_LOCATION_CONFIG_ECC_SIZE_MASK (0x7FF0000) -#define ELM_LOCATION_CONFIG_ECC_SIZE_POS (16) -#define ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID (0x00010000) -#define ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK (0x100) -#define ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK (0x1F) - -#ifndef __ASSEMBLY__ - -enum bch_level { - BCH_4_BIT = 0, - BCH_8_BIT, - BCH_16_BIT -}; - - -/* BCH syndrome registers */ -struct syndrome { - u32 syndrome_fragment_x[7]; /* 0x400, 0x404.... 0x418 */ - u8 res1[36]; /* 0x41c */ -}; - -/* BCH error status & location register */ -struct location { - u32 location_status; /* 0x800 */ - u8 res1[124]; /* 0x804 */ - u32 error_location_x[16]; /* 0x880.... */ - u8 res2[64]; /* 0x8c0 */ -}; - -/* BCH ELM register map - do not try to allocate memmory for this structure. - * We have used plenty of reserved variables to fill the slots in the ELM - * register memory map. - * Directly initialize the struct pointer to ELM base address. - */ -struct elm { - u32 rev; /* 0x000 */ - u8 res1[12]; /* 0x004 */ - u32 sysconfig; /* 0x010 */ - u32 sysstatus; /* 0x014 */ - u32 irqstatus; /* 0x018 */ - u32 irqenable; /* 0x01c */ - u32 location_config; /* 0x020 */ - u8 res2[92]; /* 0x024 */ - u32 page_ctrl; /* 0x080 */ - u8 res3[892]; /* 0x084 */ - struct syndrome syndrome_fragments[8]; /* 0x400 */ - u8 res4[512]; /* 0x600 */ - struct location error_location[8]; /* 0x800 */ -}; - -int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, - u32 *error_locations); -int elm_config(enum bch_level level); -void elm_reset(void); -void elm_init(void); -#endif /* __ASSEMBLY__ */ -#endif /* __ASM_ARCH_ELM_H */ diff --git a/arch/arm/include/asm/omap_elm.h b/arch/arm/include/asm/omap_elm.h new file mode 100644 index 0000000..45454ea --- /dev/null +++ b/arch/arm/include/asm/omap_elm.h @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2010-2011 Texas Instruments, + * Mansoor Ahamed + * + * Derived from work done by Rohit Choraria for omap3 + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#ifndef __ASM_ARCH_ELM_H +#define __ASM_ARCH_ELM_H +/* + * ELM Module Registers + */ + +/* ELM registers bit fields */ +#define ELM_SYSCONFIG_SOFTRESET_MASK (0x2) +#define ELM_SYSCONFIG_SOFTRESET (0x2) +#define ELM_SYSSTATUS_RESETDONE_MASK (0x1) +#define ELM_SYSSTATUS_RESETDONE (0x1) +#define ELM_LOCATION_CONFIG_ECC_BCH_LEVEL_MASK (0x3) +#define ELM_LOCATION_CONFIG_ECC_SIZE_MASK (0x7FF0000) +#define ELM_LOCATION_CONFIG_ECC_SIZE_POS (16) +#define ELM_SYNDROME_FRAGMENT_6_SYNDROME_VALID (0x00010000) +#define ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK (0x100) +#define ELM_LOCATION_STATUS_ECC_NB_ERRORS_MASK (0x1F) + +#ifndef __ASSEMBLY__ + +enum bch_level { + BCH_4_BIT = 0, + BCH_8_BIT, + BCH_16_BIT +}; + + +/* BCH syndrome registers */ +struct syndrome { + u32 syndrome_fragment_x[7]; /* 0x400, 0x404.... 0x418 */ + u8 res1[36]; /* 0x41c */ +}; + +/* BCH error status & location register */ +struct location { + u32 location_status; /* 0x800 */ + u8 res1[124]; /* 0x804 */ + u32 error_location_x[16]; /* 0x880.... */ + u8 res2[64]; /* 0x8c0 */ +}; + +/* BCH ELM register map - do not try to allocate memmory for this structure. + * We have used plenty of reserved variables to fill the slots in the ELM + * register memory map. + * Directly initialize the struct pointer to ELM base address. + */ +struct elm { + u32 rev; /* 0x000 */ + u8 res1[12]; /* 0x004 */ + u32 sysconfig; /* 0x010 */ + u32 sysstatus; /* 0x014 */ + u32 irqstatus; /* 0x018 */ + u32 irqenable; /* 0x01c */ + u32 location_config; /* 0x020 */ + u8 res2[92]; /* 0x024 */ + u32 page_ctrl; /* 0x080 */ + u8 res3[892]; /* 0x084 */ + struct syndrome syndrome_fragments[8]; /* 0x400 */ + u8 res4[512]; /* 0x600 */ + struct location error_location[8]; /* 0x800 */ +}; + +int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, + u32 *error_locations); +int elm_config(enum bch_level level); +void elm_reset(void); +void elm_init(void); +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_ARCH_ELM_H */ diff --git a/doc/README.nand b/doc/README.nand index 3a507b6..ce7ea5e 100644 --- a/doc/README.nand +++ b/doc/README.nand @@ -179,6 +179,25 @@ Configuration Options: Please convert your driver even if you don't need the extra flexibility, so that one day we can eliminate the old mechanism. + +Platform specific options +========================= + CONFIG_NAND_OMAP_GPMC + Enables omap_gpmc.c driver for OMAPx and AMxxxx platforms. + GPMC controller is used for parallel NAND flash devices, and can + do ECC calculation (not ECC error detection) for HAM1, BCH4, BCH8 + and BCH16 ECC algorithms. + + CONFIG_NAND_OMAP_ELM + Enables omap_elm.c driver for OMAPx and AMxxxx platforms. + ELM controller is used for ECC error detection (not ECC calculation) + of BCH4, BCH8 and BCH16 ECC algorithms. + Some legacy platforms like OMAP3xx do not have in-built ELM h/w engine, + thus such SoC platforms need to depend on software library for ECC error + detection. However ECC calculation on such plaforms would still be + done by GPMC controller. + + NOTE: ===== diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index eb1eafa..e145cd1 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -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 diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c new file mode 100644 index 0000000..2aa7807 --- /dev/null +++ b/drivers/mtd/nand/omap_elm.c @@ -0,0 +1,196 @@ +/* + * (C) Copyright 2010-2011 Texas Instruments, + * Mansoor Ahamed + * + * 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 +#include +#include +#include +#include +#include + +#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(); +} diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index ec1787f..c828859 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -16,7 +16,7 @@ #include #include #ifdef CONFIG_AM33XX -#include +#include #endif static uint8_t cs; diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index c2ba7e3..73d8b4d 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -221,6 +221,8 @@ #define CONFIG_SPL_LDSCRIPT "$(CPUDIR)/am33xx/u-boot-spl.lds" #ifdef CONFIG_NAND +#define CONFIG_NAND_OMAP_GPMC +#define CONFIG_NAND_OMAP_ELM #define CONFIG_SYS_NAND_5_ADDR_CYCLE #define CONFIG_SYS_NAND_PAGE_COUNT (CONFIG_SYS_NAND_BLOCK_SIZE / \ CONFIG_SYS_NAND_PAGE_SIZE) diff --git a/include/configs/am335x_igep0033.h b/include/configs/am335x_igep0033.h index 2c69d4e..88ced73 100644 --- a/include/configs/am335x_igep0033.h +++ b/include/configs/am335x_igep0033.h @@ -187,6 +187,7 @@ /* NAND support */ #define CONFIG_NAND #define CONFIG_NAND_OMAP_GPMC +#define CONFIG_NAND_OMAP_ELM #define GPMC_NAND_ECC_LP_x16_LAYOUT 1 #define CONFIG_SYS_NAND_BASE (0x08000000) /* phys address CS0 */ #define CONFIG_SYS_MAX_NAND_DEVICE 1 diff --git a/include/configs/siemens-am33x-common.h b/include/configs/siemens-am33x-common.h index 9eb0a04..f3b4197 100644 --- a/include/configs/siemens-am33x-common.h +++ b/include/configs/siemens-am33x-common.h @@ -431,6 +431,7 @@ "\0" #define CONFIG_NAND_OMAP_GPMC +#define CONFIG_NAND_OMAP_ELM #define GPMC_NAND_ECC_LP_x16_LAYOUT 1 #define CONFIG_SYS_NAND_BASE (0x08000000) /* physical address */ /* to access nand at */ -- cgit v0.10.2 From d016dc42cedbf6102e100fa9ecb58462edfb14f8 Mon Sep 17 00:00:00 2001 From: pekon gupta Date: Mon, 18 Nov 2013 19:03:00 +0530 Subject: mtd: nand: omap: enable BCH ECC scheme using ELM for generic platform BCH8_ECC scheme implemented in omap_gpmc.c driver has following favours +-----------------------------------+-----------------+-----------------+ |ECC Scheme | ECC Calculation | Error Detection | +-----------------------------------+-----------------+-----------------+ |OMAP_ECC_BCH8_CODE_HW |GPMC |ELM H/W engine | |OMAP_ECC_BCH8_CODE_HW_DETECTION_SW |GPMC |S/W BCH library | +-----------------------------------+-----------------+-----------------+ Current implementation limits the BCH8_CODE_HW only for AM33xx device family. (using CONFIG_AM33XX). However, other SoC families (like TI81xx) also have ELM hardware module, and can support ECC error detection using ELM. This patch - removes CONFIG_AM33xx Thus this driver can be reused by all devices having ELM h/w engine. - adds omap_select_ecc_scheme() A common function to handle ecc-scheme related configurations. This can be used both during device-probe and via user-space u-boot commads to change ecc-scheme. During device probe ecc-scheme is selected based on CONFIG_NAND_OMAP_ELM or CONFIG_NAND_OMAP_BCH8 - enables CONFIG_BCH S/W library (lib/bch.c) required by OMAP_ECC_BCHx_CODE_HW_DETECTION_SW is enabled by CONFIG_BCH. - enables CONFIG_SYS_NAND_ONFI_DETECTION for auto-detection of ONFI compliant NAND devices - updates following README doc doc/README.nand board/ti/am335x/README doc/README.omap3 Signed-off-by: Pekon Gupta [scottwood@freescale.com: fixed unused variable warning] Signed-off-by: Scott Wood diff --git a/arch/arm/include/asm/omap_gpmc.h b/arch/arm/include/asm/omap_gpmc.h index dd40cb6..d4143ec 100644 --- a/arch/arm/include/asm/omap_gpmc.h +++ b/arch/arm/include/asm/omap_gpmc.h @@ -68,4 +68,20 @@ } #endif +enum omap_ecc { + /* 1-bit ECC calculation by Software, Error detection by Software */ + OMAP_ECC_HAM1_CODE_SW = 1, /* avoid un-initialized int can be 0x0 */ + /* 1-bit ECC calculation by GPMC, Error detection by Software */ + /* ECC layout compatible to legacy ROMCODE. */ + OMAP_ECC_HAM1_CODE_HW, + /* 4-bit ECC calculation by GPMC, Error detection by Software */ + OMAP_ECC_BCH4_CODE_HW_DETECTION_SW, + /* 4-bit ECC calculation by GPMC, Error detection by ELM */ + OMAP_ECC_BCH4_CODE_HW, + /* 8-bit ECC calculation by GPMC, Error detection by Software */ + OMAP_ECC_BCH8_CODE_HW_DETECTION_SW, + /* 8-bit ECC calculation by GPMC, Error detection by ELM */ + OMAP_ECC_BCH8_CODE_HW, +}; + #endif /* __ASM_OMAP_GPMC_H */ diff --git a/doc/README.nand b/doc/README.nand index ce7ea5e..487548f 100644 --- a/doc/README.nand +++ b/doc/README.nand @@ -180,6 +180,17 @@ Configuration Options: flexibility, so that one day we can eliminate the old mechanism. + CONFIG_SYS_NAND_ONFI_DETECTION + Enables detection of ONFI compliant devices during probe. + And fetching device parameters flashed on device, by parsing + ONFI parameter page. + + CONFIG_BCH + Enables software based BCH ECC algorithm present in lib/bch.c + This is used by SoC platforms which do not have built-in ELM + hardware engine required for BCH ECC correction. + + Platform specific options ========================= CONFIG_NAND_OMAP_GPMC diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index c828859..e6b289d 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -15,15 +15,13 @@ #include #include #include -#ifdef CONFIG_AM33XX #include -#endif + +#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"); - } -#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"); + 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; } -#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,32 @@ 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; - -#if defined(CONFIG_AM33XX) || defined(CONFIG_NAND_OMAP_BCH8) -#ifdef CONFIG_AM33XX - /* AM33xx uses the ELM */ - /* required in case of BCH */ - elm_init(); -#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; + nand->ecc.layout = &omap_ecclayout; + + /* select ECC scheme */ +#if defined(CONFIG_NAND_OMAP_ELM) + err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW, + CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); +#elif defined(CONFIG_NAND_OMAP_BCH8) + err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW_DETECTION_SW, + CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); +#elif !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC) + err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW, + 0, 0); #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 + err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_HW, + CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); #endif + if (err) + return err; #ifdef CONFIG_SPL_BUILD if (nand->options & NAND_BUSWIDTH_16) -- cgit v0.10.2 From 3f719069c884284b2457448a7afe32b02bd4f782 Mon Sep 17 00:00:00 2001 From: pekon gupta Date: Mon, 18 Nov 2013 19:03:01 +0530 Subject: mtd: nand: omap: add CONFIG_NAND_OMAP_ECCSCHEME for selection of ecc-scheme This patch adds new CONFIG_NAND_OMAP_ECCSCHEME, replacing other distributed CONFIG_xx used for selecting NAND ecc-schemes. This patch aims at solving following issues. 1) Currently ecc-scheme is tied to SoC platform, which prevents user to select other ecc-schemes also supported in hardware. like; - most of OMAP3 SoC platforms use only 1-bit Hamming ecc-scheme, inspite the fact that they can use higher ecc-schemes like 8-bit ecc-schemes with software based error detection (OMAP_ECC_BCH4_CODE_HW_DETECTION_SW). - most of AM33xx SoC plaforms use 8-bit BCH ecc-scheme for now, but hardware supports BCH16 ecc-scheme also. 2) Different platforms use different CONFIG_xx to select ecc-schemes, which adds confusion for user while migrating platforms. - *CONFIG_NAND_OMAP_ELM* which enables ELM hardware engine, selects only 8-bit BCH ecc-scheme with h/w based error-correction (OMAP_ECC_BCH8_CODE_HW) whereas ELM hardware engine supports other ecc-schemes also like; BCH4, and BCH16 (in future). - *CONFIG_NAND_OMAP_BCH8* selects 8-bit BCH ecc-scheme with s/w based error correction (OMAP_ECC_BCH8_CODE_HW_DETECTION_SW). - *CONFIG_SPL_NAND_SOFTECC* selects 1-bit Hamming ecc-scheme using s/w library Thus adding new *CONFIG_NAND_OMAP_ECCSCHEME* de-couples ecc-scheme dependency on SoC platform and NAND driver. And user can select ecc-scheme independently foreach board. However, selection some hardware based ecc-schemes (OMAP_ECC_BCHx_CODE_HW) still depends on presence of ELM hardware engine on SoC. (Refer doc/README.nand) Signed-off-by: Pekon Gupta diff --git a/doc/README.nand b/doc/README.nand index 487548f..b91f198 100644 --- a/doc/README.nand +++ b/doc/README.nand @@ -208,6 +208,29 @@ Platform specific options detection. However ECC calculation on such plaforms would still be done by GPMC controller. + CONFIG_NAND_OMAP_ECCSCHEME + On OMAP platforms, this CONFIG specifies NAND ECC scheme. + It can take following values: + OMAP_ECC_HAM1_CODE_SW + 1-bit Hamming code using software lib. + (for legacy devices only) + OMAP_ECC_HAM1_CODE_HW + 1-bit Hamming code using GPMC hardware. + (for legacy devices only) + OMAP_ECC_BCH4_CODE_HW_DETECTION_SW + 4-bit BCH code (unsupported) + OMAP_ECC_BCH4_CODE_HW + 4-bit BCH code (unsupported) + OMAP_ECC_BCH8_CODE_HW_DETECTION_SW + 8-bit BCH code with + - ecc calculation using GPMC hardware engine, + - error detection using software library. + - requires CONFIG_BCH to enable software BCH library + (For legacy device which do not have ELM h/w engine) + OMAP_ECC_BCH8_CODE_HW + 8-bit BCH code with + - ecc calculation using GPMC hardware engine, + - error detection using ELM hardware engine. NOTE: ===== diff --git a/doc/README.omap3 b/doc/README.omap3 index 1fbe79d..a62c357 100644 --- a/doc/README.omap3 +++ b/doc/README.omap3 @@ -161,8 +161,7 @@ BCH8 To enable hardware assisted BCH8 (8-bit BCH [Bose, Chaudhuri, Hocquenghem]) on OMAP3 devices we can use the BCH library in lib/bch.c. To do so add CONFIG_BCH -to enable the library and CONFIG_NAND_OMAP_BCH8 to to enable hardware assisted -syndrom generation to your board config. +and set CONFIG_NAND_OMAP_ECCSCHEME=5 (refer README.nand) for selecting BCH8_SW. The NAND OOB layout is the same as in linux kernel, if the linux kernel BCH8 implementation for OMAP3 works for you so the u-boot version should also. When you require the SPL to read with BCH8 there are two more configs to diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index e6b289d..5e7e6b3 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -1004,18 +1004,13 @@ int board_nand_init(struct nand_chip *nand) nand->ecc.layout = &omap_ecclayout; /* select ECC scheme */ -#if defined(CONFIG_NAND_OMAP_ELM) - err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW, +#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); -#elif defined(CONFIG_NAND_OMAP_BCH8) - err = omap_select_ecc_scheme(nand, OMAP_ECC_BCH8_CODE_HW_DETECTION_SW, - CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); -#elif !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC) +#else + /* pagesize and oobsize are not required to configure sw ecc-scheme */ err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW, 0, 0); -#else - err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_HW, - CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE); #endif if (err) return err; diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index 73d8b4d..1d59167 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -240,7 +240,8 @@ #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 14 - +#define CONFIG_SYS_NAND_ONFI_DETECTION +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_BCH8_CODE_HW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE #define CONFIG_SYS_NAND_U_BOOT_OFFS 0x80000 #endif diff --git a/include/configs/am335x_igep0033.h b/include/configs/am335x_igep0033.h index 88ced73..115d1b3 100644 --- a/include/configs/am335x_igep0033.h +++ b/include/configs/am335x_igep0033.h @@ -264,6 +264,7 @@ #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 14 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_BCH8_CODE_HW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE diff --git a/include/configs/am3517_crane.h b/include/configs/am3517_crane.h index c5e67bf..b24ef54 100644 --- a/include/configs/am3517_crane.h +++ b/include/configs/am3517_crane.h @@ -340,6 +340,7 @@ 10, 11, 12, 13} #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_HW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE #define CONFIG_SYS_NAND_U_BOOT_OFFS 0x80000 diff --git a/include/configs/am3517_evm.h b/include/configs/am3517_evm.h index 5ff65c6..f13fd70 100644 --- a/include/configs/am3517_evm.h +++ b/include/configs/am3517_evm.h @@ -334,6 +334,7 @@ 10, 11, 12, 13} #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_HW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE #define CONFIG_SYS_NAND_U_BOOT_OFFS 0x80000 diff --git a/include/configs/devkit8000.h b/include/configs/devkit8000.h index 8343891..13315dc 100644 --- a/include/configs/devkit8000.h +++ b/include/configs/devkit8000.h @@ -327,6 +327,7 @@ #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_HW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE diff --git a/include/configs/mcx.h b/include/configs/mcx.h index 4619dfb..56102f5 100644 --- a/include/configs/mcx.h +++ b/include/configs/mcx.h @@ -353,7 +353,6 @@ #define CONFIG_SPL_FRAMEWORK #define CONFIG_SPL_BOARD_INIT #define CONFIG_SPL_NAND_SIMPLE -#define CONFIG_SPL_NAND_SOFTECC #define CONFIG_SPL_LIBCOMMON_SUPPORT #define CONFIG_SPL_LIBDISK_SUPPORT @@ -395,6 +394,7 @@ 56, 57, 58, 59, 60, 61, 62, 63} #define CONFIG_SYS_NAND_ECCSIZE 256 #define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_SW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h index 47d9902..8b68635 100644 --- a/include/configs/omap3_beagle.h +++ b/include/configs/omap3_beagle.h @@ -432,6 +432,7 @@ 10, 11, 12, 13} #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_HW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE #define CONFIG_SYS_NAND_U_BOOT_OFFS 0x80000 diff --git a/include/configs/omap3_evm.h b/include/configs/omap3_evm.h index 3ace8bb..b7638fb 100644 --- a/include/configs/omap3_evm.h +++ b/include/configs/omap3_evm.h @@ -107,6 +107,7 @@ 10, 11, 12, 13} #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_HW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE #define CONFIG_SYS_NAND_U_BOOT_OFFS 0x80000 diff --git a/include/configs/omap3_evm_quick_nand.h b/include/configs/omap3_evm_quick_nand.h index 9ecd70d..4427e88 100644 --- a/include/configs/omap3_evm_quick_nand.h +++ b/include/configs/omap3_evm_quick_nand.h @@ -86,6 +86,7 @@ 10, 11, 12, 13} #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_HW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE #define CONFIG_SYS_NAND_U_BOOT_OFFS 0x80000 diff --git a/include/configs/omap3_igep00x0.h b/include/configs/omap3_igep00x0.h index ac36ac6..cdaa9ba 100644 --- a/include/configs/omap3_igep00x0.h +++ b/include/configs/omap3_igep00x0.h @@ -362,6 +362,7 @@ 10, 11, 12, 13} #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_HW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE #define CONFIG_SYS_NAND_U_BOOT_OFFS 0x80000 #endif diff --git a/include/configs/omap3_overo.h b/include/configs/omap3_overo.h index 4641694..00d7c6c 100644 --- a/include/configs/omap3_overo.h +++ b/include/configs/omap3_overo.h @@ -325,6 +325,7 @@ 10, 11, 12, 13} #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_HW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE #define CONFIG_SYS_NAND_U_BOOT_OFFS 0x80000 diff --git a/include/configs/siemens-am33x-common.h b/include/configs/siemens-am33x-common.h index f3b4197..e394478 100644 --- a/include/configs/siemens-am33x-common.h +++ b/include/configs/siemens-am33x-common.h @@ -196,6 +196,7 @@ #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 14 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_BCH8_CODE_HW #define CONFIG_SYS_NAND_ECCSTEPS 4 #define CONFIG_SYS_NAND_ECCTOTAL (CONFIG_SYS_NAND_ECCBYTES * \ diff --git a/include/configs/tam3517-common.h b/include/configs/tam3517-common.h index 683bc54..48698b5 100644 --- a/include/configs/tam3517-common.h +++ b/include/configs/tam3517-common.h @@ -225,7 +225,6 @@ #define CONFIG_SPL_BOARD_INIT #define CONFIG_SPL_CONSOLE #define CONFIG_SPL_NAND_SIMPLE -#define CONFIG_SPL_NAND_SOFTECC #define CONFIG_SPL_NAND_WORKSPACE 0x8f07f000 /* below BSS */ #define CONFIG_SPL_LIBCOMMON_SUPPORT @@ -262,6 +261,7 @@ 56, 57, 58, 59, 60, 61, 62, 63} #define CONFIG_SYS_NAND_ECCSIZE 256 #define CONFIG_SYS_NAND_ECCBYTES 3 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_HAM1_CODE_SW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE diff --git a/include/configs/tricorder.h b/include/configs/tricorder.h index 590eab7..3ca1fd0 100644 --- a/include/configs/tricorder.h +++ b/include/configs/tricorder.h @@ -138,7 +138,6 @@ #define CONFIG_SYS_MAX_NAND_DEVICE 1 /* Max number of NAND */ /* devices */ -#define CONFIG_NAND_OMAP_BCH8 #define CONFIG_BCH #define CONFIG_SYS_NAND_MAX_OOBFREE 2 #define CONFIG_SYS_NAND_MAX_ECCPOS 56 @@ -376,6 +375,7 @@ #define CONFIG_SYS_NAND_ECCSIZE 512 #define CONFIG_SYS_NAND_ECCBYTES 13 +#define CONFIG_NAND_OMAP_ECCSCHEME OMAP_ECC_BCH8_CODE_HW_DETECTION_SW #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE -- cgit v0.10.2 From 2c17e6d1d996a1b8b9325de15f253a13d5877dee Mon Sep 17 00:00:00 2001 From: pekon gupta Date: Mon, 18 Nov 2013 19:03:02 +0530 Subject: am335x: fix GPMC config for NAND and NOR SPL boot GPMC controller is common IP to interface with both NAND and NOR flash devices. Also, it supports max 8 chip-selects, which can be independently connected to any of the devices. But ROM code expects the boot-device to be connected to only chip-select[0]. Thus to resolve conflict between NOR and NAND boot. This patch: - combines NOR and NAND configs spread in board files to common gpmc_init() - configures GPMC based on boot-mode selected for SPL boot. Signed-off-by: Pekon Gupta diff --git a/arch/arm/cpu/armv7/am33xx/mem.c b/arch/arm/cpu/armv7/am33xx/mem.c index b6eb466..56c9e7d 100644 --- a/arch/arm/cpu/armv7/am33xx/mem.c +++ b/arch/arm/cpu/armv7/am33xx/mem.c @@ -22,17 +22,6 @@ struct gpmc *gpmc_cfg; -#if defined(CONFIG_CMD_NAND) -static const u32 gpmc_m_nand[GPMC_MAX_REG] = { - M_NAND_GPMC_CONFIG1, - M_NAND_GPMC_CONFIG2, - M_NAND_GPMC_CONFIG3, - M_NAND_GPMC_CONFIG4, - M_NAND_GPMC_CONFIG5, - M_NAND_GPMC_CONFIG6, 0 -}; -#endif - void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base, u32 size) @@ -61,11 +50,34 @@ void gpmc_init(void) { /* putting a blanket check on GPMC based on ZeBu for now */ gpmc_cfg = (struct gpmc *)GPMC_BASE; - -#ifdef CONFIG_CMD_NAND - const u32 *gpmc_config = NULL; - u32 base = 0; +#if defined(CONFIG_NOR) +/* configure GPMC for NOR */ + const u32 gpmc_regs[GPMC_MAX_REG] = { STNOR_GPMC_CONFIG1, + STNOR_GPMC_CONFIG2, + STNOR_GPMC_CONFIG3, + STNOR_GPMC_CONFIG4, + STNOR_GPMC_CONFIG5, + STNOR_GPMC_CONFIG6, + STNOR_GPMC_CONFIG7 + }; + u32 size = GPMC_SIZE_16M; + u32 base = CONFIG_SYS_FLASH_BASE; +#elif defined(CONFIG_NAND) +/* configure GPMC for NAND */ + const u32 gpmc_regs[GPMC_MAX_REG] = { M_NAND_GPMC_CONFIG1, + M_NAND_GPMC_CONFIG2, + M_NAND_GPMC_CONFIG3, + M_NAND_GPMC_CONFIG4, + M_NAND_GPMC_CONFIG5, + M_NAND_GPMC_CONFIG6, + 0 + }; + u32 size = GPMC_SIZE_256M; + u32 base = CONFIG_SYS_NAND_BASE; +#else + const u32 gpmc_regs[GPMC_MAX_REG] = { 0, 0, 0, 0, 0, 0, 0 }; u32 size = 0; + u32 base = 0; #endif /* global settings */ writel(0x00000008, &gpmc_cfg->sysconfig); @@ -81,12 +93,6 @@ void gpmc_init(void) */ writel(0, &gpmc_cfg->cs[0].config7); sdelay(1000); - -#ifdef CONFIG_CMD_NAND - gpmc_config = gpmc_m_nand; - - base = PISMO1_NAND_BASE; - size = PISMO1_NAND_SIZE; - enable_gpmc_cs_config(gpmc_config, &gpmc_cfg->cs[0], base, size); -#endif + /* enable chip-select specific configurations */ + enable_gpmc_cs_config(gpmc_regs, &gpmc_cfg->cs[0], base, size); } diff --git a/arch/arm/include/asm/arch-am33xx/mem.h b/arch/arm/include/asm/arch-am33xx/mem.h index 983ea28..e7e8c58 100644 --- a/arch/arm/include/asm/arch-am33xx/mem.h +++ b/arch/arm/include/asm/arch-am33xx/mem.h @@ -68,9 +68,4 @@ #define PISMO2_NAND_CS0 7 #define PISMO2_NAND_CS1 8 -/* make it readable for the gpmc_init */ -#define PISMO1_NOR_BASE FLASH_BASE -#define PISMO1_NAND_BASE CONFIG_SYS_NAND_BASE -#define PISMO1_NAND_SIZE GPMC_SIZE_256M - #endif /* endif _MEM_H_ */ diff --git a/board/ti/am335x/board.c b/board/ti/am335x/board.c index 57fedab..0299dd6 100644 --- a/board/ti/am335x/board.c +++ b/board/ti/am335x/board.c @@ -481,26 +481,14 @@ void sdram_init(void) */ int board_init(void) { -#ifdef CONFIG_NOR - const u32 gpmc_nor[GPMC_MAX_REG] = { STNOR_GPMC_CONFIG1, - STNOR_GPMC_CONFIG2, STNOR_GPMC_CONFIG3, STNOR_GPMC_CONFIG4, - STNOR_GPMC_CONFIG5, STNOR_GPMC_CONFIG6, STNOR_GPMC_CONFIG7 }; -#endif - #if defined(CONFIG_HW_WATCHDOG) hw_watchdog_init(); #endif gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; - +#if defined(CONFIG_NOR) || defined(CONFIG_NAND) gpmc_init(); - -#ifdef CONFIG_NOR - /* Reconfigure CS0 for NOR instead of NAND. */ - enable_gpmc_cs_config(gpmc_nor, &gpmc_cfg->cs[0], - CONFIG_SYS_FLASH_BASE, GPMC_SIZE_16M); #endif - return 0; } -- cgit v0.10.2