/***************************************************************************
	FILE
		main.c
	DESCRIPTION:
		Hitoll for ARM flash access, without address limitation
	HISTORY:
	    first done: 02.03.17
	COPYRIGHT
		(c) 2002 MICETEK International Inc.,
		All rights reserved.				By SHENG 2002.03.11
***************************************************************************/
#include "flash.h"

/*********************************************************************
 * Function declare
 *********************************************************************/
void burn_boot (unsigned int *FlashParaRam,unsigned long *FlashBuffer);
void EraseAll(unsigned int *FlashParaRam);

/*
 *	main function of Programming the FlashROM
 */
int DoMain (unsigned long argc)
{
    unsigned int *FlashParaRam;	// From start address to start address+0x3f, total 0x40 bytes
    unsigned long *FlashBuffer;	// From start address+0x40 to start address+0x403f, total 0x4000 bytes
    
    FlashParaRam = (unsigned int *) argc;
    FlashBuffer = (unsigned long *) (argc + 0x40);
/*    MMU_DisableDCache();
    MMU_DisableICache();*/
 
    FlashParaRam[ErrorInfos] = OnRUN;
    switch(FlashParaRam[Command])
    {
	case Erasing:                /* 0x00: erase the flash at chip or sector mode*/
             EraseAll(FlashParaRam);
             break;
	case Programming:            /* 0x01: programming the flash*/
             burn_boot(FlashParaRam,FlashBuffer);
             break;
	default:
             FlashParaRam[ErrorInfos]=NoSupport;
             break;
    }
    if (FlashParaRam[ErrorInfos] == OnRUN)
       
       	FlashParaRam[ErrorInfos] = ExecOK;
    return 1;
}
/* Erase all chip flash, return value is the error address of blank check */
void EraseAll(unsigned int *FlashParaRam)
{
	unsigned long ErrAddress,i;
	
	i=0;
	ErrAddress=FlashParaRam[FlashStartAddress];
	if (FlashParaRam[PortSize]==Port16)
	{		
        	if (FlashParaRam[ChipCount]==1)
        	{
        		unsigned short *s16;
        		s16 = (unsigned short *) ErrAddress;
        	
        		s16[0x5555] = 0xAA;
			s16[0x2AAA] = 0x55;
			s16[0x5555] = 0x80;
			s16[0x5555] = 0xAA;
			s16[0x2AAA] = 0x55;
			s16[0x5555] = 0x10;
			while (!( (*s16) & 0x80))
			{
				if ((i++)>0xFFFFFFF)
				{
					FlashParaRam[ErrorInfos]=EreaseError;
					return;
				}
			}
			i = FlashParaRam[FlashSize];
			for ( ; i-=2; ErrAddress++, s16++ )
			{
				if ( *s16 != 0xffff)
				{
					FlashParaRam[ErrorInfos] = BlankCError;
					FlashParaRam[ErrorAddress] = ErrAddress;
					return;
				}
			}
		}
		else if (FlashParaRam[ChipCount]==2)
        	{
        		unsigned long *s16;
        		s16 = (unsigned long *) ErrAddress;
        		s16[0x5555] = 0x00AA00AA;
			s16[0x2AAA] = 0x00550055;
			s16[0x5555] = 0x00800080;
			s16[0x5555] = 0x00AA00AA;
			s16[0x2AAA] = 0x00550055;
			s16[0x5555] = 0x00100010;

			/* Data Polling, the Address needn't care */
			while( (!( (*s16) & 0x00800000))|(!( (*s16) & 0x80)))
			{
				if ((i++)>0xFFFFFFF)
				{
					FlashParaRam[ErrorInfos]=EreaseError;
					return;
				}
			}
			i = FlashParaRam[FlashSize];
			for ( ; i-=4; ErrAddress++, s16++ )
			{	
				if ( *s16 != 0xFFFFFFFF)
				{
					FlashParaRam[ErrorInfos] = BlankCError;
					FlashParaRam[ErrorAddress] = ErrAddress;
					return;
				}
			}
		}
		else 
		{
			FlashParaRam[ErrorInfos]=NoSupport;
			return;
		}
	}
	else if(FlashParaRam[PortSize]==Port8)
	{		
		if (FlashParaRam[ChipCount]==1)
		{
			unsigned char *s16;
        		s16 = (unsigned char *) ErrAddress;
        		s16[0x2AAA] = 0xAA;
			s16[0x5555] = 0x55;
			s16[0x2AAA] = 0x80;
			s16[0x2AAA] = 0xAA;
			s16[0x5555] = 0x55;
			s16[0x2AAA] = 0x10;
			while(!( (*s16) & 0x80))
			{
				if ((i++)>0xFFFFFFF)
				{
					FlashParaRam[ErrorInfos]=EreaseError;
					return;
				}
			}
			i = FlashParaRam[FlashSize];
			for ( ; i-=1; ErrAddress++, s16++ )
			{
				if ( *s16 != 0xff)
				{
					FlashParaRam[ErrorInfos] = BlankCError;
					FlashParaRam[ErrorAddress] = ErrAddress;
					return;
				}
			}
		}
		else if (FlashParaRam[ChipCount]==2)
		{
			unsigned short *s16;
        		s16 = (unsigned short *) ErrAddress;
        		s16[0x2AAA] = 0xAAAA;
			s16[0x5555] = 0x5555;
			s16[0x2AAA] = 0x8080;
			s16[0x2AAA] = 0xAAAA;
			s16[0x5555] = 0x5555;
			s16[0x2AAA] = 0x1010;
			while( (!( (*s16) & 0x8000))|(!( (*s16) & 0x80)))
			{
				if ((i++)>0xFFFFFFF)
				{
					FlashParaRam[ErrorInfos]=EreaseError;
					return;
				}
			}
			i = FlashParaRam[FlashSize];
			for ( ; i-=1; ErrAddress++, s16++ )
			{
				if ( *s16 != 0xffff)
				{
					FlashParaRam[ErrorInfos] = BlankCError;
					FlashParaRam[ErrorAddress] = ErrAddress;
					return;
				}
			}
		}
		else if (FlashParaRam[ChipCount]==4)
		{
			unsigned long *s16;
        		s16 = (unsigned long *) ErrAddress;
        		s16[0x2AAA] = 0xAAAAAAAA;
			s16[0x5555] = 0x55555555;
			s16[0x2AAA] = 0x80808080;
			s16[0x2AAA] = 0xAAAAAAAA;
			s16[0x5555] = 0x55555555;
			s16[0x2AAA] = 0x10101010;
			while( (!( (*s16) & 0x80800000))|(!( (*s16) & 0x8080)))
			{
				if ((i++)>0xFFFFFFF)
				{
					FlashParaRam[ErrorInfos]=EreaseError;
					return;
				}
			}
			i = FlashParaRam[FlashSize];
			for ( ; i-=1; ErrAddress++, s16++ )
			{
				if ( *s16 != 0xffffffff)
				{
					FlashParaRam[ErrorInfos] = BlankCError;
					FlashParaRam[ErrorAddress] = ErrAddress;
					return;
				}
			}
		}
		
	}
	else 
	{
		FlashParaRam[ErrorInfos]=NoSupport;
		return;
	}
}

