/* ADD 2005/1/9 NSS S.T START */

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

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


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

/* FlashROM Port Width 16bit or 32bit */
#if 0
	/* FlashROM Port Width 16Bit ( MBM29QM12DH-60<16BitPort> Serial Connection) */
	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_fujitsu( flash_info_t *info, FPW *dest, FPW 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( void )
{
	ulong ulFlashROMSize; /* FlashROM Size */

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

	/* Get Sise of FlashROM */
	ulFlashROMSize = flash_get_size( (FPWV *)CFG_FLASH_BASE, &flash_info[0] );

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

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

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

#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);
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * 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          */
    FPWV  *pSectorAddr; /* 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 */
	pBaseAddr = (FPWV *)(info->start[0]);

	/* 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;
		}

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

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

		/*============================*/
		/* Write Command : Erase Mode */
		/*============================*/
		pBaseAddr[0x5555] = (FPWV)0x00AA00AA;
		pBaseAddr[0x2AAA] = (FPWV)0x00550055;
		pBaseAddr[0x5555] = (FPWV)0x00800080;
		pBaseAddr[0x5555] = (FPWV)0x00AA00AA;
		pBaseAddr[0x2AAA] = (FPWV)0x00550055;
		*pSectorAddr      = (FPWV)0x00300030;

		/* 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;
			}
		}
	}

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

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


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * 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;

    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_fujitsu(info, (FPW*)addr, data);
#endif  /* FlashROM Test Mode */

    }

    return (res);
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_real_protect()
 * Protect Sector of FlashROM, Returns
 *   0 - SUCCESS
 *   1 - FAIL
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
int flash_real_protect( flash_info_t * info, long sector, int prot )
{
    FPWV *pBaseAddr;   /* Base Address   */
    FPWV *pSectorAddr; /* Sector Address */

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

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

	/*==============================*/
	/* Write Command : Protect Mode */
	/*==============================*/
	pBaseAddr[0x5555] = (FPWV)0x00AA00AA;
	pBaseAddr[0x2AAA] = (FPWV)0x00550055;
	pBaseAddr[0x5555] = (FPWV)0x00480048;

	/* Check Protect Mode */
	if( prot ){
		/* Set Protect On */
	    *pSectorAddr |= (FPWV)0x00010001;
		/* Set Protect Status : On */
		info->protect[sector] = 1;
	}else{
		/* Set Protect Off */
	    *pSectorAddr &= (FPWV)0xfffefffe;
		/* 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) {
		/* MBM29QM12DH_60 */
		case FLASH_MBM29QM12DH_60:
			/* Make Device Name */
			fmt = "MBM29QM12DH-60%s (128 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 */
	/*=================================*/
	pBaseAddr[0x5555] = (FPWV)0x00AA00AA;
	pBaseAddr[0x2AAA] = (FPWV)0x00550055;
	pBaseAddr[0x5555] = (FPWV)0x00F000F0;

	return;
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_get_offsets()
 * Get FlashROM Sector Information
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static void flash_get_offsets (ulong base, flash_info_t *info)
{
	int iLoop; /* Loop Counter */

	/*================================*/
	/* Set Sector Address SA0 - SA269 */
	/*================================*/

	/* BankA SA0 - SA7 : 16KByte x 8 */
	for( iLoop=0; iLoop<8; iLoop++ ){
		info->start[iLoop] = CFG_FLASH_BANK_A_BASE1 + ( iLoop * 0x00004000 );
	}
	/* BankA SA8 - SA38 : 128KByte x 31 */
	for( iLoop=8; iLoop<39; iLoop++ ){
		info->start[iLoop] = CFG_FLASH_BANK_A_BASE2 + ( (iLoop-8) * 0x00020000 );
	}
	/* BankB SA39 - SA134 : 128KByte x 96 */
	for( iLoop=39; iLoop<135; iLoop++ ){
		info->start[iLoop] = CFG_FLASH_BANK_B_BASE + ( (iLoop-39) * 0x00020000 );
	}
	/* BankC SA135 - SA230 : 128KByte x 96 */
	for( iLoop=135; iLoop<231; iLoop++ ){
		info->start[iLoop] = CFG_FLASH_BANK_C_BASE + ( (iLoop-135) * 0x00020000 );
	}
	/* BankD SA231 - SA261 : 128KByte x 31 */
	for( iLoop=231; iLoop<262; iLoop++ ){
		info->start[iLoop] = CFG_FLASH_BANK_D_BASE1 + ( (iLoop-231) * 0x00020000 );
	}
	/* BankD SA262 - SA269 : 16KByte x 8 */
	for( iLoop=262; iLoop<270; iLoop++ ){
		info->start[iLoop] = CFG_FLASH_BANK_D_BASE2 + ( (iLoop-262) * 0x00004000 );
	}

	return;
}


/*--------------------------------------------------------------
 ---------------------------------------------------------------
 * flash_get_size()
 * Get Size of FlashROM
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static ulong flash_get_size( FPWV *addr, flash_info_t *info )
{
	/*======================================*/
	/* Write Command : Read Manufacturer ID */
	/*======================================*/
	addr[0x5555] = 0x00AA00AA;
	addr[0x2AAA] = 0x00550055;
	addr[0x5555] = 0x00900090;

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

	/* Check Manufacturer ID */
	switch( addr[0] & 0xff ){
		/* Fujitsu */
		case (uchar)FUJ_MANUFACT:
			/* Set Manufacturer ID */
			info->flash_id = FLASH_MAN_FUJ;
			break;
		/* Others */
		default:
			/* Not Support */
			info->flash_id = FLASH_UNKNOWN;
			return 0;
	}

	/* Check Device ID */
	 switch( addr[1] ){
		/* MBM29QM12DH_60 */
		case (FPW)FUJI_ID_MBM29QM12DH_60:
			/* Logout Device Name */
			printf ("Fujitsu MBM29QM12DH-60 ");
			/* Set Device ID */
			info->flash_id += FLASH_MBM29QM12DH_60;
			/* Set Number of Sector */
			info->sector_count = CFG_MAX_FLASH_SECT;
			/* Set FlashROM Size */
			info->size = 0x02000000;
			break;
		default:
			/* Not Support */
			info->flash_id = FLASH_UNKNOWN;
			return 0;
	}

	/* 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_fujitsu()
 * Copy Memory To FlashROM, Returns
 *   0 - SUCCESS
 *   1 - FAIL
 *   2 - Flash Not Erased
 ---------------------------------------------------------------
 --------------------------------------------------------------*/
static int write_word_fujitsu (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[0x5555] = (FPWV)0x00AA00AA;
	pBaseAddr[0x2AAA] = (FPWV)0x00550055;
	pBaseAddr[0x5555] = (FPWV)0x00A000A0;
	*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[0x5555] = (FPWV)0x00AA00AA;
		pBaseAddr[0x2AAA] = (FPWV)0x00550055;
		pBaseAddr[0x5555] = (FPWV)0x00800080;
		pBaseAddr[0x5555] = (FPWV)0x00AA00AA;
		pBaseAddr[0x2AAA] = (FPWV)0x00550055;
		*pSectorAddr = (FPWV)0x00300030;

		/* 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[0x5555] = (FPWV)0x00AA00AA;
	pBaseAddr[0x2AAA] = (FPWV)0x00550055;
	pBaseAddr[0x5555] = (FPWV)0x00A000A0;
	*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[0x5555] = (FPWV)0x00AA00AA;
	pBaseAddr[0x2AAA] = (FPWV)0x00550055;
	pBaseAddr[0x5555] = (FPWV)0x00480048;

	/* 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;
}

/* ADD 2005/1/9 NSS S.T END */
