[U-Boot-Users] RFC on davinci Nand support changes

ksi at koi8.net ksi at koi8.net
Tue Sep 25 19:42:59 CEST 2007


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.   *
******************************************************************




More information about the U-Boot mailing list