* [U-Boot-Users] RFC on davinci Nand support changes @ 2007-09-25 1:10 Troy Kisky 2007-09-25 17:42 ` ksi at koi8.net 0 siblings, 1 reply; 8+ messages in thread From: Troy Kisky @ 2007-09-25 1:10 UTC (permalink / raw) To: u-boot This patch fixes Nand largepage support for Davinci Changes the ecc values stored in the spare bytes so that an erased block does not contain ecc errors. The ecc correction function is much easier to read. Chip select other than CS2 should also work now but not tested. The bus width now comes from the EM_WIDTH pin. Normal gpio may be used for EM_WAIT function. What I mainly want commented on is whether we should emulate software ECC for the hardware ecc as the hardware is flexible. I think it would be nice to use 8 - 256 byte eccs instead of 4 - 512 byte eccs. But I haven't changed that yet. I sent this to the davinci mailing list, but didn't get much interest. Linux must be modified to match the ecc if it will read blocks that u-boot writes diff --git a/cpu/arm926ejs/davinci/nand.c b/cpu/arm926ejs/davinci/nand.c index 127be9f..2fecaed 100644 --- a/cpu/arm926ejs/davinci/nand.c +++ b/cpu/arm926ejs/davinci/nand.c @@ -52,32 +52,35 @@ extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; -static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd) -{ - struct nand_chip *this = mtd->priv; - u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W; - IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); +unsigned char nandCtlSetClr[] = { + 0x00, /*1 - NAND_CTL_SETNCE, 2 - NAND_CTL_CLRNCE, Select/Deselect Chip Select (nCE) */ + MASK_CLE, /*3 - NAND_CTL_SETCLE, 4 - NAND_CTL_CLRCLE, Select/Deselect the command latch (CLE) */ + MASK_ALE, /*5 - NAND_CTL_SETALE, 6 - NAND_CTL_CLRALE, Select/Deselect the address latch (ALE) */ + 0x00, /*7 - NAND_CTL_SETWP, 8 - NAND_CTL_CLRWP, Set/Clear write protection (WP) Not used! */ +}; - switch (cmd) { - case NAND_CTL_SETCLE: - IO_ADDR_W |= MASK_CLE; - break; - case NAND_CTL_SETALE: - IO_ADDR_W |= MASK_ALE; - break; +static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd) +{ + cmd--; + if ((cmd>=0)&&(cmd<8)) { + struct nand_chip *nand = mtd->priv; + u_int32_t addr = (u_int32_t)nand->IO_ADDR_W; + if (cmd&1) addr &= ~nandCtlSetClr[cmd>>1]; + else addr |= nandCtlSetClr[cmd>>1]; + nand->IO_ADDR_W = (void *)addr; + } else { + DEBUG (MTD_DEBUG_LEVEL0, "Invalid command 0x%x\n",cmd+1); } - - this->IO_ADDR_W = (void *)IO_ADDR_W; } /* Set WP on deselect, write enable on select */ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) { +#ifdef SONATA_BOARD_GPIOWP #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 { @@ -91,232 +94,217 @@ static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) static struct nand_oobinfo davinci_nand_oobinfo = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 12, +#if 1 .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, - .oobfree = { {2, 6}, {12, 12}, {28, 12}, {44, 12}, {60, 4} } + /* The 1st two bytes of spare are reserved for factory bad block markers */ + .oobfree = { {2, 6}, {11, 13}, {27, 13}, {43, 13}, {59, 5} } +#else + /* I would prefer this format, or the software format with 8 eccs in 256 byte groups (nand_oob_64 in nand_base), what do you think? */ + .eccpos = {2,3,4, 5,6,7, 8,9,10, 11,12,13}, + /* The 1st two bytes of spare are reserved for factory bad block markers */ + .oobfree = { {14, 50} } +#endif }; #elif defined(CFG_NAND_SMALLPAGE) static struct nand_oobinfo davinci_nand_oobinfo = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 3, .eccpos = {0, 1, 2}, - .oobfree = { {6, 2}, {8, 8} } + .oobfree = { {6, 10} } }; #else #error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!" #endif -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; - emif_addr->NANDFCR |= (1 << 8); -} - -static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t region) +static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t chipNum) { 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; - else if (region == 2) - ecc = emif_base_addr->NANDF2ECC; - else if (region == 3) - ecc = emif_base_addr->NANDF3ECC; - else if (region == 4) - ecc = emif_base_addr->NANDF4ECC; - + ecc = emif_base_addr->NANDF_ECC[chipNum]; return(ecc); } - -static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) -{ - u_int32_t tmp; - int region, n; - struct nand_chip *this = mtd->priv; - - n = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1; - - 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++; - } - return(0); -} - -static void nand_davinci_gen_true_ecc(u_int8_t *ecc_buf) +static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) { - u_int32_t tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xf0) << 20) | ((ecc_buf[2] & 0x0f) << 8); + struct nand_chip *nand = mtd->priv; + u_int32_t addr = (u_int32_t)nand->IO_ADDR_R; + u_int32_t chipNum=(addr-CFG_NAND_BASE)>>25; /* 0 - cs2, 1 - cs3, 2 - cs4, 3 - cs5 */ + emifregs emif_addr; + int dummy; + if (chipNum>=4) return; - 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)); + emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + dummy = nand_davinci_readecc(mtd, chipNum); /* reset ecc to 0 */ + emif_addr->NANDFCR |= (1 << (8+chipNum)); /* start ECC on chip select region+2 */ } -static int nand_davinci_compare_ecc(u_int8_t *ecc_nand, u_int8_t *ecc_calc, u_int8_t *page_data) +static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { - 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)); + struct nand_chip *nand = mtd->priv; + u_int32_t addr = (u_int32_t)nand->IO_ADDR_R; + u_int32_t chipNum=(addr-CFG_NAND_BASE)>>25; /* 0 - cs2, 1 - cs3, 2 - cs4, 3 - cs5 */ + if (chipNum>=4) return -1; + u_int32_t tmp = nand_davinci_readecc(mtd, chipNum); +#ifdef CONFIG_MTD_DEBUG +/* calculate it ourself and compare */ +/* FORCE_ECC_ERROR is undefined for normal operation */ +/* #define FORCE_ECC_ERROR */ +#ifdef FORCE_ECC_ERROR + { + /* force single bit ecc error to test ecc correction code */ + u_char* p = (u_char*)dat; + unsigned int i = p[0] | (p[1]<<8); /* 1st word of block determines which bit is made in error */ + i &= 0xfff; + p[i>>3] ^= 1<<(i&7); + printf("Forcing ecc error, byte:%d, bit:%d\n",i>>3,i&7); } - - 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]; - - switch (ecc_sum) { - case 0: - /* Not reached because this function is not called if - ECC values are equal */ - return 0; - case 1: - /* Uncorrectable error */ - DEBUG (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]; - - DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error@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); - } - DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n"); - return(-1); +#endif + { + unsigned int i = 0x00000fff; /* 2**12 bits/ecc MAX */ + unsigned int j = mtd->eccsize; /* 256 or 512 bytes/ecc */ + unsigned int ecc = 0; + do { + unsigned int k=i; + unsigned int v = *dat++; + do { + if (v&1) ecc ^= k; + k += (1<<16); + k--; + v >>= 1; + } while (v); + i += 8<<16; + i -= 8; + j--; + } while (j); + if (tmp!=ecc) { +#ifndef FORCE_ECC_ERROR + printf("Hardware Ecc: %x, Calculated: %x\n",tmp,ecc); +#endif + tmp=ecc; + } } +#endif + tmp = (tmp&0x0fff)|((tmp&0x0fff0000)>>4); /* squeeze 0 middle bits out so that it fits in 3 bytes */ + tmp = ~tmp; /* invert so that erased block ecc is correct */ + *ecc_code++ = (u_char)(tmp); + *ecc_code++ = (u_char)(tmp >> 8); + *ecc_code++ = (u_char)(tmp >> 16); + return(0); } + 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; - int block_count = 0, i, rc; - - this = mtd->priv; - block_count = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1; - 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); + u_int32_t eccNand = read_ecc[0] | (read_ecc[1]<<8) | (read_ecc[2]<< 16); + u_int32_t eccCalc = calc_ecc[0] | (calc_ecc[1]<<8) | (calc_ecc[2]<< 16); + u_int32_t diff = eccCalc ^ eccNand; + if (diff) { + if ((((diff>>12)^diff)&0xfff)==0xfff) { + /* Correctable error */ + if ( (diff>>(12+3)) < mtd->eccsize ) { + DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at offset: %d, bit: %d\n", diff>>(12+3), ((diff>>12)&7)); + dat[diff>>(12+3)] ^= (1 << ((diff>>12)&7)); + } else { + DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR, illegal byte # %d\n",diff>>(12+3)); + return(-1); } + } else if ((diff & (-diff))==diff) { + DEBUG (MTD_DEBUG_LEVEL0, "Single bit ECC error in the ECC itself, nothing to fix\n"); + } else { + /* Uncorrectable error */ + u_int32_t hwCalc = (~eccCalc)&0xffffff; + hwCalc = (hwCalc&0xfff)|((hwCalc&0xfff000)<<4); + DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR diff:%x nandBlock:%x calc:%x hwCalc:%08x\n",diff,eccNand,eccCalc,hwCalc); + return(-1); } - read_ecc += 3; - calc_ecc += 3; - dat += 512; } return(0); } #endif +#ifdef NAND_GPIO_READY_LIST +static unsigned char nandGpioReadyList[] = {NAND_GPIO_READY_LIST}; +#endif + 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); +#ifdef NAND_GPIO_READY_LIST +#define GP_BANK0_OFFSET 0x10 +#define GP_BANK_LENGTH 0x28 +#define GP_DIR 0x00 +#define GP_OUT 0x04 +#define GP_SET 0x08 +#define GP_CLR 0x0C +#define GP_IN 0x10 + + struct nand_chip *nand = mtd->priv; + u_int32_t addr = (u_int32_t)nand->IO_ADDR_R; + u_int32_t chipNum=(addr-CFG_NAND_BASE)>>25; /* 0 - cs2, 1 - cs3, 2 - cs4, 3 - cs5 */ + if (chipNum<4) { + unsigned int gp = nandGpioReadyList[chipNum]; + if (gp) { + unsigned int bank = (gp>>5); + volatile unsigned int* p = (unsigned int*)(DAVINCI_GPIO_BASE+GP_BANK0_OFFSET+(bank*GP_BANK_LENGTH)); + int ret = (p[GP_IN>>2] >> (gp&0x1f))&1; + DEBUG (MTD_DEBUG_LEVEL3, "Ready: %d\n", ret); + return ret; + } + } +#endif + emifregs emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + return (emif_addr->NANDFSR & 0x1); } +/** + * nand_davinci_waitfunc - [DEFAULT] wait until the command is done + * @mtd: MTD device structure + * @this: NAND chip structure + * @state: state to select the max. timeout value + * + * Wait for command done. This applies to erase and program only + * Erase can take up to 400ms and program up to 20ms according to + * general NAND and SmartMedia specs + * +*/ static int nand_davinci_waitfunc(struct mtd_info *mtd, struct nand_chip *this, int state) { - while(!nand_davinci_dev_ready(mtd)) {;} - *NAND_CE0CLE = NAND_STATUS; - return(*NAND_CE0DATA); + ulong start = get_timer(0); + volatile u_int8_t * p = (volatile u_int8_t *)((unsigned int)this->IO_ADDR_R); + unsigned long timeout = (state == FL_ERASING)? ((CFG_HZ * 400) / 1000) : ((CFG_HZ * 20) / 1000); +#if 0 /* enable this if you don't trust your ready pin. */ + unsigned long mwait = (state == FL_ERASING)? 400 : 20; + udelay(mwait*1000); +#endif + + p[MASK_CLE] = NAND_CMD_STATUS; + + while (1) { + if (get_timer(start) > timeout) { + printf("!!!Nand wait Timeout!!!\n"); + return 1; + } + if (nand_davinci_dev_ready(mtd)) break; + } + return (*p); } -static void nand_flash_init(void) +#define BOOTCFG 0x01C40014 +int board_nand_init(struct nand_chip *nand) { - u_int32_t acfg1 = 0x3ffffffc; - u_int32_t acfg2 = 0x3ffffffc; - u_int32_t acfg3 = 0x3ffffffc; - u_int32_t acfg4 = 0x3ffffffc; - emifregs emif_regs; - + u_int32_t acfg = 0 + | (0<<31) /* selectStrobe */ + | (0<<30) /* extWait */ + | (1<<26) /* writeSetup 10 ns */ + | (3<<20) /* writeStrobe 40 ns */ + | (1<<17) /* writeHold 10 ns */ + | (1<<13) /* readSetup 10 ns */ + | (5<<7) /* readStrobe 60 ns */ + | (1<<4) /* readHold 10 ns */ + | (3<<2) /* turnAround ?? ns */ + ; + acfg |= (*((unsigned int*)BOOTCFG)>>5)&1; /* grab default width from EM_WIDTH */ /*------------------------------------------------------------------* * NAND FLASH CHIP TIMEOUT @ 459 MHz * * * @@ -324,46 +312,39 @@ static void nand_flash_init(void) * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns * * * *------------------------------------------------------------------*/ - acfg1 = 0 - | (0 << 31 ) /* selectStrobe */ - | (0 << 30 ) /* extWait */ - | (1 << 26 ) /* writeSetup 10 ns */ - | (3 << 20 ) /* writeStrobe 40 ns */ - | (1 << 17 ) /* writeHold 10 ns */ - | (1 << 13 ) /* readSetup 10 ns */ - | (5 << 7 ) /* readStrobe 60 ns */ - | (1 << 4 ) /* readHold 10 ns */ - | (3 << 2 ) /* turnAround ?? ns */ - | (0 << 0 ) /* asyncSize 8-bit bus */ - ; - - emif_regs = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; - emif_regs->AWCCR |= 0x10000000; - emif_regs->AB1CR = acfg1; /* 0x08244128 */; - emif_regs->AB2CR = acfg2; - emif_regs->AB3CR = acfg3; - emif_regs->AB4CR = acfg4; - emif_regs->NANDFCR = 0x00000101; -} + emifregs emif_regs = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + u_int32_t addr = (u_int32_t)nand->IO_ADDR_R; + u_int32_t chipNum=(addr-CFG_NAND_BASE)>>25; /* 0 - cs2, 1 - cs3, 2 - cs4, 3 - cs5 */ + if (chipNum>=4) return -1; + + emif_regs->AB_CR[chipNum] = acfg; /* 0x08244128 */ + emif_regs->NANDFCR |= 1<<chipNum; + +#ifdef NAND_GPIO_READY_LIST + { + unsigned int gp = nandGpioReadyList[chipNum]; + if (gp) { + unsigned int bank = (gp>>5); + volatile unsigned int* p = (unsigned int*)(DAVINCI_GPIO_BASE+GP_BANK0_OFFSET+(bank*GP_BANK_LENGTH)); + int val; + int bitNum = (gp&0x1f); + p[GP_DIR>>2] |= 1<<bitNum; /* make sure it's an input */ + val = (p[GP_IN>>2] >> bitNum)&1; + DEBUG (MTD_DEBUG_LEVEL3, "Bank: %x curVal:%x inReg:%p=%x\n", bank,val,&p[GP_IN>>2],p[GP_IN>>2]); + } + } +#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; + DEBUG (MTD_DEBUG_LEVEL3, "Nand base read:%p write:%p\n",nand->IO_ADDR_R,nand->IO_ADDR_W); nand->chip_delay = 0; nand->select_chip = nand_davinci_select_chip; + nand->options = (acfg&1)? NAND_BUSWIDTH_16 : 0; #ifdef CFG_NAND_USE_FLASH_BBT - nand->options = NAND_USE_FLASH_BBT; + nand->options |= NAND_USE_FLASH_BBT; #endif #ifdef CFG_NAND_HW_ECC -#ifdef CFG_NAND_LARGEPAGE - nand->eccmode = NAND_ECC_HW12_2048; -#elif defined(CFG_NAND_SMALLPAGE) nand->eccmode = NAND_ECC_HW3_512; -#else -#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!" -#endif nand->autooob = &davinci_nand_oobinfo; nand->calculate_ecc = nand_davinci_calculate_ecc; nand->correct_data = nand_davinci_correct_data; @@ -377,9 +358,6 @@ int board_nand_init(struct nand_chip *nand) nand->dev_ready = nand_davinci_dev_ready; nand->waitfunc = nand_davinci_waitfunc; - - nand_flash_init(); - return(0); } diff --git a/include/asm-arm/arch-davinci/emif_defs.h b/include/asm-arm/arch-davinci/emif_defs.h index 646fc77..d6b36da 100644 --- a/include/asm-arm/arch-davinci/emif_defs.h +++ b/include/asm-arm/arch-davinci/emif_defs.h @@ -29,10 +29,7 @@ typedef struct { dv_reg AWCCR; dv_reg SDBCR; dv_reg SDRCR; - dv_reg AB1CR; - dv_reg AB2CR; - dv_reg AB3CR; - dv_reg AB4CR; + dv_reg AB_CR[4]; dv_reg SDTIMR; dv_reg DDRSR; dv_reg DDRPHYCR; @@ -51,10 +48,7 @@ typedef struct { dv_reg NANDFCR; dv_reg NANDFSR; u_int8_t RSVD1[8]; - dv_reg NANDF1ECC; - dv_reg NANDF2ECC; - dv_reg NANDF3ECC; - dv_reg NANDF4ECC; + dv_reg NANDF_ECC[4]; } emif_registers; typedef emif_registers *emifregs; diff --git a/include/asm-arm/arch-davinci/nand_defs.h b/include/asm-arm/arch-davinci/nand_defs.h index 619bd47..9c324c9 100644 --- a/include/asm-arm/arch-davinci/nand_defs.h +++ b/include/asm-arm/arch-davinci/nand_defs.h @@ -26,136 +26,11 @@ #ifndef _NAND_DEFS_H_ #define _NAND_DEFS_H_ -#include <asm/arch/hardware.h> - #define MASK_CLE 0x10 -#define MASK_ALE 0x0a - -#define NAND_CE0CLE ((volatile u_int8_t *)(CFG_NAND_BASE + 0x10)) -#define NAND_CE0ALE ((volatile u_int8_t *)(CFG_NAND_BASE + 0x0a)) -#define NAND_CE0DATA ((volatile u_int8_t *)CFG_NAND_BASE) - -typedef struct { - u_int32_t NRCSR; - u_int32_t AWCCR; - u_int8_t RSVD0[8]; - u_int32_t AB1CR; - u_int32_t AB2CR; - u_int32_t AB3CR; - u_int32_t AB4CR; - u_int8_t RSVD1[32]; - u_int32_t NIRR; - u_int32_t NIMR; - u_int32_t NIMSR; - u_int32_t NIMCR; - u_int8_t RSVD2[16]; - u_int32_t NANDFCR; - u_int32_t NANDFSR; - u_int8_t RSVD3[8]; - u_int32_t NANDF1ECC; - u_int32_t NANDF2ECC; - u_int32_t NANDF3ECC; - u_int32_t NANDF4ECC; - u_int8_t RSVD4[4]; - u_int32_t IODFTECR; - u_int32_t IODFTGCR; - u_int8_t RSVD5[4]; - u_int32_t IODFTMRLR; - u_int32_t IODFTMRMR; - u_int32_t IODFTMRMSBR; - u_int8_t RSVD6[20]; - u_int32_t MODRNR; - u_int8_t RSVD7[76]; - u_int32_t CE0DATA; - u_int32_t CE0ALE; - u_int32_t CE0CLE; - u_int8_t RSVD8[4]; - u_int32_t CE1DATA; - u_int32_t CE1ALE; - u_int32_t CE1CLE; - u_int8_t RSVD9[4]; - u_int32_t CE2DATA; - u_int32_t CE2ALE; - u_int32_t CE2CLE; - u_int8_t RSVD10[4]; - u_int32_t CE3DATA; - u_int32_t CE3ALE; - u_int32_t CE3CLE; -} nand_registers; - -typedef volatile nand_registers *nandregs; +#define MASK_ALE 0x08 #define NAND_READ_START 0x00 #define NAND_READ_END 0x30 #define NAND_STATUS 0x70 -#ifdef CFG_NAND_HW_ECC -#define NAND_Ecc_P1e (1 << 0) -#define NAND_Ecc_P2e (1 << 1) -#define NAND_Ecc_P4e (1 << 2) -#define NAND_Ecc_P8e (1 << 3) -#define NAND_Ecc_P16e (1 << 4) -#define NAND_Ecc_P32e (1 << 5) -#define NAND_Ecc_P64e (1 << 6) -#define NAND_Ecc_P128e (1 << 7) -#define NAND_Ecc_P256e (1 << 8) -#define NAND_Ecc_P512e (1 << 9) -#define NAND_Ecc_P1024e (1 << 10) -#define NAND_Ecc_P2048e (1 << 11) - -#define NAND_Ecc_P1o (1 << 16) -#define NAND_Ecc_P2o (1 << 17) -#define NAND_Ecc_P4o (1 << 18) -#define NAND_Ecc_P8o (1 << 19) -#define NAND_Ecc_P16o (1 << 20) -#define NAND_Ecc_P32o (1 << 21) -#define NAND_Ecc_P64o (1 << 22) -#define NAND_Ecc_P128o (1 << 23) -#define NAND_Ecc_P256o (1 << 24) -#define NAND_Ecc_P512o (1 << 25) -#define NAND_Ecc_P1024o (1 << 26) -#define NAND_Ecc_P2048o (1 << 27) - -#define TF(v) (v ? 1 : 0) - -#define P2048e(a) (TF(a & NAND_Ecc_P2048e) << 0) -#define P2048o(a) (TF(a & NAND_Ecc_P2048o) << 1) -#define P1e(a) (TF(a & NAND_Ecc_P1e) << 2) -#define P1o(a) (TF(a & NAND_Ecc_P1o) << 3) -#define P2e(a) (TF(a & NAND_Ecc_P2e) << 4) -#define P2o(a) (TF(a & NAND_Ecc_P2o) << 5) -#define P4e(a) (TF(a & NAND_Ecc_P4e) << 6) -#define P4o(a) (TF(a & NAND_Ecc_P4o) << 7) - -#define P8e(a) (TF(a & NAND_Ecc_P8e) << 0) -#define P8o(a) (TF(a & NAND_Ecc_P8o) << 1) -#define P16e(a) (TF(a & NAND_Ecc_P16e) << 2) -#define P16o(a) (TF(a & NAND_Ecc_P16o) << 3) -#define P32e(a) (TF(a & NAND_Ecc_P32e) << 4) -#define P32o(a) (TF(a & NAND_Ecc_P32o) << 5) -#define P64e(a) (TF(a & NAND_Ecc_P64e) << 6) -#define P64o(a) (TF(a & NAND_Ecc_P64o) << 7) - -#define P128e(a) (TF(a & NAND_Ecc_P128e) << 0) -#define P128o(a) (TF(a & NAND_Ecc_P128o) << 1) -#define P256e(a) (TF(a & NAND_Ecc_P256e) << 2) -#define P256o(a) (TF(a & NAND_Ecc_P256o) << 3) -#define P512e(a) (TF(a & NAND_Ecc_P512e) << 4) -#define P512o(a) (TF(a & NAND_Ecc_P512o) << 5) -#define P1024e(a) (TF(a & NAND_Ecc_P1024e) << 6) -#define P1024o(a) (TF(a & NAND_Ecc_P1024o) << 7) - -#define P8e_s(a) (TF(a & NAND_Ecc_P8e) << 0) -#define P8o_s(a) (TF(a & NAND_Ecc_P8o) << 1) -#define P16e_s(a) (TF(a & NAND_Ecc_P16e) << 2) -#define P16o_s(a) (TF(a & NAND_Ecc_P16o) << 3) -#define P1e_s(a) (TF(a & NAND_Ecc_P1e) << 4) -#define P1o_s(a) (TF(a & NAND_Ecc_P1o) << 5) -#define P2e_s(a) (TF(a & NAND_Ecc_P2e) << 6) -#define P2o_s(a) (TF(a & NAND_Ecc_P2o) << 7) - -#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) -#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) -#endif - #endif ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [U-Boot-Users] RFC on davinci Nand support changes 2007-09-25 1:10 [U-Boot-Users] RFC on davinci Nand support changes Troy Kisky @ 2007-09-25 17:42 ` ksi at koi8.net 2007-09-25 19:22 ` Troy Kisky 0 siblings, 1 reply; 8+ messages in thread From: ksi at koi8.net @ 2007-09-25 17:42 UTC (permalink / raw) To: u-boot On Mon, 24 Sep 2007, Troy Kisky wrote: First of all, one should always remember rule number one -- if it ain't broke, don't fix it. Leaving techical details for later let's start with generic, philosophical question first -- what are you trying to achieve with that "fix"? What is your goal, why fix a working code? What advantages would your fix give us versus existing working and tested code? I can see none and problems are aplenty -- you wanna go against what silicon designers did, against the Linux kernel and against common sense. Now for the technical side. First of all, erased blocks do _NOT_ contain ECC errors. They are _ERASED_ i.e. _EVERYTHING_ is set to all ones. Erased blocks simply do not have ECC. And ECC code just skips erased blocks. One can _NOT_ "fix" OOB bytes for erased blocks because it will make them _NOT_ erased thus making those blocks dirty and unsuitable for writing any data into them. "Much easier to read function" is not a reason for a change to working code. Less for the fact that easiness is in the eye of beholder, the existing code is taken almost verbatim from MontaVista Linux kernel that everybody use with a bugfix for unaligned access that made original code hang the U-Boot (why it works in the kernel is left as an exercize for the reader.) And this has been done _DELIBERATELY_ to make U-Boot compatible with the kernel. Now you propose some "fix" that 1.) breakes that compatibility thus forcing everybody not only change working U-Boot code but also mess with a working kernel for no apparent reason; 2.) makes it different from the kernel source thus splitting the code base. Also I can see no reason for using any other chip select for NAND with DaVinci. If one boots it off of NAND it _MUST_ be on CS2 because it is hardcoded in DaVinci ROM bootcode. If one has NAND there is no reason to have NOR flash in the system ergo nothing's going to CS2 so why just don't put NAND on that chip select according to what silicon design suggests? The only reason I can see is using _SEVERAL_ NAND chips to get a bigger memory. But that is totally different question that should be addressed in board-specific portion so it does not pertain to those 3 boards currently supported, none of them have more than one NAND chip and none have it on anything but CS2. And frankly I don't see a reason for having more than one such chip with current NAND chip densities. Bus width from EM_WIDTH pin is also unnecessary, that is what NAND Device ID for. As for EM_WAIT, there is a special pin dedicated exactly for this purpose on DaVinci so I can see no reason for not using it and using some precious GPIO instead. And anyways, if one wants to do it despite common sense, this belongs to board-specific portion, not to generic NAND code. Hardware ECC in DaVinci is _NOT_ flexible, it only works with 512-byte blocks. That is why large page NAND ECC is done in 4 steps. There is also absolutely no sane reason to forfeit perfectly working hardware ECC in spite of software ECC that is a kludge for those systems that don't have appropriate hardware. It brings additional code with all its penalties -- bigger size, slower speed etc. Why emulate something we do have in hardware? What's wrong with it? And no, DaVinci hardware ECC does _NOT_ overwrite factory bad block markers. Neither in small page NAND devices nor in large page ones. That is even true for NAND initial boot loader that does not use true ECC, just raw hardware syndrome that is only used for checking if data is correct, not for correction. The ECC part TI guys managed to implement properly unlike some other parts of silicon that are either buggy or braindead... So it is definite NACK for something like this from your's truly KSI who did initial DaVinci port. > This patch fixes Nand largepage support for Davinci > Changes the ecc values stored in the spare bytes so that > an erased block does not contain ecc errors. > The ecc correction function is much easier to read. > Chip select other than CS2 should also work now but not tested. > The bus width now comes from the EM_WIDTH pin. > Normal gpio may be used for EM_WAIT function. > > What I mainly want commented on is whether we should emulate software > ECC for the hardware ecc as the hardware is flexible. I think it would > be nice to use 8 - 256 byte eccs instead of 4 - 512 byte eccs. But I > haven't > changed that yet. I sent this to the davinci mailing list, but didn't > get much > interest. > > Linux must be modified to match the ecc if it will > read blocks that u-boot writes > > diff --git a/cpu/arm926ejs/davinci/nand.c b/cpu/arm926ejs/davinci/nand.c > index 127be9f..2fecaed 100644 > --- a/cpu/arm926ejs/davinci/nand.c > +++ b/cpu/arm926ejs/davinci/nand.c > @@ -52,32 +52,35 @@ > > extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; > > -static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd) > -{ > - struct nand_chip *this = mtd->priv; > - u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W; > > - IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); > +unsigned char nandCtlSetClr[] = { > + 0x00, /*1 - NAND_CTL_SETNCE, 2 - NAND_CTL_CLRNCE, > Select/Deselect Chip Select (nCE) */ > + MASK_CLE, /*3 - NAND_CTL_SETCLE, 4 - NAND_CTL_CLRCLE, > Select/Deselect the command latch (CLE) */ > + MASK_ALE, /*5 - NAND_CTL_SETALE, 6 - NAND_CTL_CLRALE, > Select/Deselect the address latch (ALE) */ > + 0x00, /*7 - NAND_CTL_SETWP, 8 - NAND_CTL_CLRWP, > Set/Clear write protection (WP) Not used! */ > +}; > > - switch (cmd) { > - case NAND_CTL_SETCLE: > - IO_ADDR_W |= MASK_CLE; > - break; > - case NAND_CTL_SETALE: > - IO_ADDR_W |= MASK_ALE; > - break; > +static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd) > +{ > + cmd--; > + if ((cmd>=0)&&(cmd<8)) { > + struct nand_chip *nand = mtd->priv; > + u_int32_t addr = (u_int32_t)nand->IO_ADDR_W; > + if (cmd&1) addr &= ~nandCtlSetClr[cmd>>1]; > + else addr |= nandCtlSetClr[cmd>>1]; > + nand->IO_ADDR_W = (void *)addr; > + } else { > + DEBUG (MTD_DEBUG_LEVEL0, "Invalid command > 0x%x\n",cmd+1); > } > - > - this->IO_ADDR_W = (void *)IO_ADDR_W; > } > > /* Set WP on deselect, write enable on select */ > static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) > { > +#ifdef SONATA_BOARD_GPIOWP > #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 { > @@ -91,232 +94,217 @@ static void nand_davinci_select_chip(struct > mtd_info *mtd, int chip) > static struct nand_oobinfo davinci_nand_oobinfo = { > .useecc = MTD_NANDECC_AUTOPLACE, > .eccbytes = 12, > +#if 1 > .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, > - .oobfree = { {2, 6}, {12, 12}, {28, 12}, {44, 12}, {60, 4} } > + /* The 1st two bytes of spare are reserved for factory bad block > markers */ > + .oobfree = { {2, 6}, {11, 13}, {27, 13}, {43, 13}, {59, 5} } > +#else > + /* I would prefer this format, or the software format with 8 > eccs in 256 byte groups (nand_oob_64 in nand_base), what do you think? > */ > + .eccpos = {2,3,4, 5,6,7, 8,9,10, 11,12,13}, > + /* The 1st two bytes of spare are reserved for factory bad block > markers */ > + .oobfree = { {14, 50} } > +#endif > }; > #elif defined(CFG_NAND_SMALLPAGE) > static struct nand_oobinfo davinci_nand_oobinfo = { > .useecc = MTD_NANDECC_AUTOPLACE, > .eccbytes = 3, > .eccpos = {0, 1, 2}, > - .oobfree = { {6, 2}, {8, 8} } > + .oobfree = { {6, 10} } > }; > #else > #error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be > defined!" > #endif > > -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; > > - emif_addr->NANDFCR |= (1 << 8); > -} > - > -static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t > region) > +static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t > chipNum) > { > 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; > - else if (region == 2) > - ecc = emif_base_addr->NANDF2ECC; > - else if (region == 3) > - ecc = emif_base_addr->NANDF3ECC; > - else if (region == 4) > - ecc = emif_base_addr->NANDF4ECC; > - > + ecc = emif_base_addr->NANDF_ECC[chipNum]; > return(ecc); > } > - > -static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const > u_char *dat, u_char *ecc_code) > -{ > - u_int32_t tmp; > - int region, n; > - struct nand_chip *this = mtd->priv; > - > - n = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1; > - > - 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++; > - } > - return(0); > -} > - > -static void nand_davinci_gen_true_ecc(u_int8_t *ecc_buf) > +static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) > { > - u_int32_t tmp = ecc_buf[0] | (ecc_buf[1] << 16) | > ((ecc_buf[2] & 0xf0) << 20) | ((ecc_buf[2] & 0x0f) << 8); > + struct nand_chip *nand = mtd->priv; > + u_int32_t addr = (u_int32_t)nand->IO_ADDR_R; > + u_int32_t chipNum=(addr-CFG_NAND_BASE)>>25; /* 0 - > cs2, 1 - cs3, 2 - cs4, 3 - cs5 */ > + emifregs emif_addr; > + int dummy; > + if (chipNum>=4) return; > > - 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)); > + emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; > + dummy = nand_davinci_readecc(mtd, chipNum); /* reset ecc to > 0 */ > + emif_addr->NANDFCR |= (1 << (8+chipNum)); /* start ECC on > chip select region+2 */ > } > > -static int nand_davinci_compare_ecc(u_int8_t *ecc_nand, u_int8_t > *ecc_calc, u_int8_t *page_data) > +static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const > u_char *dat, u_char *ecc_code) > { > - 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)); > + struct nand_chip *nand = mtd->priv; > + u_int32_t addr = (u_int32_t)nand->IO_ADDR_R; > + u_int32_t chipNum=(addr-CFG_NAND_BASE)>>25; /* 0 - > cs2, 1 - cs3, 2 - cs4, 3 - cs5 */ > + if (chipNum>=4) return -1; > + u_int32_t tmp = nand_davinci_readecc(mtd, chipNum); > +#ifdef CONFIG_MTD_DEBUG > +/* calculate it ourself and compare */ > +/* FORCE_ECC_ERROR is undefined for normal operation */ > +/* #define FORCE_ECC_ERROR */ > +#ifdef FORCE_ECC_ERROR > + { > + /* force single bit ecc error to test ecc correction > code */ > + u_char* p = (u_char*)dat; > + unsigned int i = p[0] | (p[1]<<8); /* 1st word of > block determines which bit is made in error */ > + i &= 0xfff; > + p[i>>3] ^= 1<<(i&7); > + printf("Forcing ecc error, byte:%d, bit:%d\n",i>>3,i&7); > } > - > - 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]; > - > - switch (ecc_sum) { > - case 0: > - /* Not reached because this function is not > called if > - ECC values are equal */ > - return 0; > - case 1: > - /* Uncorrectable error */ > - DEBUG (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]; > - > - DEBUG (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); > - } > - DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR > default\n"); > - return(-1); > +#endif > + { > + unsigned int i = 0x00000fff; /* 2**12 bits/ecc MAX */ > + unsigned int j = mtd->eccsize; /* 256 > or 512 bytes/ecc */ > + unsigned int ecc = 0; > + do { > + unsigned int k=i; > + unsigned int v = *dat++; > + do { > + if (v&1) ecc ^= k; > + k += (1<<16); > + k--; > + v >>= 1; > + } while (v); > + i += 8<<16; > + i -= 8; > + j--; > + } while (j); > + if (tmp!=ecc) { > +#ifndef FORCE_ECC_ERROR > + printf("Hardware Ecc: %x, Calculated: > %x\n",tmp,ecc); > +#endif > + tmp=ecc; > + } > } > +#endif > + tmp = (tmp&0x0fff)|((tmp&0x0fff0000)>>4); /* squeeze 0 > middle bits out so that it fits in 3 bytes */ > + tmp = ~tmp; > /* invert so that erased block ecc is correct */ > + *ecc_code++ = (u_char)(tmp); > + *ecc_code++ = (u_char)(tmp >> 8); > + *ecc_code++ = (u_char)(tmp >> 16); > + return(0); > } > > + > 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; > - int block_count = 0, i, rc; > - > - this = mtd->priv; > - block_count = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1; > - 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); > + u_int32_t eccNand = read_ecc[0] | (read_ecc[1]<<8) | > (read_ecc[2]<< 16); > + u_int32_t eccCalc = calc_ecc[0] | (calc_ecc[1]<<8) | > (calc_ecc[2]<< 16); > + u_int32_t diff = eccCalc ^ eccNand; > + if (diff) { > + if ((((diff>>12)^diff)&0xfff)==0xfff) { > + /* Correctable error */ > + if ( (diff>>(12+3)) < mtd->eccsize ) { > + DEBUG (MTD_DEBUG_LEVEL0, "Correcting > single bit ECC error at offset: %d, bit: %d\n", diff>>(12+3), > ((diff>>12)&7)); > + dat[diff>>(12+3)] ^= (1 << > ((diff>>12)&7)); > + } else { > + DEBUG (MTD_DEBUG_LEVEL0, "ECC > UNCORRECTED_ERROR, illegal byte # %d\n",diff>>(12+3)); > + return(-1); > } > + } else if ((diff & (-diff))==diff) { > + DEBUG (MTD_DEBUG_LEVEL0, "Single bit ECC error > in the ECC itself, nothing to fix\n"); > + } else { > + /* Uncorrectable error */ > + u_int32_t hwCalc = (~eccCalc)&0xffffff; > + hwCalc = (hwCalc&0xfff)|((hwCalc&0xfff000)<<4); > + DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR > diff:%x nandBlock:%x calc:%x > hwCalc:%08x\n",diff,eccNand,eccCalc,hwCalc); > + return(-1); > } > - read_ecc += 3; > - calc_ecc += 3; > - dat += 512; > } > return(0); > } > #endif > > +#ifdef NAND_GPIO_READY_LIST > +static unsigned char nandGpioReadyList[] = {NAND_GPIO_READY_LIST}; > +#endif > + > 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); > +#ifdef NAND_GPIO_READY_LIST > +#define GP_BANK0_OFFSET 0x10 > +#define GP_BANK_LENGTH 0x28 > +#define GP_DIR 0x00 > +#define GP_OUT 0x04 > +#define GP_SET 0x08 > +#define GP_CLR 0x0C > +#define GP_IN 0x10 > + > + struct nand_chip *nand = mtd->priv; > + u_int32_t addr = (u_int32_t)nand->IO_ADDR_R; > + u_int32_t chipNum=(addr-CFG_NAND_BASE)>>25; /* 0 - > cs2, 1 - cs3, 2 - cs4, 3 - cs5 */ > + if (chipNum<4) { > + unsigned int gp = nandGpioReadyList[chipNum]; > + if (gp) { > + unsigned int bank = (gp>>5); > + volatile unsigned int* p = (unsigned > int*)(DAVINCI_GPIO_BASE+GP_BANK0_OFFSET+(bank*GP_BANK_LENGTH)); > + int ret = (p[GP_IN>>2] >> (gp&0x1f))&1; > + DEBUG (MTD_DEBUG_LEVEL3, "Ready: %d\n", ret); > + return ret; > + } > + } > +#endif > + emifregs emif_addr = > (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; > + return (emif_addr->NANDFSR & 0x1); > } > > +/** > + * nand_davinci_waitfunc - [DEFAULT] wait until the command is done > + * @mtd: MTD device structure > + * @this: NAND chip structure > + * @state: state to select the max. timeout value > + * > + * Wait for command done. This applies to erase and program only > + * Erase can take up to 400ms and program up to 20ms according to > + * general NAND and SmartMedia specs > + * > +*/ > static int nand_davinci_waitfunc(struct mtd_info *mtd, struct > nand_chip *this, int state) > { > - while(!nand_davinci_dev_ready(mtd)) {;} > - *NAND_CE0CLE = NAND_STATUS; > - return(*NAND_CE0DATA); > + ulong start = get_timer(0); > + volatile u_int8_t * p = (volatile u_int8_t *)((unsigned > int)this->IO_ADDR_R); > + unsigned long timeout = (state == FL_ERASING)? ((CFG_HZ * 400) / > 1000) : ((CFG_HZ * 20) / 1000); > +#if 0 /* enable this if you don't trust your ready pin. */ > + unsigned long mwait = (state == FL_ERASING)? 400 : 20; > + udelay(mwait*1000); > +#endif > + > + p[MASK_CLE] = NAND_CMD_STATUS; > + > + while (1) { > + if (get_timer(start) > timeout) { > + printf("!!!Nand wait Timeout!!!\n"); > + return 1; > + } > + if (nand_davinci_dev_ready(mtd)) break; > + } > + return (*p); > } > > -static void nand_flash_init(void) > +#define BOOTCFG 0x01C40014 > +int board_nand_init(struct nand_chip *nand) > { > - u_int32_t acfg1 = 0x3ffffffc; > - u_int32_t acfg2 = 0x3ffffffc; > - u_int32_t acfg3 = 0x3ffffffc; > - u_int32_t acfg4 = 0x3ffffffc; > - emifregs emif_regs; > - > + u_int32_t acfg = 0 > + | (0<<31) /* selectStrobe */ > + | (0<<30) /* extWait */ > + | (1<<26) /* writeSetup 10 ns */ > + | (3<<20) /* writeStrobe 40 ns */ > + | (1<<17) /* writeHold 10 ns */ > + | (1<<13) /* readSetup 10 ns */ > + | (5<<7) /* readStrobe 60 ns */ > + | (1<<4) /* readHold 10 ns */ > + | (3<<2) /* turnAround ?? ns */ > + ; > + acfg |= (*((unsigned int*)BOOTCFG)>>5)&1; /* grab default > width from EM_WIDTH */ > /*-------------------------------------------------------------- > ----* > * NAND FLASH CHIP TIMEOUT @ 459 MHz > * > * > * > @@ -324,46 +312,39 @@ static void nand_flash_init(void) > * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns > * > * > * > *-------------------------------------------------------------- > ----*/ > - acfg1 = 0 > - | (0 << 31 ) /* selectStrobe */ > - | (0 << 30 ) /* extWait */ > - | (1 << 26 ) /* writeSetup 10 ns */ > - | (3 << 20 ) /* writeStrobe 40 ns */ > - | (1 << 17 ) /* writeHold 10 ns */ > - | (1 << 13 ) /* readSetup 10 ns */ > - | (5 << 7 ) /* readStrobe 60 ns */ > - | (1 << 4 ) /* readHold 10 ns */ > - | (3 << 2 ) /* turnAround ?? ns */ > - | (0 << 0 ) /* asyncSize 8-bit bus */ > - ; > - > - emif_regs = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; > > - emif_regs->AWCCR |= 0x10000000; > - emif_regs->AB1CR = acfg1; /* 0x08244128 */; > - emif_regs->AB2CR = acfg2; > - emif_regs->AB3CR = acfg3; > - emif_regs->AB4CR = acfg4; > - emif_regs->NANDFCR = 0x00000101; > -} > + emifregs emif_regs = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; > + u_int32_t addr = (u_int32_t)nand->IO_ADDR_R; > + u_int32_t chipNum=(addr-CFG_NAND_BASE)>>25; /* 0 - > cs2, 1 - cs3, 2 - cs4, 3 - cs5 */ > + if (chipNum>=4) return -1; > + > + emif_regs->AB_CR[chipNum] = acfg; /* 0x08244128 */ > + emif_regs->NANDFCR |= 1<<chipNum; > + > +#ifdef NAND_GPIO_READY_LIST > + { > + unsigned int gp = nandGpioReadyList[chipNum]; > + if (gp) { > + unsigned int bank = (gp>>5); > + volatile unsigned int* p = (unsigned > int*)(DAVINCI_GPIO_BASE+GP_BANK0_OFFSET+(bank*GP_BANK_LENGTH)); > + int val; > + int bitNum = (gp&0x1f); > + p[GP_DIR>>2] |= 1<<bitNum; /* make > sure it's an input */ > + val = (p[GP_IN>>2] >> bitNum)&1; > + DEBUG (MTD_DEBUG_LEVEL3, "Bank: %x curVal:%x > inReg:%p=%x\n", bank,val,&p[GP_IN>>2],p[GP_IN>>2]); > + } > + } > +#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; > + DEBUG (MTD_DEBUG_LEVEL3, "Nand base read:%p > write:%p\n",nand->IO_ADDR_R,nand->IO_ADDR_W); > nand->chip_delay = 0; > nand->select_chip = nand_davinci_select_chip; > + nand->options = (acfg&1)? NAND_BUSWIDTH_16 : 0; > #ifdef CFG_NAND_USE_FLASH_BBT > - nand->options = NAND_USE_FLASH_BBT; > + nand->options |= NAND_USE_FLASH_BBT; > #endif > #ifdef CFG_NAND_HW_ECC > -#ifdef CFG_NAND_LARGEPAGE > - nand->eccmode = NAND_ECC_HW12_2048; > -#elif defined(CFG_NAND_SMALLPAGE) > nand->eccmode = NAND_ECC_HW3_512; > -#else > -#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be > defined!" > -#endif > nand->autooob = &davinci_nand_oobinfo; > nand->calculate_ecc = nand_davinci_calculate_ecc; > nand->correct_data = nand_davinci_correct_data; > @@ -377,9 +358,6 @@ int board_nand_init(struct nand_chip *nand) > > nand->dev_ready = nand_davinci_dev_ready; > nand->waitfunc = nand_davinci_waitfunc; > - > - nand_flash_init(); > - > return(0); > } > > diff --git a/include/asm-arm/arch-davinci/emif_defs.h > b/include/asm-arm/arch-davinci/emif_defs.h > index 646fc77..d6b36da 100644 > --- a/include/asm-arm/arch-davinci/emif_defs.h > +++ b/include/asm-arm/arch-davinci/emif_defs.h > @@ -29,10 +29,7 @@ typedef struct { > dv_reg AWCCR; > dv_reg SDBCR; > dv_reg SDRCR; > - dv_reg AB1CR; > - dv_reg AB2CR; > - dv_reg AB3CR; > - dv_reg AB4CR; > + dv_reg AB_CR[4]; > dv_reg SDTIMR; > dv_reg DDRSR; > dv_reg DDRPHYCR; > @@ -51,10 +48,7 @@ typedef struct { > dv_reg NANDFCR; > dv_reg NANDFSR; > u_int8_t RSVD1[8]; > - dv_reg NANDF1ECC; > - dv_reg NANDF2ECC; > - dv_reg NANDF3ECC; > - dv_reg NANDF4ECC; > + dv_reg NANDF_ECC[4]; > } emif_registers; > > typedef emif_registers *emifregs; > diff --git a/include/asm-arm/arch-davinci/nand_defs.h > b/include/asm-arm/arch-davinci/nand_defs.h > index 619bd47..9c324c9 100644 > --- a/include/asm-arm/arch-davinci/nand_defs.h > +++ b/include/asm-arm/arch-davinci/nand_defs.h > @@ -26,136 +26,11 @@ > #ifndef _NAND_DEFS_H_ > #define _NAND_DEFS_H_ > > -#include <asm/arch/hardware.h> > - > #define MASK_CLE 0x10 > -#define MASK_ALE 0x0a > - > -#define NAND_CE0CLE ((volatile u_int8_t *)(CFG_NAND_BASE + 0x10)) > -#define NAND_CE0ALE ((volatile u_int8_t *)(CFG_NAND_BASE + 0x0a)) > -#define NAND_CE0DATA ((volatile u_int8_t *)CFG_NAND_BASE) > - > -typedef struct { > - u_int32_t NRCSR; > - u_int32_t AWCCR; > - u_int8_t RSVD0[8]; > - u_int32_t AB1CR; > - u_int32_t AB2CR; > - u_int32_t AB3CR; > - u_int32_t AB4CR; > - u_int8_t RSVD1[32]; > - u_int32_t NIRR; > - u_int32_t NIMR; > - u_int32_t NIMSR; > - u_int32_t NIMCR; > - u_int8_t RSVD2[16]; > - u_int32_t NANDFCR; > - u_int32_t NANDFSR; > - u_int8_t RSVD3[8]; > - u_int32_t NANDF1ECC; > - u_int32_t NANDF2ECC; > - u_int32_t NANDF3ECC; > - u_int32_t NANDF4ECC; > - u_int8_t RSVD4[4]; > - u_int32_t IODFTECR; > - u_int32_t IODFTGCR; > - u_int8_t RSVD5[4]; > - u_int32_t IODFTMRLR; > - u_int32_t IODFTMRMR; > - u_int32_t IODFTMRMSBR; > - u_int8_t RSVD6[20]; > - u_int32_t MODRNR; > - u_int8_t RSVD7[76]; > - u_int32_t CE0DATA; > - u_int32_t CE0ALE; > - u_int32_t CE0CLE; > - u_int8_t RSVD8[4]; > - u_int32_t CE1DATA; > - u_int32_t CE1ALE; > - u_int32_t CE1CLE; > - u_int8_t RSVD9[4]; > - u_int32_t CE2DATA; > - u_int32_t CE2ALE; > - u_int32_t CE2CLE; > - u_int8_t RSVD10[4]; > - u_int32_t CE3DATA; > - u_int32_t CE3ALE; > - u_int32_t CE3CLE; > -} nand_registers; > - > -typedef volatile nand_registers *nandregs; > +#define MASK_ALE 0x08 > > #define NAND_READ_START 0x00 > #define NAND_READ_END 0x30 > #define NAND_STATUS 0x70 > > -#ifdef CFG_NAND_HW_ECC > -#define NAND_Ecc_P1e (1 << 0) > -#define NAND_Ecc_P2e (1 << 1) > -#define NAND_Ecc_P4e (1 << 2) > -#define NAND_Ecc_P8e (1 << 3) > -#define NAND_Ecc_P16e (1 << 4) > -#define NAND_Ecc_P32e (1 << 5) > -#define NAND_Ecc_P64e (1 << 6) > -#define NAND_Ecc_P128e (1 << 7) > -#define NAND_Ecc_P256e (1 << 8) > -#define NAND_Ecc_P512e (1 << 9) > -#define NAND_Ecc_P1024e (1 << 10) > -#define NAND_Ecc_P2048e (1 << 11) > - > -#define NAND_Ecc_P1o (1 << 16) > -#define NAND_Ecc_P2o (1 << 17) > -#define NAND_Ecc_P4o (1 << 18) > -#define NAND_Ecc_P8o (1 << 19) > -#define NAND_Ecc_P16o (1 << 20) > -#define NAND_Ecc_P32o (1 << 21) > -#define NAND_Ecc_P64o (1 << 22) > -#define NAND_Ecc_P128o (1 << 23) > -#define NAND_Ecc_P256o (1 << 24) > -#define NAND_Ecc_P512o (1 << 25) > -#define NAND_Ecc_P1024o (1 << 26) > -#define NAND_Ecc_P2048o (1 << 27) > - > -#define TF(v) (v ? 1 : 0) > - > -#define P2048e(a) (TF(a & NAND_Ecc_P2048e) << 0) > -#define P2048o(a) (TF(a & NAND_Ecc_P2048o) << 1) > -#define P1e(a) (TF(a & NAND_Ecc_P1e) << 2) > -#define P1o(a) (TF(a & NAND_Ecc_P1o) << 3) > -#define P2e(a) (TF(a & NAND_Ecc_P2e) << 4) > -#define P2o(a) (TF(a & NAND_Ecc_P2o) << 5) > -#define P4e(a) (TF(a & NAND_Ecc_P4e) << 6) > -#define P4o(a) (TF(a & NAND_Ecc_P4o) << 7) > - > -#define P8e(a) (TF(a & NAND_Ecc_P8e) << 0) > -#define P8o(a) (TF(a & NAND_Ecc_P8o) << 1) > -#define P16e(a) (TF(a & NAND_Ecc_P16e) << 2) > -#define P16o(a) (TF(a & NAND_Ecc_P16o) << 3) > -#define P32e(a) (TF(a & NAND_Ecc_P32e) << 4) > -#define P32o(a) (TF(a & NAND_Ecc_P32o) << 5) > -#define P64e(a) (TF(a & NAND_Ecc_P64e) << 6) > -#define P64o(a) (TF(a & NAND_Ecc_P64o) << 7) > - > -#define P128e(a) (TF(a & NAND_Ecc_P128e) << 0) > -#define P128o(a) (TF(a & NAND_Ecc_P128o) << 1) > -#define P256e(a) (TF(a & NAND_Ecc_P256e) << 2) > -#define P256o(a) (TF(a & NAND_Ecc_P256o) << 3) > -#define P512e(a) (TF(a & NAND_Ecc_P512e) << 4) > -#define P512o(a) (TF(a & NAND_Ecc_P512o) << 5) > -#define P1024e(a) (TF(a & NAND_Ecc_P1024e) << 6) > -#define P1024o(a) (TF(a & NAND_Ecc_P1024o) << 7) > - > -#define P8e_s(a) (TF(a & NAND_Ecc_P8e) << 0) > -#define P8o_s(a) (TF(a & NAND_Ecc_P8o) << 1) > -#define P16e_s(a) (TF(a & NAND_Ecc_P16e) << 2) > -#define P16o_s(a) (TF(a & NAND_Ecc_P16o) << 3) > -#define P1e_s(a) (TF(a & NAND_Ecc_P1e) << 4) > -#define P1o_s(a) (TF(a & NAND_Ecc_P1o) << 5) > -#define P2e_s(a) (TF(a & NAND_Ecc_P2e) << 6) > -#define P2o_s(a) (TF(a & NAND_Ecc_P2o) << 7) > - > -#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) > -#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) > -#endif > - > #endif > > ------------------------------------------------------------------------ > - > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio 2005. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > _______________________________________________ > U-Boot-Users mailing list > U-Boot-Users at lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/u-boot-users > --- ****************************************************************** * KSI at home KOI8 Net < > The impossible we do immediately. * * Las Vegas NV, USA < > Miracles require 24-hour notice. * ****************************************************************** ^ permalink raw reply [flat|nested] 8+ messages in thread
* [U-Boot-Users] RFC on davinci Nand support changes 2007-09-25 17:42 ` ksi at koi8.net @ 2007-09-25 19:22 ` Troy Kisky 2007-09-26 22:33 ` ksi at koi8.net 0 siblings, 1 reply; 8+ messages in thread From: Troy Kisky @ 2007-09-25 19:22 UTC (permalink / raw) To: u-boot ksi at koi8.net wrote: > On Mon, 24 Sep 2007, Troy Kisky wrote: > > First of all, one should always remember rule number one -- if it ain't > broke, don't fix it. > > Leaving techical details for later let's start with generic, philosophical > question first -- what are you trying to achieve with that "fix"? What is > your goal, why fix a working code? What advantages would your fix give us > versus existing working and tested code? I can see none and problems are > aplenty -- you wanna go against what silicon designers did, against the > Linux kernel and against common sense. How can I go against silicon designers? I think you give me far too much credit for ingenuity. > > Now for the technical side. > > First of all, erased blocks do _NOT_ contain ECC errors. They are _ERASED_ > i.e. _EVERYTHING_ is set to all ones. Erased blocks simply do not have ECC. > And ECC code just skips erased blocks. One can _NOT_ "fix" OOB bytes for > erased blocks because it will make them _NOT_ erased thus making those > blocks dirty and unsuitable for writing any data into them. Well, the software ecc algorithm is designed to produce a ecc of ffffff for an erased block. I was merely following that philosophy. It also leads to more concise code without special cases. > > "Much easier to read function" is not a reason for a change to working > code. You say, the code is working. I say it doesn't. It is far easier for someone to prove an error, than to prove correctness. Have you ever tried to force an ecc error into the last ecc block of a large page nand chip? Does the current code correctly detect and fix it? I have tried, and my code does fix it. But ignoring that, easier to read usually also means less buggy and more efficient. The current code is far from obvious. It counts for 12 bits of differences, which can lead to fixing an ecc error which, in reality, was unfixable. My approach of XORING the high and low 12 bits and comparing to fff is much safer, as well as more efficient. > Less for the fact that easiness is in the eye of beholder, the existing > code In this case, I don't think you'll find many that will argue that the old code looks better. Do you argue that yourself? > is taken almost verbatim from MontaVista Linux kernel that everybody use > with a bugfix for unaligned access that made original code hang the U-Boot > (why it works in the kernel is left as an exercize for the reader.) And > this > has been done _DELIBERATELY_ to make U-Boot compatible with the kernel. I agree, linux must change if hardware ecc is being used. I said as much in the initial email. Is anyone using davinci hardware ecc under linux???? Just curious. > Now > you propose some "fix" that 1.) breakes that compatibility thus forcing > everybody not only change working U-Boot code but also mess with a working > kernel for no apparent reason; 2.) makes it different from the kernel > source > thus splitting the code base. I am more than willing to fix the linux kernel as well. And I'd probably agree that should happen first. > > Also I can see no reason for using any other chip select for NAND with > DaVinci. If one boots it off of NAND it _MUST_ be on CS2 because it is > hardcoded in DaVinci ROM bootcode. If one has NAND there is no reason to > have NOR flash in the system ergo nothing's going to CS2 so why just don't > put NAND on that chip select according to what silicon design suggests? The > only reason I can see is using _SEVERAL_ NAND chips to get a bigger memory. > But that is totally different question that should be addressed in > board-specific portion so it does not pertain to those 3 boards currently > supported, none of them have more than one NAND chip and none have it on > anything but CS2. And frankly I don't see a reason for having more than one > such chip with current NAND chip densities. > > Bus width from EM_WIDTH pin is also unnecessary, that is what NAND > Device ID > for. True, but then an error message is printed. I wish there was a callback to set the width after the ID is obtained. Maybe there is, but I didn't see it. > > As for EM_WAIT, there is a special pin dedicated exactly for this > purpose on > DaVinci so I can see no reason for not using it and using some precious > GPIO > instead. And anyways, if one wants to do it despite common sense, this > belongs to board-specific portion, not to generic NAND code. It is ifdefed out if you don't use it, so it won't cause a larger image. EM_WAIT is used for more than just NAND chips. If you want to free EM_WAIT for another purpose, something must take it's place. I.e. harddrive, boot from NOR, and NAND chip used concurrently. Although I'm not sure that would work, I see no reason for this code to make that policy decision. > > Hardware ECC in DaVinci is _NOT_ flexible, it only works with 512-byte > blocks. That is why large page NAND ECC is done in 4 steps. I can find no documentation that says that. And if I did, I would still try it. I cannot think of a logical reason as to why it wouldn't work. But my question isn't will it work. My question is is it beneficial. > > There is also absolutely no sane reason to forfeit perfectly working > hardware ECC in spite of software ECC that is a kludge for those systems > that don't have appropriate hardware. It brings additional code with all > its > penalties -- bigger size, slower speed etc. Why emulate something we do > have > in hardware? What's wrong with it? Your forgetting its biggest advantage, more eccs on smaller groups, means more single bit ecc errors can be corrected before giving up and a longer NAND flash life. If you read the ecc from the hardware after 256 bytes, instead of 512, it should just return the current value. It will be a little slower, but should not require a complete software implementation. It will require double the hardware ecc register reads, and double the comparisons. Thanks, this is exactly the discussion I wanted to start. > > And no, DaVinci hardware ECC does _NOT_ overwrite factory bad block > markers. > Neither in small page NAND devices nor in large page ones. That is even > true > for NAND initial boot loader that does not use true ECC, just raw hardware > syndrome that is only used for checking if data is correct, not for > correction. The ECC part TI guys managed to implement properly unlike some > other parts of silicon that are either buggy or braindead... > > So it is definite NACK for something like this from your's truly KSI who > did > initial DaVinci port. > I appreciate the effort you went to in this response. I hope more people will also look at it. I hope you will copy the segment that I have ifdefed to force an ecc error into your code, and let us know if the current implementation does indeed work. Sincerely, Troy Kisky ^ permalink raw reply [flat|nested] 8+ messages in thread
* [U-Boot-Users] RFC on davinci Nand support changes 2007-09-25 19:22 ` Troy Kisky @ 2007-09-26 22:33 ` ksi at koi8.net 2007-09-26 22:55 ` Wolfgang Denk 2007-09-27 0:52 ` Troy Kisky 0 siblings, 2 replies; 8+ messages in thread From: ksi at koi8.net @ 2007-09-26 22:33 UTC (permalink / raw) To: u-boot On Tue, 25 Sep 2007, Troy Kisky wrote: > ksi at koi8.net wrote: >> On Mon, 24 Sep 2007, Troy Kisky wrote: >> >> First of all, one should always remember rule number one -- if it > ain't >> broke, don't fix it. >> >> Leaving techical details for later let's start with generic, > philosophical >> question first -- what are you trying to achieve with that "fix"? What > is >> your goal, why fix a working code? What advantages would your fix give > us >> versus existing working and tested code? I can see none and problems > are >> aplenty -- you wanna go against what silicon designers did, against > the >> Linux kernel and against common sense. > How can I go against silicon designers? I think you give me far too much > credit for ingenuity. You are trying to do something that goes against silicon designers' intentions. >> Now for the technical side. >> >> First of all, erased blocks do _NOT_ contain ECC errors. They are > _ERASED_ >> i.e. _EVERYTHING_ is set to all ones. Erased blocks simply do not have > ECC. >> And ECC code just skips erased blocks. One can _NOT_ "fix" OOB bytes > for >> erased blocks because it will make them _NOT_ erased thus making those >> blocks dirty and unsuitable for writing any data into them. > > Well, the software ecc algorithm is designed to produce a ecc of ffffff > for an > erased block. I was merely following that philosophy. It also leads to > more concise > code without special cases. Hardware algorithm does exactly the same. >> "Much easier to read function" is not a reason for a change to working >> code. > You say, the code is working. I say it doesn't. It is far easier for > someone > to prove an error, than to prove correctness. Have you ever tried to > force > an ecc error into the last ecc block of a large page nand chip? Does the > current > code correctly detect and fix it? I have tried, and my code does fix it. > But ignoring that, easier to read usually also means less buggy and more > efficient. > The current code is far from obvious. It counts for 12 bits of > differences, > which can lead to fixing an ecc error which, in reality, was unfixable. > My approach of XORING the high and low 12 bits and comparing to fff is > much > safer, as well as more efficient. Again, you are trying to reinvent the wheel. The ECC algorithm is described in details in TI documentation and MontaVista implemented it verbatim. >> Less for the fact that easiness is in the eye of beholder, the > existing >> code > In this case, I don't think you'll find many that will argue that the > old > code looks better. Do you argue that yourself? This code is a verbatim implementation of what is described in TI documentation. It's not supposed to look nice, it's supposed to work. >> is taken almost verbatim from MontaVista Linux kernel that everybody > use >> with a bugfix for unaligned access that made original code hang the > U-Boot >> (why it works in the kernel is left as an exercize for the reader.) > And >> this >> has been done _DELIBERATELY_ to make U-Boot compatible with the > kernel. > > I agree, linux must change if hardware ecc is being used. I said as much > in the initial email. Is anyone using davinci hardware ecc under > linux???? > Just curious. I did. One must use some kind of ECC. And there is absolutely no reason to attach a horse to a car, it's much better without. >> Now >> you propose some "fix" that 1.) breakes that compatibility thus > forcing >> everybody not only change working U-Boot code but also mess with a > working >> kernel for no apparent reason; 2.) makes it different from the kernel >> source >> thus splitting the code base. > I am more than willing to fix the linux kernel as well. And I'd probably > agree > that should happen first. Why do you want to fix something that is not broken? Don't you have anything better to spend your time on? And why do you think that TI guys that designed that silicon are deceiving us all with bad algorithm in their documentation? And why do you think most of HWECC implementations in different chips from different vendors include the same algorithm in their documentation almost verbatim? Are they all stupid or you discovered a conspiracy? >> Also I can see no reason for using any other chip select for NAND with >> DaVinci. If one boots it off of NAND it _MUST_ be on CS2 because it is >> hardcoded in DaVinci ROM bootcode. If one has NAND there is no reason > to >> have NOR flash in the system ergo nothing's going to CS2 so why just > don't >> put NAND on that chip select according to what silicon design > suggests? The >> only reason I can see is using _SEVERAL_ NAND chips to get a bigger > memory. >> But that is totally different question that should be addressed in >> board-specific portion so it does not pertain to those 3 boards > currently >> supported, none of them have more than one NAND chip and none have it > on >> anything but CS2. And frankly I don't see a reason for having more > than one >> such chip with current NAND chip densities. >> >> Bus width from EM_WIDTH pin is also unnecessary, that is what NAND >> Device ID >> for. > True, but then an error message is printed. I wish there was a callback > to set the width after the ID is obtained. Maybe there is, but I didn't > see it. >> As for EM_WAIT, there is a special pin dedicated exactly for this >> purpose on >> DaVinci so I can see no reason for not using it and using some > precious >> GPIO >> instead. And anyways, if one wants to do it despite common sense, this >> belongs to board-specific portion, not to generic NAND code. > It is ifdefed out if you don't use it, so it won't cause a larger image. > EM_WAIT is used for more than just NAND chips. If you want to free > EM_WAIT > for another purpose, something must take it's place. I.e. harddrive, > boot from > NOR, and NAND chip used concurrently. Although I'm not sure that would > work, > I see no reason for this code to make that policy decision. You can NOT use ATA and NAND/NOR together in DaVinci. There is also absolutely no reason to add a NOR Flash to a board that already has NAND. And all those READY/WAIT outputs are always OD (or OC) so they work perfectly well in wired-OR. That is how they are always designed. >> Hardware ECC in DaVinci is _NOT_ flexible, it only works with 512-byte >> blocks. That is why large page NAND ECC is done in 4 steps. > I can find no documentation that says that. And if I did, I would still > try it. > I cannot think of a logical reason as to why it wouldn't work. But my > question > isn't will it work. My question is is it beneficial. Have you tried to read TI documentation on DaVinci? >> There is also absolutely no sane reason to forfeit perfectly working >> hardware ECC in spite of software ECC that is a kludge for those > systems >> that don't have appropriate hardware. It brings additional code with > all >> its >> penalties -- bigger size, slower speed etc. Why emulate something we > do >> have >> in hardware? What's wrong with it? > Your forgetting its biggest advantage, more eccs on smaller groups, > means > more single bit ecc errors can be corrected before giving up and a > longer NAND > flash life. If you read the ecc from the hardware after 256 bytes, > instead of 512, > it should just return the current value. It will be a little slower, but > should not > require a complete software implementation. It will require double the > hardware ecc > register reads, and double the comparisons. Thanks, this is exactly the > discussion > I wanted to start. It won't prolong NAND life. The first thing one does when encountered an error is copying data to a different block and mark the entire faulted block as bad. Existing ECC is good enough to detect an error and, in most cases, correct it at least once while data being moved to a spare block. And you probably don't know that those OOB bytes are precious resource. Some guys do really use it and every single byte counts. If you take some bytes from them their data won't fit in the remaining space thus making some extremely useful software unusable with nothing gained in return. >> And no, DaVinci hardware ECC does _NOT_ overwrite factory bad block >> markers. >> Neither in small page NAND devices nor in large page ones. That is > even >> true >> for NAND initial boot loader that does not use true ECC, just raw > hardware >> syndrome that is only used for checking if data is correct, not for >> correction. The ECC part TI guys managed to implement properly unlike > some >> other parts of silicon that are either buggy or braindead... >> >> So it is definite NACK for something like this from your's truly KSI > who >> did >> initial DaVinci port. > I appreciate the effort you went to in this response. I hope more people > will > also look at it. I hope you will copy the segment that I have ifdefed to > force > an ecc error into your code, and let us know if the current > implementation does > indeed work. --- ****************************************************************** * KSI at home KOI8 Net < > The impossible we do immediately. * * Las Vegas NV, USA < > Miracles require 24-hour notice. * ****************************************************************** ^ permalink raw reply [flat|nested] 8+ messages in thread
* [U-Boot-Users] RFC on davinci Nand support changes 2007-09-26 22:33 ` ksi at koi8.net @ 2007-09-26 22:55 ` Wolfgang Denk 2007-09-26 23:11 ` ksi at koi8.net 2007-09-27 0:52 ` Troy Kisky 1 sibling, 1 reply; 8+ messages in thread From: Wolfgang Denk @ 2007-09-26 22:55 UTC (permalink / raw) To: u-boot In message <Pine.LNX.4.64ksi.0709261459210.20962@home-gw.koi8.net> you wrote: > > You can NOT use ATA and NAND/NOR together in DaVinci. There is also > absolutely no reason to add a NOR Flash to a board that already has NAND. In that general form that statement is incorrect. I can imagine *many* reasons to use NOR flash on a board that also has NAND. Best regards, Wolfgang Denk -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de I paid too much for it, but its worth it. ^ permalink raw reply [flat|nested] 8+ messages in thread
* [U-Boot-Users] RFC on davinci Nand support changes 2007-09-26 22:55 ` Wolfgang Denk @ 2007-09-26 23:11 ` ksi at koi8.net 0 siblings, 0 replies; 8+ messages in thread From: ksi at koi8.net @ 2007-09-26 23:11 UTC (permalink / raw) To: u-boot On Thu, 27 Sep 2007, Wolfgang Denk wrote: > In message <Pine.LNX.4.64ksi.0709261459210.20962@home-gw.koi8.net> you > wrote: >> >> You can NOT use ATA and NAND/NOR together in DaVinci. There is also >> absolutely no reason to add a NOR Flash to a board that already has > NAND. > > In that general form that statement is incorrect. I can imagine *many* > reasons to use NOR flash on a board that also has NAND. OK, let's make it "to a _DaVinci_ board that already has NAND." :)) DaVinci boots off of NAND just fine so NOR is not necessary for bootup and it does really work unlike e.g. AT91SAM9260 where it is claimed to and supposed to but won't due to silicon errata that sets wrong timings for NAND on boot thus requiring some other ROM (NOR, Dataflash) to boot. And once it booted NAND gives much more capacity for less. Yes, one can not XIP from NAND but it is hardly a requirement for a DDR2-equipped system with 600Mhz clock. As for general form, yes, it is overstatement... --- ****************************************************************** * KSI at home KOI8 Net < > The impossible we do immediately. * * Las Vegas NV, USA < > Miracles require 24-hour notice. * ****************************************************************** ^ permalink raw reply [flat|nested] 8+ messages in thread
* [U-Boot-Users] RFC on davinci Nand support changes 2007-09-26 22:33 ` ksi at koi8.net 2007-09-26 22:55 ` Wolfgang Denk @ 2007-09-27 0:52 ` Troy Kisky 2007-09-27 4:44 ` ksi at koi8.net 1 sibling, 1 reply; 8+ messages in thread From: Troy Kisky @ 2007-09-27 0:52 UTC (permalink / raw) To: u-boot > > Again, you are trying to reinvent the wheel. The ECC algorithm is described > in details in TI documentation and MontaVista implemented it verbatim. > > > This code is a verbatim implementation of what is described in TI > documentation. It's not supposed to look nice, it's supposed to work. I guess that's what happens when you implement an algorithm without understanding it. Example: You have a block of all zeros. The ecc stored in the spare bytes of this is also 0. Now, upon reading this block of zeroes, a two bit ecc occurs. The bits that happen to be read incorrectly are bit # 0 & bit # 0x3f of the block The hardware calculated ecc will be 0:0 ^ 0:fff = 0:fff after bit 0 0:fff ^ 3f:fc00 = 3f:3f after bit 3f Now, when your algorithm counts bits you get 12, and decide it is a single bit ecc error. I however xor the high and low 12 bits 3f ^ 3f = 0, 0 != fff and decide it is multi bit ecc error and give an error. Note, that both approaches would have decide it was a single bit error, if the second error wouldn't have happened. I could give an example of another error with your algorithm, but I have no desire to teach those without a desire to learn and no one else on this list seems interested in this subject. Troy ^ permalink raw reply [flat|nested] 8+ messages in thread
* [U-Boot-Users] RFC on davinci Nand support changes 2007-09-27 0:52 ` Troy Kisky @ 2007-09-27 4:44 ` ksi at koi8.net 0 siblings, 0 replies; 8+ messages in thread From: ksi at koi8.net @ 2007-09-27 4:44 UTC (permalink / raw) To: u-boot On Wed, 26 Sep 2007, Troy Kisky wrote: >> >> Again, you are trying to reinvent the wheel. The ECC algorithm is > described >> in details in TI documentation and MontaVista implemented it verbatim. >> >> >> This code is a verbatim implementation of what is described in TI >> documentation. It's not supposed to look nice, it's supposed to work. > > I guess that's what happens when you implement an algorithm without > understanding it. > Example: You have a block of all zeros. > > The ecc stored in the spare bytes of this is also 0. > Now, upon reading this block of zeroes, a two bit ecc occurs. The bits > that happen to be > read incorrectly are bit # 0 & bit # 0x3f of the block > The hardware calculated ecc will be > 0:0 ^ 0:fff = 0:fff after bit 0 > 0:fff ^ 3f:fc00 = 3f:3f after bit 3f > > Now, when your algorithm counts bits you get 12, and decide > it is a single bit ecc error. > > I however xor the high and low 12 bits 3f ^ 3f = 0, 0 != fff and > decide it is multi bit ecc error and give an error. > > Note, that both approaches would have decide it was a single bit error, > if the second > error wouldn't have happened. > > I could give an example of another error with your algorithm, but I have > no desire to teach those without a desire to learn and no one else on > this > list seems interested in this subject. Eh, that sounds like myself years, say, 20..25 ago... --- ****************************************************************** * KSI at home KOI8 Net < > The impossible we do immediately. * * Las Vegas NV, USA < > Miracles require 24-hour notice. * ****************************************************************** ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2007-09-27 4:44 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-09-25 1:10 [U-Boot-Users] RFC on davinci Nand support changes Troy Kisky 2007-09-25 17:42 ` ksi at koi8.net 2007-09-25 19:22 ` Troy Kisky 2007-09-26 22:33 ` ksi at koi8.net 2007-09-26 22:55 ` Wolfgang Denk 2007-09-26 23:11 ` ksi at koi8.net 2007-09-27 0:52 ` Troy Kisky 2007-09-27 4:44 ` ksi at koi8.net
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox