📄 drv.c
字号:
cpsr=int_disable();
/*LOCOSTO-Live Unlock Fix */
flash[0]=0x0f0;
flash[0]= 0x0060; // sector unlock sequence
flash[0]= 0x0060; // sector unlock sequence
flash[unlockOffset]= 0x0060; // sector unlock sequence (address 6 = VIH)
flash[0]=0x0f0;
/* sector erase command -- 6 cycles */
flash[0x555] =0xAA;
flash[0x2AA]=0x55;
flash[0x555]=0x80;
flash[0x555]= 0xAA;
flash[0x2AA]=0x55;
*((volatile uint16*)(dev.addr))=0x30; /* write the command to sector address */
/* Enable the interrupts */
//CQ62129 start - new while loop added
// delay re-enabling until after sector erased or we have an int to service
/* Wait for the erase to complete */
while ((*dev.addr & 0x80) == 0) /* DQ7 will have 1 on completion of erase */ /* Data polling */
// add option to suspend if a frame interrupt occurs, same as old AMD single bank driver
{ // Poll interrupts, taking interrupt mask into account and check if IRQ was actually enabled
if ((INT_REQUESTED) && !(cpsr & ~0x80))
{
// 1. suspend erase
// 2. enable interrupts
// .. now the interrupt code executes
// 3. disable interrupts
// 4. resume erase
// Suspend erase
*((volatile uint16*)(dev.addr)) = 0xB0;
// wait for erase suspend to finish
while ((*((volatile uint16*)(dev.addr)) & 0x80) == 0);
dev.state = DEV_ERASE_SUSPEND;
int_enable(cpsr);
// Other interrupts and tasks run now...
cpsr=int_disable();
// Before resuming erase we must? check if the erase is really
// suspended or if it did finish
*((volatile uint16*)(dev.addr)) = 0x30;
dev.state = DEV_ERASE;
}
}
int_enable(cpsr);
//CQ62129 end
ttw(ttr(TTrDrvErase, "}" NL));
/* change the device state to default READ mode */
dev.state=DEV_READ;
}
void ffsdrv_amd_fg_write_suspend(void)
{
OS_LOCK_MUTEX(&ffs_write_mutex);
/* Got the Mutex Write Got over */
OS_UNLOCK_MUTEX(&ffs_write_mutex);
}
void ffsdrv_amd_mb_write_halfword(volatile uint16 *addr, uint16 value)
{
volatile uint16 *flash = (volatile uint16*)dev.base;
uint32 cpsr;
uint8 * offset;
uint32 unlockOffset;
static int badFlashCount=0;
unsigned short temp1;
offset = (uint8*)addr - (uint32)(dev.base);
unlockOffset = (dev.binfo[offset2block(offset)].offset+ 0x80)>>1;
/* device state is write state */
OS_LOCK_MUTEX(&ffs_write_mutex);
dev.state=DEV_WRITE;
/* Dissable the interrupts */
cpsr=int_disable();
temp1 = (*addr);
redowrite:
flash[0]=0x0f0;
/* two unlock cycles */
flash[0x555]=0xAA;
flash[0x2AA]=0x55;
/* issue the program command now */
flash[0x555]=0xA0;
dev.addr=addr; /* record the last write */
dev.data=value;
*addr = value; /* this will be base+offset */
/* Enable the interrupts */
int_enable(cpsr);
/* Wait for the write to complete */
while (1)
{
unsigned short temp= (*addr);
badFlashCount++;
if(!((temp ^ dev.data) & 0x80))
break;
else if ((temp & 0x20))
{
if((((*addr) ^ dev.data) & 0x80))
goto redowrite;
break;
}
else
continue;
}/* Data polling */
/* change the state to default read mode */
dev.state=DEV_READ;
OS_UNLOCK_MUTEX(&ffs_write_mutex);
}
void ffsdrv_amd_mb_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_mb_write_halfword((uint16 *) mydst,
mysrc[0] | (mysrc[1] << 8));
size -= 2;
mysrc += 2;
mydst += 2;
}
if (size == 1)
ffsdrv_write_byte(mydst++, *mysrc++);
}
}
void ffsdrv_amd_mb_erase(uint8 block)
{
volatile uint16 *flash = (volatile uint16*)dev.base;
uint32 cpsr;
uint32 unlockOffset;
dev.addr = (uint16 *) block2addr(block);
unlockOffset = ((uint32)(dev.addr)-(uint32)(dev.base) + 0x80) >> 1;
/* change the device status */
dev.state=DEV_ERASE;
/* disable the interrupts */
cpsr=int_disable();
/* sector erase command -- 6 cycles */
flash[0x555] =0xAA;
flash[0x2AA]=0x55;
flash[0x555]=0x80;
flash[0x555]= 0xAA;
flash[0x2AA]=0x55;
*((volatile uint16*)(dev.addr))=0x30; /* write the command to (short) sector address */
/* Enable the interrupts */
//CQ72069 start - new while loop added
// delay re-enabling until after sector erased or we have an int to service
/* Wait for the erase to complete */
while ((*dev.addr & 0x80) == 0) /* DQ7 will have 1 on completion of erase */ /* Data polling */
// add option to suspend if a frame interrupt occurs, same as old AMD single bank driver
{ // Poll interrupts, taking interrupt mask into account and check if IRQ was actually enabled
if ((INT_REQUESTED) && !(cpsr & ~0x80))
{
// 1. suspend erase
// 2. enable interrupts
// .. now the interrupt code executes
// 3. disable interrupts
// 4. resume erase
// Suspend erase
*((volatile uint16*)(dev.addr)) = 0xB0;
// wait for erase suspend to finish
while ((*((volatile uint16*)(dev.addr)) & 0x80) == 0);
dev.state = DEV_ERASE_SUSPEND;
int_enable(cpsr);
// Other interrupts and tasks run now...
cpsr=int_disable();
// Before resuming erase we must? check if the erase is really
// suspended or if it did finish
*((volatile uint16*)(dev.addr)) = 0x30;
dev.state = DEV_ERASE;
}
}
int_enable(cpsr);
//CQ72069 end
ttw(ttr(TTrDrvErase, "}" NL));
/* change the device state to default READ mode */
dev.state=DEV_READ;
}
void ffsdrv_amd_mb_erase_sector(void *dst)
{
volatile uint16 *flash;
uint32 cpsr;
dev.addr = (uint16 *) dst;
flash= dev.addr;
/* change the device status */
dev.state=DEV_ERASE;
OS_LOCK_MUTEX(&ffs_write_mutex);
/* disable the interrupts */
cpsr=int_disable();
/* sector erase command -- 6 cycles */
flash[0x555] =0xAA;
flash[0x2AA]=0x55;
flash[0x555]=0x80;
flash[0x555]= 0xAA;
flash[0x2AA]=0x55;
*((volatile uint16*)(dev.addr))=0x30; /* write the command to sector address */
/* Enable the interrupts */
int_enable(cpsr);
/* Wait for the erase to complete */
while ((*dev.addr & 0x80) == 0); /* DQ7 will have 1 on completion of erase */ /* Data polling */
/* change the device state to default READ mode */
dev.state=DEV_READ;
}
void ffsdrv_amd_mb_write_erase_suspend(void)
{
uint32 cpsr;
tlw(led_on(LED_ERASE_SUSPEND));
ttw(str(TTrDrvErase, "es" NL));
// if erase has finished then all is ok
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, */
/* becose DQ7==1 on entering to erase suspend mode */
;
int_enable(cpsr);
}
void ffsdrv_amd_write_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));
}
void ffsdrv_amd_mb_buffer_write(void *dst, const void *src, uint16 size)
{
uint8 *mydst = dst;
const uint8 *mysrc = src;
uint8 unalignedbytes = 0;
uint16 sizeEven;
// use halfword write for size less than 32 bytes
if (size <= 32)
{
if ((unsigned int) mydst & 1) {
ffsdrv_write_byte(mydst++, *mysrc++);
size--;
}
while (size >= 2)
{
ffsdrv_amd_mb_write_halfword((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8));
size -= 2;
mysrc += 2;
mydst += 2;
}
if (size == 1)
{
ffsdrv_write_byte(mydst++, *mysrc++);
size--;
}
}
// If size is more than 32 bytes then go for write buffer feature
else if (size > 32)
{
// if the destination addredd is odd, write first byte in that.
if ((unsigned int) mydst & 1) {
ffsdrv_write_byte(mydst++, *mysrc++);
size--;
}
// write unaligned bytes in the write buffer page, since write buffer feature does not allow
// write across write buffer boundaries and write can not start in the midded of the write buffer page.
unalignedbytes = (0x20 - (unsigned int) mydst & 0x0000001F);
if(unalignedbytes > 0)
{
while (unalignedbytes > 0)
{
ffsdrv_amd_mb_write_halfword((uint16 *) mydst, mysrc[0] | (mysrc[1] << 8));
size -= 2;
mysrc += 2;
mydst += 2;
unalignedbytes -= 2;
}
}
// Write data using buffer write function
if (size >=2)
{
// Truncate to an even number of bytes
sizeEven = size & (uint16) ~1;
// write the data using write buffer feature
ffsdrv_amd_mb_buffer_write_new((uint16 *) mydst, mysrc, sizeEven);
size -=sizeEven;
mysrc += sizeEven;
mydst += sizeEven;
}
// Write Last byte
if(size==1 )
{
ffsdrv_write_byte(mydst++, *mysrc++);
size--;
}
}
}
void ffsdrv_amd_mb_buffer_write_new(volatile UINT16 *dst_addr, const UINT8 *src_addr, UINT16 size)
{
volatile uint16 *flash = (volatile uint16*)dev.base;
volatile UINT16 *dst_ptr;
const UINT8 *src_ptr;
volatile UINT16 *last_loaded_addr;
UINT16 write_data;
UINT32 word_count;
UINT32 word_size = size >> 1;
uint32 cpsr;
static int badFlashCount=0;
dst_ptr=dst_addr;
src_ptr=src_addr;
OS_LOCK_MUTEX(&ffs_write_mutex);
dev.state=DEV_WRITE;
cpsr=int_disable();
// two unlock cycles
flash[0x555]=0xAA;
flash[0x2AA]=0x55;
// Unlock Bypass
flash[0x555]=0x20;
int_enable(cpsr);
while (word_size >0)
{
cpsr=int_disable();
// maximum 16 words can be written using write buffer
word_count = 16;
if (word_count > word_size)
{
word_count = word_size;
}
word_size -= word_count;
redowrite_buf:
flash[0]=0x0f0;
/* Write to Buffer Command */
FLASH_WRITE(dst_ptr, 0x25);
dev.addr=dst_ptr;
dev.data=src_ptr[0] | (src_ptr[1] << 8);
/* Write number of locations to program */
FLASH_WRITE(dst_ptr, word_count - 1);
/* Load data into buffer */
while (word_count > 0)
{
/* Store last loaded address and data value (for polling) */
last_loaded_addr = dst_ptr;
write_data = src_ptr[0] | (src_ptr[1] << 8);
/* Write Data */
*dst_ptr=write_data;
dst_ptr++;
src_ptr +=2;
word_count--;
}
/* Program Buffer to Flash Command */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -