diff options
Diffstat (limited to 'drivers/mtd/nand/omap_gpmc.c')
-rw-r--r-- | drivers/mtd/nand/omap_gpmc.c | 76 |
1 files changed, 67 insertions, 9 deletions
diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index 1a636cad236..865065e03b3 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -390,6 +390,35 @@ static void micron_set_chip_ecc(struct mtd_info *mtd, int enable) #endif } +void nand_disable_in_chip_ecc(void) +{ + struct nand_chip *nand; + struct mtd_info *mtd; + + if (nand_curr_device < 0 || + nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || + !nand_info[nand_curr_device].name) + return; + + mtd = &nand_info[nand_curr_device]; + nand = mtd->priv; + + /* If the NAND has in-chip ECC, disable it! */ + if (nand->has_chip_ecc) + micron_set_chip_ecc(mtd, 0); +} + +#ifdef CONFIG_CMD_NAND_CHIP_ECC +static int micron_get_chip_ecc(struct mtd_info *mtd) +{ + uint8_t params[4]; + + nand_get_features(mtd, 0x90, params); + + return ((params[0] & 0x08) != 0); +} +#endif + /** * nand_read_oob_chipecc - read; get status to seeif chip ECC error * @mtd: mtd info structure @@ -610,6 +639,7 @@ void omap_nand_switch_ecc(enum omap_nand_ecc_mode mode) { struct nand_chip *nand; struct mtd_info *mtd; + int in_chip_ecc = 0; if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || @@ -619,6 +649,12 @@ void omap_nand_switch_ecc(enum omap_nand_ecc_mode mode) mtd = &nand_info[nand_curr_device]; nand = mtd->priv; + if (mode == OMAP_ECC_CHIP && !nand->has_chip_ecc) + { + printf("NAND: Chip does not have internal ECC!\n"); + return; + } + nand->options |= NAND_OWN_BUFFERS; /* Reset ecc interface */ @@ -683,20 +719,12 @@ void omap_nand_switch_ecc(enum omap_nand_ecc_mode mode) nand->ecc.calculate = omap_calculate_ecc; omap_hwecc_init(nand); printf("NAND: HW ECC selected\n"); - if (nand->has_chip_ecc) - micron_set_chip_ecc(mtd, 0); } else if (mode == OMAP_ECC_SOFT) { nand->ecc.mode = NAND_ECC_SOFT; /* Use mtd default settings */ nand->ecc.layout = NULL; printf("NAND: SW ECC selected\n"); - if (nand->has_chip_ecc) - micron_set_chip_ecc(mtd, 0); } else if (mode == OMAP_ECC_CHIP) { - if (!nand->has_chip_ecc) { - printf("NAND: Chip does not have internal ECC!\n"); - return; - } nand->ecc.bytes = 0; nand->ecc.size = 2048; nand->ecc.calculate = omap_calculate_chip_hwecc; @@ -716,13 +744,17 @@ void omap_nand_switch_ecc(enum omap_nand_ecc_mode mode) nand->cmdfunc = omap_nand_command_lp; else printf("%s: Huh? not 16-bit wide\n", __FUNCTION__); - micron_set_chip_ecc(mtd, 1); printf("NAND: Internal to NAND ECC selected\n"); + in_chip_ecc = 1; } else { printf("NAND: unknown ECC mode %d\n", mode); return; } + /* Enable/disable the in-chip ECC engine appropriately */ + if (nand->has_chip_ecc) + micron_set_chip_ecc(mtd, in_chip_ecc); + current_ecc_method = mode; /* Update NAND handling after ECC mode switch */ @@ -731,6 +763,32 @@ void omap_nand_switch_ecc(enum omap_nand_ecc_mode mode) nand->options &= ~NAND_OWN_BUFFERS; } +#ifdef CONFIG_CMD_NAND_CHIP_ECC +int omap_nand_switch_chip_ecc(int get, int enable) +{ + struct nand_chip *nand; + struct mtd_info *mtd; + + if (nand_curr_device < 0 || + nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || + !nand_info[nand_curr_device].name) + return -1; + + mtd = &nand_info[nand_curr_device]; + nand = mtd->priv; + + /* If no in-chip ECC, punt! */ + if (!nand->has_chip_ecc) + return -1; + + if (get) + return micron_get_chip_ecc(mtd); + + micron_set_chip_ecc(mtd, enable); + return 0; +} +#endif + /* * Board-specific NAND initialization. The following members of the * argument are board-specific: |