/* 061212 nss ALL CHD */

/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * Inclues
 ---------------------------------------------------------------
 --------------------------------------------------------------*/

#include <common.h>
#include <environment.h>


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * Defines
 ---------------------------------------------------------------
 --------------------------------------------------------------*/

/* FlashROM Port Width 16bit or 32bit */
#if 1
	/* FlashROM Port Width 8bit  */ 
	typedef unsigned char FPC;
	typedef volatile unsigned char FPCV;

	/* FlashROM Port Width 16Bit */
	typedef unsigned short FPW;
	typedef volatile unsigned short FPWV;
#else

	/* FlashROM Port Width 32Bit ( MBM29QM12DH-60<16BitPort> Parallel Connection) */
	typedef unsigned long FPW;
	typedef volatile unsigned long FPWV;

#endif

/* FlashROM Test Mode */
#define FLASHROM_TEST_MODE 0


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * Global Variables
 ---------------------------------------------------------------
 --------------------------------------------------------------*/

/* FlashROM Information : 1 Chip Configuration */
flash_info_t flash_info[CFG_MAX_FLASH_BANKS];


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * Prototype Functions
 ---------------------------------------------------------------
 --------------------------------------------------------------*/

static void  flash_reset( flash_info_t *info );
static void  flash_get_offsets( ulong base, flash_info_t *info );
static ulong flash_get_size( FPWV *addr, flash_info_t *info );
static void  flash_sync_real_protect( flash_info_t *info );
static int   write_word ( flash_info_t *info, FPW *dest, FPW data );
static int   write_byte ( flash_info_t *info, ulong dest, uchar data);

static void  flash_test_erase( flash_info_t *info, int s_first, int s_last );
static void  flash_test_write( flash_info_t *info, FPW *dest, FPW data );
static void  flash_test_protect( flash_info_t * info, long sector, int prot );
static void  flash_test_protect_status( flash_info_t *info, int iMode );


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * Global Functions
 ---------------------------------------------------------------
 --------------------------------------------------------------*/

/*--------------------------------------------------------------
 * flash_init()
 * Sets Up flash_info and Returns Size of FlashROM (Byte)
 --------------------------------------------------------------*/
unsigned long flash_init( int num )
{
	ulong ulFlashROMSize; /* FlashROM Size */
	unsigned long addr;

	/* Initialize FlashROM ID */
	flash_info[num].flash_id = FLASH_UNKNOWN;
	flash_info[num].flash_number = num;

	switch (num) {
		case 0:
			addr = CFG_FLASH_BASE_BOOT;
			flash_info[num].chipwidth = BUSWIDTH_16BIT;
			break;
		case 1:
			addr = CFG_FLASH_BASE_OS;
			flash_info[num].chipwidth = BUSWIDTH_16BIT;
			break;
		case 2:
			addr = CFG_FLASH_BASE_FONT;
			flash_info[num].chipwidth = BUSWIDTH_8BIT;
			break;
		case 3:
			addr = CFG_FLASH_BASE_FONT2;
			flash_info[num].chipwidth = BUSWIDTH_8BIT;
			break;
		case 4:
			addr = CFG_FLASH_BASE_FPGA;
			flash_info[num].chipwidth = BUSWIDTH_8BIT;
			break;
		case 5:
			addr = CFG_FLASH_BASE_WORK;
			flash_info[num].chipwidth = BUSWIDTH_8BIT;
			break;
		default:
			return 0;
	}
	/* Get Sise of FlashROM */
	ulFlashROMSize = flash_get_size( (FPWV *)addr, &flash_info[num]);

	/* Check FlashROM ID */
	if( flash_info[num].flash_id == FLASH_UNKNOWN ){
		/* Not Support */
		printf( "## Unknown FLASH on Bank 0 - Size = 0x%08lx(%d)\n", ulFlashROMSize, num );
		return 0;
	}

	/* Get FlashROM Sector Protect Status */
	flash_sync_real_protect( &flash_info[num] );

	/* Set Protect for Environment Ares in FlashROM */
	flash_protect( FLAG_PROTECT_SET, CFG_ENV_ADDR, CFG_ENV_ADDR+CFG_ENV_SIZE-1, &flash_info[num] );

#if FLASHROM_TEST_MODE /* FlashROM Test Mode */

	FPW   *pSectorAddr;    /* Sector Address */
	uchar ucTestData[100]; /* Write Data     */
	int   iLoop;           /* Loop Counter   */

	/*===============================*/
	/* Protect / Erase Sequence Test */
	/*===============================*/

	/* Initialize Protect Status */
	flash_test_protect_status(&flash_info[0],1);
	/* Set Protect On Sector 49 */
	flash_test_protect(&flash_info[0],49,1);
	/* Erase Sector 39-49 */
	flash_test_erase(&flash_info[0],39,49);
	/* Set Protect Off Sector 49 */
	flash_test_protect(&flash_info[0],49,0);
	/* Erase Sector 39-49 */
	flash_test_erase(&flash_info[0],39,49);

	/*==============================*/
	/* Protect Status Sequence Test */
	/*==============================*/

	/* Set Protect On Sector 100-109 */
	flash_test_protect(&flash_info[0],100,1);
	flash_test_protect(&flash_info[0],101,1);
	flash_test_protect(&flash_info[0],102,1);
	flash_test_protect(&flash_info[0],103,1);
	flash_test_protect(&flash_info[0],104,1);
	flash_test_protect(&flash_info[0],105,1);
	flash_test_protect(&flash_info[0],106,1);
	flash_test_protect(&flash_info[0],107,1);
	flash_test_protect(&flash_info[0],108,1);
	flash_test_protect(&flash_info[0],109,1);
	/* Listout Protect Status */
	flash_test_protect_status(&flash_info[0],0);

	/*=====================*/
	/* Write Sequence Test */
	/*=====================*/

	/* Make Write Data */
	for( iLoop=0; iLoop<100; iLoop++ ){
		ucTestData[iLoop] = iLoop;
	}

	/* Write : Target Sector 100 */
	pSectorAddr = (FPW *)(flash_info[0].start[100]);
	write_buff(&flash_info[0], ucTestData, (ulong)pSectorAddr, iLoop );
	/* Write : Target Sector 49 */
	pSectorAddr = (FPW *)(flash_info[0].start[49]);
	write_buff(&flash_info[0], ucTestData, (ulong)pSectorAddr, iLoop );
	/* Write : Target Sector 0 */
	pSectorAddr = (FPW *)(flash_info[0].start[0]);
	write_buff(&flash_info[0], ucTestData, (ulong)pSectorAddr, iLoop );

	/*===============*/
	/* Test End Mode */
	/*===============*/

	/* Loop ... */
	for(;;){
		udelay(10000);
	}

#endif /* FlashROM Test Mode */

	/* Return FlashROM Size */
	return (ulFlashROMSize);
}

#if 0	/* Tasaki */
/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_erase()
 * Erase Sector of FlashROM, Returns
 *   0 - SUCCESS
 *   1 - FAIL
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
int flash_erase( flash_info_t *info, int s_first, int s_last )
{
    FPWV  *pBaseAddr;   /* Base Address          */
    FPCV  *pBaseAddrC;
    FPWV  *pSectorAddr; /* Sector Address        */
    FPCV  *pSectorAddrC;

    int   iIrqFlag;     /* Interrupt Flag        */
    int   iProtectNum;  /* Protect Number        */
    int   iSecLoop;     /* Sector Loop Counter   */
    int   iLoop;        /* Loop Counter          */
    int   iRtnCode = 0; /* Return Code : SUCCESS */


	/* Check Sector Number */
	if( (s_first<0) || ( s_first>s_last) ){
		/* Out of Range */
		printf ("- No Sectors To Erase\n");
		return 1;
	}

	/* All Sector Loop */
	for( iLoop=s_first,iProtectNum=0; iLoop<=s_last; iLoop++ ){
		/* Check Protect Status */
		if( info->protect[iLoop] ){
			/* Check Sector of Protect On */
			iProtectNum++;
		}
	}

	/* Check Protect Status */
	if( iProtectNum ){
		/* Logout Warning */
		printf ("- Warning: %d Protected Sectors Will Not Be Erased!\n", iProtectNum );
	}

	/*====================================*/
	/* Start Erase On UnProtected Sectors */
	/*====================================*/

	/* Get Base Address */
	switch ( info->chipwidth ) {
	case BUSWIDTH_8BIT:
		pBaseAddrC = (FPCV *)(info->start[0]);
		break;
	case BUSWIDTH_16BIT:
		pBaseAddr  = (FPWV *)(info->start[0]);
		break;
	default:
		printf ("- Flash Bus width not specific.[0x%d]\n",info->chipwidth);
		return 1;
	}

	/* Erase Sector Loop */
	for( iSecLoop=s_first; (iSecLoop<=s_last)&&(iRtnCode==0); iSecLoop++ ){

		/* Check Protect Status */
		if( info->protect[iSecLoop] != 0 ){
			/* Skip, Cause Protected Sector */
			continue;
		}

		switch ( info->chipwidth ) {
		case BUSWIDTH_8BIT:
			/* Get Sector Address */
			pSectorAddrC = (FPCV *)(info->start[iSecLoop]);

			/* Disable Interrupts */
			iIrqFlag = disable_interrupts();

			/*============================*/
			/* Write Command : Erase Mode */
			/*============================*/
			pBaseAddrC[0xAAA] = (FPCV)0xAA;
			pBaseAddrC[0x555] = (FPCV)0x55;
			pBaseAddrC[0xAAA] = (FPCV)0x80;
			pBaseAddrC[0xAAA] = (FPCV)0xAA;
			pBaseAddrC[0x555] = (FPCV)0x55;
			*pSectorAddrC     = (FPCV)0x30;

			/* Re-Enable Interrupts */
			if( iIrqFlag ){
				enable_interrupts();
			}
			break;

		case BUSWIDTH_16BIT:
			/* Get Sector Address */
			pSectorAddr = (FPWV *)(info->start[iSecLoop]);

			/* Disable Interrupts */
			iIrqFlag = disable_interrupts();

			/*============================*/
			/* Write Command : Erase Mode */
			/*============================*/
			pBaseAddr[0x555] = (FPWV)0x00AA;
			pBaseAddr[0x2AA] = (FPWV)0x0055;
			pBaseAddr[0x555] = (FPWV)0x0080;
			pBaseAddr[0x555] = (FPWV)0x00AA;
			pBaseAddr[0x2AA] = (FPWV)0x0055;
			*pSectorAddr     = (FPWV)0x0030;

			/* Re-Enable Interrupts */
			if( iIrqFlag ){
				enable_interrupts();
			}
			break;
		}


		/* Wait Loop until Erase Time */
		for( iLoop=0; iLoop<CFG_FLASH_ERASE_WAIT; iLoop++ ){

			switch ( info->chipwidth ) {
			case BUSWIDTH_8BIT:
				/* Check Erase Sector Data : 0xff */
				if( *pSectorAddrC == (FPCV)0xff ){
					/* Erase Command Success */
					break;
				}
				break;
			case BUSWIDTH_16BIT:
				/* Check Erase Sector Data : 0xffff */
				if( *pSectorAddr == (FPWV)0xffffffff ){
					/* Erase Command Success */
					break;
				}
			}

			/* Show Waiting Status */
			if( (0==(iLoop%CFG_FLASH_ERASE_SHOW)) && (0!=iLoop) ){
				/* Logout Erase Status */
				putc('.');
			}
		}

		/* Check Erase Timeout */
		if( iLoop == CFG_FLASH_ERASE_WAIT ){
			/* Retry Wait Loop until Erase Time */
			for( iLoop=0; iLoop<CFG_FLASH_ERASE_REWAIT; iLoop++ ){

				switch ( info->chipwidth ) {
				case BUSWIDTH_8BIT:
					/* Check Erase Sector Data : 0xff */
					if( *pSectorAddrC == (FPCV)0xff ){
						/* Erase Command Success */
						break;
					}
					break;
				case BUSWIDTH_16BIT:
					/* Check Erase Sector Data : 0xffff */
					if( *pSectorAddr == (FPWV)0xffffffff ){
						/* Erase Command Success */
						break;
					}
					break;
				}

				/* Show Waiting Status */
				if( (0==(iLoop%CFG_FLASH_ERASE_SHOW)) && (0!=iLoop) ){
					/* Logout Erase Status */
					putc('*');
				}
			}
			/* Check Erase Timeout */
			if( iLoop == CFG_FLASH_ERASE_REWAIT ){
				/* Reset FlashROM for Read Mode */
				flash_reset(info);
				/* Erase Command Fail */
				iRtnCode = 1;
			}
		}


		printf("Sector count [%d]-[%d](%d)\n", iSecLoop,s_last,iRtnCode);

	}

	/* Logout done */
	printf (" done!\n");

	/* Return 0 or 1 (0:SUCCESS,1:FAIL) */
	return iRtnCode;
}
#endif 	/* tasaki */


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * write_buff()
 * Copy Memory To FlashROM, Returns
 *   0 - SUCCESS
 *   1 - FAIL
 *   2 - Flash Not Erased
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
{
    FPW data = 0;
    int bytes;
    int left;
    int i, res, rc;

	switch (info->chipwidth) {
	case BUSWIDTH_8BIT:

    		while (cnt > 0) {
        		if ((rc = write_byte(info, addr, *src)) != 0) {
            			return (rc);
        		}
        		addr++;
        		src++;
        		cnt--;
    		}
    		return (0);
		break;

	case BUSWIDTH_16BIT:
    		for( left=cnt, res=0; (left>0)&&(res==0); addr+=sizeof(data), left-=(sizeof(data)-bytes) ){
	
			bytes = addr & (sizeof(data)-1);
			addr &= ~(sizeof(data) - 1);
	
			for( i=0; i<sizeof(data); i++ ){
	    			data <<= 8;
	    			if( (i<bytes) || (i-bytes>=left) ){
					data += *( (uchar *)addr + i );
				}else{
					data += *src++;
				}
			}
#if FLASHROM_TEST_MODE /* FlashROM Test Mode */
			flash_test_write(info, (FPW*)addr, data);
			res = 0;
#else
			res = write_word(info, (FPW*)addr, data);
#endif  /* FlashROM Test Mode */
		}
    		return (res);
		break;
    	}

}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_real_protect()
 * Protect Sector of FlashROM, Returns
 *   0 - SUCCESS
 *   1 - FAIL
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
int flash_real_protect( flash_info_t * info, long sector, int prot )
{
	/* Check Protect Mode */
	if( prot ){
		/* Set Protect Status : On */
		info->protect[sector] = 1;
	}else{
		/* Set Protect Status : Off */
		info->protect[sector] = 0;
	}

	/* Reset FlashROM for Read Mode */
	flash_reset( info );

	/* Return 0 (SUCCESS) */
	return 0;
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_print_info()
 * Print Flash Information
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
void flash_print_info (flash_info_t *info)
{
	uchar *boottype;   /* Boot Type            */
	uchar *bootletter; /* Boot Letter          */
	uchar *fmt;        /* Logout Frame Pointer */
	int   iLoop;       /* Loop Counter         */

	uchar botbootletter[] = "B";
	uchar topbootletter[] = "T";
	uchar botboottype[]   = "bottom boot sector";
	uchar topboottype[]   = "top boot sector";

	/* Check Vender ID */
	switch( info->flash_id & FLASH_VENDMASK ){
		/* Fujitsu */
		case FLASH_MAN_FUJ:
			/* Logout Vender Name */
			printf("FUJITSU ");
			break;
		/* Other */
		default:
			printf ("Unknown Vendor ");
			break;
	}

	/* Check Boot Type  */
	if( info->flash_id & FLASH_BTYPE ){
		/* Set Boot Type : Bottom */
		boottype = botboottype;
		bootletter = botbootletter;
	}else {
		/* Set Boot Type : Top */
		boottype = topboottype;
		bootletter = topbootletter;
	}

	/* Check Device ID */
	switch (info->flash_id & FLASH_TYPEMASK) {
		case FLASH_S29AL016:
			/* Make Device Name */
			fmt = "S29AL016D70TFI%s (16 Mbit, %s)\n";
			break;
		case FLASH_S29GL512:
			/* Make Device Name */
			fmt = "S29GL512N10TFI%s (512 Mbit, %s)\n";
			break;
		case FLASH_S29JL064:
			/* Make Device Name */
			fmt = "S29JL064H70TFI%s (64 Mbit, %s)\n";
			break;
		case FLASH_S29AL008:
			/* Make Device Name */
			fmt = "S29AL008D70TFI%s (8 Mbit, %s)\n";
			break;

		/* Other */
		default:
			fmt = "Unknown Chip Type\n";
			break;
	}

	/*=============================*/
	/* Logout FlashROM Information */
	/*=============================*/

	/* Logout Boot Type */
	printf(fmt, bootletter, boottype);

	/* Logout FlashROM Size */
	printf("  Size: %ld MB in %d Sectors\n",info->size >> 20, info->sector_count );

	/* Logout Sector Information */
	printf("  Sector Start Addresses:");

	/* Logout All Sector Information */
	for( iLoop=0; iLoop<info->sector_count; iLoop++ ){
		if( (iLoop%5) == 0 ){
			printf("\n   ");
		}
		printf(" %08lX%s", info->start[iLoop], info->protect[iLoop] ? " (RO)" : "     ");
	}

	/* Retrun New Line */
	printf ("\n");

	return;
}


/*-----------------------------------------------------------------------
 * Support for flash file system (JFFS2)
 *
 * We use custom partition info function because we have to fit the
 * file system image between first sector (containing hard reset
 * configuration word) and the sector containing U-Boot image. Standard
 * partition info function does not allow for last sector specification
 * and assumes that the file system occupies flash bank up to and
 * including bank's last sector.
 */
#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CFG_JFFS_CUSTOM_PART)

#ifndef CFG_JFFS2_FIRST_SECTOR
#define CFG_JFFS2_FIRST_SECTOR 0
#endif
#ifndef CFG_JFFS2_FIRST_BANK
#define CFG_JFFS2_FIRST_BANK 0
#endif
#ifndef CFG_JFFS2_NUM_BANKS
#define CFG_JFFS2_NUM_BANKS 1
#endif
#define CFG_JFFS2_LAST_BANK (CFG_JFFS2_FIRST_BANK + CFG_JFFS2_NUM_BANKS - 1)

#include <jffs2/jffs2.h>

static struct part_info partition;

struct part_info *jffs2_part_info(int part_num)
{
	int i;

	if (part_num == 0) {
		if (partition.usr_priv == 0) {
			partition.offset =
				(unsigned char *) flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR];
			for (i = CFG_JFFS2_FIRST_BANK; i <= CFG_JFFS2_LAST_BANK; i++)
				partition.size += flash_info[i].size;
			partition.size -=
				flash_info[CFG_JFFS2_FIRST_BANK].start[CFG_JFFS2_FIRST_SECTOR] -
				flash_info[CFG_JFFS2_FIRST_BANK].start[0];
#ifdef CFG_JFFS2_LAST_SECTOR
			i = flash_info[CFG_JFFS2_LAST_BANK].sector_count - 1;
			partition.size -=
				flash_info[CFG_JFFS2_LAST_BANK].start[i] -
				flash_info[CFG_JFFS2_LAST_BANK].start[CFG_JFFS2_LAST_SECTOR];
#endif

			partition.usr_priv = (void *)1;
		}
		return &partition;
	}

	return 0;
}

#endif /* JFFS2 */



/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * Static Functions
 ---------------------------------------------------------------
 --------------------------------------------------------------*/

/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_reest()
 * Reset FlashROM for Read Mode
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static void flash_reset( flash_info_t *info )
{
	/* Get FlashROM Base Address */
	FPWV *pBaseAddr = (FPWV *)(info->start[0]);

	/*=================================*/
	/* Write Command : Read/Reset Mode */
	/*=================================*/
#if 0	/* 2006/12/27 S.Tasaki */
	pBaseAddr[0x555] = (FPWV)0x00AA;
	pBaseAddr[0x2AA] = (FPWV)0x0055;
	pBaseAddr[0x555] = (FPWV)0x00F0;
#else
	pBaseAddr[0] = 0xF0;
#endif

	return;
}


static void s29al016_get_offset (ulong base, flash_info_t *info)
{
	int iLoop, i; /* Loop Counter */
	iLoop = 0;
	
	/* top */
	info->start[iLoop] = base;
	iLoop++;
	
	/* 16k */
	info->start[iLoop] = info->start[iLoop-1] + 0x00004000;
	iLoop++;
	
	/* 8k * 2 */
	for( i = 0; i<2; i++, iLoop++ ){
		info->start[iLoop] = info->start[iLoop-1] + 0x00002000;
	}
	
	/* 32k */
	info->start[iLoop] = info->start[iLoop-1] + 0x00008000;
	iLoop++;
	
	/* 64k */
	for ( ; iLoop < CFG_MAX_FLASH_SECT_AL016; iLoop++ ) {
		info->start[iLoop] = info->start[iLoop-1] + 0x00010000;
	}

	return;
}

static void s29gl512_get_offset (ulong base, flash_info_t *info)
{
	int iLoop; /* Loop Counter */
	iLoop = 0;
	
	/* top */
	info->start[iLoop] = base;
	iLoop++;
	
	/* 128k */
	for ( ; iLoop < CFG_MAX_FLASH_SECT_GL512; iLoop++ ) {
		info->start[iLoop] = info->start[iLoop-1] + 0x00020000;
	}

	return;
}

static void s29jl064_get_offset (ulong base, flash_info_t *info)
{
	int iLoop, i; /* Loop Counter */
	iLoop = 0;
	
	/* top */
	info->start[iLoop] = base;
	iLoop++;

	/* 8k */
	for( i = 0; i<8; i++, iLoop++ ){
		info->start[iLoop] = info->start[iLoop-1] + 0x00002000;
	}

	/* 64k */
	for( i = 0; i<126; i++, iLoop++ ){
		info->start[iLoop] = info->start[iLoop-1] + 0x00010000;
	}

	/* 8k */
	for( i = 0; i<7; i++, iLoop++ ){
		info->start[iLoop] = info->start[iLoop-1] + 0x00002000;
	}

	return;
}

static void s29al008_get_offset (ulong base, flash_info_t *info)
{
	int iLoop, i; /* Loop Counter */
	iLoop = 0;
	
	/* top */
	info->start[iLoop] = base;
	iLoop++;

	/* 64k */
	for ( i = 0; i<15; i++, iLoop++ ) {
		info->start[iLoop] = info->start[iLoop-1] + 0x00010000;
	}

	/* 32 */
	info->start[iLoop] = info->start[iLoop-1] + 0x00008000;
	iLoop++;
	
	/* 8k * 2 */
	for( i = 0; i<2; i++, iLoop++ ){
		info->start[iLoop] = info->start[iLoop-1] + 0x00002000;
	}
	
	return;
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_get_offsets()
 * Get FlashROM Sector Information
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static void flash_get_offsets (ulong base, flash_info_t *info)
{
	/* Check Device ID */
	switch (info->flash_id & FLASH_TYPEMASK) {
		case FLASH_S29AL016:
			s29al016_get_offset( base, info );
			break;
		case FLASH_S29GL512:
			s29gl512_get_offset( base, info );
			break;
		case FLASH_S29JL064:
			s29jl064_get_offset( base, info );
			break;
		case FLASH_S29AL008:
			s29al008_get_offset( base, info );
			break;

		/* Other */
		default:
			return;
			break;
	}
	return;
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_get_size()
 * Get Size of FlashROM
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
ulong flash_get_size( FPWV *addr, flash_info_t *info )
{
	unsigned char  vender_id;
	unsigned short device_id;
	unsigned char  cdevice_id;
        unsigned char *boot_type;
	FPCV 	*caddr;

	/*======================================*/
	/* Write Command : Read Manufacturer ID */
	/*======================================*/
	switch (info->chipwidth) {
	case BUSWIDTH_8BIT:
		caddr = (FPCV *)addr;
	    	caddr[0xAAA] = (FPWV)0xAA;
	    	caddr[0x555] = (FPWV)0x55;
	    	caddr[0xAAA] = (FPWV)0x90;

		/* Wait For Response */
		udelay( 10 );

		/* Check Manufacturer ID */
		vender_id = (unsigned char)caddr[0] & 0xff;

		break;
	case BUSWIDTH_16BIT:
	    	addr[0x555] = (FPWV)0x00AA;
	    	addr[0x2AA] = (FPWV)0x0055;
	    	addr[0x555] = (FPWV)0x0090;

		/* Wait For Response */
		udelay( 10 );

		/* Check Manufacturer ID */
		vender_id = (unsigned char)addr[0] & 0xff;

		break;
	default:
		info->flash_id = FLASH_UNKNOWN;
		printf ("Unknown Flash BUS Width(0x%x) \n ", info->chipwidth);
		return 0;
	}

	switch( vender_id ){
		/* Fujitsu */
		case (uchar)AMD_MANUFACT:
			/* Set Manufacturer ID */
			info->flash_id = FLASH_MAN_FUJ;
			break;
		/* Others */
		default:
			/* Not Support */
			info->flash_id = FLASH_UNKNOWN;
			printf ("Unknown Flash Manufacture Code [0x%x](0x%x) \n ", (addr[0] & 0xff), addr );
			return 0;
	}

	/* Check Device ID */
	switch (info->chipwidth) {
	case BUSWIDTH_8BIT:
		cdevice_id = (unsigned char)addr[1] & 0xff;
		switch( cdevice_id ){
		case (unsigned char)(MAN_ID_S29AL016_T & 0x00ff): 
		case (unsigned char)(MAN_ID_S29AL016_B & 0x00ff):
			/* Logout Device Name */
			printf ("SPANSION S29AL016D70TFI020 ");
			/* Set Device ID */
			info->flash_id += FLASH_S29AL016;
			/* Set Number of Sector */
			info->sector_count = CFG_MAX_FLASH_SECT_AL016;
			/* Set FlashROM Size */
			info->size = 0x00200000;
			break;
		case (unsigned char)(MAN_ID_S29JL064 & 0xff):
			/* Logout Device Name */
			printf ("SPANSION S29JL064H70TFI000 ");
			/* Set Device ID */
			info->flash_id += FLASH_S29JL064;
			/* Set Number of Sector */
			info->sector_count = CFG_MAX_FLASH_SECT_JL064;
			/* Set FlashROM Size */
			info->size = 0x00800000;
			break;
		default:
			/* Not Support */
			info->flash_id = FLASH_UNKNOWN;
			printf ("Unknown Device Id  [0x%x]\n ", cdevice_id );
			return 0;
		}

		break;
	case BUSWIDTH_16BIT:
		device_id = (unsigned short)addr[1] & 0xffff;

		/* Check Backup BOOT then set Flash device */
        	boot_type = (unsigned char *)0xfe000008;
		if ( !(((unsigned char)*boot_type) & 0x80) ) {
			printf("---------- BACKUP BOOT [0x%x]----------\n",
					(unsigned char)*boot_type );
			if (info->flash_number == 0)
				device_id = MAN_ID_S29AL016_T;
			if (info->flash_number == 1)
				device_id = MAN_ID_S29GL512;
		}


		switch( device_id ){
		/* S29AL016D70TFI020 */
		case MAN_ID_S29AL016_T: case MAN_ID_S29AL016_B:
			/* Logout Device Name */
			printf ("SPANSION S29AL016D70TFI020 ");
			/* Set Device ID */
			info->flash_id += FLASH_S29AL016;
			/* Set Number of Sector */
			info->sector_count = CFG_MAX_FLASH_SECT_AL016;
			/* Set FlashROM Size */
			info->size = 0x00200000;
			break;
		case MAN_ID_S29GL512:
			/* Logout Device Name */
			printf ("SPANSION S29GL512N10TFI020 ");
			/* Set Device ID */
			info->flash_id += FLASH_S29GL512;
			/* Set Number of Sector */
			info->sector_count = CFG_MAX_FLASH_SECT_GL512;
			/* Set FlashROM Size */
			info->size = 0x04000000;
			break;
		case MAN_ID_S29JL064:
			/* Logout Device Name */
			printf ("SPANSION S29JL064H70TFI000 ");
			/* Set Device ID */
			info->flash_id += FLASH_S29JL064;
			/* Set Number of Sector */
			info->sector_count = CFG_MAX_FLASH_SECT_JL064;
			/* Set FlashROM Size */
			info->size = 0x00800000;
			break;
		case MAN_ID_S29AL008_T: case MAN_ID_S29AL008_B:
			/* Logout Device Name */
			printf ("SPANSION S29AL008D70TFI010 ");
			/* Set Device ID */
			info->flash_id += FLASH_S29AL008;
			/* Set Number of Sector */
			info->sector_count = CFG_MAX_FLASH_SECT_AL008;
			/* Set FlashROM Size */
			info->size = 0x00100000;
			break;

		default:
			/* Not Support */
			info->flash_id = FLASH_UNKNOWN;
			printf ("Unknown Device Id  [0x%x]\n ", device_id );
			return 0;
		}
		break;
	}

	/* Get FlashROM Sector Information */
	flash_get_offsets( (ulong)addr, info );

	/* Reset FlashROM for Read Mode */
	flash_reset( info );

	/* Return Size of FlashROM */
	return (info->size);
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_sync_real_protect()
 * Get FlashROM Sector Protect Status (Initialize)
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static void flash_sync_real_protect( flash_info_t *info )
{
    int iLoop; /* Loop Counter */

	/* All Sector Loop */
	for( iLoop=0; iLoop<info->sector_count; iLoop++ ){

#if FLASHROM_TEST_MODE /* FlashROM Test Mode */

	    /* Set Protect Off ( To Real FlashROM ) */
		flash_test_protect( info, iLoop, 0 );
	    /* Set Protect Status Off */
	    info->protect[iLoop] = 0;

#else

	    /* Set Protect Off ( To Real FlashROM ) */
		flash_real_protect( info, iLoop, 0 );

#endif  /* FlashROM Test Mode */

	}

	/* Reset FlashROM for Read Mode */
	flash_reset( info );

	return;
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * write_word()
 * Copy Memory To FlashROM, Returns
 *   0 - SUCCESS
 *   1 - FAIL
 *   2 - Flash Not Erased
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static int write_word(flash_info_t *info, FPW *dest, FPW data)
{
    FPWV *pBaseAddr;   /* Base Address          */
	int  iIrqFlag;     /* Interrupt Flag        */
	int  iRtnCode = 0; /* Return Code : SUCCESS */
	int   iLoop;       /* Loop Counter          */

    /* Check Sector Erase Status */
    if( ( *dest & data ) != data ){
		/* Sector Not Erase */
		return (2);
    }

    /* Get Base Address */
    pBaseAddr = (FPWV *)(info->start[0]);

	/* Disable Interrupts */
	iIrqFlag = disable_interrupts();

	/*==============================*/
	/* Write Command : Program Mode */
	/*==============================*/
	pBaseAddr[0x555] = (FPWV)0x00AA;
	pBaseAddr[0x2AA] = (FPWV)0x0055;
	pBaseAddr[0x555] = (FPWV)0x00A0;
	*dest             = data;

	/* Re-Enable Interrupts */
	if( iIrqFlag ){
		enable_interrupts();
	}

	/* Wait Loop until Write Time */
	for( iLoop=0; iLoop<CFG_FLASH_WRITE_WAIT; iLoop++ ){
		/* Check D7 Polling */
		if( ( *dest & (FPW)0x00800080) == ( data & (FPW)0x00800080 ) ){
			/* Write Command Success */
			break;
		}
		/* Show Waiting Status */
		if( (0==(iLoop%CFG_FLASH_WRITE_SHOW)) && (0!=iLoop) ){
			/* Logout Erase Status */
			putc('.');
		}
	}

	/* Check Write Timeout */
	if( iLoop == CFG_FLASH_WRITE_WAIT ){
		/* Retry Wait Loop until Write Time */
		for( iLoop=0; iLoop<CFG_FLASH_WRITE_REWAIT; iLoop++ ){
			/* Check D7 Polling */
			if( ( *dest & (FPW)0x00800080) == ( data & (FPW)0x00800080 ) ){
				/* Write Command Success */
				break;
			}
			/* Show Waiting Status */
			if( (0==(iLoop%CFG_FLASH_WRITE_SHOW)) && (0!=iLoop) ){
				/* Logout Erase Status */
				putc('.');
			}
		}
		/* Check Write Timeout */
		if( iLoop == CFG_FLASH_WRITE_REWAIT ){
			/* Reset FlashROM for Read Mode */
			flash_reset(info);
			/* Write Command Fail */
			iRtnCode = 1;
		}
	}

	/* Return 0 or 1 (0:SUCCESS,1:FAIL) */
    return (iRtnCode);
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * Test Functions
 ---------------------------------------------------------------
 --------------------------------------------------------------*/

/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_test_write()
 * Test Of Erase Command For FlashROM
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static void flash_test_erase( flash_info_t *info, int s_first, int s_last )
{
    FPWV *pBaseAddr;   /* Base Address        */
    FPWV *pSectorAddr; /* Sector Address      */
	int  iIrqFlag;     /* Interrupt Flag      */
	int  iSecLoop;     /* Sector Loop Counter */
	int  iLoop;        /* Loop Counter        */

	/* Logout Start Tag */
	printf( "\n\n# Logout Erase ####################################\n");

    /* Get Base Address */
	pBaseAddr   = (FPWV *)(info->start[0]);

    /* Erase Sector Loop */
	for( iSecLoop=s_first; iSecLoop<=s_last; iSecLoop++ ){

	    /* Get Sector Address */
		pSectorAddr  = (FPWV *)(info->start[iSecLoop]);

		/* Disable Interrupt */
		iIrqFlag = disable_interrupts();

		/*=============================*/
		/* Write Command : Erase Mode  */
		/*=============================*/
		pBaseAddr[0x555] = (FPWV)0x00AA;
		pBaseAddr[0x2AA] = (FPWV)0x0055;
		pBaseAddr[0x555] = (FPWV)0x0080;
		pBaseAddr[0x555] = (FPWV)0x00AA;
		pBaseAddr[0x2AA] = (FPWV)0x0055;
		*pSectorAddr = (FPWV)0x0030;

		/* Enable Interrupt */
		if( iIrqFlag ){
			enable_interrupts();
		}

		/* Wait Loop until Erase Time */
		for( iLoop=0; iLoop<CFG_FLASH_ERASE_WAIT; iLoop++ ){
			/* Check Erase Sector Data : 0xffffffff */
			if( *pSectorAddr == (FPWV)0xffffffff ){
				/* Erase Command Success */
				printf("# ERASE SECTOR:%d, CNT:0x%08x YES\n", iSecLoop, iLoop);
				break;
			}
		}

		/* Check Erase Timeout */
		if( iLoop == CFG_FLASH_ERASE_WAIT ){
			/* Retry Wait Loop until Erase Time */
			for( iLoop=0; iLoop<CFG_FLASH_ERASE_REWAIT; iLoop++ ){
				/* Check Erase Sector Data : 0xffffffff */
				if( *pSectorAddr == (FPWV)0xffffffff ){
					/* Erase Command Success */
					printf("# ERASE SECTOR:%d, CNT:0x%08x YES\n", iSecLoop, iLoop);
					break;
				}
			}
			/* Check Erase Timeout */
			if( iLoop == CFG_FLASH_ERASE_REWAIT ){
				/* Erase Command Fail */
				printf("# ERASE SECTOR:%d NO\n", iSecLoop );
			}
		}

		/* Logout SectorNo, Data */
		printf("# SECTOR:%d DATA\n", iSecLoop);
		printf("# A:%08x :: ",(FPWV*)pSectorAddr);
		for( iLoop=0; iLoop<10; iLoop++ ){
			printf("%08x ", (FPWV)pSectorAddr[iLoop] );
		}
		printf(" \n");

	}

	/* Logout End Tag */
	printf( "\n#####################################################\n");

	return;
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_test_write()
 * Test Of Write Command For FlashROM
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static void flash_test_write( flash_info_t *info, FPW *dest, FPW data )
{
    FPWV *pBaseAddr; /* Base Address   */
	int  iIrqFlag;   /* Interrupt Flag */

	/* Logout Start Tag */
	printf( "\n\n# Logout Write ####################################\n");

	/* Logout Write Address, Data */
	printf("# WRITE ADDR:0x%08x DATA:0x%04x\n", dest, data );

    /* Get Base Address */
	pBaseAddr   = (FPWV *)(info->start[0]);

    /* Disable Interrupt */
	iIrqFlag = disable_interrupts();

	/*=============================*/
	/* Write Command : Write Mode  */
	/*=============================*/
	pBaseAddr[0x555] = (FPWV)0x00AA;
	pBaseAddr[0x2AA] = (FPWV)0x0055;
	pBaseAddr[0x555] = (FPWV)0x00A0;
	*dest             = data;

    /* Enable Interrupt */
	if( iIrqFlag ){
		enable_interrupts();
	}

	/* Wait For Response */
	udelay( CFG_FLASH_RESPONSE_WAIT );

	/* Wait Loop until Erase Success : D7 Polling */
	if( ( *dest & (FPW)0x00800080) == ( data & (FPW)0x00800080 ) ){
		/* Write Command Success */
		printf("\n# WRITE ADDR:0x%08x DATA:0x%08x YES\n", dest, (FPW)*dest );
	}else{
		/* Write Command Fail */
		printf("\n# WRITE ADDR:0x%08x DATA:0x%08x NO\n", dest, (FPW)*dest );
	}

	/* Logout End Tag */
	printf( "\n#####################################################\n");

	return;
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_test_protect()
 * Test Of Protect Command For FlashROM
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static void flash_test_protect( flash_info_t * info, long sector, int prot )
{
    FPWV *pBaseAddr;   /* Base Address   */
    FPWV *pSectorAddr; /* Sector Address */

	/* Logout Start Tag */
	printf( "\n\n# Logout Protect ####################################\n");

    /* Get Base Address */
    pBaseAddr = (FPWV *)(info->start[0]);

	/* Get Sector Address */
	pSectorAddr = (FPWV *)(info->start[sector]);

	/*==============================*/
	/* Write Command : Protect Mode */
	/*==============================*/
	pBaseAddr[0x555] = (FPWV)0x00AA;
	pBaseAddr[0x2AA] = (FPWV)0x0055;
	pBaseAddr[0x555] = (FPWV)0x0048;

	/* Check Protect Mode */
	if( prot ){
		/* Set Protect On */
	    *pSectorAddr |= (FPWV)0x00010001;
		/* Set Protect Status : On */
		info->protect[sector] = 1;
		/* Logout Protect Status On */
		printf("\n# Protect ON SEC:%d ADDR:0x%08x\n", sector, pSectorAddr );

	}else{
		/* Set Protect Off */
	    *pSectorAddr &= (FPWV)0xfffefffe;
		/* Set Protect Status : Off */
		info->protect[sector] = 0;
		/* Logout Protect Status Off */
		printf("\n# Protect OFF SEC:%d ADDR:0x%08x\n", sector, pSectorAddr );

	}

	/* Reset FlashROM for Read Mode */
	flash_reset( info );

	/* Logout End Tag */
	printf( "\n#####################################################\n");

	return;
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_test_protect_status()
 * Test Of Protect Command (Status) For FlashROM
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static void flash_test_protect_status( flash_info_t *info, int iMode )
{
    int iLoop; /* Loop Counter */

	/* Logout Start Tag */
	printf( "\n\n# Logout Protect Status ####################################\n");

	/* All Sector Loop */
	for( iLoop=0; iLoop<info->sector_count; iLoop++ ){
	    /* Initialise Protect Status (0:Off) */
		if( iMode ){
		    /* Set Protect Off ( To Real FlashROM ) */
			flash_test_protect( info, iLoop, 0 );
		    /* Set Protect Status Off */
		    info->protect[iLoop] = 0;
		}
		/* Logout SectorNum And Protect Status */
		printf("[%03d,%d], ",iLoop,info->protect[iLoop]);
		/* Logout New Line */
		if( 0 == ( (iLoop+1) % 10 ) ){
			printf(" \n");
		}
	}

	/* Reset FlashROM for Read Mode */
	flash_reset( info );

	/* Logout End Tag */
	printf( "\n#####################################################\n");

	return;
}

/* 061212 nss ALL CHD */


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_erase()
 * Erase Sector of FlashROM, Returns
 *   0 - SUCCESS
 *   1 - FAIL
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
int flash_erase( flash_info_t *info, int s_first, int s_last )
{
    	FPWV  *pBaseAddr;   /* Base Address          */
    	FPCV  *pBaseAddrC;  /* Base Address          */
    	FPWV  *pSectorAddr; /* Sector Address        */
    	FPCV  *pSectorAddrC;/* Sector Address        */
    	int   iIrqFlag;     /* Interrupt Flag        */
    	int   iProtectNum;  /* Protect Number        */
	int   iSecLoop;     /* Sector Loop Counter   */
	int   iLoop;        /* Loop Counter          */
	int   iRtnCode = 0; /* Return Code : SUCCESS */

	/* Check Sector Number */
	if( (s_first<0) || ( s_first>s_last) ){
		/* Out of Range */
		printf ("- No Sectors To Erase\n");
		return 1;
	}

	/* All Sector Loop */
	for( iLoop=s_first,iProtectNum=0; iLoop<=s_last; iLoop++ ){
		/* Check Protect Status */
		if( info->protect[iLoop] ){
			/* Check Sector of Protect On */
			iProtectNum++;
		}
	}

	/* Check Protect Status */
	if( iProtectNum ){
		/* Logout Warning */
		printf ("- Warning: %d Protected Sectors Will Not Be Erased!\n", iProtectNum );
	}

	/*====================================*/
	/* Start Erase On UnProtected Sectors */
	/*====================================*/

	/* Get Base Address */
	switch ( info->chipwidth ) {
	case BUSWIDTH_8BIT:
		pBaseAddrC = (FPCV *)(info->start[0]);
		break;
	case BUSWIDTH_16BIT:
		pBaseAddr  = (FPWV *)(info->start[0]);
		break;
	default:
		printf ("- Flash Bus width not specific.[0x%d]\n",info->chipwidth);
		return 1;
	}

	/* Erase Sector Loop */
	for( iSecLoop=s_first; (iSecLoop<=s_last)&&(iRtnCode==0); iSecLoop++ ){

		/* Check Protect Status */
		if( info->protect[iSecLoop] != 0 ){
			/* Skip, Cause Protected Sector */
			continue;
		}

		switch ( info->chipwidth ) {
		/*------------------------------------*/
		/*         BUS WIDTH 8BIT             */
		/*------------------------------------*/
		case BUSWIDTH_8BIT:

			/* Get Sector Address */
			pSectorAddrC = (FPCV *)(info->start[iSecLoop]);

			/* Disable Interrupts */
			iIrqFlag = disable_interrupts();

			/*============================*/
			/* Write Command : Erase Mode */
			/*============================*/
			pBaseAddrC[0xAAA] = (FPWV)0xAA;
			pBaseAddrC[0x555] = (FPWV)0x55;
			pBaseAddrC[0xAAA] = (FPWV)0x80;
			pBaseAddrC[0xAAA] = (FPWV)0xAA;
			pBaseAddrC[0x555] = (FPWV)0x55;
			*pSectorAddrC    = (FPWV)0x30;

			/* Re-Enable Interrupts */
			if( iIrqFlag ){
				enable_interrupts();
			}

			/* Wait Loop until Erase Time */
			for( iLoop=0; iLoop<CFG_FLASH_ERASE_WAIT; iLoop++ ){
				/* Check Erase Sector Data : 0xff */
				if( *pSectorAddrC == (FPWV)0xff ){
					/* Erase Command Success */
					break;
				}
				/* Show Waiting Status */
				if( (0==(iLoop%CFG_FLASH_ERASE_SHOW)) && (0!=iLoop) ){
					/* Logout Erase Status */
					putc('.');
				}
			}

			/* Check Erase Timeout */
			if( iLoop == CFG_FLASH_ERASE_WAIT ){
				/* Retry Wait Loop until Erase Time */
				for( iLoop=0; iLoop<CFG_FLASH_ERASE_REWAIT; iLoop++ ){
					/* Check Erase Sector Data : 0xff */
					if( *pSectorAddrC == (FPWV)0xff ){
						/* Erase Command Success */
						break;
					}
					/* Show Waiting Status */
					if( (0==(iLoop%CFG_FLASH_ERASE_SHOW)) && (0!=iLoop) ){
						/* Logout Erase Status */
						putc('*');
					}
				}
				/* Check Erase Timeout */
				if( iLoop == CFG_FLASH_ERASE_REWAIT ){
					/* Reset FlashROM for Read Mode */
					flash_reset(info);
					/* Erase Command Fail */
					iRtnCode = 1;
				}
			}
			break;

		/*------------------------------------*/
		/*         BUS WIDTH 16BIT            */
		/*------------------------------------*/
		case BUSWIDTH_16BIT:

			/* Get Sector Address */
			pSectorAddr = (FPWV *)(info->start[iSecLoop]);

			/* Disable Interrupts */
			iIrqFlag = disable_interrupts();

			/*============================*/
			/* Write Command : Erase Mode */
			/*============================*/
			pBaseAddr[0x555] = (FPWV)0x00AA;
			pBaseAddr[0x2AA] = (FPWV)0x0055;
			pBaseAddr[0x555] = (FPWV)0x0080;
			pBaseAddr[0x555] = (FPWV)0x00AA;
			pBaseAddr[0x2AA] = (FPWV)0x0055;
			*pSectorAddr     = (FPWV)0x0030;

			/* Re-Enable Interrupts */
			if( iIrqFlag ){
				enable_interrupts();
			}

			/* Wait Loop until Erase Time */
			for( iLoop=0; iLoop<CFG_FLASH_ERASE_WAIT; iLoop++ ){
				/* Check Erase Sector Data : 0xffffffff */
				if( *pSectorAddr == (FPWV)0xffffffff ){
					/* Erase Command Success */
					break;
				}
				/* Show Waiting Status */
				if( (0==(iLoop%CFG_FLASH_ERASE_SHOW)) && (0!=iLoop) ){
					/* Logout Erase Status */
					putc('.');
				}
			}

			/* Check Erase Timeout */
			if( iLoop == CFG_FLASH_ERASE_WAIT ){
				/* Retry Wait Loop until Erase Time */
				for( iLoop=0; iLoop<CFG_FLASH_ERASE_REWAIT; iLoop++ ){
					/* Check Erase Sector Data : 0xffffffff */
					if( *pSectorAddr == (FPWV)0xffffffff ){
						/* Erase Command Success */
						break;
					}
					/* Show Waiting Status */
					if( (0==(iLoop%CFG_FLASH_ERASE_SHOW)) && (0!=iLoop) ){
						/* Logout Erase Status */
						putc('*');
					}
				}
				/* Check Erase Timeout */
				if( iLoop == CFG_FLASH_ERASE_REWAIT ){
					/* Reset FlashROM for Read Mode */
					flash_reset(info);
					/* Erase Command Fail */
					iRtnCode = 1;
				}
			}
			break;
		}
	}

	/* Logout done */
	printf (" done\n");

	/* Return 0 or 1 (0:SUCCESS,1:FAIL) */
	return iRtnCode;
}

/*-----------------------------------------------------------------------
 * Write a byte to Flash, returns:
 * 0 - OK
 * 1 - write timeout
 * 2 - Flash not erased
 */
static int write_byte (flash_info_t *info, ulong dest, uchar data)
{
    vu_char *addr = (vu_char *)(info->start[0]);
    ulong start;
    int flag;

    /* Check if Flash is (sufficiently) erased */
    if ((*((vu_char *)dest) & data) != data) {
        return (2);
    }
    /* Disable interrupts which might cause a timeout here */
    flag = disable_interrupts();

    addr[0x0AAA] = 0xAA;
    addr[0x0555] = 0x55;
    addr[0x0AAA] = 0xA0;

    *((vu_char *)dest) = data;

    /* re-enable interrupts if necessary */
    if (flag)
      enable_interrupts();

    /* data polling for D7 */
    start = get_timer (0);
    while ((*((vu_char *)dest) & 0x80) != (data & 0x80)) {
        if (get_timer(start) > CFG_FLASH_WRITE_WAIT) {
            return (1);
        }
    }
    return (0);
}
