📄 flash_nvram.c
字号:
/*
$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 + -