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

392 lines
10 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1993 Digital Equipment Corporation
Module Name:
eeprom8k.c
Abstract:
This module implements the device-specific routines necessary to
Read and Write the Electrically Eraseable Programmable Read Only
Memory (EEPROM) containing the system environment variables. Note
that this module is used in exclusion of CMOS NVram support for the
same variables.
This module assumes that a standard PC NVRAM interface to the EEPROM
is being provided (for example the one provide by the Intel ESC
chip). This interface gives a 256 byte NVRAM page window into the
device. The current NVRAM page is selected through a page select
register.
Parts support by this module include:
Xicor X2864A
The routines implemented here are:
HalpReadNVRamBuffer() - copy data from NVRAM into memory
HalpWriteNVRamBuffer() - write memory data to NVRAM
HalpCopyNVRamBuffer() - move data within the NVRAM
Author:
Steve Brooks 5-Oct 93
Revision History:
Steve Jenness 10-Nov 93
Joe Notarangelo 10-Nov 93
Matthew Buchman 09-May 96 Stall instead of polling for Write complete.
Scott Lee 23-Sept-96 Use original write algorithm and add a check
for the last write.
--*/
#include "halp.h"
#include "cmos8k.h" // This is ok for eeprom8k.c
#include "arccodes.h"
#ifdef HAL_DBG
ULONG EepromDebug = 0;
#define EepromDbgPrint(x) if (EepromDebug) DbgPrint(x)
#else
#define EepromDbgPrint(x)
#endif //HAL_DBG
//
// Routine prototypes.
//
ARC_STATUS
HalpReadNVRamBuffer (
OUT PCHAR DataPtr,
IN PCHAR NvRamPtr,
IN ULONG Length
);
ARC_STATUS
HalpWriteNVRamBuffer (
IN PCHAR NvRamPtr,
IN PCHAR DataPtr,
IN ULONG Length
);
ARC_STATUS
HalpCopyNVRamBuffer (
IN PCHAR NvDestPtr,
IN PCHAR NvSrcPtr,
IN ULONG Length
);
ARC_STATUS
HalpReadNVRamBuffer (
OUT PCHAR DataPtr,
IN PCHAR NvRamPtr,
IN ULONG Length
)
/*++
Routine Description:
This routine reads data from the EEPROM into main memory.
Arguments:
DataPtr - Pointer to memory location to receive data
NvRamPtr - Pointer (qva) to EEPROM location to read data from
Length - Number of bytes of data to transfer
Return Value:
ESUCCESS if the operation succeeds.
--*/
{
ULONG PageSelect, ByteSelect;
PageSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
ByteSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
while ( Length -- )
{
*DataPtr++ = READ_CONFIG_RAM_DATA(NvRamPtr);
NvRamPtr ++;
ByteSelect = (ByteSelect + 1) & CONFIG_RAM_BYTE_MASK;
if (ByteSelect == 0)
{
PageSelect++;
WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
}
}
return(ESUCCESS);
}
ARC_STATUS
HalpWriteNVRamBuffer (
IN PCHAR NvRamPtr,
IN PCHAR DataPtr,
IN ULONG Length
)
/*++
Routine Description:
This routine Writes data from memory into the EEPROM. EEPROM page
mode write is used.
N.B. - This routine could have problems if interrupts are enabled
and the writing time between two bytes is over 20uSec.
N.B. - The ESC provides the NVRAM interface on 256
byte NVRAM pages. The EEPROM internally uses 16byte pages for
grouped programming. A EEPROM 16byte page commits (programs into
the EEPROM) in the same amount of time as a single byte does.
A EEPROM page has to be committed before switching to another
page. This is true if only 1 byte is written or all 16.
N.B. - This routine assumes that the base address of the 256 byte
page buffer is on a 256 byte boundary.
N.B. - With the increase in processor speed and compiler technology,
we seem to violate a time increment that must occur between
Writes followed by Reads. This results in invaliding the
last write of the page. By first waiting the amount of a
write cycle, (specified in the Data Sheet as 5ms) after the last
write before reading, we don't run into this problem.
N.B. - The last write algorithm used did not worked with the 120 nsec part.
We have reverted back to the original algorithm and added a
modification. On the last write, if it is on a 256 byte page
boundary, do not increment and write the page select. Doing so will
cause the verification of the last write to fail.
Arguments:
NvRamPtr - Pointer (qva) to EEPROM location 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.
--*/
{
ULONG PageSelect;
#define EEPROM_PAGE_SIZE 16
#define EEPROM_OFFSET_MASK 0xF
ULONG EepromPageDataValid = FALSE;
UCHAR EepromPageData[EEPROM_PAGE_SIZE];
ULONG EepromPageOffset = 0;
BOOLEAN ByteWritten = FALSE;
PCHAR LastWrittenByteAddress;
ULONG LastWrittenByteValue;
//
// Calculate which NVRAM 256 byte page to select first.
//
PageSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
//
// Loop until no more data to write.
//
while ( (Length --) != 0) {
//
// If the current page of EEPROM data hasn't been read from the
// device, do so now. The whole EEPROM page is read at once so
// that it doesn't interfere with the EEPROM programming timeout.
//
if (EepromPageDataValid == FALSE) {
PCHAR TmpNvRamPtr = NvRamPtr;
EepromPageOffset = (ULONG)NvRamPtr & EEPROM_OFFSET_MASK;
while (EepromPageOffset < EEPROM_PAGE_SIZE) {
EepromPageData[EepromPageOffset++] =
READ_CONFIG_RAM_DATA(TmpNvRamPtr);
TmpNvRamPtr++;
}
EepromPageDataValid = TRUE;
EepromPageOffset = (ULONG)NvRamPtr & EEPROM_OFFSET_MASK;
}
//
// If the EEPROM data matches the data to be written, short-circuit
// the write. This potentially saves lots of time.
// If the data is different, write it and remember that a byte
// was written for the NOT-DATA polling done later.
//
if (EepromPageData[EepromPageOffset] != *DataPtr) {
WRITE_CONFIG_RAM_DATA(NvRamPtr, *DataPtr);
ByteWritten = TRUE;
LastWrittenByteValue = *DataPtr;
LastWrittenByteAddress = NvRamPtr;
EepromDbgPrint( "." );
} else {
EepromDbgPrint( "o" );
}
EepromPageOffset ++;
NvRamPtr ++;
DataPtr ++;
//
// If we're stepping into the next EEPROM 16 byte page first make
// sure that the data for the previous page has been programmed.
// Invalidate the current EEPROM page data buffer so that the next
// page will be read in (for the short-circuit above).
//
if (EepromPageOffset >= EEPROM_PAGE_SIZE) {
if (ByteWritten == TRUE) {
while((READ_CONFIG_RAM_DATA(LastWrittenByteAddress) & 0xff) !=
(UCHAR)(LastWrittenByteValue & 0xff));
ByteWritten = FALSE;
}
EepromPageDataValid = FALSE;
}
//
// If we are stepping into the next NVRAM 256 byte page, switch
// the NVRAM page select. Don't step into the next page on the
// last write, however.
//
if ((Length != 0) &&
(((ULONG)NvRamPtr & CONFIG_RAM_BYTE_MASK) == 0 ) ) {
PageSelect++;
WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
}
}
//
// Poll until the last byte written is programmed into the EEPROM.
//
if (ByteWritten == TRUE) {
while((READ_CONFIG_RAM_DATA(LastWrittenByteAddress) & 0xff) !=
(UCHAR)(LastWrittenByteValue & 0xff));
}
return(ESUCCESS);
}
ARC_STATUS
HalpCopyNVRamBuffer (
IN PCHAR NvDestPtr,
IN PCHAR NvSrcPtr,
IN ULONG Length
)
/*++
Routine Description:
This routine copies data between two locations within the EEPROM. It is
the callers responsibility to assure that the destination region does not
overlap the src region i.e. if the regions overlap, NvSrcPtr > NvDestPtr.
This routine does not use page mode access since we're unsure that
we can guarantee the 20uSec inter-byte timing required during a
page write. Currently, each byte is written and then checked for
commit into the EEPROM.
N.B. - This routine has not been optimized like HalpWriteNVRamBuffer.
N.B. - This routine doesn't appear to be used anywhere in either the
firmware, the HAL, or the kernel. It might not work.
Arguments:
NvDestPtr - Pointer (qva) to NVRam location to write data into
NvSrcPtr - Pointer (qva) to NVRam location of data to copy
Length - Number of bytes of data to transfer
Return Value:
ESUCCESS if the operation succeeds.
--*/
{
ULONG PageSelect0, ByteSelect0; // Src Pointer Page & offset
ULONG PageSelect1, ByteSelect1; // Dest Pointer Page & offset
PageSelect0 = (NvSrcPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
ByteSelect0 = (NvSrcPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
PageSelect1 = (NvDestPtr-(PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
ByteSelect1 = (NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect0);
while ( Length -- )
{
UCHAR AChar;
//
// Check the Page select for the src pointer, and write the
// select register if necessary:
//
if (ByteSelect0 == 0)
{
PageSelect0++;
}
if ( PageSelect0 != PageSelect1 )
{
WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect0);
}
AChar = READ_CONFIG_RAM_DATA(NvSrcPtr);
ByteSelect0 = (ByteSelect0 + 1) & CONFIG_RAM_BYTE_MASK;
//
// Check the page select for the dest pointer, and write
// the select register if necessary:
//
if (ByteSelect1 == 0)
{
PageSelect1++;
}
if ( PageSelect1 != PageSelect0 )
{
WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect1);
}
WRITE_CONFIG_RAM_DATA(NvDestPtr, AChar);
while ( READ_CONFIG_RAM_DATA(NvDestPtr) != AChar )
;
ByteSelect1 = (ByteSelect1 + 1) & CONFIG_RAM_BYTE_MASK;
NvSrcPtr ++;
NvDestPtr ++;
}
return(ESUCCESS);
}