NT4/private/ntos/fw/mips/selftest.c
2020-09-30 17:12:29 +02:00

2520 lines
63 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) 1990 Microsoft Corporation
Module Name:
selftest.c
Abstract:
This module contains the routines that perform the selftest of
the IO devices.
Author:
Lluis Abello (lluis) 03-Jan-1991
Environment:
Revision History:
--*/
#include "fwp.h"
#include "iodevice.h"
#include "led.h"
#include "selfmap.h"
#include "selftest.h"
#include "ioaccess.h"
#include "fwstring.h"
#include "stdio.h"
typedef CACHEERR *PCACHEERR;
#define SetCursorPosition(Row,Column) \
FwPrint("\x9B"#Row";"#Column"H")
#define MoveCursorLeft(Spaces) \
FwPrint("\x9B"#Spaces"D")
#define ClearScreen() FwPrint("\x9B""2J");
PUCHAR TranslationTable = "0123456789ABCDEF";
UCHAR StationAddress[6];
BOOLEAN ProcessorBEnabled = FALSE;
BOOLEAN ValidEthernetAddress; // True if station address is OK False Otherwise
BOOLEAN ConfigurationBit; // read value from diagnostic register
BOOLEAN LoopOnError; // read value from diagnostic register
BOOLEAN IgnoreErrors; // read value from diagnostic register
volatile LONG TimerTicks; // Counter for timeouts
BOOLEAN KeyboardInitialized; // True if the keyboard is initialized
BOOLEAN MctadrRev2; // True if this is a rev2 ASIC
PRTL_ALLOCATE_STRING_ROUTINE RtlAllocateStringRoutine =
(PRTL_ALLOCATE_STRING_ROUTINE)FwAllocatePool;
PRTL_FREE_STRING_ROUTINE RtlFreeStringRoutine = FwpFreeStub;
#ifndef DUO
//
// Table of memory size for each valid configuration.
//
UCHAR ConfigurationSize[64]=
{ 0, 0, 0, 0, 4, 16, 0, 0,
0, 0, 0, 0, 8, 20, 20, 32,
0, 0, 0, 0, 8, 32, 0, 0,
0, 0, 0, 0, 12, 36, 24, 48,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 16, 40, 40, 64
};
USHORT FConfigurationSize[256]=
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
4, 16, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
8, 20, 68, 0, 0, 32, 80, 0, 0, 0,128, 0, 0, 0, 0, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
8, 32,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
12, 36,132, 0, 0, 48,144, 0, 0, 0,192, 0, 0, 0, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 24, 72, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
16, 40,136, 0, 0, 64,160, 0, 0, 0,256, 0, 0, 0, 0, 0 // F
};
#else
//
// This table indexed with the low 4 bits of the MemoryGroup config register,
// returns the size of memory installed in the group in Megabytes.
//
UCHAR GroupSize[16]=
{ 0, 0, 0, 0, // No SIMM installes
4, 16, 64, 0, // Single Sided
0, 0, 0, 0, // Reserved
8, 32,128, 0 // Double Sided.
};
#endif
//
// This variable is initialized to the size of the memory in Megabytes
//
ULONG MemorySize;
ULONG KSEG_BASE[3]={KSEG1_BASE,KSEG0_BASE,KSEG0_BASE};
ULONG XOR_KSEG_WRITE[3]={0x00000000,0xFFFFFFFF,0x01010101};
ULONG XOR_KSEG_READ[3]={0x00000000,0xFFFFFFFF,0x01010101};
//
// Declare function prototypes.
//
VOID
ReportJazzCacheErrorException(
IN ULONG CacheErr
);
VOID
ReportDuoCacheErrorException(
IN ULONG CacheErr
);
VOID
LoadDoubleWord(
IN ULONG Address,
OUT PVOID Result
);
VOID
InitializePCR(
);
VOID
FwBootSystem(
IN VOID
);
VOID
RomSelftest(
IN VOID
);
ARC_STATUS
SerialBootWrite(
CHAR Char,
ULONG SP
);
BOOLEAN
ValidNvram(
OUT PUCHAR StationAddress
);
VOID
WriteMemoryAddressTest(
ULONG StartAddress,
ULONG Size,
ULONG Xorpattern
);
PULONG
CheckMemoryAddressTest(
ULONG StartAddress,
ULONG Size,
ULONG Xorpattern,
ULONG LedDisplayValue
);
VOID
WriteVideoMemoryAddressTest(
ULONG StartAddress,
ULONG Size
);
ULONG
CheckVideoMemoryAddressTest(
ULONG StartAddress,
ULONG Size
);
VOID
SetSmallDCacheBlock(
IN VOID
);
VOID
WildZeroMemory(
ULONG StartAddress,
ULONG Size
);
VOID
SerialBootSetup(
IN ULONG FileId
);
VOID
FwSelftest(
IN ULONG Cause,
IN ULONG Arg1
);
VOID
FwSelftest(
IN ULONG Cause,
IN ULONG Arg1
)
/*++
Routine Description:
This routine is the c routine called from the ROM. It must be placed
at the beginning of the C code because the ROM copies the code from this
point to the end and then jumps to it.
Arguments:
Cause - 0 on a normal reset/powerup
1 on a softreset.
2 if an NMI occurred.
3 if a cache error/parity occurred.
Arg1 - Error EPC if an NMI occurred
CacheErr register if a cache error occurred
Return Value:
Never returns.
--*/
{
ULONG IntSrc;
#ifdef DUO
ULONG Config;
ULONG MemConfig;
LONG Group;
CHAR Diag;
#endif
CHAR String[128];
ULONG ProcessorBootStatus;
#ifndef DUO
//
// Initialize MemorySize to the size of memory in MegaBytes. Look for the
// MCT_ADR REV2 Map Prom bit in the configuration register, if there this
// is a REV2, otherwise REV1.
//
if (DMA_CONTROL->Configuration.Long & 0x400) {
MemorySize = FConfigurationSize[DMA_CONTROL->Configuration.Long & 0xFF];
MctadrRev2 = TRUE;
} else {
MemorySize = ConfigurationSize[DMA_CONTROL->Configuration.Long & 0x3F];
MctadrRev2 = FALSE;
}
#else
if (READ_REGISTER_ULONG(&DMA_CONTROL->WhoAmI.Long)) {
if (Cause == 2) {
//
// NMI
//
sprintf(String,
ST_NMI_MSG,
Arg1
);
FwPrint(ST_PROCESSOR_B_MSG);
FwPrint(String);
FwPrint(FW_SYSTEM_HALT_MSG);
for (;;) {
}
} else if (Cause == 3) {
//
// Cache error
//
} else {
//
// soft or cold reset.
//
ProcessorBMain();
}
}
MemorySize = 0;
for(Group=0;Group < 4; Group++) {
MemConfig = DMA_CONTROL->MemoryConfig[Group].Long;
MemorySize += GroupSize[MemConfig&0xF]; // plus size of group.
}
#endif
//
// Set variables according to the bits in configuration register
//
ConfigurationBit = FALSE;
IgnoreErrors = FALSE;
LoopOnError = FALSE;
DisplayOutput = FALSE;
SerialOutput = FALSE;
KeyboardInitialized = FALSE;
//
// Look for configuration register.
//
#ifdef DUO
Diag=READ_REGISTER_UCHAR(DIAGNOSTIC_VIRTUAL_BASE);
if ((Diag & LOOP_ON_ERROR_MASK) == 0) {
LoopOnError = TRUE;
}
if ((Diag & CONFIGURATION_MASK) == 0) {
ConfigurationBit = TRUE;
}
if ((Diag & IGNORE_ERRORS_MASK) == 0) {
IgnoreErrors = TRUE;
}
#endif
// Diag=READ_REGISTER_UCHAR(DIAGNOSTIC_VIRTUAL_BASE) & DIAGNOSTIC_MASK;
// switch (Diag) {
// case 0: IgnoreErrors = TRUE;
// break;
// case (1<<7): LoopOnError = TRUE;
// break;
// case (1<<6): ConfigurationBit = TRUE;
// break;
// }
//
// Set interrupt lines to a known state.
//
WRITE_REGISTER_UCHAR(&SP1_WRITE->ModemControl,0x08);
WRITE_REGISTER_UCHAR(&SP2_WRITE->ModemControl,0x08);
#ifndef DUO
WRITE_REGISTER_UCHAR(&FLOPPY_WRITE->DigitalOutput,0x08);
#endif
READ_REGISTER_UCHAR(&PARALLEL_READ->Status);
//
// Initialize the system parameter block.
//
SYSTEM_BLOCK->Signature = 0x53435241;
SYSTEM_BLOCK->Length = sizeof(SYSTEM_PARAMETER_BLOCK);
SYSTEM_BLOCK->Version = ARC_VERSION;
SYSTEM_BLOCK->Revision = ARC_REVISION;
//
// Allocate the restart block.
//
SYSTEM_BLOCK->RestartBlock = (PRESTART_BLOCK)((ULONG)((PUCHAR)SYSTEM_BLOCK + sizeof(SYSTEM_PARAMETER_BLOCK)) | KSEG1_BASE);
SYSTEM_BLOCK->DebugBlock = NULL;
#ifdef DUO
//
// Link the second restart block for processor B.
//
SYSTEM_BLOCK->RestartBlock->NextRestartBlock = (PRESTART_BLOCK)(((ULONG)SYSTEM_BLOCK + sizeof(SYSTEM_PARAMETER_BLOCK) + sizeof(RESTART_BLOCK)) | KSEG1_BASE);
SYSTEM_BLOCK->RestartBlock->NextRestartBlock->NextRestartBlock = NULL;
SYSTEM_BLOCK->FirmwareVector = (PVOID)((ULONG)((PUCHAR)SYSTEM_BLOCK + sizeof(SYSTEM_PARAMETER_BLOCK) + 2*sizeof(RESTART_BLOCK)) | KSEG1_BASE);
#else
SYSTEM_BLOCK->RestartBlock->NextRestartBlock = NULL;
SYSTEM_BLOCK->FirmwareVector =
(PVOID)((PUCHAR)SYSTEM_BLOCK + sizeof(SYSTEM_PARAMETER_BLOCK) + sizeof(RESTART_BLOCK));
#endif
SYSTEM_BLOCK->FirmwareVectorLength = (ULONG)MaximumRoutine * sizeof(ULONG);
SYSTEM_BLOCK->VendorVectorLength = (ULONG)MaximumVendorRoutine * sizeof(ULONG);
SYSTEM_BLOCK->VendorVector =
(PVOID)(SYSTEM_BLOCK->FirmwareVector +
SYSTEM_BLOCK->FirmwareVectorLength);
//
// If the configuration bit is set, go to the serial port.
//
PutLedDisplay(LED_NVRAM);
if (ConfigurationBit) {
//
// Test the serial port if not a soft reset.
//
if (Cause == 0) {
ExecuteTest((TestRoutine)RomSerialResetTest,LED_SERIAL_RESET);
ExecuteTest((TestRoutine)RomSerial1RegistersTest,LED_SERIAL1_REG);
ExecuteTest((TestRoutine)RomSerial2RegistersTest,LED_SERIAL2_REG);
ExecuteTest((TestRoutine)RomSerial1LoopBackTest,LED_SERIAL1_LBACK);
ExecuteTest((TestRoutine)RomSerial2LoopBackTest,LED_SERIAL2_LBACK);
PutLedDisplay(LED_SERIAL_INIT);
}
//
// Initialize the serial port as there is no configuration
// data to initialize the video.
//
SerialBootSetup(COMPORT2_VIRTUAL_BASE);
SerialOutput = TRUE;
ClearScreen()
} else {
//
// If there is a valid Ethernet station address, protect it.
//
if (ValidNvram(StationAddress) == TRUE) {
// WRITE_REGISTER_ULONG (&DMA_CONTROL->SystemSecurity.Long,READ_ONLY_DISABLE_WRITE);
}
//
// Test the video memory.
// Doesn't work for VXL
//
if (Cause == 0) {
// ExecuteTest((TestRoutine)RomVideoMemory,LED_VIDEOMEM);
PutLedDisplay(LED_VIDEO_CONTROLLER);
}
//TEMPTEMP
// if (DisplayBootInitialize() != ESUCCESS) {
// //
// // If video is broken and the NVRAM was ok and the config
// // bit was not set do not attempt to write to the serial port.
// // No output device is available, so hang.
// //
// PutLedDisplay((LED_BLINK << 16) | LED_VIDEO_CONTROLLER);
// } else {
// //
// // Video is ready to display messages.
// //
// DisplayOutput=TRUE;
// }
//TEMPTEMP
DisplayBootInitialize();
DisplayOutput=TRUE;
}
if (Cause == 2) {
//
// This is an NMI. Display a message and hang.
//
sprintf(String,
ST_NMI_MSG,
Arg1
);
FwPrint(String);
//
// Read The Interrupt source register and check the cause of the NMI.
//
#ifndef DUO
IntSrc = READ_REGISTER_ULONG(&DMA_CONTROL->InterruptSource.Long);
if (IntSrc & (1<<9)) {
sprintf(String,
ST_INVALID_ADDRESS_MSG,
READ_REGISTER_ULONG(&DMA_CONTROL->InvalidAddress.Long)
);
FwPrint(String);
}
if (IntSrc & (1<<10)) {
sprintf(String,
ST_IO_CACHE_ADDRESS_MSG,
READ_REGISTER_ULONG(&DMA_CONTROL->MemoryFailedAddress.Long)
);
FwPrint(String);
}
FwPrint(FW_SYSTEM_HALT_MSG);
#else
IntSrc = READ_REGISTER_ULONG(&DMA_CONTROL->NmiSource.Long);
if (IntSrc & (1<<1)) {
sprintf(String,
ST_INVALID_ADDRESS_MSG,
READ_REGISTER_ULONG(&DMA_CONTROL->InvalidAddress.Long)
);
FwPrint(String);
}
if (IntSrc & (1<<2)) {
sprintf(String,
ST_IO_CACHE_ADDRESS_MSG,
READ_REGISTER_ULONG(&DMA_CONTROL->MemoryFailedAddress.Long)
);
FwPrint(String);
}
//
// Notify processor B
//
WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
#endif
//
// Hang blinking LED.
//
PutLedDisplay((LED_BLINK << 16) | LED_NMI);
}
if (Cause == 3) {
#ifndef DUO
ReportJazzCacheErrorException(Arg1);
#else
ReportDuoCacheErrorException(Arg1);
#endif
PutLedDisplay((LED_BLINK << 16) | LED_PARITY);
}
//
// Reset the EISA bus. This is required because the EBC reset line on Jazz
// is connected wrong.
//
WRITE_REGISTER_UCHAR(&EISA_CONTROL->ExtendedNmiResetControl,0x01);
FwStallExecution(10);
WRITE_REGISTER_UCHAR(&EISA_CONTROL->ExtendedNmiResetControl,0x00);
FwStallExecution(10);
if (Cause == 0) {
//
// Execute selftest if it's not a soft reset.
//
FwPrintVersion();
FwPrint(FW_CRLF_MSG);
RomSelftest();
} else {
//
// Need to initialize whatever the Selftest initializes.
//
PutLedDisplay(LED_KEYBOARD_CTRL);
if (InitKeyboardController()) {
FwPrint(ST_KEYBOARD_ERROR_MSG);
}
PutLedDisplay(LED_ISP);
RomInitISP();
}
//
// Initialize master processor boot status.
//
ProcessorBootStatus = 0;
((PBOOT_STATUS)&ProcessorBootStatus)->ProcessorReady = 1;
((PBOOT_STATUS)&ProcessorBootStatus)->ProcessorRunning = 1;
((PBOOT_STATUS)&ProcessorBootStatus)->ProcessorStart = 1;
((PBOOT_STATUS)&ProcessorBootStatus)->BootStarted = 1;
SYSTEM_BLOCK->RestartBlock->BootStatus = *((PBOOT_STATUS)&ProcessorBootStatus);
//
// Zero the entire Memory.
//
PutLedDisplay(LED_ZEROMEM);
// WildZeroMemory(FW_TOP_ADDRESS,MEMORY_SIZE - FW_TOP_ADDRESS);
RtlZeroMemory((PVOID)(FW_TOP_ADDRESS | KSEG0_BASE),MEMORY_SIZE - FW_TOP_ADDRESS);
#ifdef DUO
//
// Initialize processor B boot status to not ready.
//
ProcessorBootStatus = 0;
//
// Processor B Has been idle all this time. Check if it is present
// and enable it.
//
Diag=READ_REGISTER_UCHAR(DIAGNOSTIC_VIRTUAL_BASE);
if (!(Diag & 1)) {
InitializePCR();
FwPrint(ST_ENABLE_PROCESSOR_B_MSG);
// HalSweepDcache();
//
// TEMPTEMP we want to see all icache misses for now
//
// HalSweepIcache();
//
// end TEMPTEMP
//
Config = READ_REGISTER_ULONG(&DMA_CONTROL->Configuration.Long);
WRITE_REGISTER_ULONG(&DMA_CONTROL->Configuration.Long,Config | ENABLE_PROCESSOR_B);
//
// Processor B has been enabled. It will execute the rom code to initialize
// its caches and then call ProcessorBMain from where it will issue
// an Ip interrupt to us.
//
if (WaitForIpInterrupt(5000) == FALSE) {
FwPrint(ST_TIMEOUT_PROCESSOR_B_MSG);
} else {
FwPrint(FW_OK_MSG);
//
// If Processor B passes selftest, set processor ready bit in boot status.
// Otherwise disable processor B
//
if (ProcessorBSelftest()) {
((PBOOT_STATUS)&ProcessorBootStatus)->ProcessorReady = 1;
ProcessorBEnabled = TRUE;
}
}
//
// If processor B failed selftest or never received its IP interrupt
// Disable It.
//
if (!ProcessorBEnabled) {
WRITE_REGISTER_ULONG(&DMA_CONTROL->Configuration.Long,Config);
FwPrint(ST_PROCESSOR_B_DISABLED_MSG);
}
} else {
FwPrint(ST_PROCESSOR_B_NOT_PRESENT_MSG);
}
SYSTEM_BLOCK->RestartBlock->NextRestartBlock->BootStatus = *((PBOOT_STATUS)&ProcessorBootStatus);
//
// Disable all interrupts except IP and Local Device (for keyboard)
//
WRITE_REGISTER_ULONG(&DMA_CONTROL->InterruptEnable.Long,
(ENABLE_IP_INTERRUPTS | ENABLE_DEVICE_INTERRUPTS));
#endif
InitializePCR();
PutLedDisplay(LED_BLANK<<4);
FwBootSystem();
//
// Hang if we come back.
//
PutLedDisplay((LED_BLINK << 16) | 0xBB);
}
VOID
RomSelftest (
IN VOID
)
/*++
Routine Description:
This routine implements the self-test video phase.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG Status;
ULONG i,j,Test,CurrentK;
LONG BlockSize;
CHAR String[128];
ULONG SIZE_OF_UNTESTED_MEMORY = MEMORY_SIZE-(FW_TOP_ADDRESS);
//TEMPTEMP
PULONG Cached;
PutLedDisplay(LED_MAIN_MEMORY);
//
// Display in the screen that the memory is being tested.
//
SetCursorPosition(4,1);
// sprintf(String,"Total memory is %d MBytes (%x)\r\n",MemorySize,DMA_CONTROL->Configuration.Long);
// FwPrint(String);
FwPrint(ST_MEMORY_TEST_MSG);
//
// Zero the memory so that memtest can run cached.
//
//WildZeroMemory(FW_TOP_ADDRESS,SIZE_OF_UNTESTED_MEMORY);
for (Test=0;Test<1;Test++) { // 3!!
//
// display on the screen and LED that we start writing.
//
// SetCursorPosition(1,14);
// sprintf(String,"%x",Test+1);
// FwPrint(String);
PutLedDisplay(LED_MAIN_MEMORY+Test+1);
//
// Write address test to the remaining untested memory
//
WriteMemoryAddressTest(KSEG0_BASE+FW_TOP_ADDRESS,
SIZE_OF_UNTESTED_MEMORY,
XOR_KSEG_WRITE[Test]);
//
// Adjust first block size to align the tested memory to a block boundary
//
BlockSize = KB_PER_TEST - TESTED_KB;
while (BlockSize <= 0) {
BlockSize += KB_PER_TEST;
}
CurrentK = TESTED_KB;
do {
//
// Display what has been tested so far.
//
SetCursorPosition(4,15);
sprintf(String,"%6d",CurrentK);
FwPrint(String);
Cached = CheckMemoryAddressTest(
KSEG0_BASE + (CurrentK << 10), // cached address
BlockSize << 10, // test up to next block boundary
XOR_KSEG_READ[Test], // Xor Pattern
(LED_BLINK << 16) + LED_MAIN_MEMORY);
if (Cached != 0) {
//
// Memory Error found.
//
FwPrint(ST_MEMORY_ERROR_MSG);
if (LoopOnError) {
// display in the LED that we start looping.
PutLedDisplay((LED_LOOP_ERROR << 16)+LED_MAIN_MEMORY);
for (;;) {
CheckMemoryAddressTest(
KSEG0_BASE + (CurrentK << 10), // cached address
BlockSize << 10, // test up to next block boundary
XOR_KSEG_READ[Test], // Xor Pattern
(LED_BLINK << 16) + LED_MAIN_MEMORY);
}
} else {
FwPrint(ST_HANG_MSG);
// hang blinking the LED
PutLedDisplay((LED_BLINK << 16) + LED_MAIN_MEMORY + Test + 1);
}
}
CurrentK += BlockSize;
BlockSize = KB_PER_TEST;
} while (CurrentK < KB_OF_MEMORY);
//
// display the final amount of tested memory.
//
SetCursorPosition(4,15);
sprintf(String,"%6d",CurrentK);
FwPrint(String);
}
// TEMPTEMP This test won't work on a secondary cache machine, fix.
// ExecuteTest((TestRoutine)RomReadMergeWrite,LED_READ_MERGE_WRITE);
//
// Test the rest of devices in the board.
//
FwPrint(ST_TEST_MSG);
FwPrint(ST_MEMORY_CONTROLLER_MSG);
if (ExecuteTest((TestRoutine)RomIOCacheTest,LED_IO_CACHE)) {
return;
}
//
// Enable interrupts and initialize dispatch table.
//
FwPrint(ST_TEST_MSG);
FwPrint(ST_INTERRUPT_CONTROLLER_MSG);
ConnectInterrupts();
if (ExecuteTest((TestRoutine)InterruptControllerTest,LED_INTERRUPT)) {
return;
}
FwPrint(ST_TEST_MSG);
FwPrint(ST_KEYBOARD_CONTROLLER_MSG);
if (ExecuteTest((TestRoutine)InitKeyboardController,LED_KEYBOARD_CTRL)) {
return;
}
KeyboardInitialized=TRUE;
MoveCursorLeft(3);
FwPrint(" ");
MoveCursorLeft(3);
PutLedDisplay(LED_KEYBOARD_INIT);
if (Status=InitKeyboard()) {
FwPrint(ST_ERROR_MSG);
if (Status == TIME_OUT) {
FwPrint(ST_KEYBOARD_NOT_PRESENT_MSG);
}
if (LoopOnError) {
PutLedDisplay((LED_LOOP_ERROR << 16) | LED_KEYBOARD_INIT);
for (;;) {
InitKeyboard();
}
} else {
if (IgnoreErrors) {
return;
} else {
FwPrint(ST_HANG_MSG);
PutLedDisplay((LED_BLINK << 16) | LED_KEYBOARD_INIT); // does not return.
}
}
} else {
FwPrint(FW_OK_MSG);
}
//
// Test the serial port if it's not being used as the output device.
//
if (SerialOutput == FALSE) {
FwPrint(ST_TEST_MSG);
FwPrint(ST_SERIAL_LINE_MSG);
if (ExecuteTest((TestRoutine)RomSerialResetTest,LED_SERIAL_RESET)) {
return;
}
if (ExecuteTest((TestRoutine)RomSerial1RegistersTest,LED_SERIAL1_REG)) {
return;
}
if (ExecuteTest((TestRoutine)RomSerial2RegistersTest,LED_SERIAL2_REG)) {
return;
}
if (ExecuteTest((TestRoutine)RomSerial1LoopBackTest,LED_SERIAL1_LBACK)) {
return;
}
if (ExecuteTest((TestRoutine)RomSerial2LoopBackTest,LED_SERIAL2_LBACK)) {
return;
}
}
FwPrint(ST_TEST_MSG);
FwPrint(ST_PARALLEL_PORT_MSG);
if (ExecuteTest((TestRoutine)RomParallelRegistersTest,LED_PARALLEL_REG)) {
return;
}
#ifndef DUO
FwPrint(ST_TEST_MSG);
FwPrint(ST_FLOPPY_MSG);
if (ExecuteTest((TestRoutine)RomFloppyResetTest,LED_FLOPPY_RESET)) {
return;
}
if (ExecuteTest((TestRoutine)RomFloppyRegistersTest,LED_FLOPPY_REG)) {
return;
}
#endif
FwPrint(ST_TEST_MSG);
FwPrint(ST_SCSI_MSG);
if (ExecuteTest((TestRoutine)RomScsiResetTest,LED_SCSI_RESET)) {
return;
}
if (ExecuteTest((TestRoutine)RomScsiRegistersTest,LED_SCSI_REG)) {
return;
}
FwPrint(ST_TEST_MSG);
FwPrint(ST_ETHERNET_MSG);
if (ExecuteTest((TestRoutine)RomSonicResetTest,LED_SONIC_RESET)) {
return;
}
if (ExecuteTest((TestRoutine)RomSonicRegistersTest,LED_SONIC_REG)) {
return;
}
//
// Do a loopback test if a valid address was found in the NVRAM.
//
if (ValidEthernetAddress) {
FwPrint(ST_ETHERNET_ADDRESS_MSG);
j=0;
for (i=0;i<6;i++) {
String[j++]=TranslationTable[StationAddress[i]>>4];
String[j++]=TranslationTable[StationAddress[i]&0xF];
}
String[j]='\0';
FwPrint(String);
FwPrint(ST_ETHERNET_LOOPBACK_MSG);
if (ExecuteTest((TestRoutine)RomSonicLoopBackTest,LED_SONIC_LOOPBACK)) {
return;
}
}
// RomSoundTest();
//
// Invalidate DMA translation table
//
WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationInvalidate.Long,0);
FwPrint(ST_TEST_MSG);
FwPrint(ST_ISP_MSG);
if (ExecuteTest((TestRoutine)RomInitISP,LED_ISP)) {
return;
}
FwPrint(ST_TEST_MSG);
FwPrint(ST_RTC_MSG);
if (ExecuteTest((TestRoutine)RomRTCTest,LED_RTC)) {
return;
}
FwPrint(FW_CRLF_MSG);
//
// Disable Interrupts so that the firmware can be initialized
//
DisableInterrupts();
}
BOOLEAN
ExecuteTest(
IN TestRoutine Test,
IN ULONG LedVal
)
/*++
Routine Description:
This routine executes the specified test. If the test fails and
the loop-on-error bit is set it sets the dot in the LED and reexecutes
the test for ever. If the loop-on-error bit is not set it will display
an error message and hang blinking the test and subtest number in the LED.
Arguments:
Test - Supplies a pointer to the rutine to execute.
LedVal - Subtest identifier to be displayed in the LED in case of error.
Return Value:
if the test passes returns FALSE.
if the test fails:
if Normal Mode and not KeyboardInitialized blinks test and subtest number in LED and hangs.
if Normal Mode and KeyboardInitialized, prompts for keypress and then returns TRUE.
if LoopOnError mode reexecutes the test indefinitly and hangs.
if IgnoreErrors mode returns TRUE.
--*/
{
PutLedDisplay(LedVal);
if (Test()) {
//
// The test failed.
//
FwPrint(ST_ERROR_MSG);
if (LoopOnError) {
PutLedDisplay((LED_LOOP_ERROR << 16) | LedVal);
for (;;) {
Test();
}
} else {
if (IgnoreErrors) {
//
// Invalidate TT and disable interrupts.
//
WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationInvalidate.Long,0);
DisableInterrupts();
return TRUE;
} else {
FwPrint(ST_HANG_MSG);
}
}
} else {
//
// display ...OK. and move the cursor left 3 chars
// so that if an error follows it overwrites OK.
//
FwPrint(FW_OK_MSG);
FwPrint("\x9B""3D");
return FALSE;
}
}
VOID
RomPutLine(
IN PCHAR String
)
/*++
Routine Description:
This routine displays the string in the video monitor or sends
it to a terminal trough the serial port during selftest.
Arguments:
String - String to display
Return Value:
None.
--*/
{
ULONG Count;
if (DisplayOutput) {
//
// Display message on the video.
//
DisplayWrite(0,String,strlen(String),&Count);
}
if (SerialOutput) {
//
// Display message on serial Line.
//
while (*String) {
SerialBootWrite(*String,COMPORT2_VIRTUAL_BASE);
String++;
}
}
}
ULONG
RomSerialRegistersTest(
IN ULONG SP_BASE
)
/*++
Routine Description:
This routine verifies that the Serial port 2 registers can be writen and
read.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
//
// Test registers
//
WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->LineControl,0xA5); // sets DLAB
WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->TransmitBuffer,0xC); // write DL (lsb) for 9600
WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->InterruptEnable,0x0); // write DL (msb) for 9600
CHECK_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->ReceiveBuffer,0xC) // check DL (lsb)
CHECK_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->InterruptEnable,0x0) // check DL (msb)
WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->LineControl,0x3); // Clears DLAB & sets8 bit no parity 1 stop bit
WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->InterruptEnable,0x0); // disable interrupts
WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->FifoControl,0x0); // disable fifo
CHECK_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->InterruptEnable,0x0) // check Int enable
CHECK_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->LineControl,0x3)
return Errors;
}
ULONG
RomSerialLoopBackTest(
IN ULONG SP_BASE
)
/*++
Routine Description:
This routine verifies that the Serial port is operational.
It performs an internal loopback of the ACE.
Arguments:
SP_BASE - Supplies the virtual address of the serial port.
Return Value:
Number of Errors found.
--*/
{
ULONG Errors=0;
ULONG i;
//
// Set loopback mode.
//
WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->ModemControl,0x18);
READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->LineStatus); // Clear status
READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->ReceiveBuffer); // Clear Data
for (i=0;i<256;i++) {
WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->TransmitBuffer,(UCHAR)i); // write to port
TimerTicks=3;
while (((READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->LineStatus) & 1) == 0) && TimerTicks) {
}
if (TimerTicks) {
CHECK_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->ReceiveBuffer,(UCHAR)i) // read and check
} else {
Errors++; // Timeout
}
}
//
// clear loopback mode and enable Interrupt line so it's not floating
//
WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->ModemControl,0x08);
return Errors;
}
ULONG
RomSerialResetTest(
)
/*++
Routine Description:
This routine verifies that the Serial port has been properly reset.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
//
// Check that was properly reset by checking the reset values.
//
CHECK_UCHAR(&SP1_READ->InterruptEnable, 0)
CHECK_UCHAR(&SP1_READ->InterruptId, 1)
CHECK_UCHAR(&SP1_READ->LineControl, 0)
CHECK_UCHAR(&SP1_READ->ModemControl, 0x8)
//
// Do the same with COM2
//
CHECK_UCHAR(&SP2_READ->InterruptEnable, 0)
CHECK_UCHAR(&SP2_READ->InterruptId, 1)
CHECK_UCHAR(&SP2_READ->LineControl, 0)
CHECK_UCHAR(&SP2_READ->ModemControl, 0x8)
return Errors;
}
ULONG
RomSerial1RegistersTest(
)
/*++
Routine Description:
This routine verifies that the Serial port 1 registers can be writen and
read.
Arguments:
None.
Return Value:
Returns the number of errors found.
--*/
{
return RomSerialRegistersTest(COMPORT1_VIRTUAL_BASE);
}
ULONG
RomSerial2RegistersTest(
)
/*++
Routine Description:
This routine verifies that the Serial port 1 registers can be writen and
read.
Arguments:
None.
Return Value:
Returns the number of errors found.
--*/
{
return RomSerialRegistersTest(COMPORT2_VIRTUAL_BASE);
}
ULONG
RomSerial1LoopBackTest(
)
/*++
Routine Description:
This routine verifies that the Serial is operational.
It performs an internal loopback of the ACE.
Arguments:
None.
Return Value:
Number of Errors found.
--*/
{
return RomSerialLoopBackTest(COMPORT1_VIRTUAL_BASE);
}
ULONG
RomSerial2LoopBackTest(
)
/*++
Routine Description:
This routine verifies that the Serial is operational.
It performs an internal loopback of the ACE.
Arguments:
None.
Return Value:
Number of Errors found.
--*/
{
return RomSerialLoopBackTest(COMPORT2_VIRTUAL_BASE);
}
ULONG
RomParallelRegistersTest(
)
/*++
Routine Description:
This routine verifies that the Parallel port registers can be writen and
read.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
UCHAR DataByte;
//
// Test registers. This only checks the static bits. Note: bit 2 of the
// status register and bit 5 of the control register are used in the second
// silicon.
//
DataByte = READ_REGISTER_UCHAR(&PARALLEL_READ->Status);
if ((DataByte & 0x1) != 0x1) {
Errors++;
}
DataByte = READ_REGISTER_UCHAR(&PARALLEL_READ->Control);
if ((DataByte & 0xC0) != 0xC0) {
Errors++;
}
return Errors;
}
#ifndef DUO
ULONG
RomScsiRegistersTest(
)
/*++
Routine Description:
This routine verifies that the NCR 53c94 SCSI controller registers can be writen and
read.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
//
// Test Registers
//
SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountLow,0xAA);
SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountHigh,0x55);
SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Command,0x80); // Issue a DMA NOP to load the counter
if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountLow) != 0xAA) { // check counter
Errors++;
}
if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountHigh) != 0x55) { // check counter
Errors++;
}
SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountLow,0x00);
SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountHigh,0x00);
SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Command,0x80); // Issue a DMA NOP to load the counter
if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountLow) != 0x00) { // check counter
Errors++;
}
if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountHigh) != 0x00) { // check counter
Errors++;
}
SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration1,0x57);
SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration2,0x58);
if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration1) != 0x57) { // check config1
Errors++;
}
if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration2) != 0x58) { // check config2
Errors++;
}
SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration1,0x00);
SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration2,0x00);
return Errors;
}
#else
ULONG
RomScsiRegistersTest(
)
/*++
Routine Description:
This routine verifies that the NCR C700 SCSI controller registers can be writen and
read.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
ULONG Entry;
UCHAR ByteLane;
UCHAR ScsiTestData[8] = {0x55,0xAA,0x11,0x22,0x44,0x88,0xFF,0x00};
UCHAR ScsiTestParity[8] = {0x8,0x0,0x8,0x8,0x0,0x0,0x8,0x0};
UCHAR Temp;
ULONG TempLong;
//
// Test SCSI 1 Registers
//
SCSI_WRITE_USHORT((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSP[0],0x5A0F); // write pattern to DSP pointer
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSPS[0],0xE1); // write pattern to DSPS0 pointer
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSPS[1],0xD2); // write pattern to DSPS0 pointer
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSPS[2],0xB4); // write pattern to DSPS0 pointer
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSPS[3],0x78); // write pattern to DSPS0 pointer
if ((Temp=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSP[0])) != 0x0F) { // check low 4 register
FwPrint("\r\nRegister %s Expected %lx received %lx\r\n","DSP[0]",0xf,Temp);
return 1;
Errors++;
}
if ((Temp=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSP[1])) != 0x5A) { // check low 4 register
FwPrint("\r\nRegister %s Expected %lx received %lx\r\n","DSP[1]",0x5A,Temp);
return 1;
Errors++;
}
if ((TempLong=SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSPS)) != 0x78B4D2E1) { // check low 4 register
FwPrint("\r\nRegister %s Expected %lx received %lx\r\n","DSPS",0x78B4D2E1,TempLong);
return 1;
Errors++;
}
//
// Test SCSI 2 Registers
//
SCSI_WRITE_USHORT((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSP[0],0x5A0F); // write pattern to DSP pointer
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSPS[0],0xE1); // write pattern to DSPS0 pointer
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSPS[1],0xD2); // write pattern to DSPS0 pointer
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSPS[2],0xB4); // write pattern to DSPS0 pointer
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSPS[3],0x78); // write pattern to DSPS0 pointer
if (SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSP[0]) != 0x0F) { // check low 4 register
FwPrint("Reg 22");
return 1;
Errors++;
}
if (SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSP[1]) != 0x5A) { // check low 4 register
FwPrint("Reg 33");
Errors++;
}
if (SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSPS) != 0x78B4D2E1) { // check low 4 register
FwPrint("Reg 44");
return 1;
Errors++;
}
//
// Test SCSI 1 DMA Fifo
//
for (ByteLane=0; ByteLane < 4; ByteLane++) {
//
// Select ByteLane
//
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST4,4+ByteLane);
//
// Write
//
for (Entry=0;Entry<8;Entry++) {
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST7,ScsiTestParity[Entry]);
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST6,ScsiTestData[Entry]);
}
//
// Read and check
//
for (Entry=0;Entry<8;Entry++) {
if ((Temp=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST6)) != ScsiTestData[Entry]) {
FwPrint("Reg CTEST6 expected %lx received %lx\r\n", ScsiTestData[Entry], Temp);
return 1;
Errors++;
}
if (((Temp=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST2))&0x8) != ScsiTestParity[Entry]) {
FwPrint("Reg CTEST2 expected %lx received %lx\r\n", ScsiTestParity[Entry], Temp);
return 1;
Errors++;
}
}
}
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST4,0);
//
// Test SCSI 2 DMA Fifo
//
for (ByteLane=0; ByteLane < 4; ByteLane++) {
//
// Select ByteLane
//
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST4,4+ByteLane);
//
// Write
//
for (Entry=0;Entry<8;Entry++) {
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST7,ScsiTestParity[Entry]);
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST6,ScsiTestData[Entry]);
}
//
// Read and check
//
for (Entry=0;Entry<8;Entry++) {
if ((Temp = SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST6)) != ScsiTestData[Entry]) {
FwPrint("Reg2 CTEST6 expected %lx received %lx\r\n", ScsiTestData[Entry], Temp);
return 1;
Errors++;
}
if (((Temp = SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST2))&0x8) != ScsiTestParity[Entry]) {
FwPrint("Reg2 CTEST2 expected %lx received %lx\r\n", ScsiTestParity[Entry], Temp);
return 1;
Errors++;
}
}
}
SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST4,0);
return Errors;
}
#endif
#ifndef DUO
ULONG
RomFloppyRegistersTest(
)
/*++
Routine Description:
This routine verifies that the Floppy controller registers can be writen and
read.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
//
// Test registers
//
WRITE_REGISTER_UCHAR(&FLOPPY_WRITE->DigitalOutput,0xec);
CHECK_UCHAR(&FLOPPY_READ->DigitalOutput,0xec )
WRITE_REGISTER_UCHAR(&FLOPPY_WRITE->DigitalOutput,0x7B);
CHECK_UCHAR(&FLOPPY_READ->DigitalOutput,0x7B )
WRITE_REGISTER_UCHAR(&FLOPPY_WRITE->DigitalOutput,0x08);
CHECK_UCHAR(&FLOPPY_READ->DigitalOutput, 0x08)
return Errors;
}
#endif
ULONG
RomSonicRegistersTest(
)
/*++
Routine Description:
This routine verifies that the Sonic registers can be writen and
read. It doesn't test all the accessible registers but all the
address bits are toggled.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
PSONIC_REGISTERS SonicBase = (volatile PSONIC_REGISTERS) NET_VIRTUAL_BASE;
USHORT Tmp;
//
// Test registers
//
WRITE_REGISTER_USHORT(&SonicBase->UTDA.Reg,0xAAAA);
WRITE_REGISTER_USHORT(&SonicBase->CRDA.Reg,0x5555);
WRITE_REGISTER_USHORT(&SonicBase->RRP.Reg,0x1E1E);
WRITE_REGISTER_USHORT(&SonicBase->RWP.Reg,0xC33C);
WRITE_REGISTER_USHORT(&SonicBase->WatchdogTimer0.Reg,0xFFFF);
WRITE_REGISTER_USHORT(&SonicBase->WatchdogTimer1.Reg,0x0000);
WRITE_REGISTER_USHORT(&SonicBase->FaeTally.Reg,0xFFFF); // clear counter
CHECK_USHORT(&SonicBase->UTDA.Reg, 0xAAAA)
CHECK_USHORT(&SonicBase->CRDA.Reg, 0x5555)
CHECK_USHORT(&SonicBase->RRP.Reg, 0x1E1E)
CHECK_USHORT(&SonicBase->RWP.Reg, 0xC33C)
CHECK_USHORT(&SonicBase->WatchdogTimer0.Reg, 0xFFFF)
CHECK_USHORT(&SonicBase->WatchdogTimer1.Reg, 0)
CHECK_USHORT(&SonicBase->FaeTally.Reg,0)
return Errors;
}
#ifndef DUO
ULONG
RomScsiResetTest(
)
/*++
Routine Description:
This routine verifies that the NCR 53c94 SCSI controller was properly reset.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
//
// Test that SCSI was properly reset
//
if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Fifo) != 0) { // check Fifo
Errors++;
}
if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,FifoFlags) != 0 ) { // check Fifo flags
Errors++;
}
if ((SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,ScsiStatus) & 0xF8) != 0) { // check status
Errors++;
}
return Errors;
}
#else
ULONG
RomScsiResetTest(
)
/*++
Routine Description:
This routine verifies that the NCR c700 SCSI controller was properly reset.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
ULONG Temp;
UCHAR Char;
USHORT Short;
//
// Test that SCSI 1 was properly reset
//
if ((Temp=SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,SCNTL0)) != 0xC0) { // check low 4 register
FwPrint("\r\nRegister %s received %lx\r\n","SCNTL0",Temp);
Errors++;
}
if ((Temp=SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,SCID)) != 0x0) { // check next 4 register
FwPrint("\r\nRegister %s received %lx\r\n","SCID",Temp);
Errors++;
}
if ((Char = SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST1)) != 0xF0) { // check next register
FwPrint("\r\nRegister %s received %lx\r\n","CTEST1",Char);
Errors++;
}
//
// This works on power up only.
//
// if ((Short=SCSI_READ_USHORT((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST2)) != 0x21) { // check next 2 register
// FwPrint("\r\nRegister %s received %lx\r\n","CTEST2",Short);
// Errors++;
// }
SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,SSTAT0);
if ((Char=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,ISTAT)) != 0x4) { // check next register
FwPrint("\r\nRegister %s received %lx\r\n","ISTAT",Char);
Errors++;
}
//
// Test that SCSI 2 was properly reset
//
if ((Temp=SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,SCNTL0)) != 0xC0) { // check low 4 register
FwPrint("\r\nRegister2 %s received %lx\r\n","SCNTL0",Temp);
Errors++;
}
if ((Temp=SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,SCID)) != 0x0) { // check next 4 register
FwPrint("\r\nRegister2 %s received %lx\r\n","SCID",Temp);
Errors++;
}
if ((Char = SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST1)) != 0xF0) { // check next register
FwPrint("\r\nRegister2 %s received %lx\r\n","CTEST1",Char);
Errors++;
}
// if ((Short=SCSI_READ_USHORT((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST2)) != 0x21) { // check next 2 register
// FwPrint("\r\nRegister2 %s received %lx\r\n","CTEST2",Short);
// Errors++;
// }
SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,SSTAT0);
if ((Char=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,ISTAT)) != 0x4) { // check next register
FwPrint("\r\nRegister2 %s received %lx\r\n","ISTAT",Char);
Errors++;
}
return Errors;
}
#endif
#ifndef DUO
ULONG
RomFloppyResetTest(
)
/*++
Routine Description:
This routine verifies that the Floppy controller has been properly reset.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
//
// Test that Floppy controller was properly reset
//
CHECK_UCHAR(&FLOPPY_READ->DigitalOutput, 0x8)
return Errors;
}
#endif
ULONG
RomSonicResetTest(
)
/*++
Routine Description:
This routine verifies that the Sonic cotroller has been properly reset.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG Errors=0;
PSONIC_REGISTERS SonicBase = (volatile PSONIC_REGISTERS) NET_VIRTUAL_BASE;
USHORT Tmp;
//
// Test that Sonic controller was properly reset
//
CHECK_USHORT(&SonicBase->Command.Reg, 0x94)
CHECK_USHORT(&SonicBase->TransmitControl.Reg, 0x101) // this line was commented out for duo
CHECK_USHORT(&SonicBase->InterruptStatus.Reg, 0x0)
CHECK_USHORT(&SonicBase->CamEnable.Reg, 0x0)
CHECK_USHORT(&SonicBase->ReceiveSequenceCounter.Reg, 0x0)
return Errors;
}
BOOLEAN
ValidNvram(
OUT PUCHAR StationAddress
)
/*++
Routine Description:
This routine checks that the Nvram is operational.
Arguments:
StationAddress - Pointer to struct to fill with the station address found in the
Nvram if it's there.
Return Value:
TRUE if the Nvram contains valid configuration data.
FALSE Otherwise.
--*/
{
ULONG i,Errors=0;
ULONG CheckSum;
PUCHAR NVRamReadWrite = (PUCHAR) (NVRAM_PAGE0);
PUCHAR NVRamProtected = (PUCHAR) (NVRAM_PAGE1);
PUCHAR NVRamReadOnly = (PUCHAR) (NVRAM_PAGE2);
//
// Check the Station Address
//
CheckSum=0;
for (i=0;i<6;i++) {
CheckSum+=NVRamReadOnly[i];
if (CheckSum >= 256) { // carry
CheckSum++; // Add the carry
CheckSum &= 0xFF; // remove it from bit 9
}
}
if ((NVRamReadOnly[7]+CheckSum != 0xFF) || (NVRamReadOnly[6]!=0)) {
ValidEthernetAddress=FALSE;
return FALSE;
} else {
ValidEthernetAddress=TRUE;
//
// Copy the station address.
//
for (i=0;i<6;i++) {
StationAddress[i]=NVRamReadOnly[i];
}
return TRUE;
}
}
#ifndef DUO
ULONG
RomIOCacheTest(
)
/*++
Routine Description:
This routine tests that the Jazz mctadr registers can be written and read.
Arguments:
None.
Return Value:
0 if no errors found
number of errors otherwise
--*/
{
ULONG Errors=0,i,Block;
//
// Check the 32 data path between mctadr and r4000 by writting to the
// byte mask and forcing an invalidate afterwards.
//
for (Block=0;Block<8;Block++) {
WRITE_REGISTER_ULONG(&DMA_CONTROL->CacheMaintenance.Long,Block<<2); // select cache block zero
WRITE_REGISTER_ULONG(&DMA_CONTROL->LogicalTag.Long,0x80000001); // set LFN to zero
// page offsset to zero
// read from device
// and validate Tag
WRITE_REGISTER_ULONG(&DMA_CONTROL->ByteMask.Long,0x0F0F0F0F); // set even words to valid.
WRITE_REGISTER_ULONG(&DMA_CONTROL->PhysicalTag.Long,1); // set PFN to zero and validate Tag
//
// Write data in the IO cache.
//
for (i=0;i<4;i++) { // ?? 2 because of the bug in the mctadr, should be 4
WRITE_REGISTER_ULONG(&DMA_CONTROL->CacheMaintenance.Long,(Block<<2)+i);// select line & Bank
WRITE_REGISTER_ULONG(&DMA_CONTROL->BufferWindowLow.Long,Block+i);
}
//
// Read from memory (and flush buffers) at phys address zero which should match with the phys tag
// thus invalidating it and clearing the byte mask.
//
for (i=0;i<2;i++) {
CHECK_ULONG(0xA0000000+(i<<3),Block+i);
}
}
return Errors;
}
#else
ULONG
RomIOCacheTest(
)
/*++
Routine Description:
This routine tests that the Duo mctadr registers can be written and read.
Arguments:
None.
Return Value:
0 if no errors found
number of errors otherwise
--*/
{
ULONG Errors=0,i,Block;
//
// Check the 32 data path between mctadr and r4000 by writting to the
// byte mask and forcing an invalidate afterwards.
//
for (Block=0;Block<8;Block++) {
WRITE_REGISTER_ULONG(&DMA_CONTROL->IoCacheLogicalTag[Block].Long,0x80000001); // set LFN to zero
// page offsset to zero
// read from device
// and validate Tag
WRITE_REGISTER_ULONG(&DMA_CONTROL->IoCacheLowByteMask[Block].Long,0x0F0F0F0F); // set even words to valid.
WRITE_REGISTER_ULONG(&DMA_CONTROL->IoCacheHighByteMask[Block].Long,0x0F0F0F0F); // set even words to valid.
WRITE_REGISTER_ULONG(&DMA_CONTROL->IoCachePhysicalTag[Block].Long,1); // set PFN to zero and validate Tag
//
// Write data in the IO cache.
//
for (i=0;i<8;i++) { // for each buffer register
WRITE_REGISTER_ULONG(&DMA_CONTROL->IoCacheBuffer[Block*8+i],Block+i);
}
//
// Read from memory (and flush buffers) at phys address zero which should match with the phys tag
// thus invalidating it and clearing the byte mask.
//
for (i=0;i<8;i++) {
CHECK_ULONG(0xA0000000+(i<<3),Block+i);
}
}
return Errors;
}
#endif
ULONG
InterruptControllerTest(
)
/*++
Routine Description:
This routine tests that the mctadr registers can be written and read.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG Errors=0,i=0;
TimerTicks=1; // set counter to 1
// write a zero for 1msec interval.
WRITE_REGISTER_ULONG(&DMA_CONTROL->InterruptInterval.Long,0);
while (TimerTicks) { // test counter until it's zero
READ_REGISTER_UCHAR(0xBFC00000); // read from ROM to waste time
if (i++ == 0x1FFFF) { // if timeout
Errors++; // return errors
return Errors;
}
}
return Errors;
}
VOID
RomBeep(
)
/*++
Routine Description:
This routine makes the speaker beep for a seconf.
Arguments:
None.
Return Value:
None.
--*/
{
PutLedDisplay(LED_BEEP);
WRITE_REGISTER_UCHAR(&ISP->IntTimer1CommandMode,0xB6);
WRITE_REGISTER_UCHAR(&ISP->IntTimer1SpeakerTone,0x97); // LSB for 440hz
WRITE_REGISTER_UCHAR(&ISP->IntTimer1SpeakerTone,0x0A); // MSB for 440Hz
WRITE_REGISTER_UCHAR(&ISP->NMIStatus,3); // Do notforce NMI just enable the speaker beep!
while (TimerTicks>500) { // wait until counter reaches 500
}
WRITE_REGISTER_UCHAR(&ISP->NMIStatus,0); // Disable the speaker beep.
}
UCHAR
ReadRTCRegister (
UCHAR Register
)
/*++
Routine Description:
This routine reads the specified register of the RTC
Arguments:
Register - Number of the register to read
Return Value:
Returns the contents of the RTC register.
--*/
{
//
// Write the register number into the NMI register of the ISP
// and disable NMI
//
WRITE_REGISTER_UCHAR(&ISP->NMIEnable,Register | (1 << 7));
//
// Read the register
//
return READ_REGISTER_UCHAR((PUCHAR)RTC_VIRTUAL_BASE);
}
VOID
WriteRTCRegister (
UCHAR Register,
UCHAR Value
)
/*++
Routine Description:
This routine writes the Value to the specified RTC register
Arguments:
Register - Number of the register to write
Value - Value to write to the RTC register.
Return Value:
None
--*/
{
//
// Write the register number into the NMI register of the ISP
// and disable NMI
//
WRITE_REGISTER_UCHAR(&ISP->NMIEnable,Register | (1 << 7));
//
// Write the register
//
WRITE_REGISTER_UCHAR((PUCHAR)RTC_VIRTUAL_BASE,Value);
}
ULONG
ReadTime(
)
/*++
Routine Description:
This routine reads the current time in the RTC.
Arguments:
None.
Return Value:
Number of seconds since time zero = Jan 1st 1900 12:00:00PM
--*/
{
UCHAR DataByte;
UCHAR Minutes,Seconds;
ULONG TotalSeconds;
//
// Check for an Update In Progress
//
do {
DataByte=ReadRTCRegister(RTC_CONTROL_REGISTERA);
} while (((PRTC_CONTROL_REGISTER_A)(&DataByte))->UpdateInProgress==1);
//
// Read Time from RTC and compute seconds.
//
Minutes = ReadRTCRegister(RTC_MINUTE); // read minutes
Seconds = ReadRTCRegister(RTC_SECOND); // read seconds
TotalSeconds = (Minutes * 60) + Seconds; // compute seconds
return TotalSeconds;
}
ULONG
RomRTCTest(
)
/*++
Routine Description:
This routine checks that the RTC is operating correctly by reading
the time, waiting for a 1.1 seconds, reading time again and checking
that the two times differ in 1 or 2 seconds.
If the RTC is disabled, this routine enables it and sets the time
to 12:00:00pm Jan 1st 1900. The RTC is set in Binary count mode, and
12h time format.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
UCHAR DataByte;
ULONG Time;
DataByte = ReadRTCRegister(RTC_CONTROL_REGISTERA);
if (((PRTC_CONTROL_REGISTER_A)(&DataByte))->TimebaseDivisor != 0x2) { // test DV bits to see if rtc is counting.
//
// Enable counter
//
DataByte = 0;
((PRTC_CONTROL_REGISTER_A)(&DataByte))->TimebaseDivisor = 2;
WriteRTCRegister(RTC_CONTROL_REGISTERA, DataByte);
Time = 0;
TimerTicks = 600; // set counter to 600
while (TimerTicks) { // Wait for an update to occur
}
//
// Set RTC to 24 hour format and binary mode. Set SET Bit
//
DataByte=0;
((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1;
((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 1;
((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 1;
WriteRTCRegister(RTC_CONTROL_REGISTERB, DataByte);
//
// RTC disabled set date to 1-1-1900 0h:0m:0
//
WriteRTCRegister(RTC_SECOND,0); //
WriteRTCRegister(RTC_MINUTE,0); // 12:00:00 PM
WriteRTCRegister(RTC_HOUR,0x12); //
WriteRTCRegister(RTC_DAY_OF_WEEK,1); //sunday
WriteRTCRegister(RTC_DAY_OF_MONTH,1); // 1st
WriteRTCRegister(RTC_MONTH,1); // january
WriteRTCRegister(RTC_YEAR,0); // 1900
WriteRTCRegister(RTC_SECOND_ALARM,0xFF); // Turn alarm
WriteRTCRegister(RTC_MINUTE_ALARM,0xFF); // off
WriteRTCRegister(RTC_HOUR_ALARM,0xFF); //
}
//
// Clear SET bit and put in binary mode
//
DataByte=0;
((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1;
((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 1;
WriteRTCRegister(RTC_CONTROL_REGISTERB, DataByte);
for (DataByte=0;DataByte<2;DataByte++) { // do it twice in case Hour changes
Time = ReadTime(); // Read Current time
TimerTicks=1050; // set timeout to 1.05 seconds
RomBeep(); // Do a beep in the meantime for 500ms
while (TimerTicks) { // Wait for an update
} //
Time = ReadTime() - Time; // compute elapsed time
if ((Time == 1) || (Time == 2)) { // 1 or 2 seconds passed
return 0; // RTC counts properly
}
} // if it didn't work even the second time it's screw up.
return 1;
}
ULONG
RomVideoMemory(
IN VOID
)
/*++
Routine Description:
This routine tests the video memory.
Arguments:
None.
Return Value:
Number of errors found.
--*/
{
ULONG VideoMemoryBaseAddress;
#ifdef R3000
VideoMemoryBaseAddress=VIDEO_MEMORY_PHYSICAL_BASE,
#else
VideoMemoryBaseAddress=VIDEO_MEMORY_VIRTUAL_BASE,
#endif
WriteVideoMemoryAddressTest(VideoMemoryBaseAddress,
VIDEO_MEMORY_SIZE
);
return CheckVideoMemoryAddressTest(VideoMemoryBaseAddress,
VIDEO_MEMORY_SIZE
);
}
ULONG
RomInitISP (
VOID
)
/*++
Routine Description:
This routine initializes the EISA interrupt controller.
Arguments:
None.
Return Value:
Returns the number of errors found.
--*/
{
UCHAR DataByte;
ULONG InterruptLevel;
//
// Initialize the EISA interrupt controller. There are two cascaded
// interrupt controllers, each of which must initialized with 4 initialize
// control words.
//
DataByte = 0;
((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1;
((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1;
WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt1ControlPort0,DataByte);
WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt2ControlPort0,DataByte);
//
// The second intitialization control word sets the iterrupt vector to
// 0-15.
//
DataByte = 0;
WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt1ControlPort1,DataByte);
DataByte = 0x08;
WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt2ControlPort1,DataByte);
//
// The thrid initialization control word set the controls for slave mode.
// The master ICW3 uses bit position and the slave ICW3 uses a numberic.
//
DataByte = 1 << SLAVE_IRQL_LEVEL;
WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt1ControlPort1,DataByte);
DataByte = SLAVE_IRQL_LEVEL;
WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt2ControlPort1,DataByte);
//
// The fourth initialization control word is used to specify normal
// end-of-interrupt mode and not special-fully-nested mode.
//
DataByte = 0;
((PINITIALIZATION_COMMAND_4) &DataByte)->I80x86Mode = 1;
WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt1ControlPort1,DataByte);
WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt2ControlPort1,DataByte);
//
// Mask all the interrupts.
//
WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt1ControlPort1,0xFF);
WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt2ControlPort1,0xFF);
//
// Check that the interrupt level is 7 (i.e. no interrupt is pending)
//
#ifndef DUO
InterruptLevel=READ_REGISTER_UCHAR(&DMA_CONTROL->InterruptAcknowledge);
InterruptLevel=READ_REGISTER_UCHAR(&DMA_CONTROL->InterruptAcknowledge);
if (InterruptLevel == 0x07) {
return 0;
} else {
return 1;
}
#else
InterruptLevel=READ_REGISTER_ULONG(&DMA_CONTROL->EisaInterruptAcknowledge);
InterruptLevel=READ_REGISTER_ULONG(&DMA_CONTROL->EisaInterruptAcknowledge);
if (InterruptLevel == 0x0) {
return 0;
} else {
FwPrint("\r\nEisa Interrupt level =%lx ",InterruptLevel);
return 1;
}
#endif
}
VOID
FwPrintVersion (
VOID
)
/*++
Routine Description:
This routine prints the PROM version.
Arguments:
None.
Return Value:
None.
--*/
{
FwPrint(ST_ARC_MULTIBOOT_MSG,*(PULONG)(PROM_ENTRY(2)));
FwPrint(ST_COPYRIGHT_MSG);
return;
}
#ifndef DUO
VOID
ReportJazzCacheErrorException(
IN ULONG CacheErr
)
/*++
Routine Description:
This routine prints cache error / parity information.
Arguments:
CacheErr - R4000 CacheErr register.
Return Value:
None.
--*/
{
ULONG ParityDiag[3];
PULONG ParDiag;
ULONG IntSrc;
UCHAR String[128];
//
// Display cache error exception message
//
FwPrint(MON_CACHE_ERROR_MSG);
FwPrint(MON_EXCEPTION_MSG);
//
// Align ParDiag to a double word.
//
ParDiag = (PULONG) ((ULONG)(&ParityDiag[1]) & 0xFFFFFFF8);
if (((PCACHEERR)(&CacheErr))->EE == 1) {
//
// This is a parity error on the Memory or SysAd bus.
//
IntSrc = READ_REGISTER_ULONG(&DMA_CONTROL->InterruptSource.Long);
if (IntSrc & (1 << 8)) {
//
// This a parity error in memory.
// Display MFAR and Parity Diag.
//
LoadDoubleWord((ULONG)&DMA_CONTROL->ParityDiagnosticLow.Long,ParDiag);
sprintf(String,
MON_MEM_PARITY_FAILED_MSG,
READ_REGISTER_ULONG(&DMA_CONTROL->MemoryFailedAddress.Long),
*ParDiag,
*(ParDiag+1)
);
FwPrint(String);
return;
} else {
//
// The error occurred in the system bus.
//
FwPrint(MON_BUS_PARITY_ERROR);
return;
}
} else {
//
// Internal cache error.
//
sprintf(String,MON_CACHE_ERROR_REG_MSG,CacheErr);
FwPrint(String);
return;
}
}
#else
VOID
ReportDuoCacheErrorException(
IN ULONG CacheErr
)
/*++
Routine Description:
This routine prints cache error / ecc information.
Arguments:
CacheErr - R4000 CacheErr register.
Return Value:
None.
--*/
{
UCHAR String[128];
//
// Display cache error exception message
//
FwPrint(MON_CACHE_ERROR_MSG);
FwPrint(MON_EXCEPTION_MSG);
if (READ_REGISTER_ULONG(&DMA_CONTROL->WhoAmI.Long)) {
FwPrint(MON_PROCESSOR_B_EXCEPTION);
} else {
FwPrint(MON_PROCESSOR_A_EXCEPTION);
}
if (((PCACHEERR)(&CacheErr))->EE == 1) {
//
// The error occurred in the system bus.
//
FwPrint(MON_BUS_PARITY_ERROR);
return;
} else {
//
// Internal cache error.
//
sprintf(String,MON_CACHE_ERROR_REG_MSG, CacheErr);
FwPrint(String);
return;
}
}
#endif