From fcb774777562bb7bcdc53c608d0e6bae906ce0f6 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 28 Apr 2009 13:19:50 -0700 Subject: davinci_nand: cleanup I (minor) Minor cleanup for DaVinci NAND code: - Use I/O addresses from nand_chip; CONFIG_SYS_NAND_BASE won't be defined when there are multiple chipselect lines in use (as with common 2 GByte chips). - Cleanup handling of EMIF control registers * Only need one pointer pointing to them * Remove incorrect and unused struct supersetting them - Use the standard waitfunc; we don't need a custom version - Partial legacy cleanup: * Don't initialize every board like it's a DM6446 EVM * #ifdef a bit more code for BROKEN_ECC Sanity checked with small page NAND on dm355 and dm6446 EVMs; and large page on dm355 EVM (packaged as two devices, not one). Signed-off-by: David Brownell Signed-off-by: Scott Wood --- drivers/mtd/nand/davinci_nand.c | 55 +++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 33 deletions(-) (limited to 'drivers/mtd/nand/davinci_nand.c') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 8ef18b8..8b22024 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -49,6 +49,8 @@ extern struct nand_chip nand_dev_desc[CONFIG_SYS_MAX_NAND_DEVICE]; +static emif_registers *const emif_regs = (void *) DAVINCI_ASYNC_EMIF_CNTRL_BASE; + static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *this = mtd->priv; @@ -115,34 +117,31 @@ static struct nand_ecclayout davinci_nand_ecclayout = { static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) { - emifregs emif_addr; int dummy; - emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; - - dummy = emif_addr->NANDF1ECC; - dummy = emif_addr->NANDF2ECC; - dummy = emif_addr->NANDF3ECC; - dummy = emif_addr->NANDF4ECC; + dummy = emif_regs->NANDF1ECC; +#ifdef CONFIG_SYS_DAVINCI_BROKEN_ECC + dummy = emif_regs->NANDF2ECC; + dummy = emif_regs->NANDF3ECC; + dummy = emif_regs->NANDF4ECC; +#endif - emif_addr->NANDFCR |= (1 << 8); + /* FIXME: only chipselect 0 is supported for now */ + emif_regs->NANDFCR |= 1 << 8; } static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t region) { u_int32_t ecc = 0; - emifregs emif_base_addr; - - emif_base_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; if (region == 1) - ecc = emif_base_addr->NANDF1ECC; + ecc = emif_regs->NANDF1ECC; else if (region == 2) - ecc = emif_base_addr->NANDF2ECC; + ecc = emif_regs->NANDF2ECC; else if (region == 3) - ecc = emif_base_addr->NANDF3ECC; + ecc = emif_regs->NANDF3ECC; else if (region == 4) - ecc = emif_base_addr->NANDF4ECC; + ecc = emif_regs->NANDF4ECC; return(ecc); } @@ -369,24 +368,18 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char * static int nand_davinci_dev_ready(struct mtd_info *mtd) { - emifregs emif_addr; - - emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; - - return(emif_addr->NANDFSR & 0x1); -} - -static int nand_davinci_waitfunc(struct mtd_info *mtd, struct nand_chip *this) -{ - while(!nand_davinci_dev_ready(mtd)) {;} - *NAND_CE0CLE = NAND_STATUS; - return(*NAND_CE0DATA); + return emif_regs->NANDFSR & 0x1; } static void nand_flash_init(void) { + /* This is for DM6446 EVM and *very* similar. DO NOT GROW THIS! + * Instead, have your board_init() set EMIF timings, based on its + * knowledge of the clocks and what devices are hooked up ... and + * don't even do that unless no UBL handled it. + */ +#ifdef CONFIG_SOC_DM6446 u_int32_t acfg1 = 0x3ffffffc; - emifregs emif_regs; /*------------------------------------------------------------------* * NAND FLASH CHIP TIMEOUT @ 459 MHz * @@ -408,17 +401,14 @@ static void nand_flash_init(void) | (0 << 0 ) /* asyncSize 8-bit bus */ ; - emif_regs = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; - emif_regs->AB1CR = acfg1; /* CS2 */ emif_regs->NANDFCR = 0x00000101; /* NAND flash on CS2 */ +#endif } int board_nand_init(struct nand_chip *nand) { - nand->IO_ADDR_R = (void __iomem *)NAND_CE0DATA; - nand->IO_ADDR_W = (void __iomem *)NAND_CE0DATA; nand->chip_delay = 0; nand->select_chip = nand_davinci_select_chip; #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT @@ -452,7 +442,6 @@ int board_nand_init(struct nand_chip *nand) nand->cmd_ctrl = nand_davinci_hwcontrol; nand->dev_ready = nand_davinci_dev_ready; - nand->waitfunc = nand_davinci_waitfunc; nand_flash_init(); -- cgit v1.1 From 6e29ed8e576a6900c5d8dcde36b423ac576894dc Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 28 Apr 2009 13:19:53 -0700 Subject: davinci_nand: cleanup II (CONFIG_SYS_DAVINCI_BROKEN_ECC) Remove CONFIG_SYS_DAVINCI_BROKEN_ECC option. It's not just nasty; it's also unused by any current boards, and doesn't even match the main U-Boot distributions from TI (which use soft ECC, or 4-bit ECC on newer chips that support it). DaVinci GIT kernels since 2.6.24, and mainline Linux since 2.6.30, match non-BROKEN code paths for 1-bit HW ECC. The BROKEN code paths do seem to partially match what MontaVista/TI kernels (4.0/2.6.10, and 5.0/2.6.18) do ... but only for small pages. Large page support is really broken (and it's unclear just what software it was trying to match!), and the ECC layout was making three more bytes available for use by filesystem (or whatever) code. Since this option itself seems broken, remove it. Add a comment about the MV/TI compat issue, and the most straightforward way to address it (should someone really need to solve it). Signed-off-by: David Brownell Signed-off-by: Scott Wood --- drivers/mtd/nand/davinci_nand.c | 218 +++------------------------------------- 1 file changed, 13 insertions(+), 205 deletions(-) (limited to 'drivers/mtd/nand/davinci_nand.c') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 8b22024..9e7b9dd 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -86,45 +86,12 @@ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) } #ifdef CONFIG_SYS_NAND_HW_ECC -#ifdef CONFIG_SYS_DAVINCI_BROKEN_ECC -/* Linux-compatible ECC uses MTD defaults. */ -/* These layouts are not compatible with Linux or RBL/UBL. */ -#ifdef CONFIG_SYS_NAND_LARGEPAGE -static struct nand_ecclayout davinci_nand_ecclayout = { - .eccbytes = 12, - .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, - .oobfree = { - {.offset = 2, .length = 6}, - {.offset = 12, .length = 12}, - {.offset = 28, .length = 12}, - {.offset = 44, .length = 12}, - {.offset = 60, .length = 4} - } -}; -#elif defined(CONFIG_SYS_NAND_SMALLPAGE) -static struct nand_ecclayout davinci_nand_ecclayout = { - .eccbytes = 3, - .eccpos = {0, 1, 2}, - .oobfree = { - {.offset = 6, .length = 2}, - {.offset = 8, .length = 8} - } -}; -#else -#error "Either CONFIG_SYS_NAND_LARGEPAGE or CONFIG_SYS_NAND_SMALLPAGE must be defined!" -#endif -#endif /* CONFIG_SYS_DAVINCI_BROKEN_ECC */ static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) { int dummy; dummy = emif_regs->NANDF1ECC; -#ifdef CONFIG_SYS_DAVINCI_BROKEN_ECC - dummy = emif_regs->NANDF2ECC; - dummy = emif_regs->NANDF3ECC; - dummy = emif_regs->NANDF4ECC; -#endif /* FIXME: only chipselect 0 is supported for now */ emif_regs->NANDFCR |= 1 << 8; @@ -149,29 +116,6 @@ static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t region) static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { u_int32_t tmp; -#ifdef CONFIG_SYS_DAVINCI_BROKEN_ECC - /* - * This is not how you should read ECCs on large page Davinci devices. - * The region parameter gets you ECCs for flash chips on different chip - * selects, not the 4x512 byte pages in a 2048 byte page. - * - * Preserved for backwards compatibility though. - */ - - int region, n; - struct nand_chip *this = mtd->priv; - - n = (this->ecc.size/512); - - region = 1; - while (n--) { - tmp = nand_davinci_readecc(mtd, region); - *ecc_code++ = tmp; - *ecc_code++ = tmp >> 16; - *ecc_code++ = ((tmp >> 8) & 0x0f) | ((tmp >> 20) & 0xf0); - region++; - } -#else const int region = 1; tmp = nand_davinci_readecc(mtd, region); @@ -186,148 +130,26 @@ static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u *ecc_code++ = tmp; *ecc_code++ = tmp >> 8; *ecc_code++ = tmp >> 16; -#endif /* CONFIG_SYS_DAVINCI_BROKEN_ECC */ - return(0); -} - -#ifdef CONFIG_SYS_DAVINCI_BROKEN_ECC -static void nand_davinci_gen_true_ecc(u_int8_t *ecc_buf) -{ - u_int32_t tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xf0) << 20) | ((ecc_buf[2] & 0x0f) << 8); - - ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp)); - ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp)); - ecc_buf[2] = ~( P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | P1e(tmp) | P2048o(tmp) | P2048e(tmp)); -} - -static int nand_davinci_compare_ecc(u_int8_t *ecc_nand, u_int8_t *ecc_calc, u_int8_t *page_data) -{ - u_int32_t i; - u_int8_t tmp0_bit[8], tmp1_bit[8], tmp2_bit[8]; - u_int8_t comp0_bit[8], comp1_bit[8], comp2_bit[8]; - u_int8_t ecc_bit[24]; - u_int8_t ecc_sum = 0; - u_int8_t find_bit = 0; - u_int32_t find_byte = 0; - int is_ecc_ff; - - is_ecc_ff = ((*ecc_nand == 0xff) && (*(ecc_nand + 1) == 0xff) && (*(ecc_nand + 2) == 0xff)); - - nand_davinci_gen_true_ecc(ecc_nand); - nand_davinci_gen_true_ecc(ecc_calc); - - for (i = 0; i <= 2; i++) { - *(ecc_nand + i) = ~(*(ecc_nand + i)); - *(ecc_calc + i) = ~(*(ecc_calc + i)); - } - - for (i = 0; i < 8; i++) { - tmp0_bit[i] = *ecc_nand % 2; - *ecc_nand = *ecc_nand / 2; - } - - for (i = 0; i < 8; i++) { - tmp1_bit[i] = *(ecc_nand + 1) % 2; - *(ecc_nand + 1) = *(ecc_nand + 1) / 2; - } - - for (i = 0; i < 8; i++) { - tmp2_bit[i] = *(ecc_nand + 2) % 2; - *(ecc_nand + 2) = *(ecc_nand + 2) / 2; - } - for (i = 0; i < 8; i++) { - comp0_bit[i] = *ecc_calc % 2; - *ecc_calc = *ecc_calc / 2; - } - - for (i = 0; i < 8; i++) { - comp1_bit[i] = *(ecc_calc + 1) % 2; - *(ecc_calc + 1) = *(ecc_calc + 1) / 2; - } - - for (i = 0; i < 8; i++) { - comp2_bit[i] = *(ecc_calc + 2) % 2; - *(ecc_calc + 2) = *(ecc_calc + 2) / 2; - } - - for (i = 0; i< 6; i++) - ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2]; - - for (i = 0; i < 8; i++) - ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i]; - - for (i = 0; i < 8; i++) - ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i]; - - ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0]; - ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1]; - - for (i = 0; i < 24; i++) - ecc_sum += ecc_bit[i]; + /* NOTE: the above code matches mainline Linux: + * .PQR.stu ==> ~PQRstu + * + * MontaVista/TI kernels encode those bytes differently, use + * complicated (and allegedly sometimes-wrong) correction code, + * and usually shipped with U-Boot that uses software ECC: + * .PQR.stu ==> PsQRtu + * + * If you need MV/TI compatible NAND I/O in U-Boot, it should + * be possible to (a) change the mangling above, (b) reverse + * that mangling in nand_davinci_correct_data() below. + */ - switch (ecc_sum) { - case 0: - /* Not reached because this function is not called if - ECC values are equal */ - return 0; - case 1: - /* Uncorrectable error */ - MTDDEBUG (MTD_DEBUG_LEVEL0, - "ECC UNCORRECTED_ERROR 1\n"); - return(-1); - case 12: - /* Correctable error */ - find_byte = (ecc_bit[23] << 8) + - (ecc_bit[21] << 7) + - (ecc_bit[19] << 6) + - (ecc_bit[17] << 5) + - (ecc_bit[15] << 4) + - (ecc_bit[13] << 3) + - (ecc_bit[11] << 2) + - (ecc_bit[9] << 1) + - ecc_bit[7]; - - find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1]; - - MTDDEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC " - "error at offset: %d, bit: %d\n", - find_byte, find_bit); - - page_data[find_byte] ^= (1 << find_bit); - - return(0); - default: - if (is_ecc_ff) { - if (ecc_calc[0] == 0 && ecc_calc[1] == 0 && ecc_calc[2] == 0) - return(0); - } - MTDDEBUG (MTD_DEBUG_LEVEL0, - "UNCORRECTED_ERROR default\n"); - return(-1); - } + return 0; } -#endif /* CONFIG_SYS_DAVINCI_BROKEN_ECC */ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { struct nand_chip *this = mtd->priv; -#ifdef CONFIG_SYS_DAVINCI_BROKEN_ECC - int block_count = 0, i, rc; - - block_count = (this->ecc.size/512); - for (i = 0; i < block_count; i++) { - if (memcmp(read_ecc, calc_ecc, 3) != 0) { - rc = nand_davinci_compare_ecc(read_ecc, calc_ecc, dat); - if (rc < 0) { - return(rc); - } - } - read_ecc += 3; - calc_ecc += 3; - dat += 512; - } -#else u_int32_t ecc_nand = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16); u_int32_t ecc_calc = calc_ecc[0] | (calc_ecc[1] << 8) | @@ -361,7 +183,6 @@ static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char * return -1; } } -#endif /* CONFIG_SYS_DAVINCI_BROKEN_ECC */ return(0); } #endif /* CONFIG_SYS_NAND_HW_ECC */ @@ -416,21 +237,8 @@ int board_nand_init(struct nand_chip *nand) #endif #ifdef CONFIG_SYS_NAND_HW_ECC nand->ecc.mode = NAND_ECC_HW; -#ifdef CONFIG_SYS_DAVINCI_BROKEN_ECC - nand->ecc.layout = &davinci_nand_ecclayout; -#ifdef CONFIG_SYS_NAND_LARGEPAGE - nand->ecc.size = 2048; - nand->ecc.bytes = 12; -#elif defined(CONFIG_SYS_NAND_SMALLPAGE) - nand->ecc.size = 512; - nand->ecc.bytes = 3; -#else -#error "Either CONFIG_SYS_NAND_LARGEPAGE or CONFIG_SYS_NAND_SMALLPAGE must be defined!" -#endif -#else nand->ecc.size = 512; nand->ecc.bytes = 3; -#endif /* CONFIG_SYS_DAVINCI_BROKEN_ECC */ nand->ecc.calculate = nand_davinci_calculate_ecc; nand->ecc.correct = nand_davinci_correct_data; nand->ecc.hwctl = nand_davinci_enable_hwecc; -- cgit v1.1 From 154b5484ac7dcbcd0fb5ba388d930b02f87fa302 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 10 May 2009 15:43:01 -0700 Subject: davinci_nand chipselect/init cleanup Update chipselect handling in davinci_nand.c so that it can handle 2 GByte chips the same way Linux does: as one device, even though it has two halves with independent chip selects. For such chips the "nand info" command reports: Device 0: 2x nand0, sector size 128 KiB Switch to use the default chipselect function unless the board really needs its own. The logic for the Sonata board moves out of the driver into board-specific code. (Which doesn't affect current build breakage if its NAND support is enabled...) Signed-off-by: David Brownell Signed-off-by: Scott Wood --- drivers/mtd/nand/davinci_nand.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) (limited to 'drivers/mtd/nand/davinci_nand.c') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 9e7b9dd..ca40c6a 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -47,8 +47,6 @@ #include #include -extern struct nand_chip nand_dev_desc[CONFIG_SYS_MAX_NAND_DEVICE]; - static emif_registers *const emif_regs = (void *) DAVINCI_ASYNC_EMIF_CNTRL_BASE; static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) @@ -70,21 +68,6 @@ static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int c writeb(cmd, this->IO_ADDR_W); } -/* Set WP on deselect, write enable on select */ -static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) -{ -#define GPIO_SET_DATA01 0x01c67018 -#define GPIO_CLR_DATA01 0x01c6701c -#define GPIO_NAND_WP (1 << 4) -#ifdef SONATA_BOARD_GPIOWP - if (chip < 0) { - REG(GPIO_CLR_DATA01) |= GPIO_NAND_WP; - } else { - REG(GPIO_SET_DATA01) |= GPIO_NAND_WP; - } -#endif -} - #ifdef CONFIG_SYS_NAND_HW_ECC static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) @@ -228,10 +211,9 @@ static void nand_flash_init(void) #endif } -int board_nand_init(struct nand_chip *nand) +void davinci_nand_init(struct nand_chip *nand) { nand->chip_delay = 0; - nand->select_chip = nand_davinci_select_chip; #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT nand->options = NAND_USE_FLASH_BBT; #endif @@ -252,6 +234,12 @@ int board_nand_init(struct nand_chip *nand) nand->dev_ready = nand_davinci_dev_ready; nand_flash_init(); +} - return(0); +int board_nand_init(struct nand_chip *chip) __attribute__((weak)); + +int board_nand_init(struct nand_chip *chip) +{ + davinci_nand_init(chip); + return 0; } -- cgit v1.1