6 * Technology initialization and control workd support for DDR3 LRDIMMS
8 * @xrefitem bom "File Content Label" "Release Content"
10 * @e sub-project: (Mem/Tech/DDR3)
11 * @e \$Revision: 23714 $ @e \$Date: 2009-12-09 17:28:37 -0600 (Wed, 09 Dec 2009) $
14 /*****************************************************************************
16 * Copyright (C) 2012 Advanced Micro Devices, Inc.
17 * All rights reserved.
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are met:
21 * * Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * * Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * * Neither the name of Advanced Micro Devices, Inc. nor the names of
27 * its contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
34 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
37 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 * ***************************************************************************
46 *----------------------------------------------------------------------------
49 *----------------------------------------------------------------------------
65 #include "mtlrdimm3.h"
67 #include "GeneralServices.h"
71 #define FILECODE PROC_MEM_TECH_DDR3_MTLRDIMM3_FILECODE
72 /*----------------------------------------------------------------------------
73 * DEFINITIONS AND MACROS
75 *----------------------------------------------------------------------------
78 /*----------------------------------------------------------------------------
79 * TYPEDEFS AND STRUCTURES
81 *----------------------------------------------------------------------------
84 /*----------------------------------------------------------------------------
85 * PROTOTYPES OF LOCAL FUNCTIONS
87 *----------------------------------------------------------------------------
93 IN OUT MEM_TECH_BLOCK *TechPtr,
101 MemTSendExtMBCtlWord3 (
102 IN OUT MEM_TECH_BLOCK *TechPtr,
110 MemTGetSpecialMBCtlWord3 (
111 IN OUT MEM_TECH_BLOCK *TechPtr,
119 MemTLrDimmControlRegInit3 (
120 IN OUT MEM_TECH_BLOCK *TechPtr,
121 IN OUT VOID *OptParam
126 MemTLrDimmFreqChgCtrlWrd3 (
127 IN OUT MEM_TECH_BLOCK *TechPtr,
128 IN OUT VOID *OptParam
133 MemTWLPrepareLrdimm3 (
134 IN OUT MEM_TECH_BLOCK *TechPtr,
140 MemTSendAllMRCmdsLR3 (
141 IN OUT MEM_TECH_BLOCK *TechPtr,
148 IN OUT MEM_TECH_BLOCK *TechPtr,
156 IN OUT MEM_TECH_BLOCK *TechPtr,
163 MemTLrdimmRankMultiplication (
164 IN OUT MEM_TECH_BLOCK *TechPtr,
170 MemTLrdimmBuf2DramTrain3 (
171 IN OUT MEM_TECH_BLOCK *TechPtr,
172 IN OUT VOID *OptParam
177 MemTLrdimmSyncTrainedDlys (
178 IN OUT MEM_TECH_BLOCK *TechPtr,
179 IN OUT VOID *OptParam
185 IN OUT MEM_TECH_BLOCK *TechPtr,
191 MemTLrDimmGetBufferID (
192 IN OUT MEM_TECH_BLOCK *TechPtr,
199 IN OUT MEM_TECH_BLOCK *TechPtr,
200 IN LRDIMM_HOOK_ENTRYPOINT Entrypoint,
202 IN OUT VOID *OptParam
205 /*----------------------------------------------------------------------------
208 *----------------------------------------------------------------------------
211 /* -----------------------------------------------------------------------------*/
214 * This function initializes LRDIMM functions.
216 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
221 MemTLrdimmConstructor3 (
222 IN OUT MEM_TECH_BLOCK *TechPtr
225 TechPtr->TechnologySpecificHook[LrdimmSendAllMRCmds] = MemTSendAllMRCmdsLR3;
226 TechPtr->TechnologySpecificHook[LrdimmControlRegInit] = MemTLrDimmControlRegInit3;
227 TechPtr->TechnologySpecificHook[LrdimmFreqChgCtrlWrd] = MemTLrDimmFreqChgCtrlWrd3;
228 TechPtr->TechnologySpecificHook[WlTrainingPrepareLrdimm] = MemTWLPrepareLrdimm3;
229 TechPtr->TechnologySpecificHook[LrdimmRankMultiplication] = MemTLrdimmRankMultiplication;
230 TechPtr->TechnologySpecificHook[LrdimmBuf2DramTrain] = MemTLrdimmBuf2DramTrain3;
231 TechPtr->TechnologySpecificHook[LrdimmSyncTrainedDlys] = MemTLrdimmSyncTrainedDlys;
232 TechPtr->TechnologySpecificHook[LrdimmPresence] = MemTLrdimmPresence;
236 /*----------------------------------------------------------------------------
239 *----------------------------------------------------------------------------
242 /* -----------------------------------------------------------------------------*/
245 * This function sends a Control word command to an LRDIMM Memory Buffer
247 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
248 * @param[in] Fn - control word function
249 * @param[in] Rcw - control word number
250 * @param[in] Value - value to send
257 IN OUT MEM_TECH_BLOCK *TechPtr,
265 NBPtr = TechPtr->NBPtr;
267 ASSERT (Rcw != RCW_FN_SELECT); // RC7 can only be used for function select
268 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tF%dRC%d = %x\n", Fn, Rcw, Value);
270 // Select the MB Function by sending the Fn number
271 // to the Function Select Control Word
273 MemUWait10ns (800, NBPtr->MemPtr);
274 MemTSendCtlWord3 (TechPtr, RCW_FN_SELECT, Fn);
276 // Send the value to the control word
278 MemUWait10ns (800, NBPtr->MemPtr);
279 MemTSendCtlWord3 (TechPtr, Rcw, Value);
282 /* -----------------------------------------------------------------------------*/
285 * This function sends a an Extended Control word command to an LRDIMM Memory Buffer
287 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
288 * @param[in] Addr - Extended Control Word Address
289 * Addr[15:12] Extended Control Workd Function Select
290 * Addr[11:0] Extended Control Word CSR Address
291 * @param[in] Data - value to send
292 * @param[in] Len - Length of data. 1 or 2 bytes
298 MemTSendExtMBCtlWord3 (
299 IN OUT MEM_TECH_BLOCK *TechPtr,
307 NBPtr = TechPtr->NBPtr;
309 ASSERT ((Len == 1) || (Len == 2));
311 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tExtRC_x%04x = %04x\n", Addr, Data);
313 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tExtRC_x%04x = %02x\n", Addr, (UINT8) (Data & 0xFF) );
316 // Select the MB Function by sending the Fn number
317 // to the Function Select Control Word
319 MemUWait10ns (800, NBPtr->MemPtr);
320 MemTSendCtlWord3 (TechPtr, RCW_FN_SELECT, 13);
322 // Send address via control words
324 MemUWait10ns (800, NBPtr->MemPtr);
325 MemTSendCtlWord3 (TechPtr, 9, (UINT8) (Addr >> 12));
326 MemUWait10ns (800, NBPtr->MemPtr);
327 MemTSendCtlWord3 (TechPtr, 10, (UINT8) (Addr & 0xF));
328 MemUWait10ns (800, NBPtr->MemPtr);
329 MemTSendCtlWord3 (TechPtr, 11, (UINT8) ((Addr >> 4) & 0x0F));
330 MemUWait10ns (800, NBPtr->MemPtr);
331 MemTSendCtlWord3 (TechPtr, 12, (UINT8) ((Addr >> 8) & 0x0F));
333 // Send the Lower Byte of Data
335 MemUWait10ns (800, NBPtr->MemPtr);
336 MemTSendCtlWord3 (TechPtr, 14, (UINT8) (Data & 0xF));
337 MemUWait10ns (800, NBPtr->MemPtr);
338 MemTSendCtlWord3 (TechPtr, 15, (UINT8) ((Data >> 4) & 0x0F));
340 // Send the Upper Byte of Data
343 MemUWait10ns (800, NBPtr->MemPtr);
344 MemTSendCtlWord3 (TechPtr, 10, (UINT8) ((Addr & 0xF) + 1));
345 MemUWait10ns (800, NBPtr->MemPtr);
346 MemTSendCtlWord3 (TechPtr, 14, (UINT8) ((Data >> 8) & 0xF));
347 MemUWait10ns (800, NBPtr->MemPtr);
348 MemTSendCtlWord3 (TechPtr, 15, (UINT8) ((Data >> 12) & 0xF));
352 /* -----------------------------------------------------------------------------*/
355 * This function gets the value of special RCW
357 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
358 * @param[in] Dimm - Physical LR DIMM number
359 * @param[in] Fn - control word function
360 * @param[in] Rc - control word number
362 * @return Special RCW value
368 MemTGetSpecialMBCtlWord3 (
369 IN OUT MEM_TECH_BLOCK *TechPtr,
375 CONST UINT8 F0RC13PhyRankTab[] = {3, 2, 0, 1, 0};
383 NBPtr = TechPtr->NBPtr;
385 MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm);
393 Value8 = NBPtr->PsPtr->F0RC8;
397 // 2:0 OperatingSpeed: operating speed. BIOS: Table 88.
398 if (NBPtr->DCTPtr->Timings.Speed == DDR667_FREQUENCY) {
401 Value8 = (UINT8) (NBPtr->DCTPtr->Timings.Speed / 133) - 3;
406 // 3:2 ParityCalculation: partiy calculation. BIOS: Table.
407 // 1:0 OperatingVoltage: operating voltage. BIOS: IF(VDDIO == 1.5) THEN 00b ELSEIF (VDDIO ==
408 // 1.35) THEN 01b ELSE 10b ENDIF.
409 DramCap = SpdBufferPtr[SPD_DENSITY] & 0xF;
410 if (NBPtr->PsPtr->LrdimmRowAddrBits[Dimm] > 16) {
415 Value8 |= CONVERT_VDDIO_TO_ENCODED (NBPtr->RefPtr->DDR3Voltage);
419 // 3:2 NumLogicalRanks: partiy calculation. BIOS: Table 90.
420 // 1:0 NumPhysicalRanks: operating voltage. BIOS: Table 89.
421 LogRanks = NBPtr->ChannelPtr->LrDimmLogicalRanks[Dimm] >> 1;
422 PhyRanks = F0RC13PhyRankTab[(SpdBufferPtr[SPD_RANKS] >> 3) & 7];
423 Value8 = (LogRanks << 2) | PhyRanks;
427 // 3 DramBusWidth: DRAM bus width. BIOS: IF (DeviceWidth==0) THEN 0 ELSE 1 ENDIF.
428 // 2 MRSCommandControl: MRS command control. BIOS: IF (F0RC15[RankMultiplicationControl]
429 // > 0) THEN 1 ELSE 0 ENDIF.
430 // 1 RefreshPrechargeCommandControl: refresh and precharge command control. BIOS: IF
431 // (F0RC15[RankMultiplicationControl] > 0) THEN D18F2xA8_dct[1:0][LrDimmEnhRefEn] ELSE 0 ENDIF.
432 // 0 AddressMirror: address mirror. BIOS: RankMap. See D18F2x[5C:40]_dct[1:0][OnDimmMirror].
433 if ((SpdBufferPtr[SPD_DEV_WIDTH] & 7) != 0) {
436 if (NBPtr->ChannelPtr->LrDimmRankMult[Dimm] > 1) {
438 if (NBPtr->GetBitField (NBPtr, BFLrDimmEnhRefEn) == 1) {
442 if ((SpdBufferPtr[SPD_ADDRMAP] & 1) != 0) {
448 // 3:0 RankMultiplicationControl: rank multiplication control. BIOS: Table 91.
449 DramCap = SpdBufferPtr[SPD_DENSITY] & 0xF;
450 ASSERT ((DramCap >= 2) && (DramCap <= 4)); // BKDG only lists 1Gb, 2Gb, and 4Gb
451 switch (NBPtr->ChannelPtr->LrDimmRankMult[Dimm]) {
456 Value8 = DramCap - 1;
459 Value8 = DramCap + 3;
473 Value8 = NBPtr->PsPtr->F1RC0;
474 Value8 |= (UINT8) NBPtr->GetBitField (NBPtr, BFCSTimingMux67) << 3;
478 Value8 = NBPtr->PsPtr->F1RC1;
482 Value8 = NBPtr->PsPtr->F1RC2;
486 if (NBPtr->GetBitField (NBPtr, BFLrDimmEnhRefEn) == 0) {
498 // 3 TDQSControl: TDQS control. BIOS: 0.
499 // 2:0 RttNom: RttNom. BIOS: Table 57, Table 60
500 Value8 = NBPtr->PsPtr->RttNom[Dimm << 1];
504 // 3 Vref: Vref. BIOS: 0.
505 // 2:0 RttWr: RttWr. BIOS: Table 57, Table 60.
506 Value8 = NBPtr->PsPtr->RttWr[Dimm << 1];
510 // IF (D18F2x90_dct[1:0][X4Dimm] == 0) THEN 1 ELSE 0
511 if (NBPtr->GetBitField (NBPtr, BFX4Dimm) == 0) {
526 /* -----------------------------------------------------------------------------*/
529 * This function sends LRDIMM Control Words to all LRDIMMS
531 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
532 * @param[in,out] OptParam - Optional parameter
539 MemTLrDimmControlRegInit3 (
540 IN OUT MEM_TECH_BLOCK *TechPtr,
541 IN OUT VOID *OptParam
544 CONST UINT8 RCWInitTable[] = {
546 F0, RC0, 0x00, SPD_NONE,
547 F0, RC1, 0x00, SPD_NONE,
548 F0, RC2, 0x03, SPD_67,
549 F0, RC10, 0x00, SPECIAL_CASE,
550 F0, RC11, 0x00, SPECIAL_CASE,
552 F1, RC8, 0x0F, SPD_69,
553 F1, RC11, 0xF0, SPD_69,
554 F1, RC12, 0x0F, SPD_70,
555 F1, RC13, 0xF0, SPD_70,
556 F1, RC14, 0x0F, SPD_71,
557 F1, RC15, 0xF0, SPD_71,
561 F0, RC3, 0xF0, SPD_67,
562 F0, RC4, 0x0F, SPD_68,
563 F0, RC5, 0xF0, SPD_68,
565 F0, RC6, 0x00, SPD_NONE,
566 F0, RC8, 0x00, SPECIAL_CASE,
567 F0, RC9, 0x0C, SPD_NONE,
568 F0, RC13, 0x00, SPECIAL_CASE,
569 F0, RC14, 0x00, SPECIAL_CASE,
570 F0, RC15, 0x00, SPECIAL_CASE,
572 F1, RC0, 0x00, SPECIAL_CASE,
573 F1, RC1, 0x00, SPECIAL_CASE,
574 F1, RC2, 0x00, SPECIAL_CASE,
575 F1, RC3, 0x00, SPD_NONE,
576 F1, RC9, 0x00, SPECIAL_CASE,
577 F1, RC10, 0x00, SPD_NONE,
579 F2, RC0, 0x00, SPD_NONE,
580 F2, RC1, 0x00, SPD_NONE,
581 F2, RC2, 0x0F, SPD_NONE,
582 F2, RC3, 0x00, SPD_NONE,
584 F3, RC0, 0x00, SPECIAL_CASE,
585 F3, RC1, 0x00, SPECIAL_CASE,
586 F3, RC2, 0x01, SPD_NONE,
587 F3, RC6, 0x00, SPECIAL_CASE
589 // F3 RC[8,9] are programmed in MDQ RC loop
591 // F[10:3] RC[11,10] are programmed in QxODT RC loop
593 // F[15,14] RC[15:0] are programmed in personality RC loop
604 UINT8 FreqDiffOffset;
607 MEM_DATA_STRUCT *MemPtr;
610 NBPtr = TechPtr->NBPtr;
611 MemPtr = NBPtr->MemPtr;
613 if (NBPtr->MCTPtr->Status[SbLrdimms]) {
614 for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
615 DimmMask = (UINT16)1 << Dimm;
616 if ((NBPtr->ChannelPtr->LrDimmPresent & DimmMask) != 0) {
618 // Select the Target Chipselects
620 NBPtr->SetBitField (NBPtr, BFMrsChipSel, (Dimm << 1));
621 NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (Dimm << 1));
623 MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm);
625 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tSending LRDIMM Control Words: Dimm %02x\n", Dimm);
627 for (i = 0; i < sizeof (RCWInitTable) ; i += 4) {
628 Fn = RCWInitTable[i];
629 Rc = RCWInitTable[i + 1];
630 Mask = RCWInitTable[i + 2];
631 Spd = RCWInitTable[i + 3];
633 if (Fn == WAIT_6US) {
634 MemUWait10ns (600, MemPtr); // wait 6us for TSTAB
636 if (Spd == SPD_NONE) {
638 } else if (Spd == SPECIAL_CASE) {
639 Value8 = MemTGetSpecialMBCtlWord3 (TechPtr, Dimm, Fn, Rc);
641 Value8 = (Mask > 0x0F) ? ((SpdBufferPtr[Spd] & Mask) >> 4) : (SpdBufferPtr[Spd] & Mask);
643 MemTSendMBCtlWord3 (TechPtr, Fn, Rc, Value8);
647 FreqDiffOffset = (UINT8) (SPD_FREQ_DIFF_OFFSET * (((NBPtr->DCTPtr->Timings.Speed / 133) - 3) / 2));
649 // Send RCW to program MDQ termination and drive strength
651 for (Rc = 8; Rc <= 9; Rc++) {
652 Value8 = SpdBufferPtr[SPD_MDQ_800_1066 + FreqDiffOffset];
653 Value8 = (Rc == 9) ? (Value8 >> 4) : Value8;
654 MemTSendMBCtlWord3 (TechPtr, 3, Rc, Value8 & 0x07);
657 // Send RCW to program QxODT
659 for (Fn = 3; Fn <= 10; Fn ++) {
660 for (Rc = 10; Rc <= 11; Rc++) {
661 Value8 = SpdBufferPtr[SPD_QXODT_800_1066 + FreqDiffOffset + ((Fn - 3) >> 1)];
662 Value8 = (Rc == 11) ? (Value8 >> 4) : (Value8 & 0x0F);
663 Value8 = ((Fn & 1) == 0) ? (Value8 >> 2) : (Value8 & 0x03);
664 MemTSendMBCtlWord3 (TechPtr, Fn, Rc, Value8);
668 MemTLrdimmInitHook (TechPtr, AFTER_TSTAB, Dimm, 0);
670 // Send Personality bytes from SPD
672 for (i = 0; i < 15; i ++) {
673 Value8 = SpdBufferPtr[SPD_PERSONALITY_BYTE + i];
674 Fn = (UINT8) (14 + (i >> 3));
675 Rc = (UINT8) ((i << 1) & 0x0F);
678 } else if ( i > 10) {
681 MemTSendMBCtlWord3 (TechPtr, Fn, Rc, (Value8 & 0x0F));
687 MemTSendMBCtlWord3 (TechPtr, Fn, Rc, (Value8 >> 4));
690 // Send Extended Control Words to Buffer
694 MemTSendExtMBCtlWord3 (TechPtr, 0x00AC, 0, 1);
698 Value8 = SpdBufferPtr[SPD_MR1_MR2_800_1066 + FreqDiffOffset];
699 for (i = 0x00B8; i < 0x00C0; i++) {
700 MemTSendExtMBCtlWord3 (TechPtr, i, Value8, 1);
703 // Phys ranks > 1, Rtt_nom = 0
709 Value8 = (UINT8) (NBPtr->MemNGetMR0CL (NBPtr) & 0x000000FF);
710 Value8 = ((Value8 & 0xE0) | ((Value8 & 0x04) << 1));
711 Value8 |= 1<<2; // RBT
712 Value8 |= NBPtr->GetBitField (NBPtr, BFBurstCtrl); // BL
713 MemTSendExtMBCtlWord3 (TechPtr, 0x00C8 , Value8, 1);
716 Value8 = (UINT8) (NBPtr->GetBitField (NBPtr, BFPchgPDModeSel) & 0x000000FF);
717 NBPtr->FamilySpecificHook[MR0_PPD] (NBPtr, &Value8);
718 IDS_OPTION_HOOK (IDS_MEM_MR0, &Value8, &TechPtr->NBPtr->MemPtr->StdHeader);
721 Temp32 = NBPtr->MemNGetMR0WR (NBPtr);
722 Value8 |= (UINT8) ((Temp32 >> 8) & 0x000000FF);
723 MemTSendExtMBCtlWord3 (TechPtr, 0x00C9 , Value8, 1);
725 MemTSendExtMBCtlWord3 (TechPtr, 0x00CA , 0, 1);
727 MemTSendExtMBCtlWord3 (TechPtr, 0x00CB , 0, 1);
730 Value8 = (UINT8) (NBPtr->MemNGetMR2CWL (NBPtr) & 0x000000FF);
733 MemTSendExtMBCtlWord3 (TechPtr, 0x00CC , Value8, 1);
735 MemTSendExtMBCtlWord3 (TechPtr, 0x00CD , 0, 1);
737 MemTSendExtMBCtlWord3 (TechPtr, 0x00CE , 0, 1);
739 MemTSendExtMBCtlWord3 (TechPtr, 0x00CF , 0, 1);
746 /* -----------------------------------------------------------------------------*/
749 * This function sends LRDIMM Control Words to all LRDIMMS
751 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
752 * @param[in,out] OptParam - Optional parameter
754 * @return FALSE - The current channel does not have LRDIMM populated
755 * TRUE - The current channel has LRDIMM populated
759 MemTLrDimmFreqChgCtrlWrd3 (
760 IN OUT MEM_TECH_BLOCK *TechPtr,
761 IN OUT VOID *OptParam
767 NBPtr = TechPtr->NBPtr;
769 if (NBPtr->MCTPtr->Status[SbLrdimms]) {
770 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
771 MemNSwitchDCTNb (NBPtr, Dct);
772 if (NBPtr->DCTPtr->Timings.DctMemSize != 0) {
773 MemTLrDimmControlRegInit3 (TechPtr, NULL);
781 /*-----------------------------------------------------------------------------
784 * This function prepares LRDIMMs for WL training.
786 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
787 * @param[in,out] *Wl - Indicates if WL mode should be enabled
789 * @return TRUE - LRDIMMs present
790 * ----------------------------------------------------------------------------
794 MemTWLPrepareLrdimm3 (
795 IN OUT MEM_TECH_BLOCK *TechPtr,
803 NBPtr = TechPtr->NBPtr;
805 if (NBPtr->MCTPtr->Status[SbLrdimms]) {
806 for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
807 if (*(BOOLEAN *) Wl == TRUE) {
809 NBPtr->SetBitField (NBPtr, BFWrLvOdt, NBPtr->ChannelPtr->PhyWLODT[Dimm]);
811 if ((NBPtr->ChannelPtr->LrDimmPresent & ((UINT8) 1 << Dimm)) != 0) {
812 if (Dimm == TechPtr->TargetDIMM) {
813 if (*(BOOLEAN *) Wl == TRUE) {
815 // Select the Target Chipselects
817 NBPtr->SetBitField (NBPtr, BFMrsChipSel, (Dimm << 1));
818 NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (Dimm << 1));
819 // Program F0RC12 to 1h
820 MemTSendMBCtlWord3 (TechPtr, F0, RC12, 0x01);
821 if (NBPtr->ChannelPtr->Dimms >= 2) {
822 // For two or more LRDIMMs per channel program the buffer RttNom to the
823 // corresponding specifed RttWr termination
824 Value8 = NBPtr->MemNGetDynDramTerm (NBPtr, Dimm << 2);
826 // Program RttNom as normal
827 Value8 = NBPtr->MemNGetDramTerm (NBPtr, Dimm << 2);
829 if ((Value8 & ((UINT8) 1 << 2)) != 0) {
830 MrsAddress |= ((UINT16) 1 << 9);
832 if ((Value8 & ((UINT8) 1 << 1)) != 0) {
833 MrsAddress |= ((UINT16) 1 << 6);
835 if ((Value8 & ((UINT8) 1 << 0)) != 0) {
836 MrsAddress |= ((UINT16) 1 << 2);
838 NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
840 // Program F0RC12 to 0h
841 MemTSendMBCtlWord3 (TechPtr, F0, RC12, 0x00);
852 /* -----------------------------------------------------------------------------*/
855 * This send all MR commands to all physical ranks of an LRDIMM
857 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
858 * @param[in] *CsPtr - Target Chip Select
860 * @return FALSE - The current channel does not have LRDIMM populated
861 * TRUE - The current channel has LRDIMM populated
865 MemTSendAllMRCmdsLR3 (
866 IN OUT MEM_TECH_BLOCK *TechPtr,
876 NBPtr = TechPtr->NBPtr;
877 ChipSel = *((UINT8 *) CsPtr);
879 if (NBPtr->MCTPtr->Status[SbLrdimms]) {
881 // For LRDIMMs, MR0, MR2, and MR3 can be broadcast to any physicall ranks behind
882 // each logical rank(CS) by setting MRSAddress[13]. MR1[Rtt_Nom] needs to be programmed
883 // differently per physical rank, so it must target a physical rank using MrsAddress[17:14].
884 // The actual bits used to index the physical rank are determined by the DRAM Capacity.
886 // This function will be called once for each CS where CSPresent is set, so each time
887 // it only needs to handle the Physical ranks behind each CS. If a Dimm is not using some
888 // CS due to Rank Mux, those CSPresent bits will have been already cleared.
892 // Select target chip select
894 NBPtr->SetBitField (NBPtr, BFMrsChipSel, ChipSel);
898 MemTEMRS2Lr3 (TechPtr, ChipSel);
899 NBPtr->SetBitField (NBPtr, BFMrsAddressHi, 1); // Set Address bit 13 to broadcast
900 NBPtr->SendMrsCmd (NBPtr);
902 // 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b
904 MemTEMRS33 (TechPtr);
905 NBPtr->SetBitField (NBPtr, BFMrsAddressHi, 1); // Set Address bit 13 to broadcast
906 NBPtr->SendMrsCmd (NBPtr);
908 // 15.Send EMRS(1). Send to each physical rank.
910 MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, ChipSel >> 1);
912 // Determine first physical rank relative to the LRDIMM for this CS
914 PhyRank = ((((ChipSel & NBPtr->ChannelPtr->LrDimmLogicalRanks[ChipSel >> 1]) >> 1) & 2) | (ChipSel & 1));
915 for (Rank = 0; Rank < NBPtr->ChannelPtr->LrDimmRankMult[ChipSel >> 1]; Rank++) {
916 MemTEMRS1Lr3 (TechPtr, ChipSel, PhyRank);
918 // Set Address bit 14, 15, 16, or 17 to select physical rank, relative to the CS, according to the device size
920 NBPtr->SetBitField (NBPtr, BFMrsAddressHi, Rank << ((SpdBufferPtr[SPD_DENSITY] & 0xF) - 1 ) );
921 NBPtr->SendMrsCmd (NBPtr);
923 // Index to the next physical rank
925 PhyRank = PhyRank + NBPtr->ChannelPtr->LrDimmLogicalRanks[ChipSel >> 1];
928 // 16.Send MRS with MrsAddress[8]=1(reset the DLL)
931 NBPtr->SetBitField (NBPtr, BFMrsAddressHi, 1); // Set Address bit 13 to broadcast
932 NBPtr->SendMrsCmd (NBPtr);
934 // If LRDIMM, return TRUE to skip sending regular MR commands.
939 // If not LRDIMM, send regular MR commands.
944 /* -----------------------------------------------------------------------------*/
947 * This function calculates the EMRS1 value for an LRDIMM
949 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
950 * @param[in] ChipSel - Chip select number
951 * @param[in] PhyRank - Physical rank number
957 IN OUT MEM_TECH_BLOCK *TechPtr,
965 UINT8 FreqDiffOffset;
968 NBPtr = TechPtr->NBPtr;
970 MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, ChipSel >> 1);
971 FreqDiffOffset = (UINT8) (SPD_FREQ_DIFF_OFFSET * (((NBPtr->DCTPtr->Timings.Speed / 133) - 3) / 2));
974 NBPtr->SetBitField (NBPtr, BFMrsBank, 1);
978 // program MrsAddress[5,1]=output driver impedance control (DIC): 01b
979 MrsAddress |= ((UINT16) 1 << 1);
981 // program MrsAddress[5,1]=output driver impedance control (DIC):
982 // DIC is read from SPD byte 77, 83, or 89 depending on DDR speed
983 Value8 = SpdBufferPtr[SPD_MR1_MR2_800_1066 + FreqDiffOffset] & 3;
984 if ((Value8 & ((UINT8) 1 << 1)) != 0) {
985 MrsAddress |= ((UINT16) 1 << 5);
987 if ((Value8 & ((UINT8) 1 << 0)) != 0) {
988 MrsAddress |= ((UINT16) 1 << 1);
991 // program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
992 // RttNom is read from SPD byte 77, 83, or 89 depending on DDR speed
994 Value8 = (SpdBufferPtr[SPD_MR1_MR2_800_1066 + FreqDiffOffset] >> 2) & 7;
995 if ((Value8 & ((UINT8) 1 << 2)) != 0) {
996 MrsAddress |= ((UINT16) 1 << 9);
998 if ((Value8 & ((UINT8) 1 << 1)) != 0) {
999 MrsAddress |= ((UINT16) 1 << 6);
1001 if ((Value8 & ((UINT8) 1 << 0)) != 0) {
1002 MrsAddress |= ((UINT16) 1 << 2);
1006 NBPtr->SetBitField (NBPtr, BFMrsAddress, MrsAddress);
1009 /* -----------------------------------------------------------------------------*/
1012 * This function calculates the EMRS2 value for an LRDIMM
1014 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1015 * @param[in] ChipSel - Chip select number
1021 IN OUT MEM_TECH_BLOCK *TechPtr,
1026 UINT8 *SpdBufferPtr;
1027 UINT8 FreqDiffOffset;
1028 MEM_NB_BLOCK *NBPtr;
1030 NBPtr = TechPtr->NBPtr;
1032 // Save default RttWr
1033 RttWr = NBPtr->PsPtr->RttWr[ChipSel];
1035 // Override RttWr with the value read from SPD byte 77, 83, or 89 depending on DDR speed
1036 MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, ChipSel >> 1);
1037 FreqDiffOffset = (UINT8) (SPD_FREQ_DIFF_OFFSET * (((NBPtr->DCTPtr->Timings.Speed / 133) - 3) / 2));
1038 NBPtr->PsPtr->RttWr[ChipSel] = SpdBufferPtr[SPD_MR1_MR2_800_1066 + FreqDiffOffset] >> 6;
1040 // Call EMRS2 calculation
1041 MemTEMRS23 (TechPtr);
1044 NBPtr->PsPtr->RttWr[ChipSel] = RttWr;
1047 /*-----------------------------------------------------------------------------
1050 * This function to determine the Rank Multiplication to use for an LRDIMM
1052 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1053 * @param[in,out] *DimmID - Dimm ID
1055 * @return TRUE - LRDIMM Support is installed and LRDIMMs are present
1056 * ----------------------------------------------------------------------------
1060 MemTLrdimmRankMultiplication (
1061 IN OUT MEM_TECH_BLOCK *TechPtr,
1066 UINT8 *SpdBufferPtr;
1073 MEM_NB_BLOCK *NBPtr;
1074 CH_DEF_STRUCT *ChannelPtr;
1076 ASSERT (TechPtr != NULL);
1077 ASSERT (DimmID != NULL);
1079 Dimm = *(UINT8*)DimmID;
1080 ASSERT (Dimm < MAX_DIMMS_PER_CHANNEL);
1082 NBPtr = TechPtr->NBPtr;
1083 ChannelPtr = NBPtr->ChannelPtr;
1087 if (!MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm)) {
1091 NumDimmslots = GetMaxDimmsPerChannel (NBPtr->RefPtr->PlatformMemoryConfiguration,
1092 NBPtr->MCTPtr->SocketId,
1093 ChannelPtr->ChannelID);
1095 if (NBPtr->MCTPtr->Status[SbLrdimms]) {
1098 // Determine LRDIMM Rank Multiplication
1100 Ranks = ((SpdBufferPtr[SPD_RANKS] >> 3) & 0x07) + 1;
1104 DramCapacity = (SpdBufferPtr[SPD_DENSITY] & 0x0F);
1105 Rows = 12 + ((SpdBufferPtr[SPD_ROW_SZ] >> 3) & 0x7);
1109 } else if (Ranks == 4) {
1110 RankMult = (NumDimmslots < 3) ? 1 : 2;
1111 } else if (Ranks == 8) {
1112 RankMult = ((NumDimmslots < 3) && (DramCapacity < 4)) ? 2 : 4;
1115 // Save Rank Information
1117 ChannelPtr->LrDimmRankMult[Dimm] = RankMult;
1118 ChannelPtr->LrDimmLogicalRanks[Dimm] = Ranks / RankMult;
1119 NBPtr->PsPtr->LrdimmRowAddrBits[Dimm] = Rows + (RankMult >> 1);
1123 NBPtr->SetBitField (NBPtr, BFRankDef0 + Dimm, (RankMult == 4) ? 3 : RankMult);
1125 // If LrdimmRowAddressBits > 16, then we must be using some CS signals for rank
1126 // multiplication. If this is the case, then we want to clear the CSPresent bits
1127 // that correspond to those chipselects.
1128 // If there are 3 DIMMs per channel, then it will always be CS67, if there are
1129 // 2DPCH, then DIMM0 will use CS45, and DIMM1 will use CS67.
1131 if ((ChannelPtr->LrDimmLogicalRanks[Dimm] < 4) && (Dimm >= NumDimmslots)) {
1132 NBPtr->DCTPtr->Timings.CsPresent &= ~(0x3 << (Dimm << 1));
1133 ChannelPtr->LrDimmRankMult[Dimm] = 0;
1134 ChannelPtr->LrDimmLogicalRanks[Dimm] = 0;
1135 NBPtr->PsPtr->LrdimmRowAddrBits[Dimm] = 0;
1137 IDS_HDT_CONSOLE_DEBUG_CODE (
1138 if (Dimm < NumDimmslots) {
1139 IDS_HDT_CONSOLE (MEM_FLOW,"\tDimm %d: Log. Ranks:%d Phys. Ranks:%d RowAddrBits:%d RankMult:%d\n",
1141 ChannelPtr->LrDimmLogicalRanks[Dimm],
1142 ChannelPtr->LrdimmPhysicalRanks[Dimm],
1143 NBPtr->PsPtr->LrdimmRowAddrBits[Dimm],
1153 /* -----------------------------------------------------------------------------
1155 * This function performs buffer to DRAM training for LRDIMMs
1157 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1158 * @param[in,out] OptParam - Optional parameter
1165 MemTLrdimmBuf2DramTrain3 (
1166 IN OUT MEM_TECH_BLOCK *TechPtr,
1167 IN OUT VOID *OptParam
1170 MEM_DATA_STRUCT *MemPtr;
1171 MEM_NB_BLOCK *NBPtr;
1178 NBPtr = TechPtr->NBPtr;
1179 MemPtr = NBPtr->MemPtr;
1181 if (NBPtr->MCTPtr->Status[SbLrdimms]) {
1182 IDS_HDT_CONSOLE (MEM_FLOW, "\nStart Buffer to DRAM training\n");
1183 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
1184 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
1185 NBPtr->SwitchDCT (NBPtr, Dct);
1187 // ODM needs to be set after Dram Init
1189 if (NBPtr->StartupSpeed == NBPtr->DCTPtr->Timings.Speed) {
1190 for (ChipSel = 1; ChipSel < MAX_CS_PER_CHANNEL; ChipSel += 2) {
1191 if ((NBPtr->DCTPtr->Timings.CsPresent & ((UINT16)1 << ChipSel)) != 0) {
1192 if ((NBPtr->DCTPtr->Timings.DimmMirrorPresent & (1 << (ChipSel >> 1))) != 0) {
1193 NBPtr->SetBitField (NBPtr, BFCSBaseAddr0Reg + ChipSel, ((NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + ChipSel)) | ((UINT32)1 << BFOnDimmMirror )));
1199 // Buffer to DRAM training
1201 for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm++) {
1202 DimmMask = (UINT16)1 << Dimm;
1203 if ((NBPtr->ChannelPtr->LrDimmPresent & DimmMask) != 0) {
1204 IDS_HDT_CONSOLE (MEM_STATUS, "\t\nDimm %d\n", Dimm);
1206 // Select the Target Chipselects
1208 NBPtr->SetBitField (NBPtr, BFMrsChipSel, (Dimm << 1));
1209 NBPtr->SetBitField (NBPtr, BFCtrlWordCS, 3 << (Dimm << 1));
1211 NBPtr->SetBitField (NBPtr, BFLrDimmErrOutMonEn, 1);
1212 MemTSendMBCtlWord3 (TechPtr, F2, RC3, 8);
1213 // Send F0RC12 with data = 0010b.
1214 MemTSendMBCtlWord3 (TechPtr, F0, RC12, 2);
1216 // Wait until D18F2xA0_dct[1:0][RcvParErr]=0 or tCAL * the number of physical ranks expires.
1218 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tWaiting %d ms...\n", 10 * NBPtr->ChannelPtr->LrdimmPhysicalRanks[Dimm]);
1219 for (i = 0; i < (NBPtr->ChannelPtr->LrdimmPhysicalRanks[Dimm] * 10); i++) {
1220 MemUWait10ns (1000000, MemPtr);
1222 // @todo: Provide option for polling RcvParErr to optimize DRAM bus timing.
1225 IDS_HDT_CONSOLE (MEM_FLOW, "\n\t\tRcvParErr = %02x\n", NBPtr->GetBitField (NBPtr, BFRcvParErr));
1226 NBPtr->SetBitField (NBPtr, BFLrDimmErrOutMonEn, 0);
1227 MemTSendMBCtlWord3 (TechPtr, F2, RC3, 0);
1228 // Configure for normal operation: Send F0RC12 with data = 0000b.
1229 MemTSendMBCtlWord3 (TechPtr, F0, RC12, 0);
1233 IDS_HDT_CONSOLE (MEM_FLOW, "\nEnd Buffer to DRAM training\n");
1238 /* -----------------------------------------------------------------------------*/
1241 * This function copies trained delays of the first rank of a QR LRDIMM to the third rank
1243 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1244 * @param[in,out] OptParam - Optional parameter
1251 MemTLrdimmSyncTrainedDlys (
1252 IN OUT MEM_TECH_BLOCK *TechPtr,
1253 IN OUT VOID *OptParam
1259 MEM_NB_BLOCK *NBPtr;
1260 CH_DEF_STRUCT *ChannelPtr;
1266 NBPtr = TechPtr->NBPtr;
1268 if (NBPtr->MCTPtr->Status[SbLrdimms]) {
1269 IDS_HDT_CONSOLE (MEM_STATUS, "\tSync LRDIMM Delays to remaining ranks.\n");
1270 for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
1271 IDS_HDT_CONSOLE (MEM_STATUS, "\tDct %d\n", Dct);
1272 NBPtr->SwitchDCT (NBPtr, Dct);
1273 ChannelPtr = NBPtr->ChannelPtr;
1274 for (Dimm = 0; Dimm < 2; Dimm++) {
1275 if (ChannelPtr->LrDimmLogicalRanks[Dimm] > 2) {
1276 // If logical QR LRDIMM, copy trained delays from first rank to third rank
1277 IDS_HDT_CONSOLE (MEM_FLOW, "\t\tDimm %d -> Dimm %d\n",Dimm, Dimm + 2);
1278 for (i = 0; i < TechPtr->DlyTableWidth (); i++) {
1279 WrDqsDly = ChannelPtr->WrDqsDlys[Dimm * TechPtr->DlyTableWidth () + i];
1280 NBPtr->SetTrainDly (NBPtr, AccessWrDqsDly, DIMM_BYTE_ACCESS (Dimm + 2, i), WrDqsDly);
1281 ChannelPtr->WrDqsDlys[(Dimm + 2) * TechPtr->DlyTableWidth () + i] = (UINT8)WrDqsDly;
1283 RcvEnDly = ChannelPtr->RcvEnDlys[Dimm * TechPtr->DlyTableWidth () + i];
1284 NBPtr->SetTrainDly (NBPtr, AccessRcvEnDly, DIMM_BYTE_ACCESS (Dimm + 2, i), RcvEnDly);
1285 ChannelPtr->RcvEnDlys[(Dimm + 2) * TechPtr->DlyTableWidth () + i] = RcvEnDly;
1287 RdDqsDly = ChannelPtr->RdDqsDlys[Dimm * TechPtr->DlyTableWidth () + i];
1288 NBPtr->SetTrainDly (NBPtr, AccessRdDqsDly, DIMM_BYTE_ACCESS (Dimm + 2, i), RdDqsDly);
1289 ChannelPtr->RdDqsDlys[(Dimm + 2) * TechPtr->DlyTableWidth () + i] = (UINT8)RdDqsDly;
1291 WrDatDly = ChannelPtr->WrDatDlys[Dimm * TechPtr->DlyTableWidth () + i];
1292 NBPtr->SetTrainDly (NBPtr, AccessWrDatDly, DIMM_BYTE_ACCESS (Dimm + 2, i), WrDatDly);
1293 ChannelPtr->WrDatDlys[(Dimm + 2) * TechPtr->DlyTableWidth () + i] = (UINT8)WrDatDly;
1295 if ((ChannelPtr->DimmNibbleAccess & (1 << Dimm)) != 0) {
1297 // If 2D x4 (Not Currently POR for LRDIMMs)
1299 for (i = 0; i < MAX_NUMBER_LANES; i++) {
1300 if (ChannelPtr->LrDimmLogicalRanks[Dimm] > 2) {
1301 // If logical QR LRDIMM, copy trained delays from first rank to third rank
1302 RdDqs__Dly = ChannelPtr->RdDqs__Dlys[Dimm * MAX_NUMBER_LANES + i];
1303 NBPtr->SetTrainDly (NBPtr, AccessRdDqs__Dly, DIMM_NBBL_ACCESS (Dimm + 2, i),
1304 ChannelPtr->RdDqs__Dlys[Dimm * MAX_NUMBER_LANES + i]);
1305 ChannelPtr->RdDqs__Dlys[(Dimm + 2) * MAX_NUMBER_LANES + i] = (UINT8)RdDqs__Dly;
1318 /* -----------------------------------------------------------------------------*/
1321 * This function performs LRDIMM specific tasks during Dimm Presence detection
1323 * @param[in,out] *TechPtr - Pointer to the MEM_TECH_BLOCK
1324 * @param[in,out] *DimmID - Dimm ID
1332 MemTLrdimmPresence (
1333 IN OUT MEM_TECH_BLOCK *TechPtr,
1337 MEM_NB_BLOCK *NBPtr;
1340 NBPtr = TechPtr->NBPtr;
1341 Dimm = *(UINT8*) DimmID;
1343 BufferID = MemTLrDimmGetBufferID (TechPtr, Dimm);
1344 if ((BufferID == 0x0020B304) || (BufferID == 0x0020B380)) {
1345 IDS_HDT_CONSOLE (MEM_FLOW, "\tDimm %d: Unsupported LRDIMM Buffer Revision\n", Dimm);
1346 PutEventLog (AGESA_WARNING, MEM_WARNING_UNSUPPORTED_LRDIMM, NBPtr->Node, NBPtr->Dct, NBPtr->Channel, Dimm, &NBPtr->MemPtr->StdHeader);
1347 NBPtr->DCTPtr->Timings.CsTestFail |= (UINT16)0x3 << (Dimm << 1);
1352 /* -----------------------------------------------------------------------------*/
1355 * This function returns LRDIMM Buffer ID Info from the SPD
1358 * @param[in,out] *TechPtr - Pointer to the Technology Block
1359 * @param[in] Dimm - Dimm number
1361 * @return Buffer ID Information
1367 MemTLrDimmGetBufferID (
1368 IN OUT MEM_TECH_BLOCK *TechPtr,
1372 UINT8 *SpdBufferPtr;
1376 MemTGetDimmSpdBuffer3 (TechPtr, &SpdBufferPtr, Dimm);
1377 BufferID = (SpdBufferPtr[64] << 16) | (SpdBufferPtr[66] << 8) | (SpdBufferPtr[65]);
1381 /* -----------------------------------------------------------------------------*/
1384 * This function implements special case Initialization hooks for LRDIMMs
1386 * @param[in] TechPtr - Tech Block Pointer
1387 * @param[in] Entrypoint - Entrypoint to indicate when this hook is called
1388 * @param[in] Dimm - Dimm being configured when hook is called
1389 * @param[in] OptParam - Not Used
1394 MemTLrdimmInitHook (
1395 IN OUT MEM_TECH_BLOCK *TechPtr,
1396 IN LRDIMM_HOOK_ENTRYPOINT Entrypoint,
1398 IN OUT VOID *OptParam
1401 MEM_NB_BLOCK *NBPtr;
1403 CONST UINT16 AfterTstabRcwTable[] = {
1430 if (MemTLrDimmGetBufferID (TechPtr, Dimm) != 0x0021B304) {
1433 NBPtr = TechPtr->NBPtr;
1434 switch (Entrypoint) {
1436 MemTSendMBCtlWord3 (TechPtr, F14, RC0, 0xB);
1437 for ( i = 0 ; i < (sizeof (AfterTstabRcwTable) / sizeof (UINT16)); i += 2 ) {
1438 MemTSendExtMBCtlWord3 (TechPtr, AfterTstabRcwTable[i], AfterTstabRcwTable[i + 1], 2);
1443 // If a hook entrypoint is called, it should have a case for it.