/***********************************************************************/
/*  This file is part of the uVision/ARM development tools             */
/*  Copyright (c) 2003-2010 Keil Software. All rights reserved.        */
/***********************************************************************/
/*                                                                     */
/*  FlashDev.C:  Flash Programming Functions adapted for               */
/*               NXP LPC11xx/13xx/LPC17xx Flash using IAP              */
/*                                                                     */
/***********************************************************************/

#include "..\FlashOS.H"        // FlashOS Structures

// Memory Mapping Control
//#ifdef LPC17XX
//#define MEMMAP     (*((volatile unsigned char *) 0x400FC040))
//#endif

#define M3MEMMAP   (*(volatile unsigned long *) (0x40043100))
#define BASE_M3_CLK (*(volatile unsigned long *) (0x4005006C))

#define STACK_SIZE     64      // Stack Size

#define SET_VALID_CODE 1       // Set Valid User Code Signature
#define END_SECTOR       14

unsigned long CCLK;            // CCLK in kHz

typedef void (* IAP_t)(unsigned int [],unsigned int[]);

typedef	struct {
   const IAP_t IAP;
   const unsigned OTP;
   const unsigned pEntry_AES_API;
   const unsigned pEntry_PWR_API;
   const unsigned pEntry_CLK_API;
   const unsigned pEntry_IPC_API;
   const unsigned SPIFI;
} *pENTRY_API_t; 

#define ENTRY_API_BASE 0x10400100
#define pROM_API ((pENTRY_API_t)ENTRY_API_BASE)

unsigned int command[6], result[5];

/*
 * Get Sector Number
 *    Parameter:      adr:  Sector Address
 *    Return Value:   Sector Number
 */

unsigned long GetSecNum (unsigned long adr) {
  unsigned long n;

  n = (adr & 0x000FE000) >> 13;//  Assume a 8kB Sector
  if (n > 0x7) {				//	If address is larger than 0x10000 then it's a 64kb sector
    n = 0x07 + (n >> 3);      //	Modify n to reflect a 64kB Sector
  }

  if (n > END_SECTOR) n = END_SECTOR;
  return (n);                                  // Sector Number
}


/*
 *  Initialize Flash Programming Functions
 *    Parameter:      adr:  Device Base Address
 *                    clk:  Clock Frequency (Hz)
 *                    fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

int Init (unsigned long adr, unsigned long clk, unsigned long fnc) {

//  BASE_M3_CLK = (1<<24);                       //Switch M3 core to IRC (default)
//  M3MEMMAP = 0x10000000;
//  CCLK  = 12000;                               // 12MHz Internal RC Oscillator
  BASE_M3_CLK = (1<<24);                       //Switch M3 core to IRC (default)

	command[0] = 49	;	//IAP initialization
	pROM_API->IAP(command, result);

	command[0] = 54;   // Part ID
	pROM_API->IAP(command, result);

	command[0] = 55;   // Boot code version
	pROM_API->IAP(command, result);
//  if (IAP.stat) return (1);                    // Command Failed
  return (0);
}


/*
 *  De-Initialize Flash Programming Functions
 *    Parameter:      fnc:  Function Code (1 - Erase, 2 - Program, 3 - Verify)
 *    Return Value:   0 - OK,  1 - Failed
 */

int UnInit (unsigned long fnc) {
  return (0);
}


/*
 *  Erase complete Flash Memory
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseChip (void) {

  BASE_M3_CLK = (1<<24);                       //Switch M3 core to IRC (default)
//  M3MEMMAP = 0x10000000;
  CCLK  = 12000;                               // 12MHz Internal RC Oscillator

	command[0] = 50 ; //prepare for write/erase
	command[1] = 0;		//start sector
	command[2] = END_SECTOR; // end sector
#ifdef BANK_A
	command[3] = 0;		// Flashbank A
#else
	command[3] = 1;		// Flashbank B
#endif

	pROM_API->IAP(command, result);

	command[0] = 52;		// Erase sectors
	command[1] = 0 ;		// Start sector
	command[2] = END_SECTOR;		// End sector
	command[3] = 12000;		// Core clock freq (48 MHz)
#ifdef BANK_A
	command[4] = 0;		// Flashbank A
#else
	command[4] = 1;		// Flashbank B
#endif
	pROM_API->IAP(command, result);
    if (result[0]) return (1);                 // Command Failed

  return (0);                                  // Finished without Errors
}


/*
 *  Erase Sector in Flash Memory
 *    Parameter:      adr:  Sector Address
 *    Return Value:   0 - OK,  1 - Failed
 */

int EraseSector (unsigned long adr) {
  unsigned long n;

  BASE_M3_CLK = (1<<24);                       //Switch M3 core to IRC (default)
  n = GetSecNum(adr);                          // Get Sector Number

	command[0] = 50 ; //prepare for write/erase
	command[1] = n;		//start sector
	command[2] = n;     // end sector
#ifdef BANK_A
	command[3] = 0;		// Flashbank A
#else
	command[3] = 1;		// Flashbank B
#endif
	pROM_API->IAP(command, result);

	command[0] = 52;		// Erase sectors
	command[1] = n ;		// Start sector
	command[2] = n;		// End sector
	command[3] = 12000;		// Core clock freq (48 MHz)
#ifdef BANK_A
	command[4] = 0;		// Flashbank A
#else
	command[4] = 1;		// Flashbank B
#endif
	pROM_API->IAP(command, result);
//    if (result[0]) return (1);                 // Command Failed

  return (0);                                  // Finished without Errors
}


/*
 *  Program Page in Flash Memory
 *    Parameter:      adr:  Page Start Address
 *                    sz:   Page Size
 *                    buf:  Page Data
 *    Return Value:   0 - OK,  1 - Failed
 */

int ProgramPage (unsigned long adr, unsigned long sz, unsigned char *buf) {
  unsigned long n;

  BASE_M3_CLK = (1<<24);                       //Switch M3 core to IRC (default)
#if SET_VALID_CODE != 0                        // Set valid User Code Signature
  if (adr == 0x1A000000) {                              // Check for Vector Table
    n = *((unsigned long *)(buf + 0x00)) +
        *((unsigned long *)(buf + 0x04)) +
        *((unsigned long *)(buf + 0x08)) +
        *((unsigned long *)(buf + 0x0C)) +
        *((unsigned long *)(buf + 0x10)) +
        *((unsigned long *)(buf + 0x14)) +
        *((unsigned long *)(buf + 0x18));
    *((unsigned long *)(buf + 0x1C)) = 0 - n;  // Signature at Reserved Vector
  }
#endif

  n = GetSecNum(adr);                          // Get Sector Number

	command[0] = 50 ; //prepare for write/erase
	command[1] = n;		//start sector
	command[2] = n; // end sector
#ifdef BANK_A
	command[3] = 0;		// Flashbank A
#else
	command[3] = 1;		// Flashbank B
#endif
	pROM_API->IAP(command, result);

	command[0] = 51 ;	// Copy RAM to Flash
	command[1] = adr ;
	command[2] = (unsigned long) buf ;	//source
	command[3] = 1024 ;
	command[4] = 12000;
#ifdef BANK_A
	command[5] = 0;		// Flashbank A
#else
	command[5] = 1;		// Flashbank B
#endif
	pROM_API->IAP(command, result);
    if (result[0]) return (1);                 // Command Failed

	command[0] = 60;	//Set active partition
#ifdef BANK_A
	command[1] = 0;		// Flashbank A
#else
	command[1] = 1;		// Flashbank B
#endif
	command[2] = 12000;	// CPU clk
	pROM_API->IAP(command, result);

  return (0);                                  // Finished without Errors
}
