📄 intel_flash_routines.c
字号:
/***************************************************************************
Copyright ARM Limited 1998 - 2003. All rights reserved.
****************************************************************************
Intel_Flash_Routines.c
Flash routines for Intel Flash devices using the 'Basic Command Set'
****************************************************************************/
#include "integrator.h"
// Various constants
#define TRUE 1
#define FALSE 0
#define PASS 0
#define FAIL -1
// Intel Basic Command Set Commands
#define PROGRAM_COMMAND 0x10
#define PROGRAM_VERIFY 0xD0
#define READ_STATUS 0x70
#define CLEAR_STATUS 0x50
#define READ_ARRAY 0xFF
#define BLOCK_ERASE 0x20
#define BLOCK_WRITE_MODE 0xE8
#define BLOCK_LOCK_BITS 0x60
#define BLOCK_LOCK_CONFIRM 0x01
#define CFI_QUERY_COMMAND 0x98
#define CFI_DATA_OFFS 0x20
// Intel Status masks
#define STATUS_READY 0x80
#define STATUS_LOCKED 0x01
#define LOCK_ERROR 0x10
#define ERASE_ERROR 0x20
#define MAX_WRITE_BUFF 0x0F
static int Flash_Unlock_Block(unsigned int*);
static int ReadyWait(volatile unsigned int*);
// This issues a (byte sized) command to the Flash device.
// If multiple parrallel devices are used (eg 2 * 16 bit Flash parts providing 32 bit memory)
// The command is issued to all devices
static int command(unsigned char command, unsigned int *address)
{
#ifdef fc16x2
{
*(volatile unsigned int *)address = ((unsigned int)command | (unsigned int)command<<16);
}
#endif
#ifdef fc16x1
{
*(volatile unsigned short *)address = (unsigned short)command;
}
#endif
#ifdef fc32x1
{
*(volatile unsigned int *)address = (unsigned int)command;
}
#endif
#ifdef fc8x1
{
*(volatile unsigned char *)address = (unsigned char)command;
}
#endif
#ifdef fc8x2
{
*(volatile unsigned short *)address = ((unsigned short)command | (unsigned short)command<<8);
}
#endif
#ifdef fc8x4
{
*(volatile unsigned short *)address = ((unsigned int)command | (unsigned int)command<<8 | (unsigned int)command<<16 | (unsigned int)command<<24);
}
#endif
return PASS;
}
// This routine writes a single 32 bit word to Flash. On entry, it assumes the
// Flash is in READ-ARRAY mode (which it is following reset, or exit from any other
// non-static function in this source file.
// For 16-bit access flash, Little Endian is presumed.
// This function checks whether the block is locked before attempting the write.
int Flash_Write_Word(unsigned int *address, unsigned int data)
{
#ifdef fc32x1
command(PROGRAM_COMMAND, address); // Writing 0x10 puts devices into write mode.
*(volatile unsigned int*)address = data; // Write data
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address); // Wait for write to complete.
while(*(volatile unsigned int*)address & 0x00000002) // Block was locked (if should suffice, but while good for debug).
{
Flash_Unlock_Block(address); // re-issue program command 0x10 (word)
command(PROGRAM_COMMAND, address); // address simply needs to be in the correct device
*(volatile unsigned int*)address = data; // Write required word to required address
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address);
}
#endif
#ifdef fc16x2
command(PROGRAM_COMMAND, address); // Writing 0x10 puts devices into write mode.
*(volatile unsigned int*)address = data; // Write data
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address); // Wait for write to complete.
while(*(volatile unsigned int*)address & 0x00020002) // Block was locked (if should suffice, but while good for debug).
{
Flash_Unlock_Block(address); // re-issue program command 0x10 (word)
command(PROGRAM_COMMAND, address); // address simply needs to be in the correct device
*(volatile unsigned int*)address = data; // Write required word to required address
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address);
}
#endif
#ifdef fc16x1 // ***ASSUMES LITTLE ENDIAN***
int i;
short shdata;
for (i=0;i<2;i++)
{
shdata=(short)data;
command(PROGRAM_COMMAND, address); // Writing 0x10 puts devices into write mode.
*((volatile unsigned short*)address+i) = shdata;// Write data
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address); // Wait for write to complete.
while(*(volatile unsigned short*)address & 0x0002) // Block was locked (if should suffice, but while good for debug).
{
Flash_Unlock_Block(address); // re-issue program command 0x10 (word)
command(PROGRAM_COMMAND, address); // address simply needs to be in the correct device
*((volatile unsigned short*)address+i) = shdata; // Write required word to required address
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address);
}
data=data>>16
}
#endif
#ifdef fc8x4
command(PROGRAM_COMMAND, address); // Writing 0x10 puts devices into write mode.
*(volatile unsigned int*)address = data;// Write data
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address); // Wait for write to complete.
while(*(volatile unsigned int*)address & 0x02020202) // Block was locked (if should suffice, but while good for debug).
{
Flash_Unlock_Block(address); // re-issue program command 0x10 (word)
command(PROGRAM_COMMAND, address); // address simply needs to be in the correct device
*(volatile unsigned int*)address = data; // Write required word to required address
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address);
}
#endif
#ifdef fc8x2
int i;
short shdata;
for (i=0;i<2;i++)
{
shdata=(short)data;
command(PROGRAM_COMMAND, address); // Writing 0x10 puts devices into write mode.
*((volatile unsigned short*)address+i) = shdata;// Write data
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address); // Wait for write to complete.
while(*(volatile unsigned short*)address & 0x0202) // Block was locked (if should suffice, but while good for debug).
{
Flash_Unlock_Block(address); // re-issue program command 0x10 (word)
command(PROGRAM_COMMAND, address); // address simply needs to be in the correct device
*((volatile unsigned short*)address+i) = shdata; // Write required word to required address
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address);
}
data=data>>16
}
#endif
#ifdef fc8x1
int i;
char chdata;
for (i=0;i<4;i++)
{
chdata=(char)data;
command(PROGRAM_COMMAND, address); // Writing 0x10 puts devices into write mode.
*((volatile unsigned char*)address+i) = shdata; // Write data
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address); // Wait for write to complete.
while(*(volatile unsigned char*)address & 0x02) // Block was locked (if should suffice, but while good for debug).
{
Flash_Unlock_Block(address); // re-issue program command 0x10 (word)
command(PROGRAM_COMMAND, address); // address simply needs to be in the correct device
*((volatile unsigned short*)address+i) = shdata; // Write required word to required address
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address);
}
data=data>>8
}
#endif
command(READ_ARRAY, address); // Reset for Read operation
if (*address != data) // Read word back to verify
return FAIL;
else
return PASS;
}
// This function writes an area of flash contained within a single block.
// This is quicker than individual word writes, as it only checks the block is unlocked once,
// And doesn't return to READ_ARRAY mode after each write. This also allows the
// Flash device's built in write buffer to be used effectively.
// This function DOES NOT CHECK the area to be programmed lies within a single block.
static int Flash_Write_Block(unsigned int *address, int *data, unsigned int size)
{
int n;
int *end=data+size/4;
int done = FALSE;
int s_reg;
Flash_Unlock_Block(address);
while (done != TRUE)
{
do
{
command(BLOCK_WRITE_MODE, address); // Write E8
s_reg=*address;
} while((s_reg & (STATUS_READY | (STATUS_READY<<16)))!=(STATUS_READY | (STATUS_READY<<16)));
n = (size/4) - 1; // Generate the number to write maximum of 16 words
if ((n+1) >= MAX_WRITE_BUFF) // maximum of 16 words
n = MAX_WRITE_BUFF;
command(n, address); //write word count
/* write 16 bus-width words of data (32 bytes/chip) */
for ( ; n >= 0; n--)
#if (defined fc32x1) | (defined fc16x2) | (defined fc8x4)
*(volatile unsigned int*)address++ = *data++;
#endif
#if (defined fc16x1) | (defined fc8x2)
*(volatile unsigned short*)address++ = *(unsigned short*)data++;
#endif
#if (defined fc8x1)
*(volatile unsigned char*)address++ = *(unsigned char*)data++;
#endif
/* write confirm */
command(PROGRAM_VERIFY, address);
ReadyWait(address);
/* advance pointers */
if (data >= end)
done = TRUE;
}
ReadyWait(address);
command(READ_ARRAY, address); // Switch back to READ ARRAY mode
return PASS;
}
// This function returns base and size to cover all blocks required to hold size bytes from address.
int Flash_Calc_Blocks(unsigned int **address, int *size)
{
int *endadd;
int temp;
int blockmask;
blockmask=(FLASH_BLOCK<<2)-1;
temp=(int)(*address+*size/4);
temp=temp & ~blockmask;
endadd=(int *)(temp + FLASH_BLOCK);
*address=(unsigned int *)((int)*address & ~blockmask);
*size=((int)endadd-(int)*address);
return PASS;
}
// This function writes an arbitary area of flash.
// It first verfies that the data will fit within the flash address space,
// Then divides the operation into calls to Flash_Write_Block, which writes
// data areas contained within a single block.
int Flash_Write_Area(unsigned int *address, int *data, int size)
{
int bytesinfirstblock;
int byteswritten;
if ((address >= FLASH_BASE) && ((address+size/4) <= (FLASH_BASE + FLASH_SIZE)))
{
bytesinfirstblock = FLASH_BLOCK - ((int)address - ((int)address & ~(FLASH_BLOCK-1)));
if (bytesinfirstblock > size) bytesinfirstblock=size;
Flash_Write_Block(address, data, bytesinfirstblock);
byteswritten=bytesinfirstblock;
address += byteswritten/4;
data += byteswritten/4;
while (size > byteswritten)
{
if ((size-byteswritten) < FLASH_BLOCK)
{
Flash_Write_Block(address, data, size-byteswritten);
byteswritten = size;
}
else
{
Flash_Write_Block(address, data, FLASH_BLOCK);
byteswritten += FLASH_BLOCK;
address += FLASH_BLOCK/4;
data += FLASH_BLOCK/4;
}
}
return PASS;
}
else
{
return FAIL;
}
}
// This function erases a single block, specified by it's base address
static int Flash_Erase_Block(unsigned int *address)
{
int result;
unsigned int s_reg;
Flash_Unlock_Block(address);
do
{
result = PASS;
command(BLOCK_ERASE, address); // Issue single block erase command
command(PROGRAM_VERIFY, address); // Confirm Action 0xd0 with block address
command(READ_STATUS, address);
ReadyWait(address); // Wait for erase attempt to complete
s_reg = *(volatile unsigned int*)address; // This results in reading s_reg twice (first time in readywait), so Intel errata does not cause problem.
if (s_reg & (ERASE_ERROR | (ERASE_ERROR<<16)))
{
command(CLEAR_STATUS, address);
result = FAIL;
}
// Reset for Read operation
command(READ_ARRAY, address);
} while (result == FAIL);
return (result);
}
// This function erases all blocks overlapping specified region (via calls to Flash_Erase_Block)
int Flash_Erase_Blocks(unsigned int *address, int size)
{
unsigned int* limit=address+size/4-1;
for(;address<=limit;address+=FLASH_BLOCK/4)
Flash_Erase_Block(address);
return PASS;
}
// This checks the status register, and loops untill the Flash device is 'ready'
static int ReadyWait(volatile unsigned int* address)
{
#ifdef fc32x1
while((*address & STATUS_READY )!=STATUS_READY);
#endif
#ifdef fc16x2
while((*address & (STATUS_READY | (STATUS_READY<<16)))!=(STATUS_READY | (STATUS_READY<<16)));
#endif
#ifdef fc16x1
while((*(volatile unsigned short*)address & STATUS_READY)!=STATUS_READY);
#endif
#ifdef fc8x4
while((*address & (STATUS_READY | (STATUS_READY<<8) | (STATUS_READY<<16) | (STATUS_READY<<24)))!=(STATUS_READY | (STATUS_READY<<8) | (STATUS_READY<<16) | (STATUS_READY<<24)));
#endif
#ifdef fc8x2
while((*(volatile unsigned short*)address & (STATUS_READY | (STATUS_READY<<8)))!=(STATUS_READY | (STATUS_READY<<8)));
#endif
#ifdef fc8x1
while((*(volatile unsigned char*)address & STATUS_READY)!=STATUS_READY);
#endif
return PASS;
}
static int Flash_Unlock_Block(unsigned int *address)
{
command (BLOCK_LOCK_BITS, address); // Clear lock bits write 0x60 within the device address space
command (PROGRAM_VERIFY, address); // Confirm action by writing 0xD0 within the device address space
command (READ_STATUS, address); // Put device into 'READ STATUS MODE'.
ReadyWait(address); // Wait for write to complete.
command (READ_ARRAY, address); // Put device back into read mode.
return PASS;
}
int Flash_Init ()
{
return PASS;
}
int Flash_Close ()
{
return PASS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -