1 /** @file
2 HTE handling routines for MRC use.
3 
4 Copyright (c) 2013-2015 Intel Corporation.
5 
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "mrc.h"
11 #include "memory_options.h"
12 #include "io.h"
13 
14 #include "hte.h"
15 
16 
17 #ifdef SIM
18 VOID delay_n(UINT32 nanoseconds);
19 #define MySimStall(a)   delay_n(a/1000)
20 #endif
21 
22 STATIC VOID EnableAllHteErrors(
23     UINT8 Mask)
24 /*++
25 
26  Routine Description:
27 
28  This function enables to HTE to detect all possible errors for
29  the given training parameters (per-bit or full byte lane).
30 
31  Returns:
32 
33  None
34 
35  --*/
36 {
37   isbW32m(HTE, 0x000200A2, 0xFFFFFFFF);
38   isbW32m(HTE, 0x000200A3, 0x000000FF);
39   isbW32m(HTE, 0x000200A4, 0x00000000);
40 }
41 
42 STATIC UINT32 CheckHteErrors(
43     VOID)
44 /*++
45 
46  Routine Description:
47 
48  This function goes and reads the HTE register in order to find any error
49 
50  Returns:
51 
52  The errors detected in the HTE status register
53 
54  --*/
55 {
56   return isbR32m(HTE, 0x000200A7);
57 }
58 
59 STATIC VOID WaitForHteComplete(
60     VOID)
61 /*++
62 
63  Routine Description:
64 
65  This function waits until HTE finishes
66 
67  Returns:
68 
69  None
70 
71  --*/
72 {
73   UINT32 Tmp;
74 
75   ENTERFN();
76 
77   //
78   // Is the test done?
79   //
80   do
81   {
82 #ifdef SIM
83     MySimStall (35000); // 35 ns delay
84 #endif
85   } while (0 != (isbR32m(HTE, 0x00020012) & BIT30));
86 
87   Tmp = isbR32m(HTE, 0x00020011);
88   Tmp = Tmp | BIT9;
89   Tmp = Tmp & ~(BIT13 | BIT12);
90   isbW32m(HTE, 0x00020011, Tmp);
91 
92   LEAVEFN();
93 }
94 
95 STATIC VOID ClearHteErrorRegisters(
96     VOID)
97 /*++
98 
99  Routine Description:
100 
101  Clears registers related with errors in the HTE.
102 
103  Returns:
104 
105  None
106 
107  --*/
108 {
109   UINT32 Tmp;
110 
111   //
112   // Clear all HTE errors and enable error checking
113   // for burst and chunk.
114   //
115   Tmp = isbR32m(HTE, 0x000200A1);
116   Tmp |= BIT8;
117   isbW32m(HTE, 0x000200A1, Tmp);
118 }
119 
120 UINT32 HteMemInit(
121     MRC_PARAMS *CurrentMrcData,
122     UINT8 MemInitFlag,
123     UINT8 HaltHteEngineOnError)
124 
125 /*++
126 
127  Routine Description:
128 
129  Uses HW HTE engine to initialize or test all memory attached to a given DUNIT.
130  If MemInitFlag is 1, this routine writes 0s to all memory locations to initialize
131  ECC.
132  If MemInitFlag is 0, this routine will send an 5AA55AA5 pattern to all memory
133  locations on the RankMask and then read it back.  Then it sends an A55AA55A
134  pattern to all memory locations on the RankMask and reads it back.
135 
136  Arguments:
137 
138  CurrentMrcData: Host struture for all MRC global data.
139  MemInitFlag: 0 for memtest, 1 for meminit.
140  HaltHteEngineOnError:  Halt the HTE engine on first error observed, or keep
141  running to see how many errors are found.
142 
143  Returns:
144  Errors register showing HTE failures.
145  Also prints out which rank failed the HTE test if failure occurs.
146  For rank detection to work, the address map must be left in its default
147  state.  If MRC changes the address map, this function must be modified
148  to change it back to default at the beginning, then restore it at the end.
149 
150  --*/
151 {
152   UINT32 Offset;
153   UINT8 TestNum;
154   UINT8 i;
155 
156   //
157   // Clear out the error registers at the start of each memory
158   // init or memory test run.
159   //
160   ClearHteErrorRegisters();
161 
162   isbW32m(HTE, 0x00020062, 0x00000015);
163 
164   for (Offset = 0x80; Offset <= 0x8F; Offset++)
165   {
166     isbW32m(HTE, Offset, ((Offset & 1) ? 0xA55A : 0x5AA5));
167   }
168 
169   isbW32m(HTE, 0x00020021, 0x00000000);
170 #ifdef QUICKSIM
171   // Just do 4 cache lines for simulation memtest to save time.
172   isbW32m(HTE, 0x00020022, 4-1);
173 #else
174   isbW32m(HTE, 0x00020022, (CurrentMrcData->mem_size >> 6) - 1);
175 #endif
176 
177   isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
178   isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
179   isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
180   isbW32m(HTE, 0x00020066, 0x03000000);
181 
182   switch (MemInitFlag)
183   {
184   case MrcMemInit:
185     TestNum = 1; // Only 1 write pass through memory is needed to initialize ECC.
186     break;
187   case MrcMemTest:
188     TestNum = 4; // Write/read then write/read with inverted pattern.
189     break;
190   default:
191     DPF(D_INFO, "Unknown parameter for MemInitFlag: %d\n", MemInitFlag);
192     return 0xFFFFFFFF;
193     break;
194   }
195 
196   DPF(D_INFO, "HteMemInit");
197   for (i = 0; i < TestNum; i++)
198   {
199     DPF(D_INFO, ".");
200 
201     if (i == 0)
202     {
203       isbW32m(HTE, 0x00020061, 0x00000000);
204       isbW32m(HTE, 0x00020020, 0x00110010);
205     }
206     else if (i == 1)
207     {
208       isbW32m(HTE, 0x00020061, 0x00000000);
209       isbW32m(HTE, 0x00020020, 0x00010010);
210     }
211     else if (i == 2)
212     {
213       isbW32m(HTE, 0x00020061, 0x00010100);
214       isbW32m(HTE, 0x00020020, 0x00110010);
215     }
216     else
217     {
218       isbW32m(HTE, 0x00020061, 0x00010100);
219       isbW32m(HTE, 0x00020020, 0x00010010);
220     }
221 
222     isbW32m(HTE, 0x00020011, 0x00111000);
223     isbW32m(HTE, 0x00020011, 0x00111100);
224 
225     WaitForHteComplete();
226 
227     //
228     // If this is a READ pass, check for errors at the end.
229     //
230     if ((i % 2) == 1)
231     {
232       //
233       // Return immediately if  error.
234       //
235       if (CheckHteErrors())
236       {
237         break;
238       }
239     }
240   }
241 
242   DPF(D_INFO, "done\n", i);
243   return CheckHteErrors();
244 }
245 
246 STATIC UINT16 BasicDataCompareHte(
247     MRC_PARAMS *CurrentMrcData,
248     UINT32 Address,
249     UINT8 FirstRun,
250     UINT8 Mode)
251 /*++
252 
253  Routine Description:
254 
255  Execute basic single cache line memory write/read/verify test using simple constant
256  pattern (different for READ_RAIN and WRITE_TRAIN modes.
257  See BasicWriteReadHTE which is external visible wrapper.
258 
259  Arguments:
260 
261  CurrentMrcData: Host struture for all MRC global data.
262  Address: memory adress being tested (must hit specific channel/rank)
263  FirstRun: If set then hte registers are configured, otherwise
264  it is assumed configuration is done and just re-run the test.
265  Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)
266 
267  Returns:
268  Returns byte lane failure on each bit (for Quark only bit0 and bit1)
269 
270  --*/
271 {
272   UINT32 Pattern;
273   UINT32 Offset;
274 
275   if (FirstRun)
276   {
277     isbW32m(HTE, 0x00020020, 0x01B10021);
278     isbW32m(HTE, 0x00020021, 0x06000000);
279     isbW32m(HTE, 0x00020022, Address >> 6);
280     isbW32m(HTE, 0x00020062, 0x00800015);
281     isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
282     isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
283     isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
284     isbW32m(HTE, 0x00020061, 0x00030008);
285 
286     if (Mode == WRITE_TRAIN)
287     {
288       Pattern = 0xC33C0000;
289     }
290     else // READ_TRAIN
291     {
292       Pattern = 0xAA5555AA;
293     }
294 
295     for (Offset = 0x80; Offset <= 0x8F; Offset++)
296     {
297       isbW32m(HTE, Offset, Pattern);
298     }
299   }
300 
301   isbW32m(HTE, 0x000200A1, 0xFFFF1000);
302 
303   isbW32m(HTE, 0x00020011, 0x00011000);
304   isbW32m(HTE, 0x00020011, 0x00011100);
305 
306   WaitForHteComplete();
307 
308   //
309   // Return bits 15:8 of HTE_CH0_ERR_XSTAT to check for any bytelane errors.
310   //
311   return ((CheckHteErrors() >> 8) & 0xFF);
312 }
313 
314 STATIC UINT16 ReadWriteDataCompareHte(
315     MRC_PARAMS *CurrentMrcData,
316     UINT32 Address,
317     UINT8 LoopCount,
318     UINT32 LfsrSeedVictim,
319     UINT32 LfsrSeedAggressor,
320     UINT8 VictimBit,
321     UINT8 FirstRun)
322 /*++
323 
324  Routine Description:
325 
326  Examines single cache line memory with write/read/verify test using
327  multiple data patterns (victim-aggressor algorithm).
328  See WriteStressBitLanesHTE which is external visible wrapper.
329 
330  Arguments:
331 
332  CurrentMrcData: host struture for all MRC global data.
333  Address: memory adress being tested (must hit specific channel/rank)
334  LoopCount: number of test iterations
335  LfsrSeedXxx: victim aggressor data pattern seed
336  VictimBit: should be 0 as auto rotate feature is in use.
337  FirstRun: If set then hte registers are configured, otherwise
338  it is assumed configuration is done and just re-run the test.
339 
340  Returns:
341  Returns byte lane failure on each bit (for Quark only bit0 and bit1)
342 
343  --*/
344 {
345   UINT32 Offset;
346   UINT32 Tmp;
347 
348   if (FirstRun)
349   {
350     isbW32m(HTE, 0x00020020, 0x00910024);
351     isbW32m(HTE, 0x00020023, 0x00810024);
352     isbW32m(HTE, 0x00020021, 0x06070000);
353     isbW32m(HTE, 0x00020024, 0x06070000);
354     isbW32m(HTE, 0x00020022, Address >> 6);
355     isbW32m(HTE, 0x00020025, Address >> 6);
356     isbW32m(HTE, 0x00020062, 0x0000002A);
357     isbW32m(HTE, 0x00020063, LfsrSeedVictim);
358     isbW32m(HTE, 0x00020064, LfsrSeedAggressor);
359     isbW32m(HTE, 0x00020065, LfsrSeedVictim);
360 
361     //
362     // Write the pattern buffers to select the victim bit. Start with bit0.
363     //
364     for (Offset = 0x80; Offset <= 0x8F; Offset++)
365     {
366       if ((Offset % 8) == VictimBit)
367       {
368         isbW32m(HTE, Offset, 0x55555555);
369       }
370       else
371       {
372         isbW32m(HTE, Offset, 0xCCCCCCCC);
373       }
374     }
375 
376     isbW32m(HTE, 0x00020061, 0x00000000);
377     isbW32m(HTE, 0x00020066, 0x03440000);
378     isbW32m(HTE, 0x000200A1, 0xFFFF1000);
379   }
380 
381   Tmp = 0x10001000 | (LoopCount << 16);
382   isbW32m(HTE, 0x00020011, Tmp);
383   isbW32m(HTE, 0x00020011, Tmp | BIT8);
384 
385   WaitForHteComplete();
386 
387   return (CheckHteErrors() >> 8) & 0xFF;
388 }
389 
390 UINT16 BasicWriteReadHTE(
391     MRC_PARAMS *CurrentMrcData,
392     UINT32 Address,
393     UINT8 FirstRun,
394     UINT8 Mode)
395 /*++
396 
397  Routine Description:
398 
399  Execute basic single cache line memory write/read/verify test using simple constant
400  pattern (different for READ_RAIN and WRITE_TRAIN modes.
401 
402  Arguments:
403 
404  CurrentMrcData: Host struture for all MRC global data.
405  Address: memory adress being tested (must hit specific channel/rank)
406  FirstRun: If set then hte registers are configured, otherwise
407  it is assumed configuration is done and just re-run the test.
408  Mode: READ_TRAIN or WRITE_TRAIN (the difference is in the pattern)
409 
410  Returns:
411  Returns byte lane failure on each bit (for Quark only bit0 and bit1)
412 
413  --*/
414 {
415   UINT16 ByteLaneErrors;
416 
417   ENTERFN();
418 
419   //
420   // Enable all error reporting in preparation for HTE test.
421   //
422   EnableAllHteErrors(0xFF);
423   ClearHteErrorRegisters();
424 
425   ByteLaneErrors = BasicDataCompareHte(CurrentMrcData, Address, FirstRun,
426       Mode);
427 
428   LEAVEFN();
429   return ByteLaneErrors;
430 }
431 
432 UINT16 WriteStressBitLanesHTE(
433     MRC_PARAMS *CurrentMrcData,
434     UINT32 Address,
435     UINT8 FirstRun)
436 /*++
437 
438  Routine Description:
439 
440  Examines single cache line memory with write/read/verify test using
441  multiple data patterns (victim-aggressor algorithm).
442 
443  Arguments:
444 
445  CurrentMrcData: host struture for all MRC global data.
446  Address: memory adress being tested (must hit specific channel/rank)
447  FirstRun: If set then hte registers are configured, otherwise
448  it is assumed configuration is done and just re-run the test.
449 
450  Returns:
451  Returns byte lane failure on each bit (for Quark only bit0 and bit1)
452 
453  --*/
454 {
455   UINT16 ByteLaneErrors;
456   UINT8 VictimBit = 0;
457 
458   ENTERFN();
459 
460   //
461   // Enable all error reporting in preparation for HTE test.
462   //
463   EnableAllHteErrors(0xFF);
464   ClearHteErrorRegisters();
465 
466   //
467   // Loop through each bit in the bytelane.  Each pass creates a victim bit
468   // while keeping all other bits the same - as aggressors.
469   // AVN HTE adds an auto-rotate feature which allows us to program the entire victim/aggressor
470   // sequence in 1 step. The victim bit rotates on each pass so no need to have software implement
471   // a victim bit loop like on VLV.
472   //
473   ByteLaneErrors = ReadWriteDataCompareHte(CurrentMrcData, Address,
474       HTE_LOOP_CNT, HTE_LFSR_VICTIM_SEED, HTE_LFSR_AGRESSOR_SEED, VictimBit,
475       FirstRun);
476 
477   LEAVEFN();
478   return ByteLaneErrors;
479 }
480 
481 VOID HteMemOp(
482     UINT32 Address,
483     UINT8 FirstRun,
484     UINT8 IsWrite)
485 /*++
486 
487  Routine Description:
488 
489  Execute basic single cache line memory write or read.
490  This is just for receive enable / fine write levelling purpose.
491 
492  Arguments:
493 
494  CurrentMrcData: Host structure for all MRC global data.
495  Address: memory address used (must hit specific channel/rank)
496  FirstRun: If set then hte registers are configured, otherwise
497  it is assumed configuration is done and just re-run the test.
498  IsWrite: When non-zero memory write operation executed, otherwise read
499 
500  Returns:
501  None
502 
503  --*/
504 {
505   UINT32 Offset;
506   UINT32 Tmp;
507 
508   EnableAllHteErrors(0xFF);
509   ClearHteErrorRegisters();
510 
511   if (FirstRun)
512   {
513     Tmp = IsWrite ? 0x01110021 : 0x01010021;
514     isbW32m(HTE, 0x00020020, Tmp);
515 
516     isbW32m(HTE, 0x00020021, 0x06000000);
517     isbW32m(HTE, 0x00020022, Address >> 6);
518     isbW32m(HTE, 0x00020062, 0x00800015);
519     isbW32m(HTE, 0x00020063, 0xAAAAAAAA);
520     isbW32m(HTE, 0x00020064, 0xCCCCCCCC);
521     isbW32m(HTE, 0x00020065, 0xF0F0F0F0);
522     isbW32m(HTE, 0x00020061, 0x00030008);
523 
524     for (Offset = 0x80; Offset <= 0x8F; Offset++)
525     {
526       isbW32m(HTE, Offset, 0xC33C0000);
527     }
528   }
529 
530   isbW32m(HTE, 0x000200A1, 0xFFFF1000);
531   isbW32m(HTE, 0x00020011, 0x00011000);
532   isbW32m(HTE, 0x00020011, 0x00011100);
533 
534   WaitForHteComplete();
535 }
536 
537