NT4/private/ntos/nthals/halalpha/am29f400.c

544 lines
11 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 1995 Digital Equipment Corporation
Module Name:
am29f400.c
Abstract:
This module contains the platform independent code to access the AMD
flash ROM part AM29F400.
Author:
Wim Colgate, 5/12/95
Environment:
Firmware/Kernel mode
Revision History:
--*/
#include "halp.h"
#include "arccodes.h"
#include <flash8k.h>
#include "flashbus.h"
#include "am29f400.h"
//
// External prototypes
//
VOID pWriteFlashByte(
IN ULONG FlashOffset,
IN UCHAR Data
);
UCHAR pReadFlashByte(
IN ULONG FlashOffset
);
//
// Local function prototypes
//
PFLASH_DRIVER
Am29F400_Initialize(
IN ULONG FlashOffset
);
ARC_STATUS
Am29F400_SetReadMode(
IN PUCHAR FlashOffset
);
ARC_STATUS
Am29F400_WriteByte(
IN PUCHAR FlashOffset,
IN UCHAR Data
);
ARC_STATUS
Am29F400_EraseSector(
IN PUCHAR FlashOffset
);
ARC_STATUS
Am29F400_CheckStatus(
IN PUCHAR FlashOffset,
IN FLASH_OPERATIONS Operation,
IN UCHAR OptionalData
);
PUCHAR
Am29F400_SectorAlign(
IN PUCHAR FlashOffset
);
UCHAR
Am29F400_ReadByte(
IN PUCHAR FlashOffset
);
BOOLEAN
Am29F400_OverwriteCheck(
IN UCHAR OldData,
IN UCHAR NewData
);
ULONG
Am29F400_SectorSize(
IN PUCHAR FlashOffset
);
FLASH_DRIVER Am29F400_DriverInformation = {
"AMD Am29F400",
Am29F400_SetReadMode, // SetReadModeFunction
Am29F400_WriteByte, // WriteByteFunction
Am29F400_EraseSector, // EraseSectorFunction
Am29F400_SectorAlign, // AlignSectorFunction
Am29F400_ReadByte, // ReadByteFunction
Am29F400_OverwriteCheck, // OverwriteCheckFunction
Am29F400_SectorSize, // SectorSizeFunction
// NULL, // Get last error
Am29F400_DEVICE_SIZE, // DeviceSize
Am29F400_ERASED_DATA // What an erased data looks like
};
//
// This variable tells us which bank of 8K 'nvram' are we using
// The LX3 nvram is actually two separate 8K sections of the FLASH ROM.
// One living at 0x4000, the other at 0x6000.
//
// This is NOT a QVA (which will is aliased by HalpCMOSBase in common
// code. Rather it is an offset within the FLASH ROM where the NVRAM lives.
//
extern PVOID HalpCMOSRamBase;
ULONG Am29F400NVRAMBase;
static UCHAR am29F400_GetSectorNumber(
IN PUCHAR FlashOffset
)
/*++
Routine Description:
This routine figures out which sector number we are in (for use in
clearing the sector...)
Arguments:
FlashOffset - offset within the flash ROM.
Return Value:
The sector number within the range of the offset.
--*/
{
ULONG Offset = (ULONG)FlashOffset;
if (Offset < SECTOR_1_BASE) {
return 0;
} else if (Offset < SECTOR_2_BASE) {
return 1;
} else if (Offset < SECTOR_3_BASE) {
return 2;
} else if (Offset < SECTOR_4_BASE) {
return 3;
} else {
//
// All other sectors are 0x10000, 0x20000, etc, so shift right by 64K,
// Then add the preceding section offset's
//
return (UCHAR)((Offset >> 16) + 3);
}
return 0;
}
PFLASH_DRIVER
Am29F400_Initialize(
IN ULONG FlashOffset
)
/*++
Routine Description:
This routine spanks the FLASH ROM with the auto select command, which
allows us to make sure that the device is what we think it is.
Arguments:
FlashOffset - offset within the flash ROM.
Return Value:
NULL for no driver, or the address of the FLASH_DRIVER structure for
this driver.
--*/
{
PFLASH_DRIVER ReturnDriver = NULL;
UCHAR ManufacturerID;
UCHAR DeviceID;
UCHAR temp;
Am29F400_SetReadMode((PUCHAR)SECTOR_2_BASE); // first 8K section (NVRAM)
HalpStallExecution(50); // wkc -- GACK! what a bogus part
pWriteFlashByte(COMMAND_ADDR1, COMMAND_DATA1);
pWriteFlashByte(COMMAND_ADDR2, COMMAND_DATA2);
pWriteFlashByte(COMMAND_ADDR3, COMMAND_DATA3_AUTOSELECT);
//
// Get manufacturer and device ID. Note spec says device ID lives
// at byte 1, but empirical evidence says it is at byte 2.
//
ManufacturerID = Am29F400_ReadByte((PUCHAR)0x00);
DeviceID = Am29F400_ReadByte((PUCHAR)0x02);
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("Manufacturer ID (expect 0x1) %x\n", ManufacturerID);
DbgPrint("Device ID (expect 0xab) %x\n", DeviceID);
#endif
if ((ManufacturerID == MANUFACTURER_ID) && (DeviceID == DEVICE_ID)) {
Am29F400_SetReadMode(0x0);
Am29F400_SetReadMode((PUCHAR)SECTOR_2_BASE);
// wkcfix -- check which NVRAM section we should use.
// currently use the first one setup in the HalpMapIoSpace() routine.
Am29F400NVRAMBase = (ULONG)HalpCMOSRamBase;
ReturnDriver = &Am29F400_DriverInformation;
}
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
if (ReturnDriver == NULL) {
DbgPrint("FLASH part unknown; AMD Am29F400 not loaded\n");
}
#endif
return ReturnDriver;
}
ARC_STATUS
Am29F400_SetReadMode(
IN PUCHAR FlashOffset
)
/*++
Routine Description:
This routine spanks the FLASH ROM with the read reset routine.
Arguments:
FlashOffset - offset within the flash ROM -- but not used.
Return Value:
The value of the check status routine (EIO or ESUCCESS)
--*/
{
pWriteFlashByte((ULONG)FlashOffset, COMMAND_READ_RESET);
return ESUCCESS;
}
ARC_STATUS
Am29F400_WriteByte(
IN PUCHAR FlashOffset,
IN UCHAR Data
)
/*++
Routine Description:
This routine spanks the FLASH ROM with the program command, then calls
the check status routine -- then resets the device to read.
Arguments:
FlashOffset - offset within the flash ROM.
Data - the data byte to write.
Return Value:
The value of the check status routine (EIO or ESUCCESS)
--*/
{
ARC_STATUS ReturnStatus;
pWriteFlashByte(COMMAND_ADDR1, COMMAND_DATA1);
pWriteFlashByte(COMMAND_ADDR2, COMMAND_DATA2);
pWriteFlashByte(COMMAND_ADDR3, COMMAND_DATA3_PROGRAM);
ASSERT((FlashOffset >= (PUCHAR)0x4000) && (FlashOffset < (PUCHAR)0x8000));
pWriteFlashByte((ULONG)FlashOffset, Data);
ReturnStatus = Am29F400_CheckStatus(FlashOffset, FlashByteWrite, Data);
Am29F400_SetReadMode(FlashOffset);
return ReturnStatus;
}
ARC_STATUS
Am29F400_EraseSector(
IN PUCHAR FlashOffset
)
/*++
Routine Description:
This routine spanks the FLASH ROM with the erase sector command, then calls
the check status routine
Arguments:
FlashOffset - offset within the flash ROM.
Return Value:
The value of the check status routine (EIO or ESUCCESS)
--*/
{
ARC_STATUS ReturnStatus;
UCHAR ReadBack;
ULONG Count = MAX_FLASH_READ_ATTEMPTS;
Am29F400_SetReadMode(FlashOffset);
pWriteFlashByte(COMMAND_ADDR1, COMMAND_DATA1);
pWriteFlashByte(COMMAND_ADDR2, COMMAND_DATA2);
pWriteFlashByte(COMMAND_ADDR3, COMMAND_DATA3);
pWriteFlashByte(COMMAND_ADDR4, COMMAND_DATA4);
pWriteFlashByte(COMMAND_ADDR5, COMMAND_DATA5);
pWriteFlashByte((ULONG)FlashOffset, COMMAND_DATA6_SECTOR_ERASE);
HalpStallExecution(80); // short stall for erase command to take
ReturnStatus = Am29F400_CheckStatus(FlashOffset,
FlashEraseSector,
0xff);
Am29F400_SetReadMode(FlashOffset);
return ReturnStatus;
}
ARC_STATUS
Am29F400_CheckStatus (
IN PUCHAR FlashOffset,
IN FLASH_OPERATIONS Operation,
IN UCHAR OptionalData
)
/*++
Routine Description:
This routine checks the status of the flashbus operation. The operation
may be specific, so different actions may be taken.
Arguments:
FlashOffset - offset within the flash ROM.
Opertaion - the operation performed on the FlashOffset.
OptionalData - an optional data value that may be needed for verification.
Return Value:
EIO for faiure
ESUCCESS for success
--*/
{
ARC_STATUS ReturnStatus = EIO;
UCHAR FlashRead;
ULONG Count = 0;
ULONG DataOK = FALSE;
while ((DataOK == FALSE) && (Count < MAX_FLASH_READ_ATTEMPTS)) {
FlashRead = Am29F400_ReadByte(FlashOffset);
//
// Both FlashByteWrite & FlashEraseBlock checks use polling
// algorithm found on page 1-131 of the AMD part specification
//
if ((FlashRead & 0x80) == (OptionalData & 0x80)) {
DataOK = TRUE;
} else if (FlashRead & 0x20) {
FlashRead = Am29F400_ReadByte(FlashOffset);
if ((FlashRead & 0x80) == (OptionalData & 0x80)) {
DataOK = TRUE;
} else {
break;
}
}
Count++;
}
if (DataOK == TRUE) {
ReturnStatus = ESUCCESS;
}
return ReturnStatus;
}
PUCHAR
Am29F400_SectorAlign(
IN PUCHAR FlashOffset
)
/*++
Routine Description:
This routine returns the base offset that the current offset within
a sector of the flash ROM.
Arguments:
FlashOffset - offset within the flash ROM.
Return Value:
The base offset of the current sector -- as defined by the FlashOffset.
--*/
{
ULONG Offset = (ULONG)FlashOffset;
if (Offset < SECTOR_2_BASE) {
return (PUCHAR)SECTOR_1_BASE;
} else if (Offset < SECTOR_3_BASE) {
return (PUCHAR)SECTOR_2_BASE;
} else if (Offset < SECTOR_4_BASE) {
return (PUCHAR)SECTOR_3_BASE;
} else if (Offset < SECTOR_5_BASE) {
return (PUCHAR)SECTOR_4_BASE;
} else {
return (PUCHAR)(ULONG)(Offset & ~(SECTOR_5_SIZE-1));
}
}
UCHAR
Am29F400_ReadByte(
IN PUCHAR FlashOffset
)
/*++
Routine Description:
This routine spanks the FLASH ROM with the read command, then calls
the read flash bus function.
Arguments:
FlashOffset - offset within the flash ROM.
Return Value:
The character at the appropriate location.
--*/
{
UCHAR ReturnVal;
//
// Assume Read mode is on
//
ReturnVal = pReadFlashByte((ULONG)FlashOffset);
return ReturnVal;
}
BOOLEAN
Am29F400_OverwriteCheck(
IN UCHAR OldData,
IN UCHAR NewData
)
/*++
Routine Description:
This routine returns if we can safely overwrite an existing data
with new data. Flash Rom's can go from 1-->1, 1-->0 and 0-->0, but
cannot go from 0-->1.
Return Value:
TRUE if we can safely overwrite
FALSE if we cannot safely overwrite
--*/
{
return ((NewData & ~OldData) == 0) ? TRUE: FALSE;
}
ULONG
Am29F400_SectorSize(
IN PUCHAR FlashOffset
)
/*++
Routine Description:
This routine returns the size of the sector that the offset is within.
Arguments:
FlashOffset - offset within the flash ROM.
Return Value:
The block size of the sector.
--*/
{
if (FlashOffset < (PUCHAR)SECTOR_2_BASE) {
return SECTOR_1_SIZE;
} else if (FlashOffset < (PUCHAR)SECTOR_3_BASE) {
return SECTOR_2_SIZE;
} else if (FlashOffset < (PUCHAR)SECTOR_4_BASE) {
return SECTOR_3_SIZE;
} else if (FlashOffset < (PUCHAR)SECTOR_5_BASE) {
return SECTOR_4_SIZE;
} else {
return SECTOR_5_SIZE;
}
}