/** @file | |
HTE handling routines for MRC use. | |
Copyright (c) 2013-2015 Intel Corporation. | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "mrc.h" | |
#include "memory_options.h" | |
#include "io.h" | |
#include "hte.h" | |
#ifdef SIM | |
VOID delay_n(UINT32 nanoseconds); | |
#define MySimStall(a) delay_n(a/1000) | |
#endif | |
STATIC VOID EnableAllHteErrors( | |
UINT8 Mask) | |
/*++ | |
Routine Description: | |
This function enables to HTE to detect all possible errors for | |
the given training parameters (per-bit or full byte lane). | |
Returns: | |
None | |
--*/ | |
{ | |
isbW32m(HTE, 0x000200A2, 0xFFFFFFFF); | |
isbW32m(HTE, 0x000200A3, 0x000000FF); | |
isbW32m(HTE, 0x000200A4, 0x00000000); | |
} | |
STATIC UINT32 CheckHteErrors( | |
VOID) | |
/*++ | |
Routine Description: | |
This function goes and reads the HTE register in order to find any error | |
Returns: | |
The errors detected in the HTE status register | |
--*/ | |
{ | |
return isbR32m(HTE, 0x000200A7); | |
} | |
STATIC VOID WaitForHteComplete( | |
VOID) | |
/*++ | |
Routine Description: | |
This function waits until HTE finishes | |
Returns: | |
None | |
--*/ | |
{ | |
UINT32 Tmp; | |
ENTERFN(); | |
// | |
// Is the test done? | |
// | |
do | |
{ | |
#ifdef SIM | |
MySimStall (35000); // 35 ns delay | |
#endif | |
} while (0 != (isbR32m(HTE, 0x00020012) & BIT30)); | |
Tmp = isbR32m(HTE, 0x00020011); | |
Tmp = Tmp | BIT9; | |
Tmp = Tmp & ~(BIT13 | BIT12); | |
isbW32m(HTE, 0x00020011, Tmp); | |
LEAVEFN(); | |
} | |
STATIC VOID ClearHteErrorRegisters( | |
VOID) | |
/*++ | |
Routine Description: | |
Clears registers related with errors in the HTE. | |
Returns: | |
None | |
--*/ | |
{ | |
UINT32 Tmp; | |
// | |
// Clear all HTE errors and enable error checking | |
// for burst and chunk. | |
// | |
Tmp = isbR32m(HTE, 0x000200A1); | |
Tmp |= BIT8; | |
isbW32m(HTE, 0x000200A1, Tmp); | |
} | |
UINT32 HteMemInit( | |
MRC_PARAMS *CurrentMrcData, | |
UINT8 MemInitFlag, | |
UINT8 HaltHteEngineOnError) | |
/*++ | |
Routine Description: | |
Uses HW HTE engine to initialize or test all memory attached to a given DUNIT. | |
If MemInitFlag is 1, this routine writes 0s to all memory locations to initialize | |
ECC. | |
If MemInitFlag is 0, this routine will send an 5AA55AA5 pattern to all memory | |
locations on the RankMask and then read it back. Then it sends an A55AA55A | |
pattern to all memory locations on the RankMask and reads it back. | |
Arguments: | |
CurrentMrcData: Host struture for all MRC global data. | |
MemInitFlag: 0 for memtest, 1 for meminit. | |
HaltHteEngineOnError: Halt the HTE engine on first error observed, or keep | |
running to see how many errors are found. | |
Returns: | |
Errors register showing HTE failures. | |
Also prints out which rank failed the HTE test if failure occurs. | |
For rank detection to work, the address map must be left in its default | |
state. If MRC changes the address map, this function must be modified | |
to change it back to default at the beginning, then restore it at the end. | |
--*/ | |
{ | |
UINT32 Offset; | |
UINT8 TestNum; | |
UINT8 i; | |
// | |
// Clear out the error registers at the start of each memory | |
// init or memory test run. | |
// | |
ClearHteErrorRegisters(); | |
isbW32m(HTE, 0x00020062, 0x00000015); | |
for (Offset = 0x80; Offset <= 0x8F; Offset++) | |
{ | |
isbW32m(HTE, Offset, ((Offset & 1) ? 0xA55A : 0x5AA5)); | |
} | |
isbW32m(HTE, 0x00020021, 0x00000000); | |
#ifdef QUICKSIM | |
// Just do 4 cache lines for simulation memtest to save time. | |
isbW32m(HTE, 0x00020022, 4-1); | |
#else | |
isbW32m(HTE, 0x00020022, (CurrentMrcData->mem_size >> 6) - 1); | |
#endif | |
isbW32m(HTE, 0x00020063, 0xAAAAAAAA); | |
isbW32m(HTE, 0x00020064, 0xCCCCCCCC); | |
isbW32m(HTE, 0x00020065, 0xF0F0F0F0); | |
isbW32m(HTE, 0x00020066, 0x03000000); | |
switch (MemInitFlag) | |
{ | |
case MrcMemInit: | |
TestNum = 1; // Only 1 write pass through memory is needed to initialize ECC. | |
break; | |
case MrcMemTest: | |
TestNum = 4; // Write/read then write/read with inverted pattern. | |
break; | |
default: | |
DPF(D_INFO, "Unknown parameter for MemInitFlag: %d\n", MemInitFlag); | |
return 0xFFFFFFFF; | |
break; | |
} | |
DPF(D_INFO, "HteMemInit"); | |
for (i = 0; i < TestNum; i++) | |
{ | |
DPF(D_INFO, "."); | |
if (i == 0) | |
{ | |
isbW32m(HTE, 0x00020061, 0x00000000); | |
isbW32m(HTE, 0x00020020, 0x00110010); | |
} | |
else if (i == 1) | |
{ | |
isbW32m(HTE, 0x00020061, 0x00000000); | |
isbW32m(HTE, 0x00020020, 0x00010010); | |
} | |
else if (i == 2) | |
{ | |
isbW32m(HTE, 0x00020061, 0x00010100); | |
isbW32m(HTE, 0x00020020, 0x00110010); | |
} | |
else | |
{ | |
isbW32m(HTE, 0x00020061, 0x00010100); | |
isbW32m(HTE, 0x00020020, 0x00010010); | |
} | |
isbW32m(HTE, 0x00020011, 0x00111000); | |
isbW32m(HTE, 0x00020011, 0x00111100); | |
WaitForHteComplete(); | |
// | |
// If this is a READ pass, check for errors at the end. | |
// | |
if ((i % 2) == 1) | |
{ | |
// | |
// Return immediately if error. | |
// | |
if (CheckHteErrors()) | |
{ | |
break; | |
} | |
} | |
} | |
DPF(D_INFO, "done\n", i); | |
return CheckHteErrors(); | |
} | |
STATIC UINT16 BasicDataCompareHte( | |
MRC_PARAMS *CurrentMrcData, | |
UINT32 Address, | |
UINT8 FirstRun, | |
UINT8 Mode) | |
/*++ | |
Routine Description: | |
Execute basic single cache line memory write/read/verify test using simple constant | |
pattern (different for READ_RAIN and WRITE_TRAIN modes. | |
See BasicWriteReadHTE which is external visible wrapper. | |
Arguments: | |
CurrentMrcData: Host struture for all MRC global data. | |
Address: memory adress being tested (must hit specific channel/rank) | |
FirstRun: If set then hte registers are configured, otherwise | |
it is assumed configuration is done and just re-run the test. | |
Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern) | |
Returns: | |
Returns byte lane failure on each bit (for Quark only bit0 and bit1) | |
--*/ | |
{ | |
UINT32 Pattern; | |
UINT32 Offset; | |
if (FirstRun) | |
{ | |
isbW32m(HTE, 0x00020020, 0x01B10021); | |
isbW32m(HTE, 0x00020021, 0x06000000); | |
isbW32m(HTE, 0x00020022, Address >> 6); | |
isbW32m(HTE, 0x00020062, 0x00800015); | |
isbW32m(HTE, 0x00020063, 0xAAAAAAAA); | |
isbW32m(HTE, 0x00020064, 0xCCCCCCCC); | |
isbW32m(HTE, 0x00020065, 0xF0F0F0F0); | |
isbW32m(HTE, 0x00020061, 0x00030008); | |
if (Mode == WRITE_TRAIN) | |
{ | |
Pattern = 0xC33C0000; | |
} | |
else // READ_TRAIN | |
{ | |
Pattern = 0xAA5555AA; | |
} | |
for (Offset = 0x80; Offset <= 0x8F; Offset++) | |
{ | |
isbW32m(HTE, Offset, Pattern); | |
} | |
} | |
isbW32m(HTE, 0x000200A1, 0xFFFF1000); | |
isbW32m(HTE, 0x00020011, 0x00011000); | |
isbW32m(HTE, 0x00020011, 0x00011100); | |
WaitForHteComplete(); | |
// | |
// Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for any bytelane errors. | |
// | |
return ((CheckHteErrors() >> 8) & 0xFF); | |
} | |
STATIC UINT16 ReadWriteDataCompareHte( | |
MRC_PARAMS *CurrentMrcData, | |
UINT32 Address, | |
UINT8 LoopCount, | |
UINT32 LfsrSeedVictim, | |
UINT32 LfsrSeedAggressor, | |
UINT8 VictimBit, | |
UINT8 FirstRun) | |
/*++ | |
Routine Description: | |
Examines single cache line memory with write/read/verify test using | |
multiple data patterns (victim-aggressor algorithm). | |
See WriteStressBitLanesHTE which is external visible wrapper. | |
Arguments: | |
CurrentMrcData: host struture for all MRC global data. | |
Address: memory adress being tested (must hit specific channel/rank) | |
LoopCount: number of test iterations | |
LfsrSeedXxx: victim aggressor data pattern seed | |
VictimBit: should be 0 as auto rotate feature is in use. | |
FirstRun: If set then hte registers are configured, otherwise | |
it is assumed configuration is done and just re-run the test. | |
Returns: | |
Returns byte lane failure on each bit (for Quark only bit0 and bit1) | |
--*/ | |
{ | |
UINT32 Offset; | |
UINT32 Tmp; | |
if (FirstRun) | |
{ | |
isbW32m(HTE, 0x00020020, 0x00910024); | |
isbW32m(HTE, 0x00020023, 0x00810024); | |
isbW32m(HTE, 0x00020021, 0x06070000); | |
isbW32m(HTE, 0x00020024, 0x06070000); | |
isbW32m(HTE, 0x00020022, Address >> 6); | |
isbW32m(HTE, 0x00020025, Address >> 6); | |
isbW32m(HTE, 0x00020062, 0x0000002A); | |
isbW32m(HTE, 0x00020063, LfsrSeedVictim); | |
isbW32m(HTE, 0x00020064, LfsrSeedAggressor); | |
isbW32m(HTE, 0x00020065, LfsrSeedVictim); | |
// | |
// Write the pattern buffers to select the victim bit. Start with bit0. | |
// | |
for (Offset = 0x80; Offset <= 0x8F; Offset++) | |
{ | |
if ((Offset % 8) == VictimBit) | |
{ | |
isbW32m(HTE, Offset, 0x55555555); | |
} | |
else | |
{ | |
isbW32m(HTE, Offset, 0xCCCCCCCC); | |
} | |
} | |
isbW32m(HTE, 0x00020061, 0x00000000); | |
isbW32m(HTE, 0x00020066, 0x03440000); | |
isbW32m(HTE, 0x000200A1, 0xFFFF1000); | |
} | |
Tmp = 0x10001000 | (LoopCount << 16); | |
isbW32m(HTE, 0x00020011, Tmp); | |
isbW32m(HTE, 0x00020011, Tmp | BIT8); | |
WaitForHteComplete(); | |
return (CheckHteErrors() >> 8) & 0xFF; | |
} | |
UINT16 BasicWriteReadHTE( | |
MRC_PARAMS *CurrentMrcData, | |
UINT32 Address, | |
UINT8 FirstRun, | |
UINT8 Mode) | |
/*++ | |
Routine Description: | |
Execute basic single cache line memory write/read/verify test using simple constant | |
pattern (different for READ_RAIN and WRITE_TRAIN modes. | |
Arguments: | |
CurrentMrcData: Host struture for all MRC global data. | |
Address: memory adress being tested (must hit specific channel/rank) | |
FirstRun: If set then hte registers are configured, otherwise | |
it is assumed configuration is done and just re-run the test. | |
Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern) | |
Returns: | |
Returns byte lane failure on each bit (for Quark only bit0 and bit1) | |
--*/ | |
{ | |
UINT16 ByteLaneErrors; | |
ENTERFN(); | |
// | |
// Enable all error reporting in preparation for HTE test. | |
// | |
EnableAllHteErrors(0xFF); | |
ClearHteErrorRegisters(); | |
ByteLaneErrors = BasicDataCompareHte(CurrentMrcData, Address, FirstRun, | |
Mode); | |
LEAVEFN(); | |
return ByteLaneErrors; | |
} | |
UINT16 WriteStressBitLanesHTE( | |
MRC_PARAMS *CurrentMrcData, | |
UINT32 Address, | |
UINT8 FirstRun) | |
/*++ | |
Routine Description: | |
Examines single cache line memory with write/read/verify test using | |
multiple data patterns (victim-aggressor algorithm). | |
Arguments: | |
CurrentMrcData: host struture for all MRC global data. | |
Address: memory adress being tested (must hit specific channel/rank) | |
FirstRun: If set then hte registers are configured, otherwise | |
it is assumed configuration is done and just re-run the test. | |
Returns: | |
Returns byte lane failure on each bit (for Quark only bit0 and bit1) | |
--*/ | |
{ | |
UINT16 ByteLaneErrors; | |
UINT8 VictimBit = 0; | |
ENTERFN(); | |
// | |
// Enable all error reporting in preparation for HTE test. | |
// | |
EnableAllHteErrors(0xFF); | |
ClearHteErrorRegisters(); | |
// | |
// Loop through each bit in the bytelane. Each pass creates a victim bit | |
// while keeping all other bits the same - as aggressors. | |
// AVN HTE adds an auto-rotate feature which allows us to program the entire victim/aggressor | |
// sequence in 1 step. The victim bit rotates on each pass so no need to have software implement | |
// a victim bit loop like on VLV. | |
// | |
ByteLaneErrors = ReadWriteDataCompareHte(CurrentMrcData, Address, | |
HTE_LOOP_CNT, HTE_LFSR_VICTIM_SEED, HTE_LFSR_AGRESSOR_SEED, VictimBit, | |
FirstRun); | |
LEAVEFN(); | |
return ByteLaneErrors; | |
} | |
VOID HteMemOp( | |
UINT32 Address, | |
UINT8 FirstRun, | |
UINT8 IsWrite) | |
/*++ | |
Routine Description: | |
Execute basic single cache line memory write or read. | |
This is just for receive enable / fine write levelling purpose. | |
Arguments: | |
CurrentMrcData: Host structure for all MRC global data. | |
Address: memory address used (must hit specific channel/rank) | |
FirstRun: If set then hte registers are configured, otherwise | |
it is assumed configuration is done and just re-run the test. | |
IsWrite: When non-zero memory write operation executed, otherwise read | |
Returns: | |
None | |
--*/ | |
{ | |
UINT32 Offset; | |
UINT32 Tmp; | |
EnableAllHteErrors(0xFF); | |
ClearHteErrorRegisters(); | |
if (FirstRun) | |
{ | |
Tmp = IsWrite ? 0x01110021 : 0x01010021; | |
isbW32m(HTE, 0x00020020, Tmp); | |
isbW32m(HTE, 0x00020021, 0x06000000); | |
isbW32m(HTE, 0x00020022, Address >> 6); | |
isbW32m(HTE, 0x00020062, 0x00800015); | |
isbW32m(HTE, 0x00020063, 0xAAAAAAAA); | |
isbW32m(HTE, 0x00020064, 0xCCCCCCCC); | |
isbW32m(HTE, 0x00020065, 0xF0F0F0F0); | |
isbW32m(HTE, 0x00020061, 0x00030008); | |
for (Offset = 0x80; Offset <= 0x8F; Offset++) | |
{ | |
isbW32m(HTE, Offset, 0xC33C0000); | |
} | |
} | |
isbW32m(HTE, 0x000200A1, 0xFFFF1000); | |
isbW32m(HTE, 0x00020011, 0x00011000); | |
isbW32m(HTE, 0x00020011, 0x00011100); | |
WaitForHteComplete(); | |
} | |