/**============================================================================
*@file TISecondaryBoot.c
*@desc This file contains the code that implements a secondary boot load
*      for TMS320C672x devices.
*
*==============================================================================
* Copyright (C) 2004-2005 Texas Instruments Incorporated. 
* Use of this software us controlled by the terms and conditions found in the
* license agreement under which this software has been supplied
*=============================================================================*/
/*===========================================================================*/
/* This software is provided under the following                             */
/* License Agreement:                                                        */
/*===========================================================================*/
/* THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR               */
/* REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,                    */
/* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS              */
/* FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR                    */
/* COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.                */
/* TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET                */
/* POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY                       */
/* INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR                */
/* YOUR USE OF THE PROGRAM.                                                  */
/*                                                                           */
/* IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL,               */
/* CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY                 */
/* THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED                */
/* OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT                */
/* OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM.               */
/* EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF                 */
/* REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS               */
/* OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF                 */
/* USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S                    */
/* AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF                */
/* YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS                       */
/* (U.S.$500).                                                               */
/*                                                                           */
/* Unless otherwise stated, the Program written and copyrighted              */
/* by Texas Instruments is distributed as "freeware".  You may,              */
/* only under TI's copyright in the Program, use and modify the              */
/* Program without any charge or restriction.  You may                       */
/* distribute to third parties, provided that you transfer a                 */
/* copy of this license to the third party and the third party               */
/* agrees to these terms by its first use of the Program. You                */
/* must reproduce the copyright notice and any other legend of               */
/* ownership on each copy or partial copy, of the Program.                   */
/*                                                                           */
/* You acknowledge and agree that the Program contains                       */
/* copyrighted material, trade secrets and other TI proprietary              */
/* information and is protected by copyright laws,                           */
/* international copyright treaties, and trade secret laws, as               */
/* well as other intellectual property laws.  To protect TI's                */
/* rights in the Program, you agree not to decompile, reverse                */
/* engineer, disassemble or otherwise translate any object code              */
/* versions of the Program to a human-readable form.  You agree              */
/* that in no event will you alter, remove or destroy any                    */
/* copyright notice included in the Program.  TI reserves all                */
/* rights not specifically granted under this license. Except                */
/* as specifically provided herein, nothing in this agreement                */
/* shall be construed as conferring by implication, estoppel,                */
/* or otherwise, upon you, any license or other right under any              */
/* TI patents, copyrights or trade secrets.                                  */
/*                                                                           */
/* You may not use the Program in non-TI devices.                            */
/*===========================================================================*/
#include <TISecondaryBoot.h>


/*==================================================================*/
/* external Symbol references                                       */
/*==================================================================*/
extern unsigned int TIBOOT_SEC_SIZE;
extern unsigned int TIBOOT_SEC_RUN_ADDR;

#pragma DATA_SECTION(TISecondaryBootStatus,".bss:tiSbootBss")

TISecondaryBootStatusObj TISecondaryBootStatus;

#pragma DATA_SECTION(TISecondaryBootStack,".bss:tiSbootBss")
#pragma DATA_ALIGN(TISecondaryBootStack,128);
asm("_TISecondaryBootStack_Size   .set 0x100");

unsigned int TISecondaryBootStack[64];

static unsigned int ix;
volatile unsigned char *TISecondaryBootbootPage;
unsigned char TISecondaryBootbootChar;
                              
/*==================================================================*/
/* Function Prototypes                                              */
/*==================================================================*/ 
void TISecondaryBoot_abort(unsigned int flag); 
unsigned int TISecondaryBoot_updateCRC(unsigned int *data_ptr, 
                                       unsigned int section_size, 
                                       unsigned int crc);

void TISecondaryBoot_setReg(unsigned int *regPtr, unsigned int mask, unsigned int mtype);
void TISecondaryBoot_parseAisStream(void);
unsigned TISecondaryBoot_fetchAis(void);



#pragma CODE_SECTION(TISecondaryBoot_bootstart,".TIBootStrap")
void TISecondaryBoot_bootstart(void)
{
   asm("	.global _TISecondaryBootStack, _TISecondaryBootStack_Size, $bss");
/*------------------------------------------------------------------------*/
/* SET UP THE STACK POINTER IN B15.                                       */
/* THE STACK POINTER POINTS 1 WORD PAST THE TOP OF THE STACK, SO SUBTRACT */
/* 1 WORD FROM THE SIZE. ALSO THE SP MUST BE ALIGNED ON AN 8-BYTE BOUNDARY*/
/*------------------------------------------------------------------------*/
   asm("	   MVKL		   _TISecondaryBootStack + _TISecondaryBootStack_Size - 4, SP");
   asm("	   MVKH		   _TISecondaryBootStack + _TISecondaryBootStack_Size - 4, SP");
   asm("	   AND		   ~7,SP,SP");

/*------------------------------------------------------------------------*/
/* SET UP THE GLOBAL PAGE POINTER IN B14.                                 */
/*------------------------------------------------------------------------*/
   asm("	   MVKL		   $bss,DP");
   asm("	   MVKH		   $bss,DP");
    
    /*================================================================*/
    /* Copy remainder of bootloader code                              */
    /*================================================================*/
    
    TISecondaryBootStatus.aisStreamPtr = (unsigned int *)TIBOOT_AIS_STREAM_START_ADDRESS;
                 
    TISecondaryBootStatus.sec_address = &TIBOOT_SEC_RUN_ADDR;
    TISecondaryBootStatus.sec_size = ((unsigned int)&TIBOOT_SEC_SIZE);
    for(ix=0;ix<TISecondaryBootStatus.sec_size/4;++ix){
       *TISecondaryBootStatus.sec_address++ = TISecondaryBoot_fetchAis();
    }

    TISecondaryBoot_parseAisStream();
}


#pragma CODE_SECTION(TISecondaryBoot_fetchAis,".TIBootStrap")
unsigned TISecondaryBoot_fetchAis(void) {
     // Set Page pointer
    unsigned int val = *TISecondaryBootStatus.aisStreamPtr;

    ++TISecondaryBootStatus.aisStreamPtr;
    // Read the data
     return val;
}

#pragma CODE_SECTION(TISecondaryBoot_parseAisStream,".TIBoot")
void TISecondaryBoot_parseAisStream(void) {
	unsigned int ix;
	unsigned int numSets;
    void (*jump_address)();
 
	
	TISecondaryBootStatus.bootCRC = 0;
    TISecondaryBootStatus.crcErr = 0;	
    TISecondaryBootStatus.currentAisCmd = 0xFFFFFFFF;
    TISecondaryBootStatus.lastAisCmd = 0xFFFFEEEE;
    
	while ( 1 )
    {
       TISecondaryBootStatus.currentAisCmd = TISecondaryBoot_fetchAis();
       TISecondaryBootStatus.bootErr = TISecondaryBootStatus.currentAisCmd;

       switch(TISecondaryBootStatus.currentAisCmd) 
       {
	       case SECTION_LOAD_COMMAND: 
	            { 
		            TISecondaryBootStatus.bootCRC = 0;
	                TISecondaryBootStatus.sec_address = (unsigned int *)TISecondaryBoot_fetchAis();
	                TISecondaryBootStatus.sec_size = TISecondaryBoot_fetchAis();
	                for ( ix = 0; ix < (TISecondaryBootStatus.sec_size/4); ix++ )
	                {
	                   TISecondaryBootStatus.sec_address[ix] = TISecondaryBoot_fetchAis();
	                }
	                
					TISecondaryBootStatus.bootCRC = TISecondaryBoot_updateCRC((unsigned int *)&(TISecondaryBootStatus.sec_address), 4, TISecondaryBootStatus.bootCRC);
					TISecondaryBootStatus.bootCRC = TISecondaryBoot_updateCRC(&(TISecondaryBootStatus.sec_size), 4, TISecondaryBootStatus.bootCRC);
	                TISecondaryBootStatus.bootCRC = TISecondaryBoot_updateCRC(TISecondaryBootStatus.sec_address,
	                                 TISecondaryBootStatus.sec_size, TISecondaryBootStatus.bootCRC);

	                TISecondaryBootStatus.lastAisCmd = SECTION_LOAD_COMMAND;                    
	                break;
                }

	       case ENABLE_CRC_COMMAND: 
	            {
		          TISecondaryBootStatus.bootCRC = 0;
		          TISecondaryBootStatus.crcErr = 0;
		          TISecondaryBootStatus.lastAisCmd = ENABLE_CRC_COMMAND;
		          break;
	            }  
	            
	       case REQUEST_CRC_COMMAND:
	            {
		          TISecondaryBootStatus.expectedCrc = TISecondaryBoot_fetchAis();
		          TISecondaryBootStatus.lastValidAisCmdOffset = TISecondaryBoot_fetchAis();
		          if (TISecondaryBootStatus.expectedCrc != TISecondaryBootStatus.bootCRC){
		             TISecondaryBootStatus.aisStreamPtr = (unsigned int *)((char *)TISecondaryBootStatus.aisStreamPtr + ((int) TISecondaryBootStatus.lastValidAisCmdOffset));
		             TISecondaryBootStatus.crcErr++;
	              }
	              
	              if (TISecondaryBootStatus.crcErr > 1) {
		             TISecondaryBoot_abort(TIBOOT_ERR_CRC);
	              }

	              TISecondaryBootStatus.lastAisCmd = REQUEST_CRC_COMMAND;
		          
	              break;
                }

	       case JUMP_COMMAND:
	             {
		             
		             jump_address = (void (*)())TISecondaryBoot_fetchAis();	 
		             (*jump_address)();
		              TISecondaryBootStatus.lastAisCmd = JUMP_COMMAND;
		              break;
                 }                
                                                          
	       case JUMP_CLOSE_COMMAND:
	             {
		            TISecondaryBootStatus.lastAisCmd = JUMP_CLOSE_COMMAND;
		             
		             jump_address = (void (*)())TISecondaryBoot_fetchAis();	 
		             (*jump_address)();
		              break;
                 }
                 
            case PAGE_SWAP_COMMAND:
                {
	                
	                 numSets = TISecondaryBoot_fetchAis();
	                
	                 if (numSets > 48){
		                 TISecondaryBoot_abort(2);
	                 }
	                
	                 for(ix=0;ix<numSets;++ix) {
	                    TISecondaryBootStatus.tmpPinSetup[ix].regPtr = (unsigned int*)TISecondaryBoot_fetchAis();
	                    TISecondaryBootStatus.tmpPinSetup[ix].mask   = TISecondaryBoot_fetchAis();
	                    TISecondaryBootStatus.tmpPinSetup[ix].mode = TISecondaryBoot_fetchAis();
	                 }   
	                
	                for(ix=0;ix<numSets;++ix) {
	                    TISecondaryBoot_setReg(TISecondaryBootStatus.tmpPinSetup[ix].regPtr,
	                           TISecondaryBootStatus.tmpPinSetup[ix].mask,
	                           TISecondaryBootStatus.tmpPinSetup[ix].mode);
	                 }
	                

	                TISecondaryBootStatus.lastAisCmd = PAGE_SWAP_COMMAND;

                    break;
	                 
                 }   
                 
            case DEVICE_CFG_COMMAND:
                 {
	                 
	                 TIBootSetup();
	                 
		             TISecondaryBootStatus.lastAisCmd = DEVICE_CFG_COMMAND;
	                 
	                 break;
                 }
                   
            case LATCH_ADDRESS:
                 {
	                
	                 for(ix=0;ix<=3;++ix) {
	                    TISecondaryBootStatus.tmpPinSetup[ix].regPtr = (unsigned int *)TISecondaryBoot_fetchAis();
	                    TISecondaryBootStatus.tmpPinSetup[ix].mask   = TISecondaryBoot_fetchAis();
	                    TISecondaryBootStatus.tmpPinSetup[ix].mode = TISecondaryBoot_fetchAis();
	                 }
	                 
	                /* Setups 1-3 Enable Pin, Set Direction, and Set Pin to 1 */  
	                TISecondaryBootbootPage = (unsigned char *)(*TISecondaryBootStatus.aisStreamPtr);  
	                 
	                for(ix=0;ix<3;++ix) {
	                    TISecondaryBoot_setReg(TISecondaryBootStatus.tmpPinSetup[ix].regPtr,
	                                           TISecondaryBootStatus.tmpPinSetup[ix].mask,
	                                           TISecondaryBootStatus.tmpPinSetup[ix].mode);
	                 }
	                 	 
	                 TISecondaryBootbootChar = (*TISecondaryBootbootPage);

					 asm("	nop 5");
	           
                
	                 /* Fourth Setup is Used To Clear Pin */
	                 TISecondaryBoot_setReg(TISecondaryBootStatus.tmpPinSetup[3].regPtr,
	                        TISecondaryBootStatus.tmpPinSetup[3].mask,
	                        TISecondaryBootStatus.tmpPinSetup[3].mode);
	                        
	                 /* Set pointer to start of EMIF A address */
	                 TISecondaryBootStatus.aisStreamPtr = (unsigned int *)TIBOOT_EMIF_START_ADDRESS;

		             TISecondaryBootStatus.lastAisCmd = LATCH_ADDRESS;
	                 	                 
	                 break;
                 }   
	        default :
	             {
		             TISecondaryBoot_abort(TIBOOT_ERR_INVALID_AIS_CMD);
		             break;
	             }
	   }
    }
}
 

#pragma CODE_SECTION(TISecondaryBoot_abort,".TIBoot")

void TISecondaryBoot_abort(unsigned int flag) {
	TISecondaryBootStatus.bootErr = (TISecondaryBootStatus.bootErr << 16) | flag;
	while(1) {
	}
}
    
        
      
#pragma CODE_SECTION(TISecondaryBoot_updateCRC,".TIBoot")

unsigned int TISecondaryBoot_updateCRC(unsigned int *data_ptr, unsigned int section_size, unsigned int crc)
{
	unsigned int n, crc_poly = 0x04C11DB7; /* CRC - 32 */
	unsigned int msb_bit;
	unsigned int residue_value;
	int bits;
	
	for( n = 0; n < (section_size>>2); n++ )
	{
		bits = 32;
		while( --bits >= 0 )
		{
			msb_bit = crc & 0x80000000;
			crc = (crc << 1) ^ ( (*data_ptr >> bits) & 1 );
			if ( msb_bit )
       		crc = crc ^ crc_poly;
		}
		data_ptr ++;
	}
		
	switch(section_size & 3)
	{
		case 0:
			break;
		case 1:
			residue_value = (*data_ptr & 0xFF) ;
			bits = 8;
			break;
		case 2:
			residue_value = (*data_ptr & 0xFFFF) ;
			bits = 16;
			break;
		case 3:
			residue_value = (*data_ptr & 0xFFFFFF) ;
			bits = 24;
			break;
	}
	
	if(section_size & 3)
	{

		while( --bits >= 0 )
		{
			msb_bit = crc & 0x80000000;
			crc = (crc << 1) ^ ( (residue_value >> bits) & 1 );
			if ( msb_bit ) crc = crc ^ crc_poly;
		}
	}
	return( crc );
}

#pragma CODE_SECTION(TISecondaryBoot_setReg, ".TIBoot")
void TISecondaryBoot_setReg(unsigned int *regPtr, unsigned int mask, unsigned int mtype)
{
    switch(mtype) 
    {
	    case OR:  {  *regPtr |= mask;
	                 break;
                  }
                 
        case AND: { *regPtr &= mask;
                     break;
                  }
                  
        case WRITE: { *regPtr = mask;
                     break;
                    }
        default: *regPtr |= mask;
   }
} 


