📄 cfiflash.c
字号:
{
flash_command(FLASH_ERESUME, sector, 0, 0);
return (1);
}
/*********************************************************************/
/* flash_get_sector_size() is provided for cases in which the size */
/* of a sector is required by a host application. The sector size */
/* (in bytes) is returned in the data location pointed to by the */
/* 'size' parameter. */
/*********************************************************************/
byte flash_get_sector_size(byte sector, dword *size)
{
*size = meminfo->sec[sector].size;
return(1);
}
/*********************************************************************/
/* UNLOCK BYPASS FUNCTIONS */
/*********************************************************************/
/* Unlock bypass mode is useful whenever the calling application */
/* wished to program large amounts of data in minimal time. Unlock */
/* bypass mode remove half of the bus overhead required to program */
/* a single word, from 4 cycles down to 2 cycles. Programming of */
/* individual bytes does not gain measurable benefit from unlock */
/* bypass mode, but programming large strings can see a significant */
/* decrease in required programming time. */
/*********************************************************************/
/*********************************************************************/
/* flash_ub() places the flash into unlock bypass mode. This */
/* is REQUIRED to be called before any of the other unlock bypass */
/* commands will become valid (most will be ignored without first */
/* calling this function. */
/*********************************************************************/
byte flash_ub(byte sector)
{
flash_command(FLASH_UB, sector, 0, 0);
return(1);
}
/*********************************************************************/
/* flash_write_word_ub() programs a single word using unlock bypass */
/* mode. Note that the calling application will see little benefit */
/* from programming single words using this mode (outlined above) */
/*********************************************************************/
byte flash_write_word_ub(byte sector, word offset, word data)
{
flash_command(FLASH_UBPROG, sector, offset, data);
return (1);
}
/*********************************************************************/
/* flash_write_string_ub() behaves in the exact same manner as */
/* flash_write_string() (outlined above), expect that it utilizes */
/* the unlock bypass mode of the flash device. This can remove */
/* significant overhead from the bulk programming operation, and */
/* when programming bulk data a sizeable performance increase can be */
/* observed. */
/*********************************************************************/
byte flash_write_string_ub(byte sector, word offset,
byte *buffer, word numbytes)
{
word value=0;
if(numbytes == 0)
value = (word) strlen(buffer);
else
value = numbytes;
if (value & 0x0001)
value--; /* Need to make sure we don't overrun buffer */
flash_write(sector, offset, buffer, value,TRUE);
return (1);
}
/*********************************************************************/
/* flash_reset_ub() is required to remove the flash from unlock */
/* bypass mode. This is important, as other flash commands will be */
/* ignored while the flash is in unlock bypass mode. */
/*********************************************************************/
byte flash_reset_ub(void)
{
flash_command(FLASH_UBRESET,1,0,0);
return(1);
}
/*********************************************************************/
/* Usefull funtion to return the number of sectors in the device. */
/* Can be used for functions which need to loop among all the */
/* sectors, or wish to know the number of the last sector. */
/*********************************************************************/
void flash_get_numsectors(int *num)
{
*num = meminfo->nsect;
}
/*********************************************************************/
/* flash_get_cfi() is the main CFI workhorse function. Due to it's */
/* complexity and size it need only be called once upon */
/* initializing the flash system. Once it is called, all operations */
/* are performed by looking at the meminfo structure. */
/* All possible care was made to make this algorithm as efficient as */
/* possible. 90% of all operations are memory reads, and all */
/* calculations are done using bit-shifts when possible */
/*********************************************************************/
byte flash_get_cfi(struct cfi_query *query)
{
word far *fwp; /* flash window */
int volts=0, milli=0, temp=0, i=0;
int num_secs=0, offset=0;
flash_command(FLASH_RESET,0,0,0); /* Use sector 0 for all commands */
flash_command(FLASH_CFIQUERY,0,0,0);
fwp = (word *)get_flash_memptr(0);
/* Initial house-cleaning */
for(i=0; i < 8; i++) {
query->erase_block[i].sector_size = 0;
query->erase_block[i].num_sectors = 0;
}
query->query_string[0] = fwp[0x10];
query->query_string[1] = fwp[0x11];
query->query_string[2] = fwp[0x12];
query->query_string[3] = '\0';
/* If not 'QRY', then we dont have a CFI enabled device in the
socket */
if( query->query_string[0] != 'Q' &&
query->query_string[1] != 'R' &&
query->query_string[2] != 'Y') {
return(-1);
}
query->oem_command_set = fwp[0x13];
query->primary_table_address = fwp[0x15]; /* Important one! */
query->alt_command_set = fwp[0x17];
query->alt_table_address = fwp[0x19];
/* We will do some bit translation to give the following values
numerical meaning in terms of C 'float' numbers */
volts = ((fwp[0x1B] & 0xF0) >> 4);
milli = (fwp[0x1B] & 0x0F);
query->vcc_min = (float) (volts + ((float)milli/10));
volts = ((fwp[0x1C] & 0xF0) >> 4);
milli = (fwp[0x1C] & 0x0F);
query->vcc_max = (float) (volts + ((float)milli/10));
volts = ((fwp[0x1D] & 0xF0) >> 4);
milli = (fwp[0x1D] & 0x0F);
query->vpp_min = (float) (volts + ((float)milli/10));
volts = ((fwp[0x1E] & 0xF0) >> 4);
milli = (fwp[0x1E] & 0x0F);
query->vpp_max = (float) (volts + ((float)milli/10));
/* Let's not drag in the libm library to calculate powers
for something as simple as 2^(power)
Use a bit shift instead - it's faster */
temp = fwp[0x1F];
query->timeout_single_write = (1 << temp);
temp = fwp[0x20];
if (temp != 0x00)
query->timeout_buffer_write = (1 << temp);
else
query->timeout_buffer_write = 0x00;
temp = 0;
temp = fwp[0x21];
query->timeout_block_erase = (1 << temp);
temp = fwp[0x22];
if (temp != 0x00)
query->timeout_chip_erase = (1 << temp);
else
query->timeout_chip_erase = 0x00;
temp = fwp[0x23];
query->max_timeout_single_write = (1 << temp) *
query->timeout_single_write;
temp = fwp[0x24];
if (temp != 0x00)
query->max_timeout_buffer_write = (1 << temp) *
query->timeout_buffer_write;
else
query->max_timeout_buffer_write = 0x00;
temp = fwp[0x25];
query->max_timeout_block_erase = (1 << temp) *
query->timeout_block_erase;
temp = fwp[0x26];
if (temp != 0x00)
query->max_timeout_chip_erase = (1 << temp) *
query->timeout_chip_erase;
else
query->max_timeout_chip_erase = 0x00;
temp = fwp[0x27];
query->device_size = (long) (((long)1) << temp);
query->interface_description = fwp[0x28];
temp = fwp[0x2A];
if (temp != 0x00)
query->max_multi_byte_write = (1 << temp);
else
query->max_multi_byte_write = 0;
query->num_erase_blocks = fwp[0x2C];
for(i=0; i < query->num_erase_blocks; i++) {
query->erase_block[i].num_sectors = fwp[(0x2D+(4*i))];
query->erase_block[i].num_sectors++;
query->erase_block[i].sector_size = (long) 256 *
( (long)256 * fwp[(0x30+(4*i))] +
fwp[(0x2F+(4*i))] ); ( (long)256 * fwp[(0x30+(4*i))] +
fwp[(0x2F+(4*i))] );
}
/* Store primary table offset in variable for clarity */
offset = query->primary_table_address;
query->primary_extended_query[0] = fwp[(offset)];
query->primary_extended_query[1] = fwp[(offset + 1)];
query->primary_extended_query[2] = fwp[(offset + 2)];
query->primary_extended_query[3] = '\0';
if( query->primary_extended_query[0] != 'P' &&
query->primary_extended_query[1] != 'R' &&
query->primary_extended_query[2] != 'I') {
return(2);
}
query->major_version = fwp[(offset + 3)];
query->minor_version = fwp[(offset + 4)];
query->sensitive_unlock = (byte) (fwp[(offset+5)] & 0x0F);
query->erase_suspend = (byte) (fwp[(offset+6)] & 0x0F);
query->sector_protect = (byte) (fwp[(offset+7)] & 0x0F);
query->sector_temp_unprotect = (byte) (fwp[(offset+8)] & 0x0F);
query->protect_scheme = (byte) (fwp[(offset+9)] & 0x0F);
query->is_simultaneous = (byte) (fwp[(offset+10)] & 0x0F);
query->is_burst = (byte) (fwp[(offset+11)] & 0x0F);
query->is_page = (byte) (fwp[(offset+12)] & 0x0F);
return(1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -