/**************************************************************
***************************************************************
**
** Host Application, Copyright (C) 2000-2002
** Ikanos Communication, Fremont, CA 
** All rights reserved.
**
** The information and contents of this file are the
** proprietary information of Ikanos Communication and may not
** be disclosed or used without the formal written approval of 
** Ikanos Communication
**
***************************************************************

$Revision: 1.1 $
$Date: 2006/10/16 04:34:50 $
**************************************************************/

/*******  Include Files         ***************************************/
#include <stdio.h>
#include <string.h>
#include "ipos.h"
#include "pprofile.h"
#if	defined(P2CPE) && defined(VTU_R) && defined(INI_SUPPORT)
#include "HostPtmfApi.h"
#endif
#include "oampdb.h" /*IXDP425*/

/*******  Defines               ***************************************/
#ifdef CPE_ATM

#define NVRAM_BLK2      0x50080000
#define NVRAM_MAC_FILTER  0x50080400
#define NVRAM_EVENT_LOG   0x500A0000

#else

#define NVRAM_BLK2      0xFFF80000
#define NVRAM_MAC_FILTER  0xFFF80400
#define NVRAM_EVENT_LOG   0xFFFA0000

#endif

#define NVRAM_EVENT_LOG_SIZE		0x18000			/* 96 Kb */
#define NVRAM_EVENT_LOG_CHKSTR_SIZE	32

/*******  Local Data Structures ***************************************/
typedef union
{
  struct nv2BlkRcd
  {
    char checkString[16];
    blk2Struct blkData;
  } blk2Rcd;
  char blkBuf[512 - sizeof(struct nv2BlkRcd)];
} nvramBlk;

/*******  External Functions    ***************************************/
extern void checkFlash (volatile U32 * pChip);
extern U32 FlashEraseSector(volatile U8 *pSector);
extern U32 FlashWrite(volatile U8 *pDest, U8 *pSource,U32 Length);
extern int FlashWriteVW(volatile char *pDest, char *pSource,int Length);
extern void getProfileMapping();
/*******  Global Data           ***************************************/
blk2Struct blk2Shadow = {4, 5, 1, 5, "ikanos", "superikanos", 10, 0,0x8, 1, {0, 0, 0}, {0, 0, 0}, 
                         0, 0, 0, {0, 0, 0}, 10, 0, 0, 3, {0, 0, 0}, {0, 0, 0},
                         DEFAULT_MAX_PSD};

#ifdef INI_SUPPORT 
#if defined(VTU_R) && (defined(P2CPE) || defined(BME_CPE_20))
tsIposPtmfEnetAddrFilterCfg macFilCfgShadow =
{
  0,0,0,0,0,0,0,0,0,
  {
#if defined(P2CPE)
    {0,0,0,0,0,0},        // 16 Entries Static Table
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
#endif
    {0,0,0,0,0,0},        // 8 Entries Static Table
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
    {0,0,0,0,0,0},
    {0,0,0,0,0,0}
  }
};
#endif
#endif// INI_SUPPORT 
unsigned int numCrcCheckFrames = 1;

/*******  Local Data            ***************************************/    
static char * chkStr2 = "IKANOS_NVRAM 0i";
static const char *chkEventLog = "IKANOS BME nn EVENT LOG 01";
char verChar;

#define  BMENUM_OFFSET	11

/***********************************************************************
************************************************************************

          F U N C T I O N     I N T E R F A C E S 

************************************************************************
***********************************************************************/
extern void setPprofileSize(int version);
extern void setDefaultNewProfileVal(int version);

#if	defined(P2CPE) && defined(VTU_R) && defined(INI_SUPPORT)
extern void PrRestoreEnetAddrFiltCfg(void);
#endif
void savePreviousBlk (void)
{
  	nvramBlk 	*nBlk = (nvramBlk *)NVRAM_BLK2;
  	int 		version = 0;
  	int		i;
  	tMaxPsd 	defaultMaxPsd = DEFAULT_MAX_PSD;

  	if (nBlk->blk2Rcd.checkString[13] == '0')
  	{
		memcpy (&blk2Shadow, &(nBlk->blk2Rcd.blkData), sizeof(blk2Struct));
		verChar = nBlk->blk2Rcd.checkString[14];
        if ((verChar >= '1') && (verChar <= '9'))
          version = verChar - '0';
        else if ((verChar >= 'a') && (verChar <= 'h'))
          version = verChar - 'a' + 10;
    	switch (nBlk->blk2Rcd.checkString[14])
    	{
      		case '1':
        		blk2Shadow.iniCrcThreshold = 30;
       
      		case '2':
           		blk2Shadow.utopiaMode = 0;
	
      		case '3':
           		blk2Shadow.optionMask = 0x8;

       		case '4':
    
	 		case '5':
				blk2Shadow.psdMaskLevelIndex = 0;
				for(i=0;i<3;i++) {
  					blk2Shadow.k0[i] = 0 ;
  					blk2Shadow.k1[i] = 0;
				}
	
			case '6':
			
			case '7':
			
			case '8':
			
			case '9':
                
                blk2Shadow.custId = 0;
                blk2Shadow.keys[0] =  blk2Shadow.keys[1] = blk2Shadow.keys[2] = 0;

		    case 'a':
				blk2Shadow.vdslCrcThreshold = 0;

		    case 'b':

            case 'c':   // ife 2 high power/low power configuration
                blk2Shadow.ife2_pwr_mode = 0;
				blk2Shadow.enetStatusRptEn = 0;
				case 'd':
					blk2Shadow.oamOptionMask = 0;
          		setPprofileSize(version);

	 	case 'e':
			for(i=0;i<3;i++) {
  				blk2Shadow.k0_hi[i] = 0 ;
  				blk2Shadow.k1_hi[i] = 0;
			}
	
      		case 'f':
            case 'g':
                memcpy(&blk2Shadow.maxPsd, &defaultMaxPsd, sizeof(tMaxPsd));

           case 'h':
		   	blk2Shadow.oamOptionMask |= 0x3; // PM mode as default
       
      		default:
        		break;
    	}
  	}
	
  	if (version > 0) {
    	savePreviousProfiles(version);
		setDefaultNewProfileVal(version);	
  	}
}

#if	defined(P2CPE) && defined(VTU_R) && defined(INI_SUPPORT)

typedef struct _tsIposPtmfTabeEntry
{
	U32	lsb;	/* First four bytes */
	U32 msb;	/* Last two bytes */

} tsIposPtmfTabeEntry;

typedef struct _tsIposPtmfAddrFiltTab
{
	tsIposPtmfTabeEntry	TabEntry [MAX_FILTER_TABLE_ENTRY];
	U8	NumAddrHostCtrl;
	U8  MulticastFilterEn;
	U8  BroadcastFilterEn;
	U8  MacFilterEn;
	U8	LearnEn;
} tsIposPtmfAddrFilTab, *ptsIposPtmfAddrFilTab;

void PrRestoreEnetAddrFiltCfg(void)
{
  tsIposPtmfAddrFilTab  OldFilterTable;
  int i;

  printf("\n Ethernet Address Filter Configuration Different");
  printf("\n Restoring the saved configuration to new format");
  
  memcpy (&OldFilterTable, (char *)NVRAM_MAC_FILTER,
     			sizeof(tsIposPtmfAddrFilTab));

  macFilCfgShadow.bAddrFilterEn         = OldFilterTable.MacFilterEn;
  macFilCfgShadow.bLearningEn           = OldFilterTable.LearnEn;
  macFilCfgShadow.bAgingEn              = 0;
  macFilCfgShadow.bMultiCastFilterEn    = OldFilterTable.MulticastFilterEn;
  macFilCfgShadow.bBroadCastFilterEn    = OldFilterTable.BroadcastFilterEn;
  macFilCfgShadow.uiAgingCount          = 0;
  macFilCfgShadow.uiAddrEntryEn         = 0;
  macFilCfgShadow.bStaticAddrCount      = OldFilterTable.NumAddrHostCtrl;
  macFilCfgShadow.bMaxReadCount         = MAX_FILTER_TABLE_ENTRY;

  for (i=0; i < MAX_FILTER_TABLE_ENTRY; i++)
  {
    macFilCfgShadow.abEnetAddr[i][0] = (OldFilterTable.TabEntry[i].msb >> 8) && 0xff;
    macFilCfgShadow.abEnetAddr[i][1] = (OldFilterTable.TabEntry[i].msb) && 0xff;
    macFilCfgShadow.abEnetAddr[i][2] = (OldFilterTable.TabEntry[i].lsb >> 24) && 0xff;
    macFilCfgShadow.abEnetAddr[i][3] = (OldFilterTable.TabEntry[i].lsb >> 16) && 0xff;
    macFilCfgShadow.abEnetAddr[i][4] = (OldFilterTable.TabEntry[i].lsb >> 8) && 0xff;
    macFilCfgShadow.abEnetAddr[i][5] = (OldFilterTable.TabEntry[i].lsb)  && 0xff;
  }
}

#endif //#if	defined(P2CPE) && defined(VTU_R) && defined(INI_SUPPORT)

void
readEventLogFromFlash( U32 nvramEventLogSize )
{
	U8		*eventLogShadow = NULL;
	extern U8	*sysGetEventLogAddr( int portNum );
	U8		 eventLogChkstr[ NVRAM_EVENT_LOG_CHKSTR_SIZE ];
	U32		 ulStartofFlash = 0;
	U32		*pUlong = &ulStartofFlash;

	if (nvramEventLogSize <= NVRAM_EVENT_LOG_CHKSTR_SIZE)
	{
		printf( "\nProblem reading event logs from flash\n" );
		printf( "event log size of %ld is smaller than check string size of %d\n",
			 nvramEventLogSize, NVRAM_EVENT_LOG_CHKSTR_SIZE );
		return;
	}

	/*printf( "readEventLogFromFlash called\n" );*/
	eventLogShadow = sysGetEventLogAddr( 0 );			/* 0 -> local log */
	/*printf( "would write event log to 0x%x\n", eventLogShadow );*/
	memcpy( eventLogChkstr, (U8 *) NVRAM_EVENT_LOG, NVRAM_EVENT_LOG_CHKSTR_SIZE );
	memcpy( eventLogShadow,
		(U8 *) (NVRAM_EVENT_LOG + NVRAM_EVENT_LOG_CHKSTR_SIZE),
				 nvramEventLogSize - NVRAM_EVENT_LOG_CHKSTR_SIZE
	);

/* If no event log saved to flash memory, write 4 null bytes to show an empty log */

	memcpy( pUlong, eventLogShadow, sizeof( *pUlong ) );
	if (*pUlong == 0xffffffff)
	{
		printf( "No event log saved to flash memory\n" );
		*pUlong = 0;
	}
	/*printf( "readEventLogFromFlash completes\n" );*/
}

static void
writeEventLogsToFlash( U32 nvramEventLogSize )
{
	U8		*eventLogShadow;
	U8		 eventLogChkstr[ NVRAM_EVENT_LOG_CHKSTR_SIZE ];
	U16		 iter;
	extern U8	*sysGetEventLogAddr( int portNum );

	if (nvramEventLogSize <= NVRAM_EVENT_LOG_CHKSTR_SIZE)
	{
		printf( "\nProblem writing event logs to flash\n" );
		printf( "event log size of %ld is smaller than check string size of %d\n",
			 nvramEventLogSize, NVRAM_EVENT_LOG_CHKSTR_SIZE );
		return;
	}

	for (iter = 0; iter < NVRAM_EVENT_LOG_CHKSTR_SIZE; iter++)
	  eventLogChkstr[ iter ] = '\0';
	strcpy( eventLogChkstr, chkEventLog );
	sprintf( &eventLogChkstr[ BMENUM_OFFSET ], "%02d", 1 );		/* hard code BME # 1 */
	eventLogShadow = sysGetEventLogAddr( 0 );			/* 0 -> local log */

   /* write the check string */

	FlashWrite( (volatile U8 *) NVRAM_EVENT_LOG,
				 eventLogChkstr,
				 NVRAM_EVENT_LOG_CHKSTR_SIZE
	);

   /* Use FlashWriteVW for large-size writes */

	FlashWriteVW( (volatile U8 *) (NVRAM_EVENT_LOG + NVRAM_EVENT_LOG_CHKSTR_SIZE),
				 eventLogShadow,
				 nvramEventLogSize - NVRAM_EVENT_LOG_CHKSTR_SIZE
	);
}

void nvramUpdateBlk (int blkNum)
{
#ifdef MPC_855 //IXDP425
  nvramBlk * nBlk = (nvramBlk *)NVRAM_BLK2;

  FlashEraseSector((volatile U8 *)NVRAM_BLK2);
  FlashWrite((volatile U8 *)&(nBlk->blk2Rcd.blkData),
             (U8 *)&blk2Shadow, sizeof(blk2Struct));
#if	(defined(P2CPE) || defined(BME_CPE_20)) && defined(VTU_R) && defined(INI_SUPPORT)
  FlashWrite((volatile U8 *)NVRAM_MAC_FILTER,
             (U8 *)&macFilCfgShadow, sizeof(tsIposPtmfEnetAddrFilterCfg));
#endif
  writeProfileToFlash();
  FlashWrite((volatile U8 *)&(nBlk->blk2Rcd.checkString),
             chkStr2, 16);
  writeEventLogsToFlash( NVRAM_EVENT_LOG_SIZE );
#endif
}

static void nvramVerifyBlk (int blkNum)
{
  nvramBlk * nBlk = (nvramBlk *)NVRAM_BLK2;

  if (strcmp (nBlk->blk2Rcd.checkString, chkStr2) == 0)
  {
    memcpy (&blk2Shadow, &(nBlk->blk2Rcd.blkData), sizeof(blk2Struct));

#if	(defined(P2CPE) || defined(BME_CPE_20)) && defined(VTU_R) && defined(INI_SUPPORT)
    memcpy (&macFilCfgShadow, (char *)NVRAM_MAC_FILTER,
            sizeof(tsIposPtmfEnetAddrFilterCfg));
#endif
    readProfileFromFlash (1);
    readProfileFromFlash (2);
    readProfileFromFlash (0);
	getProfileMapping();

    readEventLogFromFlash( NVRAM_EVENT_LOG_SIZE );
  }
  else
  {
    if (strncmp(nBlk->blk2Rcd.checkString, chkStr2, 13) == 0)
    {
      savePreviousBlk();
    }
    nvramUpdateBlk(2);
  }
}

void initOAMPDB (void)
{
#ifdef mpc_855 /* IXDP425 */
  nvramVerifyBlk(2);
  numCrcCheckFrames = 300000/oampGetIniCrcThreshold;
#endif

}

void testU (unsigned char data)
{
  oampSetUtopiaMode(data);
}

void oampSetK_array(float *k0, float *k1, float *k0_hi, float *k1_hi)
{
	int i;
	
	for(i=0;i<3;i++) {
		blk2Shadow.k0[i]=(long)(k0[i]*1000);
		blk2Shadow.k1[i]=(long)(k1[i]*1000);
	}
	
	for(i=0;i<3;i++) {
		blk2Shadow.k0_hi[i]=(long)(k0_hi[i]*1000);
		blk2Shadow.k1_hi[i]=(long)(k1_hi[i]*1000);
	}
	
	nvramUpdateBlk(2);
}

void oampPrintK_array()
{
	int i;

	printf("\nK1 array is");
   	for(i=0;i<3;i++) {
		printf("\n\t K1[%d] = %f", i, (float)blk2Shadow.k0[i]/1000.0);
	}
	
    /* print K1 values for the 3 higher US bands */
   	for(i=0;i<3;i++) {
		printf("\n\t K1[%d] = %f", i+3, (float)blk2Shadow.k0_hi[i]/1000.0);
	}
	
	printf("\nK2 array is");
   	for(i=0;i<3;i++) {
		printf("\n\t K2[%d] = %f", i, (float)blk2Shadow.k1[i]/1000.0);
	}

    /* print K2 values for the 3 higher US bands */
   	for(i=0;i<3;i++) {
		printf("\n\t K2[%d] = %f", i+3, (float)blk2Shadow.k1_hi[i]/1000.0);
	}
	
}
