📄 drv.c
字号:
if (*dev.addr & 0x80) {
ffsdrv_amd_erase_end();
tlw(led_off(LED_ERASE_SUSPEND));
return;
}
// NOTEME: As there is no way to be absolutely certain that erase
// doesn't finish between last poll and the following erase suspend
// command, we assume that the erase suspend is safe even though the
// erase IS actually already finished.
cpsr = int_disable();
dev.state = DEV_ERASE_SUSPEND;
*dev.addr = 0xB0;
// Wait for erase suspend to finish
while ((*dev.addr & 0x80) == 0) /* Enabling the interrupt should be after this while, */
/* because DQ7==1 on entering to erase suspend mode */
;
int_enable(cpsr);
}
void ffsdrv_amd_erase_resume(void)
{
uint32 cpsr;
ttw(str(TTrDrvErase, "er" NL));
// NOTEME: See note in erase_suspend()... We assume that the erase
// resume is safe even though the erase IS actually already finished.
cpsr = int_disable();
dev.state = DEV_ERASE;
*dev.addr = 0x30;
int_enable(cpsr);
tlw(led_off(LED_ERASE_SUSPEND));
}
#endif
/******************************************************************************
* SST Dual/Multi Bank Driver Functions
******************************************************************************/
// SST flashes use almost same command set as AMD flashes. Only the command
// addresses (4 more bits) and erase command data (0x50 instead of 0x30) are
// different. SST flashes have no erase suspend/resume commands because they
// are so fast at erasing!
void ffsdrv_sst_write_end(void);
void ffsdrv_sst_erase_end(void);
void ffsdrv_sst_write(void *dst, const void *src, uint16 size)
{
uint8 *mydst = dst;
const uint8 *mysrc = src;
if (size > 0)
{
if ((unsigned int) mydst & 1) {
ffsdrv_write_byte(mydst++, *mysrc++);
size--;
}
while (size >= 2) {
ffsdrv_amd_write_halfword((uint16 *) mydst,
mysrc[0] | (mysrc[1] << 8));
size -= 2;
mysrc += 2;
mydst += 2;
}
if (size == 1)
ffsdrv_write_byte(mydst++, *mysrc++);
}
}
// Note that SST flashes have smaller sectors than other flash families.
// Fortunately they support erasure of several of these sectors in a logical
// unit called a "block".
void ffsdrv_sst_erase(uint8 block)
{
uint16 *addr = (uint16 *) block2addr(block);
ffsdrv.erase_sector(addr);
}
void ffsdrv_sst_erase_sector(void *dst)
{
volatile char *flash = dev.base;
uint32 cpsr;
tlw(led_on(LED_ERASE));
ttw(ttr(TTrDrvErase, "e(%d)" NL, dst));
dev.addr = dst;
cpsr = int_disable();
dev.state = DEV_ERASE;
flash[0xAAAA] = 0xAA; // unlock cycle 1
flash[0x5555] = 0x55; // unlock cycle 2
flash[0xAAAA] = 0x80;
flash[0xAAAA] = 0xAA; // unlock cycle 1
flash[0x5555] = 0x55; // unlock cycle 2
*dev.addr = 0x50; // SST erase block command
int_enable(cpsr);
ffsdrv_sst_erase_end();
}
void ffsdrv_sst_erase_end(void)
{
// Wait for erase end
while ((*dev.addr & 0x80) == 0)
;
dev.state = DEV_READ;
tlw(led_off(LED_ERASE));
}
// Erase suspend/resume commands do not exist for SST flashes, so we just
// poll for the end of the erase operation...
void ffsdrv_sst_erase_suspend(void)
{
ttw(str(TTrDrvErase, "es" NL));
ffsdrv_sst_erase_end();
}
/******************************************************************************
* Intel Single Bank Driver Functions
******************************************************************************/
#ifdef INTEL_FLASH
#if (TARGET == 1)
// Forward declaration of functions in file intelsbdrv.c
int ffsdrv_ram_intel_sb_init(void);
void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, uint16 value);
void ffsdrv_ram_intel_sb_erase(uint8 block);
void ffsdrv_ram_intel_sb_erase_sector(void *dst);
void ffsdrv_ram_intel_erase(uint8 block);
void ffsdrv_ram_intel_erase_sector(void *dst);
#else // (TARGET == 0)
// On PC these functions are empty
void ffsdrv_ram_intel_sb_write_halfword(volatile uint16 *addr, uint16 value) {}
void ffsdrv_ram_intel_sb_erase(uint8 block) {}
void ffsdrv_ram_intel_sb_erase_sector(void *dst) {}
void ffsdrv_ram_intel_erase(uint8 block) {}
void ffsdrv_ram_intel_erase_sector(void *dst);
#endif // (TARGET == 1)
/******************************************************************************
* Intel Dual/Multi Bank Driver Functions
******************************************************************************/
void ffsdrv_intel_write_end(void);
void ffsdrv_intel_erase_end(void);
void ffsdrv_intel_init(void)
{
volatile uint16 *flash = (volatile uint16*)dev.base;
flash[0] = INTEL_READ_ARRAY;//reset intel flash status
}
// ffsdrv_intel_write_halfword and ffsdrv_intel_write_end is not used
// because of the bug in the intel flash device. Instead is the functions
// ffsdrv_ram_intel_sb_write_halfword and ffsdrv_ram_intel_erase used.
void ffsdrv_intel_write_halfword(volatile uint16 *addr, uint16 value)
{
uint32 cpsr;
tlw(led_on(LED_WRITE));
ttw(ttr(TTrDrvWrite, "wh(%x,%x)" NL, addr, value));
dev.addr = addr;
#if (FLASH_WRITE_CHECK == 1)
if (~*addr & value) {
ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value));
return;
}
#endif
cpsr = int_disable();
dev.state = DEV_WRITE;
#if (INTEL_UNLOCK_SLOW == 1)
*addr = 0x60; // Intel Config setup
*addr = 0xD0; // Intel Unlock block
*addr = 0x50; // Intel Clear Status Register
#endif
*addr = 0x40; // Intel program byte/word
*addr = value;
int_enable(cpsr);
ffsdrv_intel_write_end();
}
// IMPORTANT: This function presupposes that the size not is above the flash
// write buffer size and the src is half word aligned.
void ffsdrv_intel_write_buffer_mode(volatile uint16 *addr, volatile uint16 *src,
uint16 words2write)
{
uint32 cpsr;
uint16 i, status;
ttw(ttr(TTrDrvWrite, "wbuf(%x, %x, %x)" NL, addr, src, words2write));
#if (FLASH_WRITE_CHECK == 1)
// Make sure we don't try to flip a '0' to '1'.
for (i = 0; i < words2write; i++) {
if (~(int) addr[i] & (int) src[i]) {
ttw(ttr(TTrFatal, "wbuf(%x,%x->%x) fatal" NL, addr, addr[i], src[i]));
return;
}
}
#endif
cpsr = int_disable(); // FIXME can we disable interrupt for all this time?
dev.addr = addr;
dev.state = DEV_WRITE;
*dev.addr = INTEL_CLR_STATUS;
*dev.addr = INTEL_LOCK_SETUP;
*dev.addr = INTEL_UNLOCK_BLK;
// Wait for buffer ready
do {
*dev.addr = INTEL_BUFFER_PRG;
status = *dev.addr;
} while (!(status & INTEL_STATE_MACHINE_DONE));
// Write the word count - 1
*dev.addr = words2write - 1;
// Fill the write buffer
while (words2write > 0) {
*addr = *src;
words2write--;
addr++;
src++;
}
// Start the write buffer process
*dev.addr = INTEL_BUFFER_PRG_CONFIRM;
*dev.addr = INTEL_READ_STATUS;
int_enable(cpsr);
ffsdrv_intel_write_end();
// NOTEME Verify the write?
}
void ffsdrv_intel_write_end(void)
{
uint32 cpsr;
uint16 status;
// We can be interrupted and reentered thus the state can have been changed.
while (1) {
if (dev.state == DEV_WRITE) {
// write completed?
if ((*dev.addr & INTEL_STATE_MACHINE_DONE) > 0)
break; // write completed
continue;
}
else if (dev.state == DEV_WRITE_SUSPEND)
continue; // Wait until the write is resumed
else if (dev.state == DEV_READ)
break; // write completed in write_suspend() or a re-entered
// write_end()
ttw(ttr(TTrFatal, "FATAL: invalid dev.state %d" NL, dev.state));
return;
}
// The flash state and dev.state must be in sync thus the stat changes
// must be protected from being interrupted
cpsr = int_disable();
#if (FLASH_STATUS_CHECK == 1)
*dev.addr = INTEL_READ_STATUS;
status = *dev.addr;
if (status != INTEL_STATE_MACHINE_DONE)
ttw(ttr(TTrFatal, "FATAL write error 0x%x" NL, status));
#endif
dev.state = DEV_READ;
*dev.addr = INTEL_READ_ARRAY;
int_enable(cpsr);
tlw(led_off(LED_WRITE));
}
void ffsdrv_intel_write_suspend(void)
{
uint32 cpsr;
uint16 poll;
ttw(str(TTrDrvWrite, "wrs" NL));
// The flash state and dev.state must be in sync thus the stat changes
// must be protected from being interrupted
cpsr = int_disable();
dev.state = DEV_WRITE_SUSPEND;
*dev.addr = INTEL_SUSPEND;
*dev.addr = INTEL_READ_STATUS;
while (((poll = *dev.addr) & INTEL_STATE_MACHINE_DONE) == 0)
;
if ((poll & INTEL_PROGRAM_SUSPEND) == 0) {
// Write has completed
dev.state = DEV_READ;
}
// The write is fin韘hed or suspended, prepare to read data from the flash
*dev.addr = INTEL_READ_ARRAY;
int_enable(cpsr);
}
void ffsdrv_intel_write_resume(void)
{
uint32 cpsr;
ttw(str(TTrDrvWrite, "wrr" NL));
// The flash state and dev.state must be in sync thus the stat changes
// must be protected from being interrupted
cpsr = int_disable();
dev.state = DEV_WRITE;
*dev.addr = INTEL_RESUME;
// FFS always expect that the flash is in READ status mode while the
// dev.state is DEV_WRITE
*dev.addr = INTEL_READ_STATUS;
int_enable(cpsr);
}
void ffsdrv_intel_erase(uint8 block)
{
uint16 *addr = (uint16 *) block2addr(block);
ffsdrv.erase_sector(addr);
}
void ffsdrv_intel_erase_sector(void *dst)
{
uint32 cpsr;
ttw(ttr(TTrDrvErase, "e(0x%x)" NL, dst));
tlw(led_on(LED_ERASE));
dev.addr = (uint16 *)dst;
cpsr = int_disable();
dev.state = DEV_ERASE;
#if (INTEL_UNLOCK_SLOW == 1)
*dev.addr = INTEL_CLR_STATUS; // Intel clear status register (not really necessary)
*dev.addr = INTEL_LOCK_SETUP; // Intel Config setup
*dev.addr = INTEL_UNLOCK_BLK; // Intel Unlock block
#endif
*dev.addr = INTEL_BLOCK_ERASE_SETUP; // Intel erase setup
*dev.addr = INTEL_ERASE_CONFIRM; // Intel erase confirm
*dev.addr = INTEL_READ_STATUS;//fangcj added
int_enable(cpsr);
ffsdrv_intel_erase_end();
}
void ffsdrv_intel_erase_end(void)
{
uint16 status;
#if (BOARD == 46)
while ((*dev.addr & 0x80) == 0 && dev.state == DEV_ERASE)
;
#else
while ((*dev.addr & 0x80) == 0 &&
(dev.state == DEV_ERASE || dev.state == DEV_ERASE_SUSPEND))
;
#endif
#if (FLASH_STATUS_CHECK == 1)
*dev.addr = INTEL_READ_STATUS;
status = *dev.addr;
if (status != INTEL_STATE_MACHINE_DONE)
ttw(ttr(TTrFatal, "FATAL erase error 0x%x" NL, status));
#endif
*dev.addr = INTEL_READ_ARRAY; // Intel read array
dev.state = DEV_READ;
tlw(led_off(LED_ERASE));
}
void ffsdrv_intel_erase_suspend(void)
{
uint32 cpsr;
uint16 poll;
ttw(str(TTrDrvErase, "es" NL));
tlw(led_on(LED_ERASE_SUSPEND));
cpsr = int_disable();
dev.state = DEV_ERASE_SUSPEND;
*dev.addr = 0xB0; // Intel Erase Suspend
*dev.addr = 0x70; // Intel Read Status Register
while (((poll = *dev.addr) & 0x80) == 0)
;
if ((poll & 0x40) == 0) {
// Block erase has completed
tlw(led_off(LED_ERASE_SUSPEND));
dev.state = DEV_READ;
tlw(led_off(LED_ERASE));
}
*dev.addr = 0xFF; // Intel read array
int_enable(cpsr);
}
void ffsdrv_intel_erase_resume(void)
{
uint32 cpsr;
ttw(str(TTrDrvErase, "er" NL));
cpsr = int_disable();
dev.state = DEV_ERASE;
*dev.addr = 0xD0; // Intel erase resume
// The following "extra" Read Status command is required because Intel has
// changed the specification of the W30 flash! (See "1.8 Volt Intel?
// Wireless Flash Memory with 3 Volt I/O 28F6408W30, 28F640W30, 28F320W30
// Specification Update")
*dev.addr = 0x70; // Intel Read Status Register
int_enable(cpsr);
tlw(led_off(LED_ERASE_SUSPEND));
}
// NOTE this function has a little better performance than the
// generic_write() because it use less function pointers
void ffsdrv_intel_write(void *dst, const void *src, uint16 size)
{
uint8 *mydst = dst;
const uint8 *mysrc = src;
if (size > 0)
{
if ((unsigned int) mydst & 1) {
ffsdrv_write_byte(mydst++, *mysrc++);
size--;
}
while (size >= 2) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -