⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flash_nvram.c

📁 GM5621原代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
	$Workfile:   flash_nvram.c  $
	$Revision:   1.26  $
	$Date:   Jan 06 2005 16:07:04  $
*/
//******************************************************************
//
//          Copyright (C) 2001. GENESIS MICROCHIP INC.
//  All rights reserved.  No part of this program may be reproduced.
//
//  Genesis Microchip Inc., 165 Commerce Valley Dr. West
//          Thornhill, Ontario, Canada, L3T 7V8
//			Genesis Microchip Corp., 2150 Gold Street
//					Alviso, CA 95002	USA
//
//================================================================
//
//  MODULE: flash_nvram.c
//
//  USAGE : This module maintains NVRAM block data in FLASH rather than
//			EEPROM based NVRAM.  The main difference being that FLASH can
//       only be erased a minimum of 1 sector (typically 4KB) were EEPROM
//			based NVRAM can be byte erasable, allowing for a more random access
//       approach to memory management.
//       The FLASH approach to memory management is to never erase a sector
//       until it becomes full.  If a block is saved, it is simply appended
//       to the end, and when it is to be accessed, it's the last copy that
//       is the most recent.  When the sector becomes full, a prune operation
//       takes place where a second sector is erased, and only the most
//       recent block data is copied into the new sector.  The new sector
//       becomes the "working" sector, and will be pruned when it becomes full.
//
//******************************************************************


//******************************************************************
//                  I N C L U D E    F I L E S
//******************************************************************
#include "..\inc\all.h"

#if NVRAM_USE_FLASH

#include "flash_hex.h"
#include "mem.h"
#include "dos.h"
#include ".\system\Mcu186.h"

//******************************************************************
//              L O C A L    D E F I N I T I O N S
//******************************************************************
#define DEBUG_FLASH_NV    			0
#define DEBUG_FLASH_NV_EXTENDED  0
#define DEBUG_FLASH_INP				1


#if DEBUG_FLASH_NV && DEBUG_MSG
	#define	msg(a,b)	gm_Print((const char far *)a,b)
#else
	#define msg(a,b)
#endif
#if DEBUG_FLASH_NV_EXTENDED && DEBUG_MSG
	#define	msgx(a,b)	gm_Print((const char far *)a,b)
#else
	#define msgx(a,b)
#endif

#if DEBUG_FLASH_INP && DEBUG_MSG
	#define	inp_msg(a,b)	gm_Print((const char far *)a,b)
#else
	#define inp_msg(a,b)
#endif

#define LAST_BLOCK_ID	gmv_Size_RomDirectory //used to speed up prune routine, don't
// bother searching for all 0x00 -> 0xff block types if they're not used.

/********  NOTE **************************************************************
	The #defines below for sector size and start must be in 'HUGE' format, or
	normalized 'far' format.  Examples of far pointers and their normalized
	equivalents:
	  far       normalized
	---------   -----------
	0000:0123牋牋0012:0003
	0040:0056牋牋0045:0006
	500D:9407牋牋594D:0007
	7418:D03F牋牋811B:000F
	0000:1000    0100:0000 <- Example of 4KB sector size that's normalized
******************************************************************************/
#if FLASH_TYPE == PM39F010                  
	#define FLASHUserPrefSectorStartD		0x9E000000UL // use last two banks (normalized)
	#define FLASHUserPrefSectorSizeD 		0x01000000UL // 4KB sector size. (normalized)
#elif FLASH_TYPE == PM39F020
	#define FLASHUserPrefSectorStartD		0xB6000000UL // use last two banks (normalized)
	#define FLASHUserPrefSectorSizeD 		0x01000000UL // 4KB sector size. (normalized)
#elif FLASH_TYPE == SPI_FLASH
	#define FLASHUserPrefSectorStartS128	0x9E000000UL // use last two banks (normalized) for size = 128K
	#define FLASHUserPrefSectorStartS256	0xBE000000UL // use last two banks (normalized) for size = 256K
	#define FLASHUserPrefSectorStartS512	0xEE000000UL // use last two banks (normalized) for size = 512K
	#define FLASHUserPrefSectorSizeS4 		0x01000000UL // 4KB sector size. (normalized)
	#define FLASHUserPrefSectorStartST		0xA0000000UL // use last two banks (normalized) for ST (size 256K)
	#define FLASHUserPrefSectorSizeST 		0x10000000UL // 64KB sector size. (normalized)  for ST
#elif FLASH_TYPE == PROMJET_PARALLEL
	#if FLASH_CHIP_SIZE == SIZE_128K
		#define FLASHUserPrefSectorStartD		0x9E000000UL // use last two banks (normalized)
		#define FLASHUserPrefSectorSizeD 		0x01000000UL // 4KB sector size. (normalized)
	#elif FLASH_CHIP_SIZE == SIZE_256K
		#define FLASHUserPrefSectorStartD		0xB6000000UL // use last two banks (normalized)
		#define FLASHUserPrefSectorSizeD 		0x01000000UL // 4KB sector size. (normalized)
	#endif
#else
	#error "FLASH_TYPE Uknown!"
#endif

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//NOTE: Macor HUGE_OFF and HUGE assumes normalized 32-bit address as an input;
//  Otherwise, the macros will give wrong results! Only when computing Size, Room
//  or comparing address, converting the normalized 32-bit adddress to 20-bit address
//  first by using HUGE; In all other cases, keep normalized 32-bit address!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#define HUGE_OFF(a) (WORD)(((((a)>>12)&0xfff0) + FP_OFF(a)))
#define HUGE(a) (DWORD)(  (((DWORD)(a)>>12)&0xffff0UL) + (((DWORD)(a))&0xFFFFUL))

typedef enum {
	FLASH_NV_WRITE,
	FLASH_NV_SECTOR_ERASE,
	FLASH_NV_AUTODETECT				
} flash_nv_cmd;

// Moved to Nvram_def.h file
#if 0
typedef struct block_hdr_struct
{
	BYTE	Type;		// Block_ID
	BYTE	Index;   		// Block_Index
	WORD	Size;    		// Size of Block including header
	BYTE  	Checksum; 	// Checksum.
}block_hdr_type;
#endif

#define BLOCK_TYPE_OFFSET			0
#define BLOCK_INDEX_OFFSET       1
#define BLOCK_SIZE_OFFSET        2
#define BLOCK_CHECKSUM_OFFSET    4
#define BLOCK_DATA_OFFSET        5

extern BYTE DecompBuf[768];

BYTE B_FlashChipID;		// flash chip type

DWORD FLASHUserPrefSectorStart;
DWORD FLASHUserPrefSectorSize;

typedef union
{
	DWORD DW_Addr;
	BYTE  B_A[4];

} ADDRESS;

typedef union
{
	WORD W_Word;
	BYTE B_A[2];
} WORDTOBYTE;

typedef void far(*RamResidentEntry)(BYTE cmd, BYTE far *WrAddr, WORD length, BYTE far *buff);

#if FAST_FLASH_PAGE_UPDATE
	//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   //NOTE:  To optimize memory usage and speed up searching,
   //			MAX_BLOCK_ENTRIES and MAX_TOTAL_INDICES has to be manually derived from nvtable.c file,
   //			make: MAX_BLOCK_ENTRIES = gmv_Size_RomDirectory, and
   //					MAX_TOTAL_INDICES = # of total entries in gmc_RomDirectory[] array
   //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   #define MAX_BLOCK_ENTRIES		20		//maximum # of nvram blockType
   #define MAX_TOTAL_INDICES		100	//maximum # of total individual nvram blocks (different index count as 1)

   //local
   static BYTE	B_CountTable[MAX_BLOCK_ENTRIES];
   static WORD	W_AddrTable[MAX_TOTAL_INDICES];

   //extern variables
   extern gmt_BLOCKINFO ROM gmc_RomDirectory[];
   extern BYTE ROM gmv_Size_RomDirectory;

	static gmt_RET_STAT MakeCountTable(void);
#endif

static WORD getLength(BYTE far *addr);
static BYTE far *findBlockType(BYTE blockType, BYTE blockIndex, BYTE *version);
void prune(void);
static void findWorkingSector(void);
static BYTE checkChecksum(BYTE far * blockAddr);

gmt_BLOCKINFO	block_info; // WORD address, WORD length
BYTE far *workingSector;   // current FLASH sector in use.

//******************************************************************
//                          C O D E
//******************************************************************
static void executeRamResidentCmd(flash_nv_cmd cmd, BYTE far *WrAddr, WORD length, BYTE far *buff);


//Added function to set optimal SPI clock based on flash type after AutoDetect or know which flash type
//*********************************************************************************************
// FUNCTION     :   SetOptimizedSPIClock(void)
// DESCRIPTION  :   to set optimal SPI clock based on flash type
// INPUT        :   B_FlashChipID
//
// OUTPUT       :   None
// USED_REGS    :   None
//*********************************************************************************************
//Note: only call this function or after flash type is known, and there is a limitation for
//speed setting according to flash chipID since some flash with the same chipID may have different
//speed. System maker has to check whether this mechanism can be used or not before enable this option
#if (DISABLE_AUTODETECT == 0)
void SetOptimalSPIClock(void)
{
	#if  (USE_FLASHSPEED_AUTODETECT == 1)
		BYTE B_FlashClockInMHz;	// flash clock;
      BYTE B_tmpDivisor;

		switch(B_FlashChipID)
		{
			case SST25VF010_ID:
					msgx("SST",0);
               B_FlashClockInMHz = 20;
					break;

			case PM25LV010_ID:
					msgx("PMC",0);
               B_FlashClockInMHz = 25;
					break;

			default:
					msg("Error - B_FlashChipID is wrong !",B_FlashChipID);
					return;
		};

      //reset gmc_SPI_Clock_Sel based on flash clock
      if( (CPU_CLK_MHZ / B_FlashClockInMHz) > 2)
      {
      	B_tmpDivisor =  (BYTE)( (10*CPU_CLK_MHZ+9*B_FlashClockInMHz)/(10UL*B_FlashClockInMHz) - 2);
         gmc_SPI_Clock_Sel = (B_tmpDivisor<<4);
      }
      else
      {
      	gmc_SPI_Clock_Sel = 0;
      }

		gm_SetRegBitsByte(SPI_CONTROL, gmc_SPI_Clock_Sel);


      msgx("B_tmpDivisor: %d", B_tmpDivisor);
      msgx("B_FlashClockInMHz: 0x%x", B_FlashClockInMHz);
      msgx("gmc_SPI_Clock_Sel: 0x%x", gmc_SPI_Clock_Sel);
   #endif
}
#endif


// Added function to clear blocks of a same type more efficiently (especially for page-write type of flash like PMC).
//***************************************************************
// FUNCTION     :   pp_ClearNVRAMBlockWithSameType
// DESCRIPTION  :   Clear all nvram block with the same blockType, mainly for ModeDependent Entries.
// INPUT        :   B_BlockType (block id),
//        B_StartIndex (block index),
//			 B_MaxEntry (counted from startIndex)
//        buffer (allocated first for all entries, size = (Length+headerSize)*B_MaxEntry, buff has to be initialized
//                  Length (entry length)
//
// OUTPUT       :   gmt_RET_STAT
// USED_REGS    :   None
//
//Note: there could be another way to implement this function by using less buffer with size=length+hearder size,
//    but call executeRamResidentCmd for B_MaxIndex times.
//
//***************************************************************
gmt_RET_STAT pp_ClearNVRAMBlockWithSameType(BYTE B_BlockType, BYTE B_StartIndex, BYTE B_MaxEntry, BYTE *Bp_Buffer, WORD W_Length)
{
 	BYTE far *pbAddr;
 	BYTE version = 0x00;
 	WORD room, i, j;
 	block_hdr_type hdr;

   	//to format buffer for all entries
   	for (j = 0; j < B_MaxEntry; j++)
   	{
      		hdr.Type = B_BlockType;
      		hdr.Index = j + B_StartIndex;
      		hdr.Size  = W_Length + sizeof(block_hdr_type);
      		hdr.Checksum = 0;

      		for (i = 0; i < W_Length; i++)
      		{
         		hdr.Checksum += Bp_Buffer[j * hdr.Size + BLOCK_DATA_OFFSET + i];
      		}

      		//only update header
  		_fmemcpy(&Bp_Buffer[j*hdr.Size], &hdr, BLOCK_DATA_OFFSET);
   	}

 	// find an empty block
 	pbAddr = findBlockType(0xff, 0xff, &version);
 	msgx("B_BlockType %x",(WORD)B_BlockType);
 	msgx("pbAddr seg %x",(WORD)((DWORD)pbAddr >> 16));
 	msgx("pbAddr off %x",(WORD)pbAddr);

 	// see if there's enough room in this FLASH sector for our new block.
 	room = (WORD)(HUGE((DWORD)workingSector + FLASHUserPrefSectorSize) - HUGE(pbAddr));
 	msgx("room %d",(WORD)room);
 	msgx("size for an entry %d",(WORD)hdr.Size);
 	msgx("Total size %d",(WORD)hdr.Size * B_MaxEntry);

 	if( (room < (hdr.Size * B_MaxEntry)) || (pbAddr == NULL_PTR)) // not enough room.  Time to prune the sector.
 	{
  		msgx("..prune1..",0);
	 	msgx("room %d",(WORD)room);
 		msgx("size for an entry %d",(WORD)hdr.Size);
 		msgx("Total size %d",(WORD)hdr.Size * B_MaxEntry);

  		prune();

  		// find an empty block
  		pbAddr = findBlockType(0xff, 0xff, &version);

  		if (pbAddr == NULL_PTR)
   			return gmd_FAIL; // if after prune, still no room, nothing else we can do.
 	}

 	// write data in buffer for all entries to nvram
 	executeRamResidentCmd(FLASH_NV_WRITE, pbAddr, hdr.Size * B_MaxEntry, Bp_Buffer);

	msgx("pp_ClearNVRAMBlockWithSameType",0);

 	return gmd_OK;
}
// FUNCTION     :   gm_InitNVRAM
// DESCRIPTION  :   Initialize internal ROM NVRAM routines.
// INPUT        :   None
// OUTPUT       :   gmt_RET_STAT
// USED_REGS    :   None
//***************************************************************
gmt_RET_STAT pp_InitNVRAM(void)
{

#if FLASH_TYPE == SPI_FLASH
	BYTE B_FlashChipSize = 0;

#if(DISABLE_AUTODETECT == 0)

	BYTE far *Bp_Buff = &B_FlashChipID;

	msg("Begin AUTODETECT",0);
	executeRamResidentCmd(FLASH_NV_AUTODETECT, NULL_PTR, 0, Bp_Buff);
	msg("End AUTODETECT",0);

	B_FlashChipSize	= ( B_FlashChipID & 0xF0 );
	B_FlashChipID	= ( B_FlashChipID & 0x0F );

	msg("B_FlashChipID = %x",B_FlashChipID);
	msg("B_FlashChipSize = %x",B_FlashChipSize);

   //set optimal clock based on flash type
	SetOptimalSPIClock();
#else

	B_FlashChipID	= FLASH_CHIP_TYPE;
	B_FlashChipSize	= FLASH_CHIP_SIZE;

	msg("DISABLE AUTODETECT  B_FlashChipID = %x ",B_FlashChipID);
	msg("DISABLE AUTODETECT  B_FlashChipSize = %x ",B_FlashChipSize);

#endif			// #if(DISABLE_AUTODETECT == 0)

	if(ST0000000_ID == B_FlashChipID)
	{
		FLASHUserPrefSectorStart = FLASHUserPrefSectorStartST;
		FLASHUserPrefSectorSize = FLASHUserPrefSectorSizeST;
	}
	else
	{
		switch(B_FlashChipSize)
		{
			case SIZE_128K:		FLASHUserPrefSectorStart = FLASHUserPrefSectorStartS128;
								break;
			case SIZE_256K:		FLASHUserPrefSectorStart = FLASHUserPrefSectorStartS256;
								break;
			case SIZE_512K:		FLASHUserPrefSectorStart = FLASHUserPrefSectorStartS512;
								break;
			default:
				msg("Wrong B_FlashChipSize = %x ",B_FlashChipSize);
				FLASHUserPrefSectorStart = FLASHUserPrefSectorStartS128;
		};

		FLASHUserPrefSectorSize = FLASHUserPrefSectorSizeS4;
	}
#else
		FLASHUserPrefSectorStart = FLASHUserPrefSectorStartD;		// For parallel flash
		FLASHUserPrefSectorSize = FLASHUserPrefSectorSizeD;
#endif		// #if FLASH_TYPE == SPI_FLASH

	findWorkingSector();
#if FAST_FLASH_PAGE_UPDATE
	MakeCountTable();
#endif
	return gmd_OK;
}

//***************************************************************
// FUNCTION     :   pp_GetNVRAMBlockInfo
// DESCRIPTION  :   Returns gmt_BLOCKINFO on B_BlockType.  gmt_BLOCKIFO
//						  contains information like absolute address of block
//						  and the size of the block
// INPUT        :   B_BlockType (block id) and the B_BlockIndex
// OUTPUT       :   gmt_RET_STAT
// USED_REGS    :   None
//***************************************************************
	gmt_BLOCKINFO pp_GetNVRAMBlockInfo(BYTE B_BlockType, BYTE B_BlockIndex)
{
	BYTE far *pbAddr;
	BYTE version = 0x00;

	block_info.address = 0x00;
	block_info.length  = 0x00;

	pbAddr = findBlockType(B_BlockType, B_BlockIndex, &version);

	if(pbAddr != NULL_PTR)
	{
		block_info.address = (WORD)(HUGE(pbAddr) - HUGE(workingSector) + BLOCK_DATA_OFFSET);
		block_info.length  = getLength(pbAddr) - BLOCK_DATA_OFFSET;
	}
	return block_info;
}
//***************************************************************
// FUNCTION     :   pp_ReadNVRAMBlock
// DESCRIPTION  :   Read a data block into buffer.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -