/******************************************************************************\
*           Copyright (C) 2000 Texas Instruments Incorporated.
*                           All Rights Reserved
*------------------------------------------------------------------------------
* FILENAME...... bsl_flash.c
* DATE CREATED.. Thu 06/15/2001 
* LAST MODIFIED. Thu 06/15/2001 
*
\******************************************************************************/
#define _FLASH_MOD_
#define _BOARD_MOD_ 

/****************************************\
* include files
\****************************************/
#include "bsl_flash.h"

#if (FLASH_SUPPORT)
/******************************************************************************\
*                         L O C A L   S E C T I O N
\******************************************************************************/

/****************************************\
* FLASH static macro declarations
\****************************************/

#if (BOARD_6711DSK | BOARD_6211DSK)
#define FLASH_ADR1	       0x90005555    /* Used to access the FLASH ROM  */
#define FLASH_ADR2	       0x90002AAA    /* Used to access the FLASH ROM  */
#define FLASH_PROGRAM_KEY1 0xAA          /* Used to access the FLASH ROM      */
#define FLASH_PROGRAM_KEY2 0x55          /* Used to access the FLASH ROM      */
#define FLASH_PROGRAM_KEY3 0xA0          /* Used to access the FLASH ROM      */
#define FLASH_ERASE_KEY1   0xAA          /* Used to chip erase the FLASH ROM  */
#define FLASH_ERASE_KEY2   0x55          /* Used to chip erase the FLASH ROM  */
#define FLASH_ERASE_KEY3   0x80          /* Used to chip erase the FLASH ROM  */
#define FLASH_ERASE_KEY4   0xAA          /* Used to chip erase the FLASH ROM  */
#define FLASH_ERASE_KEY5   0x55          /* Used to chip erase the FLASH ROM  */
#define FLASH_ERASE_KEY6   0x10          /* Used to chip erase the FLASH ROM  */

#define PAGE_NUMBER(x)     ((x - FLASH_START_ADDR) / FLASH_PAGE_SIZE)
#endif

/****************************************\
* FLASH static typedef declarations
\****************************************/

/****************************************\
* FLASH static function declarations
\****************************************/
static inline int page_boundary_FLASH(char *flash_ptr, Uint32 page_size);
static int validate_FLASH(Uint32 flahsAddr, Uint32 length);
static inline void program_id_FLASH();
static void chip_erase_FLASH();
static inline void buffer_page_FLASH(Uint32 flashptr,char *bufferptr);

/****************************************\
* FLASH static variable definitions
\****************************************/
static char page_buffer[FLASH_PAGE_SIZE];
/****************************************\
* FLASH static function definitions
\****************************************/
/*----------------------------------------------------------------------------*/
int page_boundary_FLASH(char *flash_ptr, Uint32 page_size){
  int flag0 = ((int)flash_ptr) % page_size;
  return (!(flag0));
}

/*----------------------------------------------------------------------------*/
int validate_FLASH(Uint32 flashAddr, Uint32 length){
  int flag = 1; 
  unsigned int depth;			       /* distance into memory            */
  
  depth = flashAddr - FLASH_START_ADDR + (unsigned int)length;
  /* check for valid FLASH range */  
  if ((flashAddr < FLASH_START_ADDR) || (flashAddr>=FLASH_END_ADDR))  flag = 0; 
  /* check to make sure depth doesn't exceed FLASH_SIZE */
  if (depth >FLASH_SIZE) flag = 0;

  return (flag);
}

/*----------------------------------------------------------------------------*/
void program_id_FLASH(){
  *(volatile char *)FLASH_ADR1 = FLASH_PROGRAM_KEY1;
  *(volatile char *)FLASH_ADR2 = FLASH_PROGRAM_KEY2;
  *(volatile char *)FLASH_ADR1 = FLASH_PROGRAM_KEY3;
}
/*----------------------------------------------------------------------------*/
void chip_erase_FLASH(){
  *(volatile char *)FLASH_ADR1 = FLASH_ERASE_KEY1;
  *(volatile char *)FLASH_ADR2 = FLASH_ERASE_KEY2;
  *(volatile char *)FLASH_ADR1 = FLASH_ERASE_KEY3;
  *(volatile char *)FLASH_ADR1 = FLASH_ERASE_KEY4;
  *(volatile char *)FLASH_ADR2 = FLASH_ERASE_KEY5;
  *(volatile char *)FLASH_ADR1 = FLASH_ERASE_KEY6;
}
/*----------------------------------------------------------------------------*/
void buffer_page_FLASH(Uint32 flashptr,char *bufferptr){
  char *page_ptr = (char *)flashptr;
  char *buffer_ptr = bufferptr;
  int i;
  for (i=0;i<FLASH_PAGE_SIZE;i++){
    *buffer_ptr++ = *page_ptr++;
  }
}
/*----------------------------------------------------------------------------*/
/******************************************************************************\
*                        G L O B A L   S E C T I O N
\******************************************************************************/

/****************************************\
* FLASH global variable definitions
\****************************************/

/****************************************\
* FLASH global function definitions
\****************************************/
/*----------------------------------------------------------------------------*/
void _FLASH_init() {
  static int initialized = 0;

  if (!initialized) {
    _BOARD_init();
    initialized = 1;
  }
}
/*----------------------------------------------------------------------------*/
Uint32 FLASH_checksum(Uint32 locator, Uint32 length){

  Uint32 oldCECTL1 = EMIF_RGET(CECTL1);
  int i;
  Uint32 fchecksum;
  /* locator is address in FLASH ROM */
  unsigned char *locator_ptr = (unsigned char *)locator;

#if (BOARD_6711DSK | BOARD_6211DSK)
  /* set CE1 space to 8-bit async mode */
  EMIF_RSET(CECTL1,(oldCECTL1 & (~0x000000F0)) | 0x00000000);
#endif

  /* checksum returned as "FFFFFFFF", -1, if error has occured */
  fchecksum = 0xFFFFFFFF;
  if (validate_FLASH(locator, length)){
    fchecksum = 0;
    for (i=0;i<length;i++) 	{
      fchecksum += *locator_ptr++;            /* UNSIGNED SUMMATION OF BYTES  */
    }
  }

  EMIF_RSET(CECTL1,oldCECTL1);                  /* restore CE1 space            */


  return (fchecksum);
}  
/*----------------------------------------------------------------------------*/
void FLASH_erase(Uint32 locator, Uint32 length){

  Uint32 oldCECTL1 = EMIF_RGET(CECTL1);
  int i,j;
  /* stores the byte address of the start location to be erased */
  Uint32 start_erase;
  
  /* pointer to last byte in the FLASH */
  volatile char *end_erase_pos = (char *)(FLASH_END_ADDR - 1);

  volatile char locator_flag;
  /* destination is address in FLASH ROM */
  volatile char *locator_ptr = (char *)locator;

#if (BOARD_6711DSK | BOARD_6211DSK)
  /* set CE1 space to 8-bit async mode */
  EMIF_RSET(CECTL1,(oldCECTL1 & (~0x000000F0)) | 0x00000000);
#endif

  /*--------------------------------------------------------------------------*
  * buffer page if locator is not on page boundary                            *
  * or length is less than page size                                          *
  *---------------------------------------------------------------------------*/
  if ( (!page_boundary_FLASH((char *)locator, FLASH_PAGE_SIZE))
      || (length<FLASH_PAGE_SIZE)){
    buffer_page_FLASH( FLASH_PAGE_ADDR(PAGE_NUMBER(locator)), page_buffer);
  }

  start_erase = (locator % FLASH_PAGE_SIZE);
  for (i= start_erase; i <(length + start_erase);){
    page_buffer[i] = 0xFF;
    if (page_boundary_FLASH((char *)(++i),FLASH_PAGE_SIZE)){
      break;
    } 
  }
  i -=start_erase;

  if (length == FLASH_ERASE_ALL){
    program_id_FLASH();                  /* accesses FLASH for programming  */
    *end_erase_pos = 0;

    chip_erase_FLASH();

    /* wait for erase to complete before proceeding */ 
    locator_flag = *end_erase_pos;
    while(locator_flag != (char)0xFF){
      locator_flag = *end_erase_pos;
    }
  }
  else{
    if (validate_FLASH(locator, length)){
      program_id_FLASH();                  /* accesses FLASH for programming  */

      /* DATA ERASE */
      locator_ptr = (char *) (FLASH_PAGE_ADDR(PAGE_NUMBER(locator)));
      j=0;
      while (j<FLASH_PAGE_SIZE){
        *locator_ptr++ = page_buffer[j];   /* clears locator                  */
        j++;
      }

      locator_flag = *--locator_ptr;
      /* wait until write is completed in the FLASH before proceeding */
      while (locator_flag != page_buffer[FLASH_PAGE_SIZE - 1]){
        locator_flag = *locator_ptr;
      }/*end while*/
      
      if (i<length)   FLASH_erase((Uint32)++locator_ptr,(length-i));
    }/*end if validate_FLASH*/
  }

  EMIF_RSET(CECTL1,oldCECTL1);                  /* restore CE1 space               */
}
/*----------------------------------------------------------------------------*/
void FLASH_read(Uint32 locator, Uint32 dst, Uint32 length){

  Uint32 oldCECTL1 = EMIF_RGET(CECTL1);
  int i;
  /* destination is specified address elsewhere */
  char *dst_ptr = (char *)dst;
  /* source is address in FLASH ROM */
  char *locator_ptr = (char *)locator;

#if (BOARD_6711DSK | BOARD_6211DSK)
  /* set CE1 space to 8-bit async mode */
   EMIF_RSET(CECTL1,(oldCECTL1 & (~0x000000F0)) | 0x00000000);
#endif

  if (validate_FLASH(locator, length)){
    /* copies souce to destination */
    for (i=0;i<length;i++) 	*dst_ptr++ = *locator_ptr++;
  }

  EMIF_RSET(CECTL1,oldCECTL1);                  /* restore CE1 space            */
}
/*----------------------------------------------------------------------------*/
void FLASH_write(Uint32 src, Uint32 locator, Uint32 length){

  Uint32 oldCECTL1 = EMIF_RGET(CECTL1);
  int i,j;
  /* stores the byte address of the start location to be erased */
  Uint32 start_write;

  volatile char locator_flag;
  /* destination is address in FLASH ROM */
  volatile char *locator_ptr = (char *)locator;
  /* source is specified address elsewhere */
  volatile char *src_ptr = (char *)src;

#if (BOARD_6711DSK | BOARD_6211DSK)
  /* set CE1 space to 8-bit async mode */
  EMIF_RSET(CECTL1,(oldCECTL1 & (~0x000000F0)) | 0x00000000);
#endif

  /*--------------------------------------------------------------------------*
  * buffer page if locator is not on page boundary                            *
  * or length is less than page size                                          *
  *---------------------------------------------------------------------------*/
  if ( (!page_boundary_FLASH((char *)locator, FLASH_PAGE_SIZE))
      || (length<FLASH_PAGE_SIZE)){
    buffer_page_FLASH( FLASH_PAGE_ADDR(PAGE_NUMBER(locator)), page_buffer);
  }

  start_write = (locator % FLASH_PAGE_SIZE);
  for (i= start_write; i <(length + start_write);){
    page_buffer[i] = *src_ptr++;
    if (page_boundary_FLASH((char *)(++i),FLASH_PAGE_SIZE)){
      break;
    } 
  }
  i -= start_write;

  if (validate_FLASH(locator, length)){
    program_id_FLASH();                  /* accesses FLASH for programming    */

    /* DATA WRITE */
    locator_ptr = (char *) (FLASH_PAGE_ADDR(PAGE_NUMBER(locator)));
    for (j=0; j<FLASH_PAGE_SIZE; j++){
      *locator_ptr++ = page_buffer[j];   /* copies souce to destination       */
    }

    locator_flag = *--locator_ptr;
    /* wait until write is completed in the FLASH before proceeding */
    while (locator_flag != page_buffer[FLASH_PAGE_SIZE - 1]){
      locator_flag = *locator_ptr;
    }/*end while*/
    
    if (i<length)
      FLASH_write( (Uint32)src_ptr,
                   (Uint32)++locator_ptr,
                   (Uint32)(length - i));
  }/*end if validate_FLASH*/

  EMIF_RSET(CECTL1,oldCECTL1);                  /* restore CE1 space               */
}
/*----------------------------------------------------------------------------*/


#endif /* FLASH_SUPPORT */
/******************************************************************************\
* End of bsl_flash.c
\******************************************************************************/