mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1075 lines
27 KiB
1075 lines
27 KiB
/*++
|
|
|
|
Copyright (c) 1994 NeTpower, Inc.
|
|
|
|
Module Name:
|
|
|
|
falconnvram.h
|
|
|
|
Abstract:
|
|
|
|
This module contains definitions and code (initially) for Falcon NVRAM support.
|
|
NVRAM is a generic term on Falcon as we have 3 sources of NVRAM (Flash, Sidewinder,
|
|
EISA Bridge).
|
|
|
|
--*/
|
|
|
|
#ifndef _FALCONNVRAM_
|
|
#define _FALCONNVRAM_
|
|
|
|
//
|
|
// Define the private configuration packet structure, which contains a
|
|
// configuration component as well as pointers to the component's parent,
|
|
// peer, child, and configuration data.
|
|
//
|
|
|
|
#ifndef _LANGUAGE_ASSEMBLY
|
|
|
|
|
|
typedef struct _CONFIGURATION_PACKET {
|
|
CONFIGURATION_COMPONENT Component;
|
|
struct _CONFIGURATION_PACKET *Parent;
|
|
struct _CONFIGURATION_PACKET *Peer;
|
|
struct _CONFIGURATION_PACKET *Child;
|
|
PVOID ConfigurationData;
|
|
} CONFIGURATION_PACKET, *PCONFIGURATION_PACKET;
|
|
|
|
//
|
|
// The compressed configuration packet structure used to store configuration
|
|
// data in NVRAM.
|
|
//
|
|
|
|
typedef struct _COMPRESSED_CONFIGURATION_PACKET {
|
|
UCHAR Parent;
|
|
UCHAR Class;
|
|
UCHAR Type;
|
|
UCHAR Flags;
|
|
ULONG Key;
|
|
UCHAR Version;
|
|
UCHAR Revision;
|
|
USHORT ConfigurationDataLength;
|
|
USHORT Identifier;
|
|
USHORT ConfigurationData;
|
|
} COMPRESSED_CONFIGURATION_PACKET, *PCOMPRESSED_CONFIGURATION_PACKET;
|
|
|
|
#endif // _LANGUAGE_ASSEMBLY
|
|
|
|
//
|
|
// Defines for Identifier index.
|
|
//
|
|
|
|
#define NO_CONFIGURATION_IDENTIFIER 0xFFFF
|
|
|
|
//
|
|
// Defines for the non-volatile configuration tables.
|
|
//
|
|
|
|
#define NUMBER_OF_ENTRIES 40
|
|
#define LENGTH_OF_IDENTIFIER (1024 - (40*16) - 8)
|
|
#define LENGTH_OF_DATA 2048
|
|
#define LENGTH_OF_ENVIRONMENT 1024
|
|
#define LENGTH_OF_EISA_DATA 2044
|
|
#define MAXIMUM_ENVIRONMENT_VALUE 256
|
|
|
|
//
|
|
// Additional defines for the second configuration area
|
|
//
|
|
#define NUMBER_OF_ENTRIES2 40
|
|
#define LENGTH_OF_IDENTIFIER2 (1024 - (40*16))
|
|
#define LENGTH_OF_DATA2 1020
|
|
|
|
//
|
|
// Defines for the volatile configuration tables.
|
|
//
|
|
#define VOLATILE_NUMBER_OF_ENTRIES ( ( NUMBER_OF_ENTRIES + NUMBER_OF_ENTRIES2 ) * 2 )
|
|
#define VOLATILE_LENGTH_OF_IDENTIFIER ( (LENGTH_OF_IDENTIFIER + LENGTH_OF_IDENTIFIER2) * 4 )
|
|
#define VOLATILE_LENGTH_OF_DATA ( (LENGTH_OF_DATA + LENGTH_OF_DATA2) * 4 )
|
|
|
|
//
|
|
// The volatile configuration table structure.
|
|
//
|
|
|
|
#ifndef _LANGUAGE_ASSEMBLY
|
|
|
|
typedef struct _CONFIGURATION {
|
|
CONFIGURATION_PACKET Packet[VOLATILE_NUMBER_OF_ENTRIES];
|
|
UCHAR Identifier[VOLATILE_LENGTH_OF_IDENTIFIER];
|
|
UCHAR Data[VOLATILE_LENGTH_OF_DATA];
|
|
UCHAR EisaData[LENGTH_OF_EISA_DATA];
|
|
} CONFIGURATION, *PCONFIGURATION;
|
|
|
|
//
|
|
// The non-volatile configuration table structure.
|
|
//
|
|
|
|
typedef struct _NV_CONFIGURATION {
|
|
|
|
//
|
|
// NOTE: HAL only maps 2 pages for NVRAM. If this grows beyond
|
|
// 2 pages, the HAL must be changed.
|
|
//
|
|
// First Page
|
|
//
|
|
|
|
COMPRESSED_CONFIGURATION_PACKET Packet[NUMBER_OF_ENTRIES];
|
|
UCHAR Identifier[LENGTH_OF_IDENTIFIER];
|
|
UCHAR Data[LENGTH_OF_DATA];
|
|
UCHAR Checksum1[4];
|
|
UCHAR Environment[LENGTH_OF_ENVIRONMENT];
|
|
UCHAR Checksum2[4];
|
|
|
|
//
|
|
// Second Page
|
|
//
|
|
|
|
UCHAR EisaData[LENGTH_OF_EISA_DATA];
|
|
UCHAR Checksum3[4];
|
|
|
|
//
|
|
// Second configuration area
|
|
// must fit in 2048 bytes
|
|
//
|
|
|
|
COMPRESSED_CONFIGURATION_PACKET Packet2[NUMBER_OF_ENTRIES2]; // packets on page 2
|
|
UCHAR Identifier2[LENGTH_OF_IDENTIFIER2]; // identifiers on page 2
|
|
UCHAR Data2[LENGTH_OF_DATA2]; // data on page 2
|
|
UCHAR Checksum4[4]; // checksum on page 2
|
|
|
|
//
|
|
// Third page
|
|
//
|
|
|
|
// Ethernet Hardware Address goes in the next 8 bytes, do not use...
|
|
UCHAR EthernetHWAddress[8];
|
|
UCHAR FlashWriteCount[4];
|
|
|
|
} NV_CONFIGURATION, *PNV_CONFIGURATION;
|
|
|
|
#endif //_LANGUAGE_ASSEMBLY
|
|
|
|
//
|
|
// The non-volatile data structure contained in the Sidewinder NVRAM
|
|
//
|
|
|
|
#define SIDEWINDER_NVRAM_MAGIC_NUMBER 0xcafebabe
|
|
#define SIDEWINDER_NVRAM_SIZE 242
|
|
#define READ_SIDEWINDER_NVRAM 1
|
|
#define WRITE_SIDEWINDER_NVRAM 2
|
|
|
|
#define SNVRAM_MAGIC_OFFSET 0
|
|
#define SNVRAM_FLASH_COUNT_OFFSET 4
|
|
#define SNVRAM_NUM_PROCS_OFFSET 8
|
|
#define SNVRAM_PROC_SPEED_OFFSET 9
|
|
#define SNVRAM_PROC_1_TYPE_OFFSET 10
|
|
#define SNVRAM_PROC_2_TYPE_OFFSET 11
|
|
#define SNVRAM_MEMORY_TYPE_OFFSET 12
|
|
#define SNVRAM_MEMORY_TIMING_OFFSET 13
|
|
#define SNVRAM_ECACHE_PRESENT_OFFSET 17
|
|
#define SNVRAM_MEMORY_TIMING_SET_OFFSET 18
|
|
#define SNVRAM_EXTERNAL_SCSI_DEVICES 19
|
|
#define SNVRAM_SERIAL_PORT_0 20
|
|
#define SNVRAM_SERIAL_PORT_1 21
|
|
#define SNVRAM_PIRQ 22
|
|
#define SNVRAM_SYSAD_SPEED_OFFSET 26
|
|
#define SNVRAM_SYSAD_DIVISOR_OFFSET 27
|
|
#define SNVRAM_MEMORY_SIZE_OFFSET 28
|
|
#define SNVRAM_MEMORY_BANKS_OFFSET 30
|
|
#define SNVRAM_MEMORY_REFRESH_OFFSET 31
|
|
#define SNVRAM_MEMORY_REFRESH_SET_OFFSET 35
|
|
#define SNVRAM_PCACHE_LINESIZE_OFFSET 36
|
|
#define SNVRAM_CHECKSUM_OFFSET 106
|
|
#define SNVRAM_BOOT_FLAGS_OFFSET 113
|
|
|
|
#define SNVRAM_FLAG_SET 0x94
|
|
#define SNVRAM_PCACHE_DATA 0x1
|
|
#define SNVRAM_PCACHE_INST 0x2
|
|
|
|
#define BOOT_FLAGS_DPRINTS 0x1
|
|
#define BOOT_FLAGS_SERIAL_OUTPUT 0x2
|
|
#define BOOT_FLAGS_SLOW_TIMING 0x4
|
|
#define BOOT_FLAGS_DISABLE_ECC 0x8
|
|
#define BOOT_FLAGS_K0_EXCLUSIVE 0x10
|
|
#define BOOT_FLAGS_NAKED_ORION 0x20
|
|
|
|
#ifndef _LANGUAGE_ASSEMBLY
|
|
|
|
//
|
|
// Note, this structure has been defined such that the majority of the used fields
|
|
// are in the first half of the RAM, thus the RAM select bit in the Sidewinder does
|
|
// not need to be flipped to access this data. In addition, there are fields in the
|
|
// first half AFTER the checksum. This means that these fields will NOT be a part
|
|
// of the checksum calculation
|
|
//
|
|
|
|
typedef struct _SIDEWINDER_NV_CONFIGURATION {
|
|
|
|
UCHAR Magic[4]; // Magic number, tells if we are initialized
|
|
UCHAR FlashWriteCount[4]; // Number of times Flash has been written
|
|
UCHAR NumberOfProcessors; // Number of processors on last boot
|
|
UCHAR ProcessorSpeed; // Speed of processor
|
|
UCHAR ProcessorType[2]; // Processors MAY be different. Allows us to check
|
|
UCHAR MemoryType; // EDO vs. Non-EDO, Parity vs ECC SIMMs
|
|
UCHAR MemoryTiming[4]; // Last valid memory timing used
|
|
UCHAR ECachePresent; // Whether ECache was present on last boot
|
|
UCHAR MemoryTimingSetFlag; // A memory timing value has been entered
|
|
UCHAR ExternalScsiDevices; // Flag to enable/disable termination for external scsi devices
|
|
UCHAR SerialPort0; // What is serial port 0 configured as?
|
|
UCHAR SerialPort1; // What is serial port 1 configured as?
|
|
UCHAR PIRQ[4]; // PCI interrupt IRQ routing
|
|
UCHAR SysAdSpeed; // R4XXX SysAd speed
|
|
UCHAR SysAdDivisor; // R4XXX SysAd divisor
|
|
UCHAR MemorySize[2]; // Size of memory from last boot
|
|
UCHAR MemoryBanks; // Number of memory banks from last boot
|
|
UCHAR MemoryRefresh[4]; // Memory refresh - based on SysAd
|
|
UCHAR MemoryRefreshSetFlag; // Has memory refresh been set?
|
|
UCHAR PrimaryCacheLineSize; // Primary Cache line sizes
|
|
|
|
// Add new fields AFTER this comment, AND decrease Available by correct number of bytes
|
|
|
|
UCHAR Available[69];
|
|
UCHAR Checksum[4]; // Checksum for the NVRAM
|
|
UCHAR Temporary0; // Temporary variables that are NOT apart of the
|
|
UCHAR Temporary1; // calculated checksum
|
|
UCHAR Temporary2;
|
|
UCHAR BootFlags; // Boot flags - if this moves, fix hardcode in falcon.s
|
|
|
|
// *** End of FIRST half of NVRAM ***
|
|
|
|
UCHAR Available1[124]; // Available bytes in other half
|
|
UCHAR Checksum1[4]; // Checksum for second half of NVRAM
|
|
|
|
// *** End of SECOND half of NVRAM ***
|
|
|
|
} SIDEWINDER_NV_CONFIGURATION, *PSIDEWINDER_NV_CONFIGURATION;
|
|
|
|
#endif //_LANGUAGE_ASSEMBLY
|
|
|
|
//
|
|
// Non-volatile ram layout.
|
|
//
|
|
|
|
#define NVRAM_CONFIGURATION NVRAM_VIRTUAL_BASE
|
|
#define NVRAM_SYSTEM_ID (NVRAM_VIRTUAL_BASE + 0x00002000)
|
|
#endif // _FALCONNVRAM_
|
|
|
|
#if defined(GENERATE_NVRAM_CODE) && !defined(GENERATED_NVRAM_CODE)
|
|
#define GENERATED_NVRAM_CODE
|
|
|
|
#include "pcieisa.h"
|
|
#include "sidewind.h"
|
|
|
|
//
|
|
// To facilitate ease of sharing between the firmware and HAL, the code will exist
|
|
// here (I know it is ugly). Then the files fxnvram.c will simply define this
|
|
// define and include this file. When we get close to release, fxnvram.c will then
|
|
// contain this code, and will be removed from here.
|
|
//
|
|
|
|
//
|
|
// Falcon is using part of FLASH for NVRAM. Most of support exists in this file.
|
|
// All reads will pass unaltered to the FLASH. All writes to FLASH will be trapped
|
|
// and written to an in memory copy of Flash, then written out to the FLASH whenever
|
|
// the configuration, checksum is changed.
|
|
//
|
|
|
|
#if !defined(_FALCON_HAL_)
|
|
#define HalpFlashRamBase NVRAM_CONFIGURATION
|
|
#endif
|
|
|
|
#if defined(_FALCON_HAL_)
|
|
extern BOOLEAN HalpDisplayOwnedByHal;
|
|
#endif
|
|
|
|
NV_CONFIGURATION MirrorNvram; // Close to 8k
|
|
ULONG MirrorNvramValid = FALSE;
|
|
ULONG DelayFlashWrite = FALSE;
|
|
ULONG HaveFlash = 1;
|
|
|
|
//
|
|
// Routine prototypes.
|
|
//
|
|
|
|
VOID
|
|
WRITE_NVRAM_UCHAR (
|
|
ULONG Address,
|
|
UCHAR Data
|
|
);
|
|
|
|
UCHAR
|
|
READ_NVRAM_UCHAR (
|
|
ULONG Address
|
|
);
|
|
|
|
VOID
|
|
WriteMirrorNvramToFlash(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
AccessSidewinderNvram(
|
|
ULONG Type, // Read or Write
|
|
ULONG Offset, // Offset into SidewinderNvram
|
|
PUCHAR Data, // Pointer to Data;
|
|
ULONG Length // Length to read or write
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the routine to use if you want to read/write the Sidewinder NVRAM. Because
|
|
of the indexing involved, and having to toggle RAMSEL depending on which by you are
|
|
interested it, it is much easier to encapsulate this into its own routine.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR pData = Data;
|
|
PUCHAR SIOIndex, SIOData, RAMIndex, RAMData;
|
|
ULONG Count, NvramOffset = Offset; // Offset for first byte
|
|
ULONG High128 = 0;
|
|
UCHAR RTCcontrol;
|
|
|
|
//
|
|
// Set initial RAMSEL to zero - don't assume last value...
|
|
//
|
|
#if defined(_FALCON_HAL_)
|
|
SIOIndex = (PUCHAR)HalpEisaControlBase + 0x398;
|
|
SIOData = SIOIndex + 1;
|
|
RAMIndex = (PUCHAR)HalpEisaControlBase + 0x70;
|
|
RAMData = RAMIndex + 1;
|
|
#else
|
|
SIOIndex = (PUCHAR)EISA_CONTROL_VIRTUAL_BASE + 0x398;
|
|
SIOData = SIOIndex + 1;
|
|
RAMIndex = ESC_CMOS_RAM_ADDRESS;
|
|
RAMData = ESC_CMOS_RAM_DATA;
|
|
#endif
|
|
|
|
WRITE_REGISTER_UCHAR( SIOIndex, SUPERIO_KRR_INDEX );
|
|
RTCcontrol = READ_REGISTER_UCHAR( SIOData );
|
|
|
|
RTCcontrol &= ~SUPERIO_KRR_RAMU128B;
|
|
|
|
WRITE_REGISTER_UCHAR( SIOIndex, SUPERIO_KRR_INDEX );
|
|
WRITE_REGISTER_UCHAR( SIOData, RTCcontrol );
|
|
WRITE_REGISTER_UCHAR( SIOData, RTCcontrol );
|
|
|
|
NvramOffset += RTC_BATTERY_BACKED_UP_RAM;
|
|
|
|
for ( Count = 0; Count < Length; Count++ ) {
|
|
if ( !High128 && NvramOffset >= 128 ) {
|
|
RTCcontrol |= SUPERIO_KRR_RAMU128B;
|
|
WRITE_REGISTER_UCHAR( SIOIndex, SUPERIO_KRR_INDEX );
|
|
WRITE_REGISTER_UCHAR( SIOData, RTCcontrol );
|
|
WRITE_REGISTER_UCHAR( SIOData, RTCcontrol );
|
|
High128 = 1;
|
|
NvramOffset -= 128;
|
|
}
|
|
|
|
WRITE_REGISTER_UCHAR( RAMIndex, (UCHAR)NvramOffset++ );
|
|
if ( Type == READ_SIDEWINDER_NVRAM ) {
|
|
*pData++ = READ_REGISTER_UCHAR( RAMData );
|
|
} else {
|
|
WRITE_REGISTER_UCHAR( RAMData, *pData++ );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set RAMSEL back to first bank...
|
|
//
|
|
RTCcontrol &= ~SUPERIO_KRR_RAMU128B;
|
|
|
|
WRITE_REGISTER_UCHAR( SIOIndex, SUPERIO_KRR_INDEX );
|
|
WRITE_REGISTER_UCHAR( SIOData, RTCcontrol );
|
|
WRITE_REGISTER_UCHAR( SIOData, RTCcontrol );
|
|
}
|
|
|
|
BOOLEAN
|
|
SidewinderNvramValid(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine checks to see if the Sidewinder NVRAM is valid
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR MagicChars[4];
|
|
ULONG MagicNumber;
|
|
|
|
AccessSidewinderNvram( READ_SIDEWINDER_NVRAM, 0, &MagicChars[0], 4 );
|
|
MagicNumber = ( MagicChars[3] << 24 ) | ( MagicChars[2] << 16 ) |
|
|
( MagicChars[1] << 8 ) | MagicChars[0];
|
|
|
|
if ( MagicNumber != SIDEWINDER_NVRAM_MAGIC_NUMBER ) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
VOID
|
|
InitializeSidewinderNvram(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the Sidewinder NVRAM.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR InitialSNvram[SIDEWINDER_NVRAM_SIZE];
|
|
PSIDEWINDER_NV_CONFIGURATION pInitialSNvram = (PSIDEWINDER_NV_CONFIGURATION)&InitialSNvram;
|
|
ULONG Count;
|
|
|
|
//
|
|
// Scrub NVRAM
|
|
//
|
|
for ( Count = 0; Count < SIDEWINDER_NVRAM_SIZE; Count++ ) {
|
|
InitialSNvram[Count] = 0x0;
|
|
}
|
|
|
|
//
|
|
// Initialize the magic number header
|
|
//
|
|
|
|
pInitialSNvram->Magic[0] = (UCHAR)SIDEWINDER_NVRAM_MAGIC_NUMBER;
|
|
pInitialSNvram->Magic[1] = (UCHAR)( SIDEWINDER_NVRAM_MAGIC_NUMBER >> 8 );
|
|
pInitialSNvram->Magic[2] = (UCHAR)( SIDEWINDER_NVRAM_MAGIC_NUMBER >> 16 );
|
|
pInitialSNvram->Magic[3] = (UCHAR)( SIDEWINDER_NVRAM_MAGIC_NUMBER >> 24 );
|
|
|
|
AccessSidewinderNvram( WRITE_SIDEWINDER_NVRAM, 0, (PUCHAR)pInitialSNvram, SIDEWINDER_NVRAM_SIZE );
|
|
|
|
// XXX Checksum!
|
|
}
|
|
|
|
VOID
|
|
WRITE_NVRAM_UCHAR (
|
|
ULONG Address,
|
|
UCHAR Data
|
|
)
|
|
{
|
|
PUCHAR pMirrorNvram, pFlash;
|
|
ULONG Counter;
|
|
//
|
|
// When this routine is called, first check to see if MirrorNvramValid is FALSE.
|
|
// If it is FALSE, this is the first time a write has been called since the last
|
|
// write to the FLASH. This means we must first READ the FLASH to set get a copy
|
|
// of the FLASH into MirrorNvram
|
|
//
|
|
// Then, any and all writes are done to MirrorNvram. Then in the key *Save* routines,
|
|
// MirrorNvram will be rewritten back out to FLASH, and MirrorNvramValid will be set
|
|
// to FALSE.
|
|
//
|
|
|
|
if ( ( (PUCHAR)Address < (PUCHAR)HalpFlashRamBase ) ||
|
|
(((PUCHAR)Address - (PUCHAR)HalpFlashRamBase) > sizeof(NV_CONFIGURATION)) ) {
|
|
#if defined(_FALCON_HAL_)
|
|
if ( HalpDisplayOwnedByHal == TRUE ) {
|
|
HalDisplayString("WRITE_NVRAM_UCHAR - outside range of NVRAM\r\n");
|
|
}
|
|
#else
|
|
FwPrint("WRITE_NVRAM_UCHAR - Address: 0x%x\r\n", Address);
|
|
#endif
|
|
}
|
|
if ( !MirrorNvramValid ) {
|
|
|
|
pFlash = (PUCHAR)HalpFlashRamBase;
|
|
|
|
pMirrorNvram = (PUCHAR)&MirrorNvram;
|
|
for ( Counter = 0; Counter < sizeof(NV_CONFIGURATION); Counter++ ) {
|
|
*pMirrorNvram++ = *pFlash++;
|
|
}
|
|
MirrorNvramValid = TRUE;
|
|
}
|
|
|
|
pMirrorNvram = (PUCHAR)&MirrorNvram + ( (PUCHAR)Address - (PUCHAR)HalpFlashRamBase );
|
|
|
|
*pMirrorNvram = Data;
|
|
}
|
|
|
|
UCHAR
|
|
READ_NVRAM_UCHAR (
|
|
ULONG Address
|
|
)
|
|
{
|
|
PUCHAR pMirrorNvram;
|
|
|
|
//
|
|
// When this routine is called, first check to see if MirrorNvramValid is FALSE.
|
|
// If it is FALSE, return byte from FLASH, otherwise return byte from MirrorNvram.
|
|
//
|
|
// This routine should ONLY be used in loops calculating checksums in
|
|
// FwConfigurationSetChecksum()
|
|
// FwEnvironmentSetChecksum()
|
|
//
|
|
|
|
if ( ( (PUCHAR)Address < (PUCHAR)HalpFlashRamBase ) ||
|
|
(((PUCHAR)Address - (PUCHAR)HalpFlashRamBase) > sizeof(NV_CONFIGURATION)) ) {
|
|
#if defined(_FALCON_HAL_)
|
|
if ( HalpDisplayOwnedByHal == TRUE ) {
|
|
HalDisplayString("READ_NVRAM_UCHAR - outside range of NVRAM\r\n");
|
|
}
|
|
#else
|
|
FwPrint("READ_NVRAM_UCHAR - Address: 0x%x 0x%x 0x%x\r\n", Address, sizeof(NV_CONFIGURATION), HalpFlashRamBase);
|
|
#endif
|
|
}
|
|
if ( !MirrorNvramValid ) {
|
|
return READ_REGISTER_UCHAR( Address );
|
|
}
|
|
|
|
pMirrorNvram = (PUCHAR)&MirrorNvram + ( (PUCHAR)Address - (PUCHAR)HalpFlashRamBase );
|
|
|
|
return(*pMirrorNvram);
|
|
}
|
|
|
|
VOID
|
|
EnableFlashWrite(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the appropriate bits to enabling writing to the FLASH.
|
|
|
|
Note: This code is NOT specific to any particular FLASH part.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Data;
|
|
|
|
//
|
|
// Enable BIOS Write
|
|
//
|
|
|
|
#if defined(_FALCON_HAL_)
|
|
|
|
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Reserved1[0], ESC_CONFIG_BIOS_CSB );
|
|
Data = READ_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Reserved1[1] );
|
|
Data |= ESC_BIOS_CSB_BIOSWREN;
|
|
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Reserved1[1], Data );
|
|
|
|
#else
|
|
|
|
WRITE_REGISTER_UCHAR( ESC_CONFIG_INDEX_ADDRESS, ESC_CONFIG_BIOS_CSB );
|
|
Data = READ_REGISTER_UCHAR( ESC_CONFIG_INDEX_DATA );
|
|
Data |= ESC_BIOS_CSB_BIOSWREN;
|
|
WRITE_REGISTER_UCHAR( ESC_CONFIG_INDEX_DATA, Data );
|
|
|
|
#endif // _FALCON_HAL_
|
|
|
|
|
|
}
|
|
|
|
VOID
|
|
DisableFlashWrite(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the appropriate bits to enabling writing to the FLASH.
|
|
|
|
Note: This code is NOT specific to any particular FLASH part.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Data;
|
|
|
|
//
|
|
// Disable BIOS Write
|
|
//
|
|
|
|
#if defined(_FALCON_HAL_)
|
|
|
|
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Reserved1[0], ESC_CONFIG_BIOS_CSB );
|
|
Data = READ_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Reserved1[1] );
|
|
Data &= ~ESC_BIOS_CSB_BIOSWREN;
|
|
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Reserved1[0], ESC_CONFIG_BIOS_CSB );
|
|
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Reserved1[1], Data );
|
|
|
|
#else
|
|
|
|
WRITE_REGISTER_UCHAR( ESC_CONFIG_INDEX_ADDRESS, ESC_CONFIG_BIOS_CSB );
|
|
Data = READ_REGISTER_UCHAR( ESC_CONFIG_INDEX_DATA );
|
|
Data &= ~ESC_BIOS_CSB_BIOSWREN;
|
|
WRITE_REGISTER_UCHAR( ESC_CONFIG_INDEX_DATA, Data );
|
|
|
|
#endif _FALCON_HAL_
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
EraseFlashSector(
|
|
ULONG SectorAddress
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will erase the specified sector in the FLASH.
|
|
|
|
Note: These algorithms are AM29F040 specific!
|
|
|
|
Arguments:
|
|
|
|
SectorAddress - base address of the sector to erase
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE indicating successful erasure.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Data;
|
|
ULONG Count;
|
|
BOOLEAN Status = TRUE;
|
|
|
|
if ( !HaveFlash ) return TRUE;
|
|
|
|
//
|
|
// Set approriate bits to enable FLASH write...
|
|
//
|
|
EnableFlashWrite();
|
|
|
|
//
|
|
// First perform the unlock sequence for the AM29F040
|
|
//
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x5555, 0xAA );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x2AAA, 0x55 );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x5555, 0x80 );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x5555, 0xAA );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x2AAA, 0x55 );
|
|
|
|
// Send Erase Sector Command...
|
|
WRITE_REGISTER_UCHAR( SectorAddress, 0x30 );
|
|
|
|
//
|
|
// Wait for PROM to be erased.
|
|
//
|
|
for (Count = 0; Count < 6000; Count++) {
|
|
#if defined(_FALCON_HAL_)
|
|
KeStallExecutionProcessor(1000);
|
|
#else
|
|
FwStallExecution(1000);
|
|
#endif // _FALCON_HAL_
|
|
Data = READ_REGISTER_UCHAR( SectorAddress );
|
|
if ((Data & 0x80) != 0 ) {
|
|
break;
|
|
}
|
|
}
|
|
if ((Data & 0x80) == 0 ) {
|
|
#if defined(_FALCON_HAL_)
|
|
if ( HalpDisplayOwnedByHal == TRUE ) {
|
|
HalDisplayString("Unable to erase prom.\r\n");
|
|
}
|
|
#else
|
|
FwPrint("Unable to erase prom.\r\n");
|
|
#endif // _FALCON_HAL_
|
|
Status = FALSE;
|
|
}
|
|
DisableFlashWrite();
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
UpdateFlashWriteCount(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will update the Flash write count that exists in the Flash AND
|
|
Sidewinder NVRAM.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG FlashWriteCount, SidewinderWriteCount;
|
|
|
|
PNV_CONFIGURATION Nvram = (PNV_CONFIGURATION)HalpFlashRamBase;
|
|
// XXX Fixup for HAL
|
|
PSIDEWINDER_NV_CONFIGURATION SNvram = (PSIDEWINDER_NV_CONFIGURATION)SIDEWINDER_NVRAM_VIRTUAL_BASE;
|
|
|
|
//
|
|
// Read count
|
|
//
|
|
|
|
FlashWriteCount = (ULONG)READ_NVRAM_UCHAR( (ULONG) &Nvram->FlashWriteCount[0] ) |
|
|
(ULONG)READ_NVRAM_UCHAR( (ULONG) &Nvram->FlashWriteCount[1] ) << 8 |
|
|
(ULONG)READ_NVRAM_UCHAR( (ULONG) &Nvram->FlashWriteCount[2] ) << 16 |
|
|
(ULONG)READ_NVRAM_UCHAR( (ULONG) &Nvram->FlashWriteCount[3] ) << 24 ;
|
|
|
|
|
|
#if defined(_FALCON_HAL_)
|
|
if ( FlashWriteCount == 0 ) {
|
|
if ( HalpDisplayOwnedByHal == TRUE ) {
|
|
HalDisplayString("WARNING: FlashWriteCount == 0\r\n");
|
|
}
|
|
}
|
|
|
|
if ( FlashWriteCount > 95000 ) {
|
|
if ( HalpDisplayOwnedByHal == TRUE ) {
|
|
HalDisplayString("WARNING: Flash soon to EXCEED maximum writes\r\n");
|
|
}
|
|
}
|
|
#else
|
|
if ( FlashWriteCount == 0 ) {
|
|
StatusDisplay("WARNING: FlashWriteCount == 0");
|
|
}
|
|
|
|
if ( FlashWriteCount > 95000 && FlashWriteCount <= 100000 ) {
|
|
StatusDisplay("WARNING: Flash soon to EXCEED maximum writes (%d)", FlashWriteCount);
|
|
} else if ( FlashWriteCount > 100000 ) {
|
|
StatusDisplay("WARNING: Flash write count corrupted (0x%x)", FlashWriteCount);
|
|
FlashWriteCount = 0;
|
|
}
|
|
#endif // _FALCON_HAL_
|
|
|
|
|
|
if ( SidewinderNvramValid() == FALSE ) {
|
|
InitializeSidewinderNvram();
|
|
}
|
|
|
|
AccessSidewinderNvram( READ_SIDEWINDER_NVRAM, SNVRAM_FLASH_COUNT_OFFSET,
|
|
(PUCHAR)&SidewinderWriteCount, sizeof(SidewinderWriteCount) );
|
|
|
|
if ( SidewinderWriteCount > 10000 ) {
|
|
#if !defined(_FALCON_HAL_)
|
|
StatusDisplay("WARNING: Sidewinder write count corrupted (0x%x)", SidewinderWriteCount);
|
|
#endif
|
|
SidewinderWriteCount = 0;
|
|
}
|
|
|
|
#if defined(_FALCON_HAL_)
|
|
|
|
if ( SidewinderWriteCount != FlashWriteCount ) {
|
|
|
|
if ( HalpDisplayOwnedByHal == TRUE ) {
|
|
HalDisplayString("WARNING: Sidewinder != Flash write count\r\n");
|
|
}
|
|
|
|
if ( FlashWriteCount != 0 ) {
|
|
SidewinderWriteCount = FlashWriteCount;
|
|
} else {
|
|
FlashWriteCount = SidewinderWriteCount;
|
|
}
|
|
}
|
|
FlashWriteCount++;
|
|
SidewinderWriteCount++;
|
|
|
|
#else
|
|
|
|
if ( SidewinderWriteCount != FlashWriteCount ) {
|
|
StatusDisplay("WARNING: Sidewinder != Flash write counts 0x%x vs. 0x%x",
|
|
SidewinderWriteCount, FlashWriteCount);
|
|
if ( FlashWriteCount != 0 && FlashWriteCount != 0xFFFFFFFF ) {
|
|
SidewinderWriteCount = FlashWriteCount;
|
|
} else {
|
|
FlashWriteCount = SidewinderWriteCount;
|
|
}
|
|
}
|
|
FlashWriteCount++;
|
|
SidewinderWriteCount++;
|
|
|
|
#endif // _FALCON_HAL_
|
|
|
|
//
|
|
// Write counts. First write count that resides in the FLASH using special macros.
|
|
// Then write count that resides in the Sidewinder NVRAM with regular macro.
|
|
//
|
|
|
|
WRITE_NVRAM_UCHAR( (ULONG) &Nvram->FlashWriteCount[0], (UCHAR)FlashWriteCount);
|
|
WRITE_NVRAM_UCHAR( (ULONG) &Nvram->FlashWriteCount[1], (UCHAR)(FlashWriteCount >> 8));
|
|
WRITE_NVRAM_UCHAR( (ULONG) &Nvram->FlashWriteCount[2], (UCHAR)(FlashWriteCount >> 16));
|
|
WRITE_NVRAM_UCHAR( (ULONG) &Nvram->FlashWriteCount[3], (UCHAR)(FlashWriteCount >> 24));
|
|
|
|
AccessSidewinderNvram( WRITE_SIDEWINDER_NVRAM, SNVRAM_FLASH_COUNT_OFFSET,
|
|
(PUCHAR)&SidewinderWriteCount, sizeof(SidewinderWriteCount) );
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
ProgramFlashSector(
|
|
ULONG SectorAddress,
|
|
ULONG SectorSize,
|
|
PUCHAR ImageAddress,
|
|
ULONG ImageSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will program the specified sector in the FLASH.
|
|
|
|
If the amount of data we are writing is LESS than the sector size,
|
|
then fill the rest of the sector in with ZERO.
|
|
|
|
Note: These algorithms are AM29F040 specific!
|
|
|
|
Arguments:
|
|
|
|
SectorAddress - base address of the sector to be programmed
|
|
SectorSize - size of the physical sector
|
|
ImageAddress - base address of image to write to FLASH sector
|
|
ImageSize - size of image
|
|
|
|
Return Value:
|
|
|
|
TRUE/FALSE indicating successful programming.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR Data;
|
|
PUCHAR pImage;
|
|
ULONG Count;
|
|
BOOLEAN Status = TRUE;
|
|
|
|
//
|
|
// Set approriate bits to enable FLASH write...
|
|
//
|
|
EnableFlashWrite();
|
|
|
|
pImage = (PUCHAR)ImageAddress;
|
|
for (Count = 0; Count < SectorSize; Count++) {
|
|
|
|
if ( HaveFlash ) {
|
|
//
|
|
// First perform the unlock sequence for the AM29F040
|
|
//
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x5555, 0xAA );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x2AAA, 0x55 );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x5555, 0xA0 );
|
|
}
|
|
|
|
WRITE_REGISTER_UCHAR( SectorAddress + Count, Count < ImageSize ? *pImage: 0 );
|
|
|
|
do {
|
|
Data = READ_REGISTER_UCHAR( SectorAddress + Count );
|
|
} while (Data != ( Count < ImageSize ? *pImage : 0 ) );
|
|
pImage++;
|
|
}
|
|
|
|
DisableFlashWrite();
|
|
|
|
pImage = (PUCHAR)ImageAddress;
|
|
for (Count = 0; Count < ImageSize; Count++) {
|
|
|
|
Data = READ_REGISTER_UCHAR( SectorAddress + Count );
|
|
|
|
#if defined(_FALCON_HAL_)
|
|
|
|
if ( *pImage != Data ) {
|
|
if ( HalpDisplayOwnedByHal == TRUE ) {
|
|
HalDisplayString("..Error\r\n");
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if ((Count & 0x3FFF) == 0) {
|
|
if ( HalpDisplayOwnedByHal == TRUE ) {
|
|
// HalDisplayString(".");
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
if ( *pImage != Data ) {
|
|
FwPrint("..Error mismatch\r\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if ((Count & 0x3FFF) == 0) {
|
|
// Don't need status...
|
|
// FwPrint(".");
|
|
}
|
|
|
|
#endif // _FALCON_HAL_
|
|
|
|
pImage++;
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
ULONG
|
|
FlashOrPromICE(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will determine whether the system has a Flash or PromICE
|
|
plugged in.
|
|
|
|
--*/
|
|
|
|
{
|
|
PUCHAR SectorAddress = HalpFlashRamBase;
|
|
UCHAR Saved1, Saved2;
|
|
ULONG IsFlash;
|
|
|
|
//
|
|
// Set approriate bits to enable FLASH write...
|
|
//
|
|
EnableFlashWrite();
|
|
|
|
//
|
|
// Save characters in case this is NOT Flash
|
|
//
|
|
Saved1 = READ_REGISTER_UCHAR( SectorAddress + 0x5555 );
|
|
Saved2 = READ_REGISTER_UCHAR( SectorAddress + 0x2AAA );
|
|
|
|
//
|
|
// First perform the unlock sequence for the AM29F040
|
|
//
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x5555, 0xAA );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x2AAA, 0x55 );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x5555, 0x90 );
|
|
|
|
if ( READ_REGISTER_UCHAR( SectorAddress ) != 0x01 &&
|
|
READ_REGISTER_UCHAR( SectorAddress + 1 ) != 0xA4 ) {
|
|
IsFlash = 0;
|
|
} else {
|
|
IsFlash = 1;
|
|
}
|
|
|
|
if ( !IsFlash ) {
|
|
//
|
|
// Restore trashed bytes...
|
|
//
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x5555, Saved1 );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x2AAA, Saved2 );
|
|
} else {
|
|
//
|
|
// Put Flash back into normal mode
|
|
//
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x5555, 0xAA );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x2AAA, 0x55 );
|
|
WRITE_REGISTER_UCHAR( SectorAddress + 0x5555, 0xF0 );
|
|
}
|
|
|
|
DisableFlashWrite();
|
|
|
|
return( IsFlash );
|
|
}
|
|
|
|
VOID
|
|
WriteMirrorNvramToFlash(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will write the mirrored NVRAM to the FLASH sector dedicated to
|
|
hold the non-volatile data. It will call generic FLASH routines that will be
|
|
used to alter the FLASH in other parts of the system.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if ( DelayFlashWrite == TRUE ) {
|
|
return;
|
|
}
|
|
|
|
#if !defined(_FALCON_HAL_)
|
|
// For debug mostly...
|
|
StatusDisplay("Updating Flash...");
|
|
#endif
|
|
|
|
//
|
|
// First determine whether we have a Flash or PromICE plugged in
|
|
//
|
|
HaveFlash = FlashOrPromICE();
|
|
|
|
//
|
|
// Update the Flash write count. Need to do this in order to have
|
|
// the MirrorNvram correctly setup before erasing the Flash nvram.
|
|
//
|
|
UpdateFlashWriteCount();
|
|
|
|
//
|
|
// We are now ready to copy the contents of MirrorNvram out to the Flash, and set
|
|
// the MirrorNvramValid to FALSE
|
|
//
|
|
|
|
if ( EraseFlashSector((ULONG)HalpFlashRamBase) == FALSE ) {
|
|
|
|
//
|
|
// Failed to erase, simply return, and do not reset MirrorNvramValid.
|
|
// We will just have to run out of the Mirror which is like NO changes
|
|
// were made.
|
|
//
|
|
#if defined(_FALCON_HAL_)
|
|
if ( HalpDisplayOwnedByHal == TRUE ) {
|
|
HalDisplayString("ERROR: WriteMirrorNvramToFlash() failed to erase FLASH\n\r");
|
|
}
|
|
#else
|
|
FwPrint("ERROR: WriteMirrorNvramToFlash() failed to erase FLASH\n\r");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if ( ProgramFlashSector( (ULONG)HalpFlashRamBase, SECTOR_SIZE_AM29F040,
|
|
(PUCHAR)&MirrorNvram, sizeof(NV_CONFIGURATION) ) == FALSE ) {
|
|
#if defined(_FALCON_HAL_)
|
|
if ( HalpDisplayOwnedByHal == TRUE ) {
|
|
HalDisplayString("ERROR: WriteMirrorNvramToFlash() failed to program FLASH\n\r");
|
|
}
|
|
#else
|
|
FwPrint("ERROR: WriteMirrorNvramToFlash() failed to program FLASH\n\r");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
MirrorNvramValid = FALSE;
|
|
#if !defined(_FALCON_HAL_)
|
|
StatusClear();
|
|
#endif
|
|
}
|
|
|
|
#endif // GENERATE_NVRAM_CODE
|
|
|