318 lines
6.5 KiB
C
318 lines
6.5 KiB
C
#include "halp.h"
|
|
#include "arccodes.h"
|
|
#include "flash8k.h"
|
|
|
|
#define I28F008SA_DEVICE_SIZE 0x100000
|
|
|
|
#define SET_READ_ARRAY 0xff
|
|
#define SET_BYTE_WRITE 0x40
|
|
#define SET_ERASE_BLOCK 0x20
|
|
#define CONFIRM_ERASE_BLOCK 0xd0
|
|
#define READ_STATUS 0x70
|
|
#define RESET_STATUS 0x50
|
|
#define ID_REQUEST 0x90
|
|
|
|
#define MANUFACTURER_ID 0x89
|
|
#define DEVICE_ID 0xa2
|
|
|
|
#define BLOCK_SIZE 0x10000
|
|
#define BLANK_DATA 0xff
|
|
|
|
#define TIMEOUT_VALUE 5000000
|
|
|
|
#define STATUS_READY 0x80
|
|
#define STATUS_ERASE_SUSP 0x40
|
|
#define STATUS_ERASE_ERR 0x20
|
|
#define STATUS_WRITE_ERR 0x10
|
|
#define STATUS_VPP_LOW 0x08
|
|
#define STATUS_CMD_SEQ_ERR (STATUS_WRITE_ERR | STATUS_READ_ERR)
|
|
|
|
//
|
|
// Local function prototypes
|
|
//
|
|
PFLASH_DRIVER
|
|
I28F008SA_Initialize(
|
|
IN PUCHAR NvRamPtr
|
|
);
|
|
|
|
ARC_STATUS
|
|
I28F008SA_SetReadMode(
|
|
IN PUCHAR Address
|
|
);
|
|
|
|
ARC_STATUS
|
|
I28F008SA_WriteByte(
|
|
IN PUCHAR Address,
|
|
IN UCHAR Data
|
|
);
|
|
|
|
ARC_STATUS
|
|
I28F008SA_EraseBlock(
|
|
IN PUCHAR Address
|
|
);
|
|
|
|
ARC_STATUS
|
|
I28F008SA_CheckStatus(
|
|
IN PUCHAR Address,
|
|
FLASH_OPERATIONS Operation
|
|
);
|
|
|
|
PUCHAR
|
|
I28F008SA_BlockAlign(
|
|
IN PUCHAR Address
|
|
);
|
|
|
|
UCHAR
|
|
I28F008SA_ReadByte(
|
|
IN PUCHAR Address
|
|
);
|
|
|
|
BOOLEAN
|
|
I28F008SA_OverwriteCheck(
|
|
IN UCHAR OldData,
|
|
IN UCHAR NewData
|
|
);
|
|
|
|
ULONG
|
|
I28F008SA_BlockSize(
|
|
IN PUCHAR Address
|
|
);
|
|
|
|
ULONG
|
|
I28F008SA_GetLastError(
|
|
VOID
|
|
);
|
|
|
|
static
|
|
VOID
|
|
I28F008SA_SetLastError(
|
|
ULONG FlashStatus
|
|
);
|
|
|
|
FLASH_DRIVER I28F008SA_DriverInformation = {
|
|
"Intel 28F008SA",
|
|
I28F008SA_SetReadMode, // SetReadModeFunction
|
|
I28F008SA_WriteByte, // WriteByteFunction
|
|
I28F008SA_EraseBlock, // EraseBlockFunction
|
|
I28F008SA_BlockAlign, // AlignBlockFunction
|
|
I28F008SA_ReadByte, // ReadByteFunction
|
|
I28F008SA_OverwriteCheck, // OverwriteCheckFunction
|
|
I28F008SA_BlockSize, // BlockSizeFunction
|
|
I28F008SA_GetLastError, // GetLastErrorFunction
|
|
I28F008SA_DEVICE_SIZE, // DeviceSize
|
|
BLANK_DATA // ErasedData
|
|
};
|
|
|
|
static ULONG I28F008SA_LastError;
|
|
|
|
PFLASH_DRIVER
|
|
I28F008SA_Initialize(
|
|
IN PUCHAR NvRamPtr
|
|
)
|
|
{
|
|
PFLASH_DRIVER ReturnDriver = NULL;
|
|
UCHAR ManufacturerID;
|
|
UCHAR DeviceID;
|
|
|
|
NvRamPtr = I28F008SA_BlockAlign(NvRamPtr);
|
|
|
|
WRITE_CONFIG_RAM_DATA(NvRamPtr, ID_REQUEST);
|
|
|
|
ManufacturerID = READ_CONFIG_RAM_DATA(NvRamPtr);
|
|
DeviceID = READ_CONFIG_RAM_DATA((PUCHAR)((ULONG)NvRamPtr + 1));
|
|
|
|
if ((ManufacturerID == MANUFACTURER_ID) && (DeviceID == DEVICE_ID)) {
|
|
I28F008SA_LastError = 0;
|
|
I28F008SA_SetReadMode(NvRamPtr);
|
|
ReturnDriver = &I28F008SA_DriverInformation;
|
|
}
|
|
|
|
return ReturnDriver;
|
|
}
|
|
|
|
ARC_STATUS
|
|
I28F008SA_SetReadMode(
|
|
IN PUCHAR NvRamPtr
|
|
)
|
|
{
|
|
WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_READ_ARRAY);
|
|
HalpMb();
|
|
|
|
return ESUCCESS;
|
|
}
|
|
|
|
ARC_STATUS
|
|
I28F008SA_WriteByte(
|
|
IN PUCHAR NvRamPtr,
|
|
IN UCHAR Data
|
|
)
|
|
{
|
|
ARC_STATUS ReturnStatus;
|
|
|
|
I28F008SA_SetReadMode(NvRamPtr);
|
|
|
|
WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_BYTE_WRITE);
|
|
WRITE_CONFIG_RAM_DATA(NvRamPtr, Data);
|
|
|
|
ReturnStatus = I28F008SA_CheckStatus(NvRamPtr, FlashByteWrite);
|
|
|
|
I28F008SA_SetReadMode(NvRamPtr);
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
ARC_STATUS
|
|
I28F008SA_EraseBlock (
|
|
IN PUCHAR NvRamPtr
|
|
)
|
|
{
|
|
ARC_STATUS ReturnStatus;
|
|
|
|
WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_ERASE_BLOCK);
|
|
WRITE_CONFIG_RAM_DATA(NvRamPtr, CONFIRM_ERASE_BLOCK);
|
|
|
|
ReturnStatus = I28F008SA_CheckStatus(NvRamPtr, FlashEraseBlock);
|
|
|
|
I28F008SA_SetReadMode(NvRamPtr);
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
ARC_STATUS
|
|
I28F008SA_CheckStatus (
|
|
IN PUCHAR NvRamPtr,
|
|
IN FLASH_OPERATIONS Operation
|
|
)
|
|
{
|
|
ARC_STATUS ReturnStatus = EIO;
|
|
ULONG Timeout;
|
|
UCHAR FlashStatus;
|
|
|
|
//
|
|
// Keep reading the status until the device is done with its
|
|
// current operation.
|
|
//
|
|
Timeout = TIMEOUT_VALUE;
|
|
do {
|
|
WRITE_CONFIG_RAM_DATA(NvRamPtr, READ_STATUS);
|
|
FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr);
|
|
KeStallExecutionProcessor(1);
|
|
Timeout--;
|
|
} while (((FlashStatus & 0x80) == 0) && (Timeout > 0));
|
|
|
|
//
|
|
// Check the status for the operation requested.
|
|
//
|
|
switch(Operation) {
|
|
case FlashByteWrite:
|
|
if ((FlashStatus & 0x18) == 0) {
|
|
ReturnStatus = ESUCCESS;
|
|
} else {
|
|
I28F008SA_SetLastError(FlashStatus & 0x18);
|
|
}
|
|
break;
|
|
case FlashEraseBlock:
|
|
if (((FlashStatus & 0x28) == 0) && ((FlashStatus & 0x30) != 0x30)) {
|
|
ReturnStatus = ESUCCESS;
|
|
} else {
|
|
I28F008SA_SetLastError(FlashStatus & 0x28);
|
|
}
|
|
break;
|
|
}
|
|
if ((FlashStatus & 0x80) == 0) {
|
|
ReturnStatus = EIO;
|
|
I28F008SA_SetLastError(0);
|
|
}
|
|
|
|
//
|
|
// Clear the flash status register
|
|
// This is a silent operation. The status that gets returned is the
|
|
// status of the real operation as determined above.
|
|
//
|
|
WRITE_CONFIG_RAM_DATA(NvRamPtr, RESET_STATUS);
|
|
Timeout = TIMEOUT_VALUE;
|
|
do {
|
|
WRITE_CONFIG_RAM_DATA(NvRamPtr, READ_STATUS);
|
|
FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr);
|
|
KeStallExecutionProcessor(1);
|
|
Timeout--;
|
|
} while (((FlashStatus & 0x80) == 0) && (Timeout > 0));
|
|
|
|
return ReturnStatus;
|
|
}
|
|
|
|
PUCHAR
|
|
I28F008SA_BlockAlign(
|
|
IN PUCHAR Address
|
|
)
|
|
{
|
|
return (PUCHAR)((ULONG)Address & ~(BLOCK_SIZE-1));
|
|
}
|
|
|
|
UCHAR
|
|
I28F008SA_ReadByte(
|
|
IN PUCHAR Address
|
|
)
|
|
{
|
|
return READ_CONFIG_RAM_DATA(Address);
|
|
}
|
|
|
|
BOOLEAN
|
|
I28F008SA_OverwriteCheck(
|
|
IN UCHAR OldData,
|
|
IN UCHAR NewData
|
|
)
|
|
/*++
|
|
|
|
Return Value:
|
|
|
|
Zero if OldData can be overwritten with NewData.
|
|
Non-zero if device must be erased to write NewData.
|
|
|
|
--*/
|
|
{
|
|
return (~OldData & NewData) ? FALSE : TRUE;
|
|
}
|
|
|
|
ULONG
|
|
I28F008SA_BlockSize(
|
|
IN PUCHAR Address
|
|
)
|
|
/*++
|
|
|
|
Return Value:
|
|
|
|
The block size of the device. This is a constant because all
|
|
blocks in the 28f008sa are the same size.
|
|
|
|
--*/
|
|
{
|
|
return BLOCK_SIZE;
|
|
}
|
|
|
|
ULONG
|
|
I28F008SA_GetLastError(
|
|
VOID
|
|
)
|
|
{
|
|
return I28F008SA_LastError;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
I28F008SA_SetLastError(
|
|
ULONG FlashStatus
|
|
)
|
|
{
|
|
I28F008SA_LastError = ERROR_UNKNOWN;
|
|
if (FlashStatus == 0)
|
|
I28F008SA_LastError = ERROR_TIMEOUT;
|
|
if (FlashStatus & STATUS_WRITE_ERR)
|
|
I28F008SA_LastError = ERROR_WRITE_ERROR;
|
|
if (FlashStatus & STATUS_ERASE_ERR)
|
|
I28F008SA_LastError = ERROR_ERASE_ERROR;
|
|
if (FlashStatus & STATUS_VPP_LOW)
|
|
I28F008SA_LastError = ERROR_VPP_LOW;
|
|
}
|
|
|