#include "upgrade.h"
#include "PalmChip.h"

#if defined AM29F040 || defined MT28F016
#include "f40page7.h"	// need to rewrite the first 512 bytes in page7 for settings
#endif

#if defined MT28F016 || defined MX29LV008B
#include "f016ring.h"
#endif

#define ERASE_1K_STEPS		1
#define WRITE_1K_STEPS		2

#if defined AM29LV008T || defined MX29LV004T || defined MX29LV008B || defined MT28F016
#define PIO_STATUS
#endif

#if defined MT28F016
static DCHAR _iMainPage;
#endif

static DCHAR _iUpdatePage;

static DSHORT _iTotalSteps, _iCurSteps;
static DCHAR _iOldPercent = 101;

#ifdef GUI_UPGRADE_RING
static DCHAR _iRingHi, _iRingLo;
#endif

// Update program flash 
// program flash is devided into 16KByte pages, mapping to 8051 xdata
// space from 0x0000 - 0x3fff

static DCHAR _iPFlashPage;
static DSHORT _iPFlashAddress;

#ifdef PIO_STATUS
// read PIO15 value
#define _PIO_Polling()	while (!(XBYTE[IO_HI_DIN] & 0x80))
#endif

BOOLEAN _DisplayUpdateStatus()
{
	DCHAR iPercent;
	DLONG l;

	_iCurSteps ++;
#ifdef PIO_STATUS
	if (_iCurSteps%64)	return FALSE;	// do not blink led too fast
#endif

	l = _iCurSteps;
	l *= 100;
	iPercent = (UCHAR)(l/_iTotalSteps);
	if (iPercent == _iOldPercent)	return TRUE;

	_iOldPercent = iPercent;
/*	write_control_byte(0xc0);		// second line

	if (iPercent >= 100)
	{
		write_data_byte('1');
		write_data_byte('0');
		iPercent -= 100;
	}

	if (iPercent >= 10)
	{
		write_data_byte(iPercent/10 + '0');
		iPercent = iPercent % 10;
	}

	write_data_byte(iPercent + '0');
	write_data_byte('%');
*/
	if (iPercent >= 100)
	{
		write_control_byte(0xc0);
		write_data_byte('1');
		write_data_byte('0');
		write_data_byte('0');
	}
	else if (iPercent >= 10)
	{
		write_control_byte(0xc1);
		write_data_byte((iPercent/10) + '0');
		write_data_byte((iPercent%10) + '0');
	}
	else
	{
		write_control_byte(0xc2);
		write_data_byte(iPercent + '0');
	}
	return TRUE;
}

void _ShowStatus()
{
	if (_DisplayUpdateStatus())
	{
		Led_Blink(SECOND_LIGHT);
		Led_Blink(NORMAL_LIGHT);
		Led_Blink(KEYPAD_LIGHT);
	}
}

void _CheckStatus()
{
	// If 0x4000, we change to a new page
    if (_iPFlashAddress == 0x4000)
    {
        _iPFlashAddress = 0;
        _iPFlashPage ++;
        XBYTE[DATA_PAGE] = _iPFlashPage;
    }
	_ShowStatus();
}

#if defined AM29LV008B || defined MX29LV008B
// sectors are 16k, 8k, 8k, 32k, 64k, 64k, 64k ... 64k 

static CCHAR _cDataPage[MAX_SECTOR] = {0, 1, 1, 2, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60};
static CCHAR _cSectorSize[MAX_SECTOR] = {16, 8, 8, 32, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
#define UPGRADE_8K_SECTOR		2
#define UPGRADE_OPTIONS_SECTOR	1	// options in 0x04000
#define UPGRADE_RING_SECTOR		11	// ringtone in 0x0b0000

#ifdef MX29LV008B
#define LAST_PAGE	15
#else
#define	LAST_PAGE	7
#endif

void PFlashUpdateProgram()
{
	DCHAR i, k;

	_iTotalSteps = 64*LAST_PAGE*(ERASE_1K_STEPS+WRITE_1K_STEPS);
	_iCurSteps = 0;

	for (k = 4; k < (LAST_PAGE+4); k ++)
	{
		PFlashEraseSector(k);
	}

	PFlashWriteBegin(4);

	for (k = 0; k < LAST_PAGE; k ++)
	{
		i = 255;
		do
		{
			PFlashWriteFromSdram(FILE_IN_SDRAM_HI+k, 255-i);
			i -= 2;
		} while (i != 255);
	}
}
#endif

#if defined AM29LV008T
// sectors are 64k, 64k, 64k, 64k, 64k, 64k, ... 64k, 32k, 8k, 8k, 16k 
static CCHAR _cDataPage[MAX_SECTOR] = {   0,  4,  8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 62, 62, 63};
static CCHAR _cSectorSize[MAX_SECTOR] = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 32, 8,  8,  16};
#define UPGRADE_8K_SECTOR		17
#define UPGRADE_OPTIONS_SECTOR	17	// options in 0xfa000
#define UPGRADE_RING_SECTOR		18	// ringtone in 0xfc000

void PFlashUpdateProgram()
{
	DCHAR i, k, iSize;

	_iTotalSteps = (64*14+40)*(ERASE_1K_STEPS+WRITE_1K_STEPS);
	_iCurSteps = 0;

	for (k = 1; k < 17; k ++)
	{
		PFlashEraseSector(k);
	}

	PFlashWriteBegin(1);

	for (k = 0; k < 15; k ++)
	{
		if (k == 14)
		{
			iSize = 159;
		}
		else
		{
			iSize = 255;
		}
		i = iSize;
		do
		{
			PFlashWriteFromSdram(FILE_IN_SDRAM_HI+k, iSize - i);
			i -= 2;
		} while (i != 255);
	}
}

#endif

#if defined AM29LV004T || defined MX29LV004T
// sectors are 64k, 64k, 64k, 64k, 64k, 64k, 64k, 32k, 8k, 8k, 16k 
static CCHAR _cDataPage[MAX_SECTOR] = {0, 4, 8, 12, 16, 20, 24, 28, 30, 30, 31};
static CCHAR _cSectorSize[MAX_SECTOR] = {64, 64, 64, 64, 64, 64, 64, 32, 8, 8, 16};
#define UPGRADE_8K_SECTOR		9
#define UPGRADE_OPTIONS_SECTOR	9	// options in 0x7a000
#define UPGRADE_RING_SECTOR		10	// user-defined ring in 0x7c000

void PFlashUpdateProgram()
{
	DCHAR i, k, iSize;

	_iTotalSteps = (64*6+40)*(ERASE_1K_STEPS+WRITE_1K_STEPS);
	_iCurSteps = 0;

	for (k = 1; k < 9; k ++)
	{
		PFlashEraseSector(k);
	}

	PFlashWriteBegin(1);

	for (k = 0; k < 7; k ++)
	{
		if (k == 6)
		{
			iSize = 159;
		}
		else
		{
			iSize = 255;
		}
		i = iSize;
		do
		{
			PFlashWriteFromSdram(FILE_IN_SDRAM_HI+k, iSize - i);
			i -= 2;
		} while (i != 255);
	}
}

#endif

#ifdef AM29LV002T
// sectors are 64k, 64k, 64k, 32k, 8k, 8k, 16k 
static CCHAR _cDataPage[MAX_SECTOR] = {0, 4, 8, 12, 14, 14, 15};
static CCHAR _cSectorSize[MAX_SECTOR] = {64, 64, 64, 32, 8, 8, 16};
#define UPGRADE_8K_SECTOR		5
#define UPGRADE_OPTIONS_SECTOR	6	// options in 0x2c000

void PFlashUpdateProgram()
{
	DCHAR i, k, iSize;

	for (k = 1; k < 6; k ++)
	{
		PFlashEraseSector(k);
	}

	PFlashWriteBegin(1);

	for (k = 0; k < 3; k ++)
	{
		if (k == 2)
		{
			iSize = 191;
		}
		else
		{
			iSize = 255;
		}
		i = iSize;
		do
		{
			PFlashWriteFromSdram(FILE_IN_SDRAM_HI+k, iSize - i);
			i -= 2;
		} while (i != 255);
	}
}

#endif

#ifdef AM29F040
static CCHAR _cDataPage[MAX_SECTOR] = {0, 4, 8, 12, 16, 20, 24, 28};
static CCHAR _cSectorSize[MAX_SECTOR] = {64, 64, 64, 64, 64, 64, 64, 64};
#define UPGRADE_8K_SECTOR		255
#define UPGRADE_OPTIONS_SECTOR	7

void PFlashUpdateProgram()
{
	DCHAR i, k;

	_iTotalSteps = 64*6*(ERASE_1K_STEPS+WRITE_1K_STEPS);
	_iCurSteps = 0;

	for (k = 1; k < 7; k ++)
	{
		PFlashEraseSector(k);
	}

	PFlashWriteBegin(1);

	for (k = 0; k < 6; k ++)
	{
		i = 255;
		do
		{
			PFlashWriteFromSdram(FILE_IN_SDRAM_HI+k, 255-i);
			i -= 2;
		} while (i != 255);
	}
}

#endif

#ifdef MT28F016
static CCHAR _cDataPage[MAX_SECTOR] = {0, 4, 8, 12, 16, 20, 24, 28,
										32, 36, 40, 44, 48, 52, 56, 60,
										64, 68, 72, 76, 80, 84, 88, 92,
										96, 100, 104, 108, 112, 116, 120, 124};
static CCHAR _cSectorSize[MAX_SECTOR] = {64, 64, 64, 64, 64, 64, 64, 64, 
										64, 64, 64, 64, 64, 64, 64, 64,
										64, 64, 64, 64, 64, 64, 64, 64,
										64, 64, 64, 64, 64, 64, 64, 64};
#define UPGRADE_8K_SECTOR		255
#define UPGRADE_OPTIONS_SECTOR	31
#define UPGRADE_RING_SECTOR		30	// user-defined ring in 0x1e0000
static CCHAR _cProgramFlash[] = "MT28F016S5";

#define	WRITE_PAGES	15

void PFlashUpdateProgram()
{
	DCHAR i, k;

	_iCurSteps = 0;
	_iTotalSteps = 64*WRITE_PAGES*(ERASE_1K_STEPS+WRITE_1K_STEPS);

	for (k = _iMainPage; k < _iMainPage + WRITE_PAGES; k ++)
	{
		PFlashEraseSector(k);
	}

	PFlashWriteBegin(_iMainPage);
	for (k = 0; k < WRITE_PAGES; k ++)
	{
		i = 255;
		do
		{
			PFlashWriteFromSdram(FILE_IN_SDRAM_HI+k, 255-i);
			i -= 2;
		} while (i != 255);
	}
}

#endif


#if defined AM29LV008B || defined MX29LV008B
UCHAR PFlashErasePage(UCHAR iPage)
{
	DCHAR iSector, iCur;

	iCur = iPage;
	if (iCur)
	{
		iSector = iCur + 3;
		PFlashEraseSector(iSector);
	}
	else	// page 0
	{
		for (iSector = 0; iSector < 4; iSector ++)
		{
			PFlashEraseSector(iSector);
		}
		iSector = 0;
	}
	return iSector;
}
#elif defined AM29F040 || defined MT28F016
/*
UCHAR PFlashErasePage(UCHAR iPage)
{
	DCHAR iCur;

	iCur = iPage;
	PFlashEraseSector(iCur);
	return iCur;
}
*/
#define PFlashErasePage	PFlashEraseSector
#else	// other top flash
UCHAR PFlashErasePage(UCHAR iPage)
{
	DCHAR iSector, iCur;

	iCur = iPage;
	if (iCur < MAX_PAGE)
	{
		iSector = iCur;
		PFlashEraseSector(iSector);
	}
	else	// MAX_PAGE
	{
		for (iSector = MAX_PAGE; iSector < MAX_SECTOR; iSector ++)
		{
			PFlashEraseSector(iSector);
		}
		iSector = MAX_PAGE;
	}
	return iSector;
}
#endif

void _GetPFlashAddress(UCHAR iSector)
{
    if (iSector == UPGRADE_8K_SECTOR)
	{
		_iPFlashAddress = 0x2000;
	}
	else
	{
		_iPFlashAddress = 0;
	}
}	

// Erase pflash
UCHAR PFlashEraseSector(UCHAR iEraseSector)
{
	DCHAR iSectorSize, iSector;

	iSector = iEraseSector;

    XBYTE[PROG_DATA_MODE] = 0x41;
    XBYTE[DATA_PAGE] = 0;
#ifdef MT28F016
	XBYTE[0x0000] = 0x20;   // write 20 to any steady address
/*#elif defined MX29LV160T	 //Byte mode
	XBYTE[0x0aaa] = 0xaa;   // write AA to AAA
	XBYTE[0x0555] = 0x55;   // write 55 to 555
	XBYTE[0x0aaa] = 0x80;   // write 80 to AAA
	XBYTE[0x0aaa] = 0xaa;   // write AA to AAA
	XBYTE[0x0555] = 0x55;   // write 55 to 555
*/
#else
    XBYTE[0x0555] = 0xaa;   // write AA to 555
    XBYTE[0x02aa] = 0x55;   // write 55 to 2AA
    XBYTE[0x0555] = 0x80;   // write 80 to 555
    XBYTE[0x0555] = 0xaa;   // write AA to 555
    XBYTE[0x02aa] = 0x55;   // write 55 to 2AA
#endif

    XBYTE[DATA_PAGE] = _cDataPage[iSector];

	iSectorSize = _cSectorSize[iSector];

	// write 30 to SA, Since some sectors are 8kbytes. We have to deal differently
	_GetPFlashAddress(iSector);
#ifdef MT28F016
    XBYTE[_iPFlashAddress] = 0xD0;	// write D0 to block address (BA)
#else	
    XBYTE[_iPFlashAddress] = 0x30;	// write 30 to address of sector (SA)
#endif

#ifdef PIO_STATUS
	XBYTE[IO_HI_ENABLE] &= 0x7f;				// set PIO15 input
	_PIO_Polling();
	_iCurSteps += iSectorSize-1;
	_ShowStatus();
#else
	// wait erase sector
	while (iSectorSize)
	{
		_ShowStatus();
		SysSleep(ERASE_1K_WAIT_TIME);
		iSectorSize --;
	}
#endif

/*
#ifdef MT28F016
    XBYTE[DATA_PAGE] = 0;
	XBYTE[0x0000] = 0x50;   // write 50 to clear status register
	XBYTE[0x0000] = 0xff;   // write ff to enable flash read
#endif
*/
	return iSector;
}

void PFlashWriteBegin(UCHAR iLastSectorErased)
{
	_iPFlashPage = _cDataPage[iLastSectorErased];
//    XBYTE[PROG_DATA_MODE] = 0x41;
    XBYTE[DATA_PAGE] = _iPFlashPage;
	_GetPFlashAddress(iLastSectorErased);
}

void PFlashUpdateOptions()
{
#if defined AM29F040 || defined MT28F016
	DSHORT i;
#endif
	DCHAR j;

	_iTotalSteps = _cSectorSize[UPGRADE_OPTIONS_SECTOR] + 32;
	_iCurSteps = 0;
#if defined AM29F040 || defined MT28F016
	_iTotalSteps ++;
#endif

	PFlashEraseSector(UPGRADE_OPTIONS_SECTOR);
	PFlashWriteBegin(UPGRADE_OPTIONS_SECTOR);

#if defined AM29F040 || defined MT28F016
	for (i = 0; i < F40PAGE7_CODE_SIZE; i ++)
	{
		PFlashWrite(F40PAGE7_Code[i]);
	}
	_CheckStatus();
#endif

	for (j = 0; j < 32; j += 2)
	{
		PFlashWriteFromSdram(OPTIONS_SDRAM_HI, j);
	}
}

void PFlashWrite(UCHAR iVal)
{
	// Before write the data, we need to write the follwing sequence
//    XBYTE[DATA_PAGE] = 0;
#ifdef MT28F016
	XBYTE[0x0000] = 0x40;   // write 40 OR 10 to a steady address
/*#elif defined MX29LV160T //Byte mode
	XBYTE[0x0aaa] = 0xaa;   // write AA to AAA
	XBYTE[0x0555] = 0x55;   // write 55 to 555
	XBYTE[0x0aaa] = 0xa0;   // write a0 to AAA
*/
#else	//Word mode (not using currently)
	XBYTE[0x0555] = 0xaa;   // write AA to 555
	XBYTE[0x02aa] = 0x55;   // write 55 to 2AA
	XBYTE[0x0555] = 0xa0;   // write a0 to 555
#endif

	// write data now
//    XBYTE[DATA_PAGE] = _iPFlashPage;
    XBYTE[_iPFlashAddress] = iVal;

	// Advance our address pointer. If exceeds 0x3fff, we change to a new page
    _iPFlashAddress ++;

#ifdef PIO_STATUS
	_PIO_Polling();
#else
	SysSleep(WRITE_WAIT_TIME);
#endif

/*
#ifdef MT28F016
    XBYTE[DATA_PAGE] = 0;
	XBYTE[0x0000] = 0x50;   // write 50 to clear status register
	XBYTE[0x0000] = 0xff;   // write ff to enable flash read
#endif
*/
}

/*
#ifdef PIO_STATUS
void flash_write_mx29lv00x(PXCHAR dst, PXCHAR src)
{
	DSHORT i;
	PXCHAR_D pDst;
	PXCHAR_D pSrc;

	pDst = dst;
	pSrc = src;
	for (i = 0; i < 512; i ++)
	{
		XBYTE[0x0555] = 0xaa;   // write AA to 555
		XBYTE[0x02aa] = 0x55;   // write 55 to 2AA
		XBYTE[0x0555] = 0xa0;   // write a0 to 555
		*pDst ++ = *pSrc ++;
		_PIO_Polling();
	}
}

void flash_write_mt28f016(PXCHAR dst, PXCHAR src)
{
	DSHORT i;
	PXCHAR_D pDst;
	PXCHAR_D pSrc;

	pDst = dst;
	pSrc = src;
	for (i = 0; i < 512; i ++)
	{
		*pDst = 0x40;   // write 40 OR 10 to a steady address
		*pDst ++ = *pSrc ++;
		_PIO_Polling();
	}
}
#endif
*/

void PFlashWriteFromSdram(UCHAR iIndexHi, UCHAR iIndexLo)
{
#ifndef PIO_STATUS
	DSHORT i;
#endif

	sdram_read(iIndexHi, iIndexLo, SRAM_DMA_DWORD);
#ifdef PIO_STATUS
#ifdef MT28F016
	flash_write_mt28f016((PXCHAR)_iPFlashAddress, (PXCHAR)Sdram_pDataCache);
#else
	flash_write_mx29lv00x((PXCHAR)_iPFlashAddress, (PXCHAR)Sdram_pDataCache);
#endif
	_iPFlashAddress += 512;
#else
	for (i = 0; i < 512; i ++)
	{
		PFlashWrite(XBYTE[Sdram_pDataCache+i]);
	}
#endif
	_CheckStatus();
}

void PFlashUpdatePage()
{
	DCHAR i, iSector;

	_iTotalSteps = 64*(ERASE_1K_STEPS+WRITE_1K_STEPS);
	_iCurSteps = 0;

	iSector = PFlashErasePage(_iUpdatePage);
	PFlashWriteBegin(iSector);

	// upgrade page
	i = 255;
	do
	{	
		PFlashWriteFromSdram(FILE_IN_SDRAM_HI, 255 - i);
		i -= 2;
	} while (i != 255);
}

#ifdef GUI_UPGRADE_RING
void PFlashUpdateRing()
{
#if defined MT28F016 || defined MX29LV008B
	DSHORT k;
#endif
	DCHAR i;

	_iTotalSteps = _cSectorSize[UPGRADE_RING_SECTOR]*ERASE_1K_STEPS + (_iRingHi+1)*WRITE_1K_STEPS/4 + 1;
	_iCurSteps = 0;
#if defined MT28F016 || defined MX29LV008B
	_iTotalSteps ++;
#endif

	PFlashEraseSector(UPGRADE_RING_SECTOR);
	PFlashWriteBegin(UPGRADE_RING_SECTOR);

#if defined MT28F016 || defined MX29LV008B
	for (k = 0; k < USERRING_CODE_SIZE; k ++)
	{
		PFlashWrite(USERRING_Code[k]);
	}
	_CheckStatus();
#endif

	// ring length
	PFlashWrite(_iRingHi);
	PFlashWrite(_iRingLo);
	for (i = 0; i < 254; i ++)
	{
		PFlashWrite(0xff);
	}
	_CheckStatus();

	// data
	if (_iRingHi < 60)	_iRingHi ++;
	for (i = 0; i < _iRingHi; i += 2)
	{
		PFlashWriteFromSdram(FILE_IN_SDRAM_HI, i);
	}
}
#endif

#if defined MT28F016
BOOLEAN PFlashCheckFile()
{
	sdram_read(FILE_IN_SDRAM_HI+3, 1, SRAM_DMA_HALF_DWORD);
	if (p_strcmp_c2x((PXCHAR)Sdram_pDataCache, _cProgramFlash))		return FALSE;
	if (!p_strcmp_c2x((PXCHAR)(Sdram_pDataCache+11), (PCCHAR)"NONPROTOCOL"))
	{
		_iMainPage = 16;
	}
	else
	{
		_iMainPage = 1;
	}
	return TRUE;
}
#endif

void PFlashOperationEnd()
{
#ifdef MT28F016
    XBYTE[DATA_PAGE] = 0;
	XBYTE[0x0000] = 0x50;   // write 50 to clear status register
	XBYTE[0x0000] = 0xff;   // write ff to enable flash read

	XBYTE[IO_HI_ENABLE] |= 0x20;
	XBYTE[IO_HI_DOUT] |= 0x20;	// PIO13 = 1
//	XBYTE[IO_HI_DOUT] &= 0xdf;	// PIO13 = 0
#endif
}

void CheckSdram()
{
	DCHAR iMode, iFlag;

	sdram_read(OPTIONS_SDRAM_HI, FLAGS_SDRAM_LO, FLAGS_MAX_DWORD);

	iMode = XBYTE[Sdram_pDataCache+FLAGS_UPGRADE_MODE];
	_iUpdatePage = XBYTE[Sdram_pDataCache+FLAGS_UPGRADE_PAGE];
#ifdef GUI_UPGRADE_RING
	_iRingHi = XBYTE[Sdram_pDataCache+FLAGS_RING_SIZE];
	if (_iRingHi >= 60)	_iRingHi = 60;
	_iRingLo = XBYTE[Sdram_pDataCache+FLAGS_RING_SIZE+1];
#endif

	if (iMode != TCPIP_UPGRADE_MODE)
	{
		goto End;
	}

	// upgrade using data in 0x010000-0x01ffff
	if (_iUpdatePage == OPTIONS_UPGRADE_PAGE)
	{	// Update options only
		PFlashUpdateOptions();
		PFlashOperationEnd();
#ifdef OPTIONS_PAGE
		SetBootingFlags(SDRAM_CHECK_G723_OK + SDRAM_CHECK_G729_OK + SDRAM_CHECK_ILBC_OK + SDRAM_CHECK_RING_OK);
#endif
	}
	else if (_iUpdatePage == PROGRAM_UPGRADE_PAGE)
	{
#if defined MT28F016
		if (!PFlashCheckFile())	goto End;
#endif
		PFlashUpdateProgram();
		PFlashOperationEnd();
	}
#ifdef GUI_UPGRADE_RING
	else if (_iUpdatePage == RING_UPGRADE_PAGE)
	{
		PFlashUpdateRing();
		PFlashOperationEnd();
#ifdef OPTIONS_PAGE
		SetBootingFlags(SDRAM_CHECK_G723_OK + SDRAM_CHECK_G729_OK + SDRAM_CHECK_ILBC_OK);
#endif
	}
#endif
	else
	{
		if (_iUpdatePage > MAX_PAGE)	goto End;
		PFlashUpdatePage();
		PFlashOperationEnd();
		if (_iUpdatePage)
		{
			iFlag = SDRAM_CHECK_RING_OK;
			if (_iUpdatePage != 2)	iFlag += SDRAM_CHECK_G723_OK;
			if (_iUpdatePage != 3)	iFlag += SDRAM_CHECK_ILBC_OK;
			if (_iUpdatePage != 6)	iFlag += SDRAM_CHECK_G729_OK;
#ifdef OPTIONS_PAGE
			SetBootingFlags(iFlag);
#endif
		}
	}

End:
	SwitchPage(0);
}