/* Program flash, return value is the error address of programming */
void burn_boot (unsigned int *FlashParaRam,unsigned long *FlashBuffer)
{
	unsigned long FlashStart,counter,TotalProgramSize,FlashAddr,i;
		
	i=0;
	counter = 0;
	FlashStart = FlashParaRam[FlashStartAddress];
       	
	if (FlashParaRam[PortSize]==Port16)
	{
        	if (FlashParaRam[ChipCount]==1)
        	{
        		unsigned short *s16,*ptr16,temp0,temp1,*buffer;
        		
        	       	ptr16 = (unsigned short *) (FlashParaRam[CurrentSAddress]+FlashStart);
        		s16 = (unsigned short *)((FlashParaRam[CurrentSAddress]+FlashStart)&0xfffff000);
        		buffer=(unsigned short *)FlashBuffer;
        		
        		temp0=(FlashParaRam[CurrentLength]%2)?1:0;
        		TotalProgramSize = FlashParaRam[CurrentLength]/2+temp0;
			while (counter < TotalProgramSize)
			{
            			s16[0x5555] = 0xAA;
				s16[0x2AAA] = 0x55;
				s16[0x5555] = 0xA0;
				*ptr16 = buffer[counter];
				do{
					temp0 = *s16;
					temp0 &= 0x40;
					temp1 = *s16;
					temp1 &= 0x40;
				}while ((temp0 != temp1)&&(i++ < 0x1FFFFFF));
				if (i>0x1FFFFFF)
				{
					FlashParaRam[ErrorInfos]=ProgError;
					return;
				}
				if (*ptr16 != buffer[counter])                          /* Verify the flash image */
				{
					FlashParaRam[ErrorInfos]=ProgError;
					FlashParaRam[ErrorAddress]=counter+FlashParaRam[FlashStartAddress];
					return;
				}
				counter++;
				ptr16++;
			}
		}
		else if (FlashParaRam[ChipCount]==2)
            	{
            		unsigned long *s16,*ptr16,temp0,temp1;
            		
        	       	ptr16 = (unsigned long *) (FlashParaRam[CurrentSAddress]+FlashStart);
        		s16 = (unsigned long *)((FlashParaRam[CurrentSAddress]+FlashStart)&0xfffff000);
        		
        		temp0=(FlashParaRam[CurrentLength]%4)?1:0;
        		TotalProgramSize = FlashParaRam[CurrentLength]/4+temp0;
        		while (counter < TotalProgramSize)	
        		{
        			s16[0x5555] = 0x00AA00AA;
				s16[0x2AAA] = 0x00550055;
				s16[0x5555] = 0x00A000A0;
				*ptr16 = FlashBuffer[counter];
				do{
					temp0 = *s16;
					temp0 &= 0x00400040;
					temp1 = *s16;
					temp1 &= 0x00400040;
				}while ((temp0 != temp1)&&(i++ < 0x1FFFFFF));   /* Polling */ 
				if (i>0x1FFFFFF)
				{
					FlashParaRam[ErrorInfos]=ProgError;
					return;
				}
				if (*ptr16 != FlashBuffer[counter])                          /* Verify the flash image */
				{
					FlashParaRam[ErrorInfos]=ProgError;
					FlashParaRam[ErrorAddress]=counter+FlashParaRam[FlashStartAddress];
					return;
				}
				counter++;
				ptr16++;
			}
		}
		else  
		{
				FlashParaRam[ErrorInfos]=NoSupport;
				return;
		}
	}
	else if (FlashParaRam[PortSize]==Port8)
	{
                if (FlashParaRam[ChipCount]==1)
                {
                	unsigned char *s16,*ptr16,temp0,temp1,*buffer;
        	
        		ptr16 = (unsigned char *) (FlashParaRam[CurrentSAddress]+FlashStart);
        		s16=(unsigned char *)((FlashParaRam[CurrentSAddress]+FlashStart)&0xfffff000);
        		buffer=(unsigned char *)FlashBuffer;
        		
        		TotalProgramSize = FlashParaRam[CurrentLength];
			while (counter < (TotalProgramSize))
			{
            			s16[0x2AAA] = 0xAA;
				s16[0x5555] = 0x55;
				s16[0x2AAA] = 0xA0;
				*ptr16 = buffer[counter];
				do{
					temp0 = *s16;
					temp0 &= 0x40;
					temp1 = *s16;
					temp1 &= 0x40;
				}while ((temp0 != temp1)&&(i++ < 0x1FFFFFF));                                     /* Polling */
				if (i>0x1FFFFFF)
				{
					FlashParaRam[ErrorInfos]=ProgError;
					return;
				}
				if (*ptr16 != buffer[counter])                          /* Verify the flash image */
				{
					FlashParaRam[ErrorInfos]=ProgError;
					FlashParaRam[ErrorAddress]=counter+FlashParaRam[FlashStartAddress];
					return;
				}
				counter++;
				ptr16++;
			}
		}
		else if (FlashParaRam[ChipCount]==2)
                {
                	unsigned short *s16,*ptr16,temp0,temp1,*buffer;
                	
        		ptr16 = (unsigned short *) (FlashParaRam[CurrentSAddress]+FlashStart);
        		s16 = (unsigned short *)((FlashParaRam[CurrentSAddress]+FlashStart)&0xfffff000);
        		buffer=(unsigned short *)FlashBuffer;
        		
        		temp0=(FlashParaRam[CurrentLength]%2)?1:0;
        		TotalProgramSize = FlashParaRam[CurrentLength]/2+temp0;
			while (counter < TotalProgramSize)
			{
            			s16[0x2AAA] = 0xAAAA;
				s16[0x5555] = 0x5555;
				s16[0x2AAA] = 0xA0A0;
				*ptr16 = buffer[counter];
				do{
					temp0 = *s16;
					temp0 &= 0x4040;
					temp1 = *s16;
					temp1 &= 0x4040;
				}while ((temp0 != temp1)&&(i++ < 0x1FFFFFF));                              /* Polling */
				if (i>0x1FFFFFF)
				{
					FlashParaRam[ErrorInfos]=ProgError;
					return;
				}
				if (*ptr16 != buffer[counter])                          /* Verify the flash image */
				{
					FlashParaRam[ErrorInfos]=ProgError;
					FlashParaRam[ErrorAddress]=counter+FlashParaRam[FlashStartAddress];
					return;
				}
				counter++;
				ptr16++;
			}
		}
		else if (FlashParaRam[ChipCount]==4)
		{
			unsigned long *s16,*ptr16,temp0,temp1;
			
        	    	ptr16 = (unsigned long *) (FlashParaRam[CurrentSAddress]+FlashStart);
        		s16 = (unsigned long *)((FlashParaRam[CurrentSAddress]+FlashStart)&0xfffff000);
        		
        		temp0=(FlashParaRam[CurrentLength]%4)?1:0;
        		TotalProgramSize = FlashParaRam[CurrentLength]/4+temp0;
        		while (counter < TotalProgramSize)
			{
            			s16[0x2AAA] = 0xAAAAAAAA;
				s16[0x5555] = 0x55555555;
				s16[0x2AAA] = 0xA0A0A0A0;
				*ptr16 = FlashBuffer[counter];
				do{
					temp0 = *s16;
					temp0 &= 0x40404040;
					temp1 = *s16;
					temp1 &= 0x40404040;
				}while ((temp0 != temp1)&&(i++ < 0x1FFFFFF));   /* Polling */                           /* Polling */
				if (i>0x1FFFFFF)
				{
					FlashParaRam[ErrorInfos]=ProgError;
					return;
				}
				if (*ptr16 != FlashBuffer[counter])                          /* Verify the flash image */
				{
					FlashParaRam[ErrorInfos]=ProgError;
					FlashParaRam[ErrorAddress]=counter+FlashParaRam[FlashStartAddress];
					return;
				}
				counter++;
				ptr16++;
			}
		}
		else  
			{
				FlashParaRam[ErrorInfos]=NoSupport;
				return;
			}		
	}
	else  
	{
		FlashParaRam[ErrorInfos]=NoSupport;
		return;
	}
}

