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 --- doc/README.nand | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'doc') diff --git a/doc/README.nand b/doc/README.nand index 913e9b50b80..3a507b6c816 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. -- cgit v1.3.1 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 --- arch/arm/cpu/armv7/am33xx/Makefile | 1 - arch/arm/cpu/armv7/am33xx/elm.c | 196 --------------------------------- arch/arm/include/asm/arch-am33xx/elm.h | 77 ------------- arch/arm/include/asm/omap_elm.h | 77 +++++++++++++ doc/README.nand | 19 ++++ drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/omap_elm.c | 196 +++++++++++++++++++++++++++++++++ drivers/mtd/nand/omap_gpmc.c | 2 +- include/configs/am335x_evm.h | 2 + include/configs/am335x_igep0033.h | 1 + include/configs/siemens-am33x-common.h | 1 + 11 files changed, 298 insertions(+), 275 deletions(-) delete mode 100644 arch/arm/cpu/armv7/am33xx/elm.c delete mode 100644 arch/arm/include/asm/arch-am33xx/elm.h create mode 100644 arch/arm/include/asm/omap_elm.h create mode 100644 drivers/mtd/nand/omap_elm.c (limited to 'doc') diff --git a/arch/arm/cpu/armv7/am33xx/Makefile b/arch/arm/cpu/armv7/am33xx/Makefile index 966fcab71b4..5566310d948 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 8f1d6afdd39..00000000000 --- 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 45454eaf0f1..00000000000 --- 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 00000000000..45454eaf0f1 --- /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 3a507b6c816..ce7ea5e1e9d 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 eb1eafaf064..e145cd18421 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 00000000000..2aa7807f3e5 --- /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 ec1787f2249..c8288597a49 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 c2ba7e35d89..73d8b4dfba4 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 2c69d4e30c5..88ced7311f5 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 9eb0a04da66..f3b41975cf5 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 v1.3.1 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 --- arch/arm/include/asm/omap_gpmc.h | 16 ++ doc/README.nand | 11 ++ drivers/mtd/nand/omap_gpmc.c | 326 ++++++++++++++++++++++++--------------- 3 files changed, 228 insertions(+), 125 deletions(-) (limited to 'doc') diff --git a/arch/arm/include/asm/omap_gpmc.h b/arch/arm/include/asm/omap_gpmc.h index dd40cb6c162..d4143ecd80d 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 ce7ea5e1e9d..487548fcb8e 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 c8288597a49..e6b289dec84 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 v1.3.1 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 --- doc/README.nand | 23 +++++++++++++++++++++++ doc/README.omap3 | 3 +-- drivers/mtd/nand/omap_gpmc.c | 13 ++++--------- include/configs/am335x_evm.h | 3 ++- include/configs/am335x_igep0033.h | 1 + include/configs/am3517_crane.h | 1 + include/configs/am3517_evm.h | 1 + include/configs/devkit8000.h | 1 + include/configs/mcx.h | 2 +- include/configs/omap3_beagle.h | 1 + include/configs/omap3_evm.h | 1 + include/configs/omap3_evm_quick_nand.h | 1 + include/configs/omap3_igep00x0.h | 1 + include/configs/omap3_overo.h | 1 + include/configs/siemens-am33x-common.h | 1 + include/configs/tam3517-common.h | 2 +- include/configs/tricorder.h | 2 +- 17 files changed, 43 insertions(+), 15 deletions(-) (limited to 'doc') diff --git a/doc/README.nand b/doc/README.nand index 487548fcb8e..b91f1985d18 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 1fbe79db37d..a62c3574054 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 e6b289dec84..5e7e6b33754 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 73d8b4dfba4..1d5916753db 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 88ced7311f5..115d1b37c9e 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 c5e67bf87d4..b24ef541438 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 5ff65c6d58c..f13fd7001cc 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 8343891cb8d..13315dc4b6b 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 4619dfb3e47..56102f5712f 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 47d99020887..8b686356685 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 3ace8bb6e5c..b7638fb8a68 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 9ecd70d55b0..4427e88b7e4 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 ac36ac69504..cdaa9ba9a44 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 46416946c79..00d7c6cebca 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 f3b41975cf5..e3944782f68 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 683bc54a2c1..48698b57da4 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 590eab7e483..3ca1fd0e657 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 v1.3.1