NT4/private/ntos/nthals/halalpha/28f008sa.c
2020-09-30 17:12:29 +02:00

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;
}