📄 amdflash.c
字号:
/*****************************************************************************
FILE NAME: AmdFlashDrv.c
DESCRIPTION:
For AMD Dual-bank flash.
Copyright (c) 2002, VIA Technologies, Inc.
*****************************************************************************/
#include "fsmdefs.h"
#include "fsmflash.h"
#include "amdflash.h"
#include "ostype.h"
#define BLOCK_SIZE 0x10000
#define FSM_DATA_BLOCKS 7
#define FSM_DATA_START_ADDR 0x07010000
#define COPY_BUFFER_SIZE 32
#define GET_MIN(a, b) (((a) < (b)) ? (a) : (b))
#define ALIGN_ADDRESS(addr) ((uint32) ((addr) & ((uint32) ~(sizeof(FLASH_DATA) - 1))))
#define UNALIGNED_BYTES(addr) ((uint32) ((addr) & ((uint32) (sizeof(FLASH_DATA) - 1))))
uint32 FsmAmdFlashInit(FsmDevObjHdrT * DevObjP);
uint32 FsmAmdFlashRead(FsmDevObjHdrT * DevObjP, uint8 * buf, uint32 Addr, uint32 length);
uint32 FsmAmdFlashWrite(FsmDevObjHdrT * DevObjP, uint8 * buf, uint32 Addr, uint32 length);
uint32 FsmAmdFlashErase(FsmDevObjHdrT * DevObjP, uint32 Addr);
uint32 FsmAmdFlashCopy(FsmDevObjHdrT * DevObjP, uint32 DstAddr, uint32 SrcAddr, uint32 length);
uint32 FsmAmdFlashCtrl(FsmDevObjHdrT * DevObjP, uint32 CtrlCode, void *arg);
/* =============== global variables ========================= */
const FsmDevDrvT AmdFlashDrv = \
{
FsmAmdFlashRead,
FsmAmdFlashWrite,
FsmAmdFlashCopy,
FsmAmdFlashErase,
FsmAmdFlashCtrl,
FsmAmdFlashInit
};
FsmFlashDevT FlashDev = /* Amd Flash Device */
{
{ (FsmDevDrvT *)&AmdFlashDrv, DEV_TYPE_FLASH, NULL },
NULL,
NULL,
BLOCK_SIZE,
FSM_DATA_BLOCKS,
FSM_DATA_START_ADDR
};
volatile uint8 FsmStarting = FALSE;
/*-------------------------------- Local Functions ------------------------------*/
/******************************************************************************
* PollWait()
*
* descriptions:
* The data polling bit, DQ7, indicates whether a program or erase operation
* is in progress or completed. While programming or erasure is in process
* DQ7 indicates the complement of the programmed data at bit 7. When the
* operation completes, DQ7 indicates the programmed data.
*
* parameters:
*
* p - Flash address for which poll wait status will be returned.
* Data - Data that was programmed to the flash (0xff for erase operations).
* EraseFlag - Flag indicating if the poll is on an erase or program operation.
*
* return:
* Poll wait status results. OKAY if the program/erase operation completes
* without a timeout condition. FAIL is returned otherwise.
*
*****************************************************************************/
static uint8 PollWait(volatile FLASH_DATA *p, FLASH_DATA Data)
{
FLASH_DATA dq7;
dq7 = Data & DQ7_MASK;
/*
Read the status word. If bit 7 doesn't match bit 7 of
the data that was programmed (or erased) then the operation
is not complete
*/
while (((*p) & DQ7_MASK) != dq7)
{
/*
If bit 5 goes high then the program or erase time has
exceeded a specified internal pulse count limit.
*/
if (((*p) & DQ5_MASK) != 0)
{
if (((*p) & DQ7_MASK) != dq7)
{
/* Reset the flash to read mode */
RESET_TO_READ(p);
return FALSE;
}
else
break;
}
}
return TRUE;
}
static BANK_STATUS BankEraseStatus(volatile FLASH_DATA *p)
{
FLASH_DATA old_dq_2_6;
FLASH_DATA new_dq_2_6;
FLASH_DATA dq_2_6_mask;
/* if(((*p) & DQ7_MASK) != 0)
{
return BANK_STATUS_READY;
} */
dq_2_6_mask = (DQ2_MASK | DQ6_MASK);
/*
Read the status word twice to check if the
bits (DQ2,DQ6) both toggles. If not both toggles,
then the earse operation is complete.
*/
old_dq_2_6 = (*p) & dq_2_6_mask;
new_dq_2_6 = (*p) & dq_2_6_mask;
if ((old_dq_2_6 ^ new_dq_2_6) == dq_2_6_mask)
{
/*
If toggles, then read status word again to check DQ5,
if it is low, then the erase operation is in progress.
if it is high, then it is timeout, we should check
toggle bits again.
*/
if (((*p) & DQ5_MASK) != 0)
{
old_dq_2_6 = (*p) & dq_2_6_mask;
new_dq_2_6 = (*p) & dq_2_6_mask;
/*
If these two bits toggle still even if timeout,
then we must write reset command to return to
reading array data.
*/
if ((old_dq_2_6 ^ new_dq_2_6) == dq_2_6_mask)
{
/*RESET_TO_READ(p);*/ /* SHOULD let the initiator know the timeout */
return BANK_STATUS_TIMEOUT;
}
else
return BANK_STATUS_READY;
}
else
return BANK_STATUS_BUSY;
}
return BANK_STATUS_READY;
}
static uint8 IsEraseSuspended(volatile FLASH_DATA *p)
{
FLASH_DATA old_dq_2_6;
FLASH_DATA new_dq_2_6;
if(((*p) & DQ7_MASK) == 0)
{
return FALSE;
}
/*
Read the status word twice to check if the
bits (DQ2,DQ6) both toggles. If not both toggles,
then the earse operation is complete.
*/
old_dq_2_6 = (*p) & (DQ2_MASK | DQ6_MASK);
new_dq_2_6 = (*p) & (DQ2_MASK | DQ6_MASK);
if ((old_dq_2_6 ^ new_dq_2_6) == DQ2_MASK)
{
return TRUE;
}
else
return FALSE;
}
static BANK_STATUS BankStatus(volatile FLASH_DATA *p)
{
FLASH_DATA old_dq_6;
FLASH_DATA new_dq_6;
/*
Read the status word twice to check if the
bits (DQ2,DQ6) both toggles. If not both toggles,
then the earse operation is complete.
*/
old_dq_6 = (*p) & DQ6_MASK;
new_dq_6 = (*p) & DQ6_MASK;
if ((old_dq_6 ^ new_dq_6) == DQ6_MASK)
{
/*
If toggles, then read status word again to check DQ5,
if it is low, then the erase operation is in progress.
if it is high, then it is timeout, we should check
toggle bits again.
*/
if (((*p) & DQ5_MASK) != 0)
{
old_dq_6 = (*p) & DQ6_MASK;
new_dq_6 = (*p) & DQ6_MASK;
/*
If these two bits toggle still even if timeout,
then we must write reset command to return to
reading array data.
*/
if ((old_dq_6 ^ new_dq_6) == DQ6_MASK)
{
/* RESET_TO_READ(p); */ /* SHOULD let the initiator know the timeout */
return BANK_STATUS_TIMEOUT;
}
else
return BANK_STATUS_READY;
}
else
return BANK_STATUS_BUSY;
}
return BANK_STATUS_READY;
}
/******************************************************************************
* WriteToFlash()
*
* descriptions:
* Writes data to flash.
*
* parameters:
* FLASH_DATA_PTR dst_ptr - A pointer to the data destination.
* FLASH_DATA_PTR src_ptr - A pointer to the data source.
* uint32 size - The number of FLASH_DATA units to write.
*
* return:
* If any portion of the data is not written successfully, the function
* returns HW_ERR_WRITE; otherwise, the function returns HW_ERR_NONE.
*
*****************************************************************************/
static uint32 WriteToFlash(
volatile FLASH_DATA * flash_ptr,
const FLASH_DATA * ram_ptr,
uint32 size,
uint32 start_addr
)
{
uint8 bRet;
while (size > 0)
{
/* If try to program data bit from 0 to 1. */
if(((*ram_ptr) & (~(*flash_ptr))) != 0)
{
return HW_ERR_WRITE;
}
/* If the result data is not equal to original. */
else if((*ram_ptr) != (*flash_ptr))
{
/* write to flash */
DISABLE_INTERRUPTS();
WRITE_FLASH(flash_ptr, *ram_ptr, start_addr);
ENABLE_INTERRUPTS();
/* wait until flash is done */
bRet = PollWait(flash_ptr, *ram_ptr);
RESET_TO_READ(flash_ptr); /* perhaps it is superfluous for AMD flash. */
/* check for errors */
if (!bRet)
{
return HW_ERR_WRITE;
}
}
/* If the result data is equal to original. */
else
{
}
/* update pointers */
flash_ptr++;
ram_ptr++;
size--;
}
return HW_ERR_NONE;
}
/*----------------------- Global Functions ---------------------*/
/******************************************************************************
* FsmAmdFlashInit()
*
* descriptions:
* reset flash device to read-mode.
*
* parameters:
* FsmDevObjHdrT * DevObjP - device object
*
* return:
* HW_ERR_NONE.
*
*****************************************************************************/
uint32 FsmAmdFlashInit(FsmDevObjHdrT * DevObjP)
{
volatile FLASH_DATA_PTR dst_data_ptr;
FsmFlashDevT * pDev;
pDev = (FsmFlashDevT *)DevObjP;
dst_data_ptr = (volatile FLASH_DATA_PTR)(pDev->DevStartAddr);
RESET_TO_READ(dst_data_ptr);
return HW_ERR_NONE;
}
/******************************************************************************
* FsmAmdFlashWrite()
*
* descriptions:
* write data to flash.
*
* parameters:
* FsmDevObjHdrT * DevObjP - device object
* uint8 * buf - buffer contains the data to be written.
* uint32 Addr - the destination address within flash device.
* uint32 length - The amount of data, in bytes, to be written.
*
* return:
* HW_ERR_NONE, HW_ERR_SYSTEM, HW_ERR_PARAM, HW_ERR_WRITE.
*
*****************************************************************************/
uint32 FsmAmdFlashWrite(FsmDevObjHdrT * DevObjP, uint8 * buf, uint32 Addr, uint32 length)
{
volatile FLASH_DATA_PTR dst_data_ptr;
FLASH_DATA temp_buffer[COPY_BUFFER_SIZE / sizeof(FLASH_DATA)];
uint8 * dst_byte_ptr;
uint8 * src_byte_ptr;
uint32 dst_offset;
uint32 byte_size;
uint32 data_size;
uint32 status = HW_ERR_NONE;
uint32 rem_byte_size;
uint8 suspended = (uint8)FALSE;
BANK_STATUS bank_status;
FsmFlashDevT * pDev;
pDev = (FsmFlashDevT *)DevObjP;
/* validate address */
#ifdef VALIDATE_ADDRESS
if((Addr + length) > (pDev->BlockSize * pDev->Blocks))
{
return HW_ERR_PARAM;
}
#endif /* VALIDATE_ADDRESS */
Addr += pDev->DevStartAddr;
/* return if nothing to write */
if (length == 0)
{
return HW_ERR_NONE;
}
dst_data_ptr = (volatile FLASH_DATA_PTR) ALIGN_ADDRESS(Addr);
dst_offset = UNALIGNED_BYTES(Addr);
dst_byte_ptr = (uint8 *) temp_buffer + dst_offset;
data_size = COPY_BUFFER_SIZE - dst_offset;
src_byte_ptr = buf;
/* get flash write mutex. */
if(FsmGetMtxSem(pDev->DevWriteLock) != ERR_NONE)
{
if(FsmStarting == FALSE)
return HW_ERR_SYSTEM;
}
/* suspend if flash is busy erasing */
bank_status = BankEraseStatus(dst_data_ptr);
if (bank_status == BANK_STATUS_BUSY)
{
ERASE_SUSPEND(dst_data_ptr);
PollWait(dst_data_ptr, FLASH_ERASE_DATA);
if (IsEraseSuspended(dst_data_ptr))
{
suspended = (uint8) TRUE;
}
}
else if (bank_status == BANK_STATUS_TIMEOUT)
{
/*
we SHOULD delay some time to let the
erase initiator know what has happened.
*/
TASK_SLEEP(100);
RESET_TO_READ(dst_data_ptr);
}
else
{
/* The bank is ready */
}
while ((length > 0) && (status == HW_ERR_NONE))
{
/* */
byte_size = GET_MIN(data_size, length);
/* calculate the number of FLASH_DATA to write */
data_size = (byte_size + dst_offset + sizeof(FLASH_DATA) - 1) /
sizeof(FLASH_DATA);
/* For AMD flash device, if you attempt to program a bit
* from 0 to 1, device will timeout, so we can't initialize
* the leader spare area to 0xFF, we must read data from
* flash to initialize these bytes, the same to the remainder
* area for the buffer.
*/
RESET_TO_READ(dst_data_ptr);
if(dst_offset != 0)
{
FsmMemoryMove((uint8 *)temp_buffer, (uint8 *)dst_data_ptr, dst_offset);
}
rem_byte_size = (byte_size + dst_offset) % (sizeof(FLASH_DATA));
if(rem_byte_size != 0)
{
FsmMemoryMove(((uint8 *)temp_buffer) + byte_size + dst_offset, \
((uint8 *)dst_data_ptr) + byte_size + dst_offset, \
sizeof(FLASH_DATA) - rem_byte_size
);
}
FsmMemoryMove(dst_byte_ptr, src_byte_ptr, (uint16)byte_size);
/* write buffer */
status = WriteToFlash(dst_data_ptr, temp_buffer, data_size, pDev->DevStartAddr);
/* update pointers/variables */
dst_data_ptr += data_size;
dst_byte_ptr = (uint8 *) temp_buffer;
src_byte_ptr += byte_size;
length -= byte_size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -