519 lines
12 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 1994 Digital Equipment Corporation
Module Name:
flash8k.c
Abstract:
This module implements the flash-specific, device-independent routines
necessary to Read and Write the flash ROM containing the system environment
variables. The routines implemented here are:
HalpReadNVRamBuffer() - copy data from Flash into memory
HalpWriteNVRamBuffer() - write memory data to Flash
HalpCopyNVRamBuffer() - stubbed for compatibility with NVRAM
Author:
Steve Brooks 5-Oct 93
Revision History:
Wim Colgate 1-May-1995
Added LX3 specfic code for Bankset 8 mumbo-jumbo for the LX3 specific
'Flash Bus'.
--*/
#include "halp.h"
#include "pflash.h"
#include "flash8k.h"
#include "arccodes.h"
//
// To access the flash bus, one needs to enable the bankset 8 in
// the APECS chipset.
//
#define BANKSET8_CONFIGURATION_REGISTER HAL_MAKE_QVA( 0x180000B00 )
#define BANKSET8_ENABLE 0x1
#define STALL_VALUE 16
//
// 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 0x8000.
//
// This 'base' is not a QVA as in other platforms -- rather it is a base
// index off of the FLASH ROM device (0-512K).
extern ULONG Am29F400NVRAMBase;
//
// Variables:
//
// PFLASH_DRIVER HalpFlashDriver
// Pointer to the device-specific flash driver.
//
PFLASH_DRIVER HalpFlashDriver = NULL;
//
// Flash Drivers
//
// Each platform which uses this module must define FlashDriverList as an
// array of pointers to the initialize functions of any flash drivers for
// which the flash device might be used for the environment in the system.
//
extern PFLASH_DRIVER (*FlashDriverList[])(ULONG);
//
// Local function prototypes.
//
ARC_STATUS
HalpReadNVRamBuffer (
OUT PCHAR DataPtr,
IN PCHAR NvRamOffset,
IN ULONG Length
);
ARC_STATUS
HalpWriteNVRamBuffer (
IN PCHAR NvRamOffset,
IN PCHAR DataPtr,
IN ULONG Length
);
ARC_STATUS
HalpCopyNVRamBuffer (
IN PCHAR NvDestPtr,
IN PCHAR NvSrcPtr,
IN ULONG Length
);
PFLASH_DRIVER
HalpInitializeFlashDriver(
IN ULONG NvRamOffset
);
#ifdef AXP_FIRMWARE
#pragma alloc_text(DISTEXT, HalpReadNVRamBuffer )
#pragma alloc_text(DISTEXT, HalpWriteNVRamBuffer )
#pragma alloc_text(DISTEXT, HalpCopyNVRamBuffer )
#pragma alloc_text(DISTEXT, HalpInitializeFlashDriver )
#endif
ARC_STATUS HalpReadNVRamBuffer (
OUT PCHAR DataPtr,
IN PCHAR NvRamOffset,
IN ULONG Length )
/*++
Routine Description:
This routine Reads data from the NVRam into main memory
Arguments:
DataPtr - Pointer to memory location to receive data
NvRamOffset- NVRam offset to read data from
Length - Number of bytes of data to transfer
Return Value:
ESUCCESS if the operation succeeds.
ENODEV if no flash driver is loaded
E2BIG if we attempt to read beyond the end of the NVRAM location
--*/
{
ULONG CsrMask;
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("HalpReadNVRamBuffer(%08x, %08x, %d)\r\n",(ULONG)DataPtr,
NvRamOffset, Length);
#endif
//
// If there is no flash driver, return an error.
//
if ((HalpFlashDriver == NULL) &&
((HalpFlashDriver =
HalpInitializeFlashDriver((ULONG)NvRamOffset)) == NULL)) {
return ENODEV;
}
//
// Check to see if we will read beyond the bounds...
// (normalize offset - base + length)
//
if (NvRamOffset - Am29F400NVRAMBase + Length > (PUCHAR)NVRAM1_SECTOR_SIZE) {
return E2BIG;
}
//
// Adjust the offset by the NVRAM Base -- The NVRAM Offset is going
// to be 0-8K. The Base is where in the FLASH ROM the NVRAM is located.
// Since these routines are going to call the lower FLASH ROM routines,
// (which spans 0-512K), we need to adjust the NVRAM offset appropriately.
//
//
// Enable Bankset 8
//
CsrMask = READ_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER );
WRITE_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER,
CsrMask | BANKSET8_ENABLE );
//
// Read from the flash.
//
HalpFlash8kSetReadMode(NvRamOffset);
while(Length--) {
*DataPtr = HalpFlash8kReadByte(NvRamOffset);
DataPtr++;
NvRamOffset++;
}
//
// Disable Bankset 8 (Restore original state)
//
WRITE_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER, CsrMask );
return ESUCCESS;
}
ARC_STATUS
HalpWriteNVRamBuffer (
IN PCHAR NvRamOffset,
IN PCHAR DataPtr,
IN ULONG Length )
/*++
Routine Description:
This routine Writes data from memory into the NVRam
Arguments:
NvRamOffset- NVRam Offset to write data into
DataPtr - Pointer to memory location of data to be written
Length - Number of bytes of data to transfer
Return Value:
ESUCCESS if the operation succeeds.
ENODEV if no flash driver is loaded
EIO if a device error was detected
E2BIG if we attempt to write beyond the end of the NVRAM location
--*/
{
ARC_STATUS ReturnStatus = ESUCCESS;
UCHAR NeedToErase = FALSE;
UCHAR Byte;
ULONG Index;
ULONG Offset;
ULONG CsrMask;
PUCHAR FlashBuffer;
ULONG SectorSize;
ULONG SectorBase;
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("HalpWriteNVRamBuffer(%08x, %08x, %d)\r\n", NvRamOffset,
(ULONG)DataPtr, Length);
#endif
//
// If there is no flash driver, return an error.
//
if ((HalpFlashDriver == NULL) &&
((HalpFlashDriver =
HalpInitializeFlashDriver((ULONG)NvRamOffset)) == NULL)) {
return ENODEV;
}
//
// Check to see if we will write beyond the bounds...
// (normalize offset - base + length)
//
if (NvRamOffset - Am29F400NVRAMBase + Length > (PUCHAR)NVRAM1_SECTOR_SIZE) {
return E2BIG;
}
//
// Enable Bankset 8
//
CsrMask = READ_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER );
WRITE_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER,
CsrMask | BANKSET8_ENABLE );
//
// Read the whole bloody Physical NVRAM into a temporary buffer for
// comparisons
//
SectorBase = (ULONG)HalpFlash8kSectorAlign(NvRamOffset);
SectorSize = HalpFlash8kSectorSize(SectorBase);
FlashBuffer = ExAllocatePool(NonPagedPool, SectorSize);
if (FlashBuffer == NULL) {
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("HalpWriteNVRamBuffer: Could not allocate shadow\r\n");
#endif
return ENOMEM;
}
ReturnStatus = HalpReadNVRamBuffer(FlashBuffer,
(PUCHAR)SectorBase,
SectorSize);
//
// Check to see if we can write the data as is. Since we're dealing with
// a flash ROM device, we can only program 1-->1 and 1-->0, but not 0-->1.
//
Offset = (ULONG)NvRamOffset;
for (Index = 0; (Index < Length) && !NeedToErase; Index++, Offset++) {
Byte = FlashBuffer[Offset - SectorBase];
if (!HalpFlash8kOverwriteCheck(Byte, (UCHAR)DataPtr[Index])) {
NeedToErase = TRUE;
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("Need to erase flash because byte at %08x (%02x) ",
Offset, Byte);
DbgPrint("Cannot be written with %02x\r\n", (UCHAR)DataPtr[Index]);
#endif
}
}
//
// We can either program directly, or we must erase first.
// split this path here.
//
if (!NeedToErase) {
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("Don't need to erase -- simple overwrite\n");
#endif
Offset = (ULONG)NvRamOffset;
for (Index = 0; Index < Length; Index++, Offset++) {
//
// if byte is the same - don't bother writing
//
Byte = FlashBuffer[Offset - SectorBase];
if (Byte != (UCHAR)DataPtr[Index]) {
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("Writing %02x at %x\n", (UCHAR)DataPtr[Index], Offset);
#endif
HalpStallExecution(STALL_VALUE);
ReturnStatus = HalpFlash8kWriteByte(Offset,DataPtr[Index]);
if (ReturnStatus != ESUCCESS) {
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("Failed to write %02x (was %02x) at %x status %x (Retrying...)\n",
(UCHAR)DataPtr[Index], Byte, Offset, ReturnStatus);
#endif
//
// Retry
//
Index--; Offset--;
}
}
}
} else {
//
// We need to erase the flash block in order to write some of the
// requested data.
//
//
// Merge our data with the existing FLASH ROM data.
//
for(Index = 0; Index < Length; Index++) {
FlashBuffer[(ULONG)NvRamOffset - SectorBase + Index] =
DataPtr[Index];
}
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("Erasing sector\n");
#endif
//
// Erase the sector
//
ReturnStatus = HalpFlash8kEraseSector(SectorBase);
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("Returned from erase: %x\n", ReturnStatus);
DbgPrint("Writing %x bytes to %x\n", SectorSize, SectorBase);
#endif
for (Index = 0; Index < SectorSize; Index++, Offset++) {
if (FlashBuffer[Index] != HalpFlashDriver->ErasedData) {
HalpStallExecution(STALL_VALUE);
ReturnStatus = HalpFlash8kWriteByte(SectorBase + Index,
FlashBuffer[Index]);
if (ReturnStatus != ESUCCESS) {
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("Failed to write %02x at %x status %x (Retrying...)\n",
(UCHAR)FlashBuffer[Index], SectorBase + Index, ReturnStatus);
#endif
//
// Retry
//
Index--; Offset--;
}
}
}
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("\nReturned from write: %x\n", ReturnStatus);
DbgPrint("Wrote %x bytes\n", Index);
#endif
}
//
// Disable Bankset 8 (Restore original state)
//
WRITE_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER, CsrMask );
HalpFlash8kSetReadMode(NvRamOffset);
ExFreePool(FlashBuffer);
return ReturnStatus;
}
//
//
//
ARC_STATUS HalpCopyNVRamBuffer (
IN PCHAR NvDestPtr,
IN PCHAR NvSrcPtr,
IN ULONG Length )
/*++
Routine Description:
This routine is not supported.
Arguments:
NvDestPtr- NVRam Offset to write data into
NvSrcPtr - NVRam Offset of data to copy
Length - Number of bytes of data to transfer
Return Value:
ENODEV if no flash driver is loaded
EIO if a flash driver is loaded
--*/
{
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
DbgPrint("HalpCopyNVRamBuffer()\r\n");
#endif
//
// If there is no flash driver, return an error.
//
if (HalpFlashDriver == NULL) {
return ENODEV;
}
return EIO;
}
PFLASH_DRIVER
HalpInitializeFlashDriver(
IN ULONG NvRamOffset
)
/*++
Routine Description:
This routine attempts to recognize the flash device present in the
system by calling each known flash driver's Initialize() function
with the address passed in. The Initialize() functions will each
return NULL if they do not recognize the flash device at the specified
address and a pointer to a FLASH_DRIVER structure if the device is
recognized. This routine looks until it either recognizes a flash device
or runs out of known flash devices.
Arguments:
NvRamOffset - an Offset within the flash device
Return Value:
A pointer to the FLASH_DRIVER structure of the driver which corresponds
to the flash device in the system. NULL if no known flash device was
recognized.
--*/
{
PFLASH_DRIVER FlashDriver = NULL;
ULONG DriverNumber;
for(DriverNumber=0; FlashDriverList[DriverNumber] != NULL; DriverNumber++) {
FlashDriver = FlashDriverList[DriverNumber](NvRamOffset);
if (FlashDriver != NULL) {
break;
}
}
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
if (FlashDriver == NULL) {
DbgPrint("ERROR: No flash device found at %08x\r\n", NvRamOffset);
}
#endif
return FlashDriver;
}