summaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mct_d.c')
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mct_d.c3725
1 files changed, 3725 insertions, 0 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
new file mode 100644
index 0000000000..453a8ba357
--- /dev/null
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -0,0 +1,3725 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Description: Main memory controller system configuration for DDR 3 */
+
+/* KNOWN ISSUES - ERRATA
+ *
+ * Trtp is not calculated correctly when the controller is in 64-bit mode, it
+ * is 1 busclock off. No fix planned. The controller is not ordinarily in
+ * 64-bit mode.
+ *
+ * 32 Byte burst not supported. No fix planned. The controller is not
+ * ordinarily in 64-bit mode.
+ *
+ * Trc precision does not use extra Jedec defined fractional component.
+ * InsteadTrc (course) is rounded up to nearest 1 ns.
+ *
+ * Mini and Micro DIMM not supported. Only RDIMM, UDIMM, SO-DIMM defined types
+ * supported.
+ */
+
+static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static void MCTMemClrSync_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static u8 NodePresent_D(u8 Node);
+static void SyncDCTsReady_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static void StartupDCT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void ClearDCT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void GetPresetmaxF_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 PlatformSpec_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static u16 Get_Fk_D(u8 k);
+static u8 Get_DIMMAddress_D(struct DCTStatStruc *pDCTstat, u8 i);
+static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static void mct_DramInit(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_SyncDCTsReady(struct DCTStatStruc *pDCTstat);
+static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_AfterGetCLT(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 mct_SPDCalcWidth(struct MCTStatStruc *pMCTstat,\
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static u8 mct_DIMMPresence(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void Set_OtherTiming(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void Get_Twrwr(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void Get_Twrrd(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void Get_TrwtTO(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void Get_TrwtWB(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
+ u32 dev, u32 index_reg);
+static void Get_WrDatGross_Diff(struct DCTStatStruc *pDCTstat, u8 dct,
+ u32 dev, u32 index_reg);
+static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
+ u32 dev, u32 index_reg, u32 index);
+static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat, u8 dct,
+ u32 dev, u32 index_reg, u32 index);
+static void mct_InitialMCT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static void mct_init(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static void clear_legacy_Mode(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static void SetCSTriState(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void SetODTTriState(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static u32 mct_NodePresent_D(void);
+static void mct_OtherTiming(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static void mct_ResetDataStruct_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+void mct_ClrClToNB_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+void mct_ClrWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat);
+static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA);
+static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u32 DramConfigLo, u8 dct);
+
+static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dimm);
+static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2);
+static void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat);
+static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+static void SyncSetting(struct DCTStatStruc *pDCTstat);
+static u8 crcCheck(u8 smbaddr);
+
+/*See mctAutoInitMCT header for index relationships to CL and T*/
+static const u16 Table_F_k[] = {00,200,266,333,400,533 };
+static const u8 Tab_BankAddr[] = {0x3F,0x01,0x09,0x3F,0x3F,0x11,0x0A,0x19,0x12,0x1A,0x21,0x22,0x23};
+static const u8 Table_DQSRcvEn_Offset[] = {0x00,0x01,0x10,0x11,0x2};
+
+/****************************************************************************
+ Describe how platform maps MemClk pins to logical DIMMs. The MemClk pins
+ are identified based on BKDG definition of Fn2x88[MemClkDis] bitmap.
+ AGESA will base on this value to disable unused MemClk to save power.
+
+ If MEMCLK_MAPPING or MEMCLK_MAPPING contains all zeroes, AGESA will use
+ default MemClkDis setting based on package type.
+
+ Example:
+ BKDG definition of Fn2x88[MemClkDis] bitmap for AM3 package is like below:
+ Bit AM3/S1g3 pin name
+ 0 M[B,A]_CLK_H/L[0]
+ 1 M[B,A]_CLK_H/L[1]
+ 2 M[B,A]_CLK_H/L[2]
+ 3 M[B,A]_CLK_H/L[3]
+ 4 M[B,A]_CLK_H/L[4]
+ 5 M[B,A]_CLK_H/L[5]
+ 6 M[B,A]_CLK_H/L[6]
+ 7 M[B,A]_CLK_H/L[7]
+
+ And platform has the following routing:
+ CS0 M[B,A]_CLK_H/L[4]
+ CS1 M[B,A]_CLK_H/L[2]
+ CS2 M[B,A]_CLK_H/L[3]
+ CS3 M[B,A]_CLK_H/L[5]
+
+ Then:
+ ; CS0 CS1 CS2 CS3 CS4 CS5 CS6 CS7
+ MEMCLK_MAPPING EQU 00010000b, 00000100b, 00001000b, 00100000b, 00000000b, 00000000b, 00000000b, 00000000b
+*/
+
+/* Note: If you are not sure about the pin mappings at initial stage, we dont have to disable MemClk.
+ * Set entries in the tables all 0xFF. */
+static const u8 Tab_L1CLKDis[] = {0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04};
+static const u8 Tab_AM3CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00};
+static const u8 Tab_S1CLKDis[] = {0xA2, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static const u8 Tab_ManualCLKDis[]= {0x10, 0x04, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00};
+
+static const u8 Table_Comp_Rise_Slew_20x[] = {7, 3, 2, 2, 0xFF};
+static const u8 Table_Comp_Rise_Slew_15x[] = {7, 7, 3, 2, 0xFF};
+static const u8 Table_Comp_Fall_Slew_20x[] = {7, 5, 3, 2, 0xFF};
+static const u8 Table_Comp_Fall_Slew_15x[] = {7, 7, 5, 3, 0xFF};
+
+static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ /*
+ * Memory may be mapped contiguously all the way up to 4GB (depending on setup
+ * options). It is the responsibility of PCI subsystem to create an uncacheable
+ * IO region below 4GB and to adjust TOP_MEM downward prior to any IO mapping or
+ * accesses. It is the same responsibility of the CPU sub-system prior to
+ * accessing LAPIC.
+ *
+ * Slot Number is an external convention, and is determined by OEM with accompanying
+ * silk screening. OEM may choose to use Slot number convention which is consistent
+ * with DIMM number conventions. All AMD engineering platforms do.
+ *
+ * Build Requirements:
+ * 1. MCT_SEG0_START and MCT_SEG0_END macros to begin and end the code segment,
+ * defined in mcti.inc.
+ *
+ * Run-Time Requirements:
+ * 1. Complete Hypertransport Bus Configuration
+ * 2. SMBus Controller Initialized
+ * 1. BSP in Big Real Mode
+ * 2. Stack at SS:SP, located somewhere between A000:0000 and F000:FFFF
+ * 3. Checksummed or Valid NVRAM bits
+ * 4. MCG_CTL=-1, MC4_CTL_EN=0 for all CPUs
+ * 5. MCi_STS from shutdown/warm reset recorded (if desired) prior to entry
+ * 6. All var MTRRs reset to zero
+ * 7. State of NB_CFG.DisDatMsk set properly on all CPUs
+ * 8. All CPUs at 2Ghz Speed (unless DQS training is not installed).
+ * 9. All cHT links at max Speed/Width (unless DQS training is not installed).
+ *
+ *
+ * Global relationship between index values and item values:
+ *
+ * pDCTstat.CASL pDCTstat.Speed
+ * j CL(j) k F(k)
+ * --------------------------
+ * 0 2.0 - -
+ * 1 3.0 1 200 Mhz
+ * 2 4.0 2 266 Mhz
+ * 3 5.0 3 333 Mhz
+ * 4 6.0 4 400 Mhz
+ * 5 7.0 5 533 Mhz
+ * 6 8.0 6 667 Mhz
+ * 7 9.0 7 800 Mhz
+ */
+ u8 Node, NodesWmem;
+ u32 node_sys_base;
+
+restartinit:
+ mctInitMemGPIOs_A_D(); /* Set any required GPIOs*/
+ NodesWmem = 0;
+ node_sys_base = 0;
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+ pDCTstat->Node_ID = Node;
+ pDCTstat->dev_host = PA_HOST(Node);
+ pDCTstat->dev_map = PA_MAP(Node);
+ pDCTstat->dev_dct = PA_DCT(Node);
+ pDCTstat->dev_nbmisc = PA_NBMISC(Node);
+ pDCTstat->NodeSysBase = node_sys_base;
+
+ mct_init(pMCTstat, pDCTstat);
+ mctNodeIDDebugPort_D();
+ pDCTstat->NodePresent = NodePresent_D(Node);
+ if (pDCTstat->NodePresent) { /* See if Node is there*/
+ clear_legacy_Mode(pMCTstat, pDCTstat);
+ pDCTstat->LogicalCPUID = mctGetLogicalCPUID_D(Node);
+
+ mct_InitialMCT_D(pMCTstat, pDCTstat);
+
+ mctSMBhub_Init(Node); /* Switch SMBUS crossbar to proper node*/
+
+ mct_initDCT(pMCTstat, pDCTstat);
+ if (pDCTstat->ErrCode == SC_FatalErr) {
+ goto fatalexit; /* any fatal errors?*/
+ } else if (pDCTstat->ErrCode < SC_StopError) {
+ NodesWmem++;
+ }
+ } /* if Node present */
+ node_sys_base = pDCTstat->NodeSysBase;
+ node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
+ }
+ if (NodesWmem == 0) {
+ printk(BIOS_DEBUG, "No Nodes?!\n");
+ goto fatalexit;
+ }
+
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
+ SyncDCTsReady_D(pMCTstat, pDCTstatA); /* Make sure DCTs are ready for accesses.*/
+
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: HTMemMapInit_D\n");
+ HTMemMapInit_D(pMCTstat, pDCTstatA); /* Map local memory into system address space.*/
+ mctHookAfterHTMap();
+
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
+ CPUMemTyping_D(pMCTstat, pDCTstatA); /* Map dram into WB/UC CPU cacheability */
+ mctHookAfterCPU(); /* Setup external northbridge(s) */
+
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
+ DQSTiming_D(pMCTstat, pDCTstatA); /* Get Receiver Enable and DQS signal timing*/
+
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
+ UMAMemTyping_D(pMCTstat, pDCTstatA); /* Fix up for UMA sizing */
+
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
+ mct_OtherTiming(pMCTstat, pDCTstatA);
+
+ if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 1st pass of DIMM spare enabled*/
+ goto restartinit;
+ }
+
+ InterleaveNodes_D(pMCTstat, pDCTstatA);
+ InterleaveChannels_D(pMCTstat, pDCTstatA);
+
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
+ if (ECCInit_D(pMCTstat, pDCTstatA)) { /* Setup ECC control and ECC check-bits*/
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
+ MCTMemClr_D(pMCTstat,pDCTstatA);
+ }
+
+ mct_FinalMCT_D(pMCTstat, (pDCTstatA + 0) ); /* Node 0 */
+ printk(BIOS_DEBUG, "All Done\n");
+ return;
+
+fatalexit:
+ die("mct_d: fatalexit");
+}
+
+static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ u8 ret;
+
+ if (mctGet_NVbits(NV_CS_SpareCTL)) {
+ if (MCT_DIMM_SPARE_NO_WARM) {
+ /* Do no warm-reset DIMM spare */
+ if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
+ LoadDQSSigTmgRegs_D(pMCTstat, pDCTstatA);
+ ret = 0;
+ } else {
+ mct_ResetDataStruct_D(pMCTstat, pDCTstatA);
+ pMCTstat->GStatus |= 1 << GSB_EnDIMMSpareNW;
+ ret = 1;
+ }
+ } else {
+ /* Do warm-reset DIMM spare */
+ if (mctGet_NVbits(NV_DQSTrainCTL))
+ mctWarmReset_D();
+ ret = 0;
+ }
+ } else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ u8 nv_DQSTrainCTL;
+
+ if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
+ return;
+ }
+
+ nv_DQSTrainCTL = mctGet_NVbits(NV_DQSTrainCTL);
+ /* FIXME: BOZO- DQS training every time*/
+ nv_DQSTrainCTL = 1;
+
+ mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
+ phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
+
+ if (nv_DQSTrainCTL) {
+ mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
+ /* TODO: should be in mctHookBeforeAnyTraining */
+ _WRMSR(0x26C, 0x04040404, 0x04040404);
+ _WRMSR(0x26D, 0x04040404, 0x04040404);
+ _WRMSR(0x26E, 0x04040404, 0x04040404);
+ _WRMSR(0x26F, 0x04040404, 0x04040404);
+ mct_WriteLevelization_HW(pMCTstat, pDCTstatA);
+
+ TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
+
+ mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
+
+ /* Second Pass never used for Barcelona! */
+ /* TrainReceiverEn_D(pMCTstat, pDCTstatA, SecondPass); */
+
+ mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
+
+ /* FIXME - currently uses calculated value TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
+ mctHookAfterAnyTraining();
+ mctSaveDQSSigTmg_D();
+
+ MCTMemClr_D(pMCTstat, pDCTstatA);
+ } else {
+ mctGetDQSSigTmg_D(); /* get values into data structure */
+ LoadDQSSigTmgRegs_D(pMCTstat, pDCTstatA); /* load values into registers.*/
+ /* mctDoWarmResetMemClr_D(); */
+ MCTMemClr_D(pMCTstat, pDCTstatA);
+ }
+}
+
+static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ u8 Node, Receiver, Channel, Dir, DIMM;
+ u32 dev;
+ u32 index_reg;
+ u32 reg;
+ u32 index;
+ u32 val;
+ u8 ByteLane;
+ u8 txdqs;
+
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+
+ if (pDCTstat->DCTSysLimit) {
+ dev = pDCTstat->dev_dct;
+ for (Channel = 0;Channel < 2; Channel++) {
+ /* there are four receiver pairs,
+ loosely associated with chipselects.*/
+ index_reg = 0x98 + Channel * 0x100;
+ for (Receiver = 0; Receiver < 8; Receiver += 2) {
+ /* Set Receiver Enable Values */
+ mct_SetRcvrEnDly_D(pDCTstat,
+ 0, /* RcvrEnDly */
+ 1, /* FinalValue, From stack */
+ Channel,
+ Receiver,
+ dev, index_reg,
+ (Receiver >> 1) * 3 + 0x10, /* Addl_Index */
+ 2); /* Pass Second Pass ? */
+ /* Restore Write levelization training data */
+ for (ByteLane = 0; ByteLane < 9; ByteLane ++) {
+ txdqs = pDCTstat->CH_D_B_TxDqs[Channel][Receiver >> 1][ByteLane];
+ index = Table_DQSRcvEn_Offset[ByteLane >> 1];
+ index += (Receiver >> 1) * 3 + 0x10 + 0x20; /* Addl_Index */
+ val = Get_NB32_index_wait(dev, 0x98 + 0x100*Channel, index);
+ if (ByteLane & 1) { /* odd byte lane */
+ val &= ~(0xFF << 16);
+ val |= txdqs << 16;
+ } else {
+ val &= ~0xFF;
+ val |= txdqs;
+ }
+ Set_NB32_index_wait(dev, 0x98 + 0x100*Channel, index, val);
+ }
+ }
+ }
+ for (Channel = 0; Channel<2; Channel++) {
+ SetEccDQSRcvrEn_D(pDCTstat, Channel);
+ }
+
+ for (Channel = 0; Channel < 2; Channel++) {
+ u8 *p;
+ index_reg = 0x98 + Channel * 0x100;
+
+ /* NOTE:
+ * when 400, 533, 667, it will support dimm0/1/2/3,
+ * and set conf for dimm0, hw will copy to dimm1/2/3
+ * set for dimm1, hw will copy to dimm3
+ * Rev A/B only support DIMM0/1 when 800Mhz and above
+ * + 0x100 to next dimm
+ * Rev C support DIMM0/1/2/3 when 800Mhz and above
+ * + 0x100 to next dimm
+ */
+ for (DIMM = 0; DIMM < 4; DIMM++) {
+ if (DIMM == 0) {
+ index = 0; /* CHA Write Data Timing Low */
+ } else {
+ if (pDCTstat->Speed >= 4) {
+ index = 0x100 * DIMM;
+ } else {
+ break;
+ }
+ }
+ for (Dir = 0; Dir < 2; Dir++) {/* RD/WR */
+ p = pDCTstat->CH_D_DIR_B_DQS[Channel][DIMM][Dir];
+ val = stream_to_int(p); /* CHA Read Data Timing High */
+ Set_NB32_index_wait(dev, index_reg, index+1, val);
+ val = stream_to_int(p+4); /* CHA Write Data Timing High */
+ Set_NB32_index_wait(dev, index_reg, index+2, val);
+ val = *(p+8); /* CHA Write ECC Timing */
+ Set_NB32_index_wait(dev, index_reg, index+3, val);
+ index += 4;
+ }
+ }
+ }
+
+ for (Channel = 0; Channel<2; Channel++) {
+ reg = 0x78 + Channel * 0x100;
+ val = Get_NB32(dev, reg);
+ val &= ~(0x3ff<<22);
+ val |= ((u32) pDCTstat->CH_MaxRdLat[Channel] << 22);
+ val &= ~(1<<DqsRcvEnTrain);
+ Set_NB32(dev, reg, val); /* program MaxRdLatency to correspond with current delay*/
+ }
+ }
+ }
+}
+
+static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ u8 Node;
+ u32 NextBase, BottomIO;
+ u8 _MemHoleRemap, DramHoleBase, DramHoleOffset;
+ u32 HoleSize, DramSelBaseAddr;
+
+ u32 val;
+ u32 base;
+ u32 limit;
+ u32 dev, devx;
+ struct DCTStatStruc *pDCTstat;
+
+ _MemHoleRemap = mctGet_NVbits(NV_MemHole);
+
+ if (pMCTstat->HoleBase == 0) {
+ DramHoleBase = mctGet_NVbits(NV_BottomIO);
+ } else {
+ DramHoleBase = pMCTstat->HoleBase >> (24-8);
+ }
+
+ BottomIO = DramHoleBase << (24-8);
+
+ NextBase = 0;
+ pDCTstat = pDCTstatA + 0;
+ dev = pDCTstat->dev_map;
+
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ pDCTstat = pDCTstatA + Node;
+ devx = pDCTstat->dev_map;
+ DramSelBaseAddr = 0;
+ pDCTstat = pDCTstatA + Node; /* ??? */
+ if (!pDCTstat->GangedMode) {
+ DramSelBaseAddr = pDCTstat->NodeSysLimit - pDCTstat->DCTSysLimit;
+ /*In unganged mode, we must add DCT0 and DCT1 to DCTSysLimit */
+ val = pDCTstat->NodeSysLimit;
+ if ((val & 0xFF) == 0xFE) {
+ DramSelBaseAddr++;
+ val++;
+ }
+ pDCTstat->DCTSysLimit = val;
+ }
+
+ base = pDCTstat->DCTSysBase;
+ limit = pDCTstat->DCTSysLimit;
+ if (limit > base) {
+ base += NextBase;
+ limit += NextBase;
+ DramSelBaseAddr += NextBase;
+ printk(BIOS_DEBUG, " Node: %02x base: %02x limit: %02x BottomIO: %02x\n", Node, base, limit, BottomIO);
+
+ if (_MemHoleRemap) {
+ if ((base < BottomIO) && (limit >= BottomIO)) {
+ /* HW Dram Remap */
+ pDCTstat->Status |= 1 << SB_HWHole;
+ pMCTstat->GStatus |= 1 << GSB_HWHole;
+ pDCTstat->DCTSysBase = base;
+ pDCTstat->DCTSysLimit = limit;
+ pDCTstat->DCTHoleBase = BottomIO;
+ pMCTstat->HoleBase = BottomIO;
+ HoleSize = _4GB_RJ8 - BottomIO; /* HoleSize[39:8] */
+ if ((DramSelBaseAddr > 0) && (DramSelBaseAddr < BottomIO))
+ base = DramSelBaseAddr;
+ val = ((base + HoleSize) >> (24-8)) & 0xFF;
+ DramHoleOffset = val;
+ val <<= 8; /* shl 16, rol 24 */
+ val |= DramHoleBase << 24;
+ val |= 1 << DramHoleValid;
+ Set_NB32(devx, 0xF0, val); /* Dram Hole Address Reg */
+ pDCTstat->DCTSysLimit += HoleSize;
+ base = pDCTstat->DCTSysBase;
+ limit = pDCTstat->DCTSysLimit;
+ } else if (base == BottomIO) {
+ /* SW Node Hoist */
+ pMCTstat->GStatus |= 1<<GSB_SpIntRemapHole;
+ pDCTstat->Status |= 1<<SB_SWNodeHole;
+ pMCTstat->GStatus |= 1<<GSB_SoftHole;
+ pMCTstat->HoleBase = base;
+ limit -= base;
+ base = _4GB_RJ8;
+ limit += base;
+ pDCTstat->DCTSysBase = base;
+ pDCTstat->DCTSysLimit = limit;
+ } else {
+ /* No Remapping. Normal Contiguous mapping */
+ pDCTstat->DCTSysBase = base;
+ pDCTstat->DCTSysLimit = limit;
+ }
+ } else {
+ /*No Remapping. Normal Contiguous mapping*/
+ pDCTstat->DCTSysBase = base;
+ pDCTstat->DCTSysLimit = limit;
+ }
+ base |= 3; /* set WE,RE fields*/
+ pMCTstat->SysLimit = limit;
+ }
+ Set_NB32(dev, 0x40 + (Node << 3), base); /* [Node] + Dram Base 0 */
+
+ val = limit & 0xFFFF0000;
+ val |= Node;
+ Set_NB32(dev, 0x44 + (Node << 3), val); /* set DstNode */
+
+ printk(BIOS_DEBUG, " Node: %02x base: %02x limit: %02x \n", Node, base, limit);
+ limit = pDCTstat->DCTSysLimit;
+ if (limit) {
+ NextBase = (limit & 0xFFFF0000) + 0x10000;
+ }
+ }
+
+ /* Copy dram map from Node 0 to Node 1-7 */
+ for (Node = 1; Node < MAX_NODES_SUPPORTED; Node++) {
+ u32 reg;
+ pDCTstat = pDCTstatA + Node;
+ devx = pDCTstat->dev_map;
+
+ if (pDCTstat->NodePresent) {
+ reg = 0x40; /*Dram Base 0*/
+ do {
+ val = Get_NB32(dev, reg);
+ Set_NB32(devx, reg, val);
+ reg += 4;
+ } while ( reg < 0x80);
+ } else {
+ break; /* stop at first absent Node */
+ }
+ }
+
+ /*Copy dram map to F1x120/124*/
+ mct_HTMemMapExt(pMCTstat, pDCTstatA);
+}
+
+static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+
+ /* Initiates a memory clear operation for all node. The mem clr
+ * is done in paralel. After the memclr is complete, all processors
+ * status are checked to ensure that memclr has completed.
+ */
+ u8 Node;
+ struct DCTStatStruc *pDCTstat;
+
+ if (!mctGet_NVbits(NV_DQSTrainCTL)){
+ /* FIXME: callback to wrapper: mctDoWarmResetMemClr_D */
+ } else { /* NV_DQSTrainCTL == 1 */
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ pDCTstat = pDCTstatA + Node;
+
+ if (pDCTstat->NodePresent) {
+ DCTMemClr_Init_D(pMCTstat, pDCTstat);
+ }
+ }
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ pDCTstat = pDCTstatA + Node;
+
+ if (pDCTstat->NodePresent) {
+ DCTMemClr_Sync_D(pMCTstat, pDCTstat);
+ }
+ }
+ }
+}
+
+static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 val;
+ u32 dev;
+ u32 reg;
+
+ /* Initiates a memory clear operation on one node */
+ if (pDCTstat->DCTSysLimit) {
+ dev = pDCTstat->dev_dct;
+ reg = 0x110;
+
+ do {
+ val = Get_NB32(dev, reg);
+ } while (val & (1 << MemClrBusy));
+
+ val |= (1 << MemClrInit);
+ Set_NB32(dev, reg, val);
+ }
+}
+
+static void MCTMemClrSync_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ /* Ensures that memory clear has completed on all node.*/
+ u8 Node;
+ struct DCTStatStruc *pDCTstat;
+
+ if (!mctGet_NVbits(NV_DQSTrainCTL)){
+ /* callback to wrapper: mctDoWarmResetMemClr_D */
+ } else { /* NV_DQSTrainCTL == 1 */
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ pDCTstat = pDCTstatA + Node;
+
+ if (pDCTstat->NodePresent) {
+ DCTMemClr_Sync_D(pMCTstat, pDCTstat);
+ }
+ }
+ }
+}
+
+static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 val;
+ u32 dev = pDCTstat->dev_dct;
+ u32 reg;
+
+ /* Ensure that a memory clear operation has completed on one node */
+ if (pDCTstat->DCTSysLimit){
+ reg = 0x110;
+
+ do {
+ val = Get_NB32(dev, reg);
+ } while (val & (1 << MemClrBusy));
+
+ do {
+ val = Get_NB32(dev, reg);
+ } while (!(val & (1 << Dr_MemClrStatus)));
+ }
+
+ val = 0x0FE40FC0; /* BKDG recommended */
+ val |= MCCH_FlushWrOnStpGnt; /* Set for S3 */
+ Set_NB32(dev, 0x11C, val);
+}
+
+static u8 NodePresent_D(u8 Node)
+{
+ /*
+ * Determine if a single Hammer Node exists within the network.
+ */
+ u32 dev;
+ u32 val;
+ u32 dword;
+ u8 ret = 0;
+
+ dev = PA_HOST(Node); /*test device/vendor id at host bridge */
+ val = Get_NB32(dev, 0);
+ dword = mct_NodePresent_D(); /* FIXME: BOZO -11001022h rev for F */
+ if (val == dword) { /* AMD Hammer Family CPU HT Configuration */
+ if (oemNodePresent_D(Node, &ret))
+ goto finish;
+ /* Node ID register */
+ val = Get_NB32(dev, 0x60);
+ val &= 0x07;
+ dword = Node;
+ if (val == dword) /* current nodeID = requested nodeID ? */
+ ret = 1;
+ }
+finish:
+ return ret;
+}
+
+static void DCTInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ /*
+ * Initialize DRAM on single Athlon 64/Opteron Node.
+ */
+ u8 stopDCTflag;
+ u32 val;
+
+ ClearDCT_D(pMCTstat, pDCTstat, dct);
+ stopDCTflag = 1; /*preload flag with 'disable' */
+ /* enable DDR3 support */
+ val = Get_NB32(pDCTstat->dev_dct, 0x94 + dct * 0x100);
+ val |= 1 << Ddr3Mode;
+ Set_NB32(pDCTstat->dev_dct, 0x94 + dct * 0x100, val);
+ if (mct_DIMMPresence(pMCTstat, pDCTstat, dct) < SC_StopError) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_DIMMPresence Done\n");
+ if (mct_SPDCalcWidth(pMCTstat, pDCTstat, dct) < SC_StopError) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth Done\n");
+ if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoCycTiming_D Done\n");
+ if (AutoConfig_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D Done\n");
+ if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: PlatformSpec_D Done\n");
+ stopDCTflag = 0;
+ if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) {
+ printk(BIOS_DEBUG, "\t\tDCTInit_D: StartupDCT_D\n");
+ StartupDCT_D(pMCTstat, pDCTstat, dct); /*yeaahhh! */
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (stopDCTflag) {
+ u32 reg_off = dct * 0x100;
+ val = 1<<DisDramInterface;
+ Set_NB32(pDCTstat->dev_dct, reg_off+0x94, val);
+ /*To maximize power savings when DisDramInterface=1b,
+ all of the MemClkDis bits should also be set.*/
+ val = 0xFF000000;
+ Set_NB32(pDCTstat->dev_dct, reg_off+0x88, val);
+ } else {
+ /* mct_EnDllShutdownSR */
+ }
+}
+
+static void SyncDCTsReady_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ /* Wait (and block further access to dram) for all DCTs to be ready,
+ * by polling all InitDram bits and waiting for possible memory clear
+ * operations to be complete. Read MemClkFreqVal bit to see if
+ * the DIMMs are present in this node.
+ */
+ u8 Node;
+ u32 val;
+
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+ mct_SyncDCTsReady(pDCTstat);
+ }
+ /* v6.1.3 */
+ /* re-enable phy compensation engine when dram init is completed on all nodes. */
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+ if (pDCTstat->NodePresent) {
+ if (pDCTstat->DIMMValidDCT[0] > 0 || pDCTstat->DIMMValidDCT[1] > 0) {
+ /* re-enable phy compensation engine when dram init on both DCTs is completed. */
+ val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8);
+ val &= ~(1 << DisAutoComp);
+ Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8, val);
+ }
+ }
+ }
+ /* wait 750us before any memory access can be made. */
+ mct_Wait(15000);
+}
+
+static void StartupDCT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ /* Read MemClkFreqVal bit to see if the DIMMs are present in this node.
+ * If the DIMMs are present then set the DRAM Enable bit for this node.
+ *
+ * Setting dram init starts up the DCT state machine, initializes the
+ * dram devices with MRS commands, and kicks off any
+ * HW memory clear process that the chip is capable of. The sooner
+ * that dram init is set for all nodes, the faster the memory system
+ * initialization can complete. Thus, the init loop is unrolled into
+ * two loops so as to start the processeses for non BSP nodes sooner.
+ * This procedure will not wait for the process to finish.
+ * Synchronization is handled elsewhere.
+ */
+ u32 val;
+ u32 dev;
+ u32 reg_off = dct * 0x100;
+
+ dev = pDCTstat->dev_dct;
+ val = Get_NB32(dev, 0x94 + reg_off);
+ if (val & (1<<MemClkFreqVal)) {
+ mctHookBeforeDramInit(); /* generalized Hook */
+ if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)))
+ mct_DramInit(pMCTstat, pDCTstat, dct);
+ AfterDramInit_D(pDCTstat, dct);
+ mctHookAfterDramInit(); /* generalized Hook*/
+ }
+}
+
+static void ClearDCT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 reg_end;
+ u32 dev = pDCTstat->dev_dct;
+ u32 reg = 0x40 + 0x100 * dct;
+ u32 val = 0;
+
+ if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
+ reg_end = 0x78 + 0x100 * dct;
+ } else {
+ reg_end = 0xA4 + 0x100 * dct;
+ }
+
+ while(reg < reg_end) {
+ Set_NB32(dev, reg, val);
+ reg += 4;
+ }
+
+ val = 0;
+ dev = pDCTstat->dev_map;
+ reg = 0xF0;
+ Set_NB32(dev, reg, val);
+}
+
+static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u8 i;
+ u16 Twr, Trtp;
+ u16 Trp, Trrd, Trcd, Tras, Trc;
+ u8 Trfc[4];
+ u16 Tfaw;
+ u32 DramTimingLo, DramTimingHi;
+ u8 tCK16x;
+ u16 Twtr;
+ u8 LDIMM;
+ u8 MTB16x;
+ u8 byte;
+ u32 dword;
+ u32 dev;
+ u32 reg_off;
+ u32 val;
+ u16 smbaddr;
+
+ /* Gather all DIMM mini-max values for cycle timing data */
+ Trp = 0;
+ Trrd = 0;
+ Trcd = 0;
+ Trtp = 0;
+ Tras = 0;
+ Trc = 0;
+ Twr = 0;
+ Twtr = 0;
+ for (i=0; i < 4; i++)
+ Trfc[i] = 0;
+ Tfaw = 0;
+
+ for ( i = 0; i< MAX_DIMMS_SUPPORTED; i++) {
+ LDIMM = i >> 1;
+ if (pDCTstat->DIMMValid & (1 << i)) {
+ smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
+
+ val = mctRead_SPD(smbaddr, SPD_MTBDivisor); /* MTB=Dividend/Divisor */
+ MTB16x = ((mctRead_SPD(smbaddr, SPD_MTBDividend) & 0xFF)<<4);
+ MTB16x /= val; /* transfer to MTB*16 */
+
+ byte = mctRead_SPD(smbaddr, SPD_tRPmin);
+ val = byte * MTB16x;
+ if (Trp < val)
+ Trp = val;
+
+ byte = mctRead_SPD(smbaddr, SPD_tRRDmin);
+ val = byte * MTB16x;
+ if (Trrd < val)
+ Trrd = val;
+
+ byte = mctRead_SPD(smbaddr, SPD_tRCDmin);
+ val = byte * MTB16x;
+ if (Trcd < val)
+ Trcd = val;
+
+ byte = mctRead_SPD(smbaddr, SPD_tRTPmin);
+ val = byte * MTB16x;
+ if (Trtp < val)
+ Trtp = val;
+
+ byte = mctRead_SPD(smbaddr, SPD_tWRmin);
+ val = byte * MTB16x;
+ if (Twr < val)
+ Twr = val;
+
+ byte = mctRead_SPD(smbaddr, SPD_tWTRmin);
+ val = byte * MTB16x;
+ if (Twtr < val)
+ Twtr = val;
+
+ val = mctRead_SPD(smbaddr, SPD_Upper_tRAS_tRC) & 0xFF;
+ val >>= 4;
+ val <<= 8;
+ val |= mctRead_SPD(smbaddr, SPD_tRCmin) & 0xFF;
+ val *= MTB16x;
+ if (Trc < val)
+ Trc = val;
+
+ byte = mctRead_SPD(smbaddr, SPD_Density) & 0xF;
+ if (Trfc[LDIMM] < byte)
+ Trfc[LDIMM] = byte;
+
+ val = mctRead_SPD(smbaddr, SPD_Upper_tRAS_tRC) & 0xF;
+ val <<= 8;
+ val |= (mctRead_SPD(smbaddr, SPD_tRASmin) & 0xFF);
+ val *= MTB16x;
+ if (Tras < val)
+ Tras = val;
+
+ val = mctRead_SPD(smbaddr, SPD_Upper_tFAW) & 0xF;
+ val <<= 8;
+ val |= mctRead_SPD(smbaddr, SPD_tFAWmin) & 0xFF;
+ val *= MTB16x;
+ if (Tfaw < val)
+ Tfaw = val;
+ } /* Dimm Present */
+ }
+
+ /* Convert DRAM CycleTiming values and store into DCT structure */
+ byte = pDCTstat->DIMMAutoSpeed;
+ if (byte == 7)
+ tCK16x = 20;
+ else if (byte == 6)
+ tCK16x = 24;
+ else if (byte == 5)
+ tCK16x = 30;
+ else
+ tCK16x = 40;
+
+ /* Notes:
+ 1. All secondary time values given in SPDs are in binary with units of ns.
+ 2. Some time values are scaled by 16, in order to have least count of 0.25 ns
+ (more accuracy). JEDEC SPD spec. shows which ones are x1 and x4.
+ 3. Internally to this SW, cycle time, tCK16x, is scaled by 16 to match time values
+ */
+
+ /* Tras */
+ pDCTstat->DIMMTras = (u16)Tras;
+ val = Tras / tCK16x;
+ if (Tras % tCK16x) { /* round up number of busclocks */
+ val++;
+ }
+ if (val < Min_TrasT)
+ val = Min_TrasT;
+ else if (val > Max_TrasT)
+ val = Max_TrasT;
+ pDCTstat->Tras = val;
+
+ /* Trp */
+ pDCTstat->DIMMTrp = Trp;
+ val = Trp / tCK16x;
+ if (Trp % tCK16x) { /* round up number of busclocks */
+ val++;
+ }
+ if (val < Min_TrpT)
+ val = Min_TrpT;
+ else if (val > Max_TrpT)
+ val = Max_TrpT;
+ pDCTstat->Trp = val;
+
+ /*Trrd*/
+ pDCTstat->DIMMTrrd = Trrd;
+ val = Trrd / tCK16x;
+ if (Trrd % tCK16x) { /* round up number of busclocks */
+ val++;
+ }
+ if (val < Min_TrrdT)
+ val = Min_TrrdT;
+ else if (val > Max_TrrdT)
+ val = Max_TrrdT;
+ pDCTstat->Trrd = val;
+
+ /* Trcd */
+ pDCTstat->DIMMTrcd = Trcd;
+ val = Trcd / tCK16x;
+ if (Trcd % tCK16x) { /* round up number of busclocks */
+ val++;
+ }
+ if (val < Min_TrcdT)
+ val = Min_TrcdT;
+ else if (val > Max_TrcdT)
+ val = Max_TrcdT;
+ pDCTstat->Trcd = val;
+
+ /* Trc */
+ pDCTstat->DIMMTrc = Trc;
+ val = Trc / tCK16x;
+ if (Trc % tCK16x) { /* round up number of busclocks */
+ val++;
+ }
+ if (val < Min_TrcT)
+ val = Min_TrcT;
+ else if (val > Max_TrcT)
+ val = Max_TrcT;
+ pDCTstat->Trc = val;
+
+ /* Trtp */
+ pDCTstat->DIMMTrtp = Trtp;
+ val = Trtp / tCK16x;
+ if (Trtp % tCK16x) {
+ val ++;
+ }
+ if (val < Min_TrtpT)
+ val = Min_TrtpT;
+ else if (val > Max_TrtpT)
+ val = Max_TrtpT;
+ pDCTstat->Trtp = val;
+
+ /* Twr */
+ pDCTstat->DIMMTwr = Twr;
+ val = Twr / tCK16x;
+ if (Twr % tCK16x) { /* round up number of busclocks */
+ val++;
+ }
+ if (val < Min_TwrT)
+ val = Min_TwrT;
+ else if (val > Max_TwrT)
+ val = Max_TwrT;
+ pDCTstat->Twr = val;
+
+ /* Twtr */
+ pDCTstat->DIMMTwtr = Twtr;
+ val = Twtr / tCK16x;
+ if (Twtr % tCK16x) { /* round up number of busclocks */
+ val++;
+ }
+ if (val < Min_TwtrT)
+ val = Min_TwtrT;
+ else if (val > Max_TwtrT)
+ val = Max_TwtrT;
+ pDCTstat->Twtr = val;
+
+ /* Trfc0-Trfc3 */
+ for (i=0; i<4; i++)
+ pDCTstat->Trfc[i] = Trfc[i];
+
+ /* Tfaw */
+ pDCTstat->DIMMTfaw = Tfaw;
+ val = Tfaw / tCK16x;
+ if (Tfaw % tCK16x) { /* round up number of busclocks */
+ val++;
+ }
+ if (val < Min_TfawT)
+ val = Min_TfawT;
+ else if (val > Max_TfawT)
+ val = Max_TfawT;
+ pDCTstat->Tfaw = val;
+
+ mctAdjustAutoCycTmg_D();
+
+ /* Program DRAM Timing values */
+ DramTimingLo = 0; /* Dram Timing Low init */
+ val = pDCTstat->CASL - 2; /* pDCTstat.CASL to reg. definition */
+ DramTimingLo |= val;
+
+ val = pDCTstat->Trcd - Bias_TrcdT;
+ DramTimingLo |= val<<4;
+
+ val = pDCTstat->Trp - Bias_TrpT;
+ val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+ DramTimingLo |= val<<7;
+
+ val = pDCTstat->Trtp - Bias_TrtpT;
+ DramTimingLo |= val<<10;
+
+ val = pDCTstat->Tras - Bias_TrasT;
+ DramTimingLo |= val<<12;
+
+ val = pDCTstat->Trc - Bias_TrcT;
+ DramTimingLo |= val<<16;
+
+ val = pDCTstat->Trrd - Bias_TrrdT;
+ DramTimingLo |= val<<22;
+
+ DramTimingHi = 0; /* Dram Timing High init */
+ val = pDCTstat->Twtr - Bias_TwtrT;
+ DramTimingHi |= val<<8;
+
+ val = 2;
+ DramTimingHi |= val<<16;
+
+ val = 0;
+ for (i=4;i>0;i--) {
+ val <<= 3;
+ val |= Trfc[i-1];
+ }
+ DramTimingHi |= val << 20;
+
+ dev = pDCTstat->dev_dct;
+ reg_off = 0x100 * dct;
+ /* Twr */
+ val = pDCTstat->Twr;
+ if (val == 10)
+ val = 9;
+ else if (val == 12)
+ val = 10;
+ val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+ val -= Bias_TwrT;
+ val <<= 4;
+ dword = Get_NB32(dev, 0x84 + reg_off);
+ dword &= ~0x70;
+ dword |= val;
+ Set_NB32(dev, 0x84 + reg_off, dword);
+
+ /* Tfaw */
+ val = pDCTstat->Tfaw;
+ val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+ val -= Bias_TfawT;
+ val >>= 1;
+ val <<= 28;
+ dword = Get_NB32(dev, 0x94 + reg_off);
+ dword &= ~0xf0000000;
+ dword |= val;
+ Set_NB32(dev, 0x94 + reg_off, dword);
+
+ /* dev = pDCTstat->dev_dct; */
+ /* reg_off = 0x100 * dct; */
+
+ if (pDCTstat->Speed > 4) {
+ val = Get_NB32(dev, 0x88 + reg_off);
+ val &= 0xFF000000;
+ DramTimingLo |= val;
+ }
+ Set_NB32(dev, 0x88 + reg_off, DramTimingLo); /*DCT Timing Low*/
+
+ if (pDCTstat->Speed > 4) {
+ DramTimingLo |= 1 << DisAutoRefresh;
+ }
+ DramTimingHi |= 0x000018FF;
+ Set_NB32(dev, 0x8c + reg_off, DramTimingHi); /*DCT Timing Hi*/
+
+ /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+}
+
+static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ /* Initialize DCT Timing registers as per DIMM SPD.
+ * For primary timing (T, CL) use best case T value.
+ * For secondary timing params., use most aggressive settings
+ * of slowest DIMM.
+ *
+ * There are three components to determining "maximum frequency":
+ * SPD component, Bus load component, and "Preset" max frequency
+ * component.
+ *
+ * The SPD component is a function of the min cycle time specified
+ * by each DIMM, and the interaction of cycle times from all DIMMs
+ * in conjunction with CAS latency. The SPD component only applies
+ * when user timing mode is 'Auto'.
+ *
+ * The Bus load component is a limiting factor determined by electrical
+ * characteristics on the bus as a result of varying number of device
+ * loads. The Bus load component is specific to each platform but may
+ * also be a function of other factors. The bus load component only
+ * applies when user timing mode is 'Auto'.
+ *
+ * The Preset component is subdivided into three items and is
+ * the minimum of the set: Silicon revision, user limit
+ * setting when user timing mode is 'Auto' and memclock mode
+ * is 'Limit', OEM build specification of the maximum
+ * frequency. The Preset component is only applies when user
+ * timing mode is 'Auto'.
+ */
+
+ /* Get primary timing (CAS Latency and Cycle Time) */
+ if (pDCTstat->Speed == 0) {
+ mctGet_MaxLoadFreq(pDCTstat);
+
+ /* and Factor in presets (setup options, Si cap, etc.) */
+ GetPresetmaxF_D(pMCTstat, pDCTstat);
+
+ /* Go get best T and CL as specified by DIMM mfgs. and OEM */
+ SPDGetTCL_D(pMCTstat, pDCTstat, dct);
+ /* skip callback mctForce800to1067_D */
+ pDCTstat->Speed = pDCTstat->DIMMAutoSpeed;
+ pDCTstat->CASL = pDCTstat->DIMMCASL;
+
+ }
+ mct_AfterGetCLT(pMCTstat, pDCTstat, dct);
+
+ SPD2ndTiming(pMCTstat, pDCTstat, dct);
+
+ printk(BIOS_DEBUG, "AutoCycTiming: Status %x\n", pDCTstat->Status);
+ printk(BIOS_DEBUG, "AutoCycTiming: ErrStatus %x\n", pDCTstat->ErrStatus);
+ printk(BIOS_DEBUG, "AutoCycTiming: ErrCode %x\n", pDCTstat->ErrCode);
+ printk(BIOS_DEBUG, "AutoCycTiming: Done\n\n");
+
+ mctHookAfterAutoCycTmg();
+
+ return pDCTstat->ErrCode;
+}
+
+static void GetPresetmaxF_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ /* Get max frequency from OEM platform definition, from any user
+ * override (limiting) of max frequency, and from any Si Revision
+ * Specific information. Return the least of these three in
+ * DCTStatStruc.PresetmaxFreq.
+ */
+ u16 proposedFreq;
+ u16 word;
+
+ /* Get CPU Si Revision defined limit (NPT) */
+ proposedFreq = 533; /* Rev F0 programmable max memclock is */
+
+ /*Get User defined limit if "limit" mode */
+ if ( mctGet_NVbits(NV_MCTUSRTMGMODE) == 1) {
+ word = Get_Fk_D(mctGet_NVbits(NV_MemCkVal) + 1);
+ if (word < proposedFreq)
+ proposedFreq = word;
+
+ /* Get Platform defined limit */
+ word = mctGet_NVbits(NV_MAX_MEMCLK);
+ if (word < proposedFreq)
+ proposedFreq = word;
+
+ word = pDCTstat->PresetmaxFreq;
+ if (word > proposedFreq)
+ word = proposedFreq;
+
+ pDCTstat->PresetmaxFreq = word;
+ }
+ /* Check F3xE8[DdrMaxRate] for maximum DRAM data rate support */
+}
+
+static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ /* Find the best T and CL primary timing parameter pair, per Mfg.,
+ * for the given set of DIMMs, and store into DCTStatStruc
+ * (.DIMMAutoSpeed and .DIMMCASL). See "Global relationship between
+ * index values and item values" for definition of CAS latency
+ * index (j) and Frequency index (k).
+ */
+ u8 i, CASLatLow, CASLatHigh;
+ u16 tAAmin16x;
+ u8 MTB16x;
+ u16 tCKmin16x;
+ u16 tCKproposed16x;
+ u8 CLactual, CLdesired, CLT_Fail;
+
+ u8 smbaddr, byte, bytex;
+
+ CASLatLow = 0xFF;
+ CASLatHigh = 0xFF;
+ tAAmin16x = 0;
+ tCKmin16x = 0;
+ CLT_Fail = 0;
+
+ for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
+ if (pDCTstat->DIMMValid & (1 << i)) {
+ smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
+ /* Step 1: Determine the common set of supported CAS Latency
+ * values for all modules on the memory channel using the CAS
+ * Latencies Supported in SPD bytes 14 and 15.
+ */
+ byte = mctRead_SPD(smbaddr, SPD_CASLow);
+ CASLatLow &= byte;
+ byte = mctRead_SPD(smbaddr, SPD_CASHigh);
+ CASLatHigh &= byte;
+ /* Step 2: Determine tAAmin(all) which is the largest tAAmin
+ value for all modules on the memory channel (SPD byte 16). */
+ byte = mctRead_SPD(smbaddr, SPD_MTBDivisor);
+
+ MTB16x = ((mctRead_SPD(smbaddr, SPD_MTBDividend) & 0xFF)<<4);
+ MTB16x /= byte; /* transfer to MTB*16 */
+
+ byte = mctRead_SPD(smbaddr, SPD_tAAmin);
+ if (tAAmin16x < byte * MTB16x)
+ tAAmin16x = byte * MTB16x;
+ /* Step 3: Determine tCKmin(all) which is the largest tCKmin
+ value for all modules on the memory channel (SPD byte 12). */
+ byte = mctRead_SPD(smbaddr, SPD_tCKmin);
+
+ if (tCKmin16x < byte * MTB16x)
+ tCKmin16x = byte * MTB16x;
+ }
+ }
+ /* calculate tCKproposed16x */
+ tCKproposed16x = 16000 / pDCTstat->PresetmaxFreq;
+ if (tCKmin16x > tCKproposed16x)
+ tCKproposed16x = tCKmin16x;
+
+ /* mctHookTwo1333DimmOverride(); */
+ /* For UDIMM, if there are two DDR3-1333 on the same channel,
+ downgrade DDR speed to 1066. */
+
+ /* TODO: get user manual tCK16x(Freq.) and overwrite current tCKproposed16x if manual. */
+ if (tCKproposed16x == 20)
+ pDCTstat->TargetFreq = 7;
+ else if (tCKproposed16x <= 24) {
+ pDCTstat->TargetFreq = 6;
+ tCKproposed16x = 24;
+ }
+ else if (tCKproposed16x <= 30) {
+ pDCTstat->TargetFreq = 5;
+ tCKproposed16x = 30;
+ }
+ else {
+ pDCTstat->TargetFreq = 4;
+ tCKproposed16x = 40;
+ }
+ /* Running through this loop twice:
+ - First time find tCL at target frequency
+ - Second tim find tCL at 400MHz */
+
+ for (;;) {
+ CLT_Fail = 0;
+ /* Step 4: For a proposed tCK value (tCKproposed) between tCKmin(all) and tCKmax,
+ determine the desired CAS Latency. If tCKproposed is not a standard JEDEC
+ value (2.5, 1.875, 1.5, or 1.25 ns) then tCKproposed must be adjusted to the
+ next lower standard tCK value for calculating CLdesired.
+ CLdesired = ceiling ( tAAmin(all) / tCKproposed )
+ where tAAmin is defined in Byte 16. The ceiling function requires that the
+ quotient be rounded up always. */
+ CLdesired = tAAmin16x / tCKproposed16x;
+ if (tAAmin16x % tCKproposed16x)
+ CLdesired ++;
+ /* Step 5: Chose an actual CAS Latency (CLactual) that is greather than or equal
+ to CLdesired and is supported by all modules on the memory channel as
+ determined in step 1. If no such value exists, choose a higher tCKproposed
+ value and repeat steps 4 and 5 until a solution is found. */
+ for (i = 0, CLactual = 4; i < 15; i++, CLactual++) {
+ if ((CASLatHigh << 8 | CASLatLow) & (1 << i)) {
+ if (CLdesired <= CLactual)
+ break;
+ }
+ }
+ if (i == 15)
+ CLT_Fail = 1;
+ /* Step 6: Once the calculation of CLactual is completed, the BIOS must also
+ verify that this CAS Latency value does not exceed tAAmax, which is 20 ns
+ for all DDR3 speed grades, by multiplying CLactual times tCKproposed. If
+ not, choose a lower CL value and repeat steps 5 and 6 until a solution is found. */
+ if (CLactual * tCKproposed16x > 320)
+ CLT_Fail = 1;
+ /* get CL and T */
+ if (!CLT_Fail) {
+ bytex = CLactual - 2;
+ if (tCKproposed16x == 20)
+ byte = 7;
+ else if (tCKproposed16x == 24)
+ byte = 6;
+ else if (tCKproposed16x == 30)
+ byte = 5;
+ else
+ byte = 4;
+ } else {
+ /* mctHookManualCLOverride */
+ /* TODO: */
+ }
+
+ if (tCKproposed16x != 40) {
+ if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
+ pDCTstat->DIMMAutoSpeed = byte;
+ pDCTstat->DIMMCASL = bytex;
+ break;
+ } else {
+ pDCTstat->TargetCASL = bytex;
+ tCKproposed16x = 40;
+ }
+ } else {
+ pDCTstat->DIMMAutoSpeed = byte;
+ pDCTstat->DIMMCASL = bytex;
+ break;
+ }
+ }
+
+ printk(BIOS_DEBUG, "SPDGetTCL_D: DIMMCASL %x\n", pDCTstat->DIMMCASL);
+ printk(BIOS_DEBUG, "SPDGetTCL_D: DIMMAutoSpeed %x\n", pDCTstat->DIMMAutoSpeed);
+
+ printk(BIOS_DEBUG, "SPDGetTCL_D: Status %x\n", pDCTstat->Status);
+ printk(BIOS_DEBUG, "SPDGetTCL_D: ErrStatus %x\n", pDCTstat->ErrStatus);
+ printk(BIOS_DEBUG, "SPDGetTCL_D: ErrCode %x\n", pDCTstat->ErrCode);
+ printk(BIOS_DEBUG, "SPDGetTCL_D: Done\n\n");
+}
+
+static u8 PlatformSpec_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 dev;
+ u32 reg;
+ u32 val;
+
+ mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
+
+ if (pDCTstat->GangedMode == 1) {
+ mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
+ }
+
+ if ( pDCTstat->_2Tmode == 2) {
+ dev = pDCTstat->dev_dct;
+ reg = 0x94 + 0x100 * dct; /* Dram Configuration Hi */
+ val = Get_NB32(dev, reg);
+ val |= 1 << 20; /* 2T CMD mode */
+ Set_NB32(dev, reg, val);
+ }
+
+ mct_PlatformSpec(pMCTstat, pDCTstat, dct);
+ if (pDCTstat->DIMMAutoSpeed == 4)
+ InitPhyCompensation(pMCTstat, pDCTstat, dct);
+ mctHookAfterPSCfg();
+
+ return pDCTstat->ErrCode;
+}
+
+static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 DramControl, DramTimingLo, Status;
+ u32 DramConfigLo, DramConfigHi, DramConfigMisc, DramConfigMisc2;
+ u32 val;
+ u32 reg_off;
+ u32 dev;
+ u16 word;
+ u32 dword;
+ u8 byte;
+
+ DramConfigLo = 0;
+ DramConfigHi = 0;
+ DramConfigMisc = 0;
+ DramConfigMisc2 = 0;
+
+ /* set bank addessing and Masks, plus CS pops */
+ SPDSetBanks_D(pMCTstat, pDCTstat, dct);
+ if (pDCTstat->ErrCode == SC_StopError)
+ goto AutoConfig_exit;
+
+ /* map chip-selects into local address space */
+ StitchMemory_D(pMCTstat, pDCTstat, dct);
+ InterleaveBanks_D(pMCTstat, pDCTstat, dct);
+
+ /* temp image of status (for convenience). RO usage! */
+ Status = pDCTstat->Status;
+
+ dev = pDCTstat->dev_dct;
+ reg_off = 0x100 * dct;
+
+
+ /* Build Dram Control Register Value */
+ DramConfigMisc2 = Get_NB32 (dev, 0xA8 + reg_off); /* Dram Control*/
+ DramControl = Get_NB32 (dev, 0x78 + reg_off); /* Dram Control*/
+
+ /* FIXME: Skip mct_checkForDxSupport */
+ /* REV_CALL mct_DoRdPtrInit if not Dx */
+ if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
+ val = 5;
+ else
+ val = 6;
+ DramControl &= ~0xFF;
+ DramControl |= val; /* RdPrtInit = 6 for Cx CPU */
+
+ if (mctGet_NVbits(NV_CLKHZAltVidC3))
+ DramControl |= 1<<16; /* check */
+
+ DramControl |= 0x00002A00;
+
+ /* FIXME: Skip for Ax versions */
+ /* callback not required - if (!mctParityControl_D()) */
+ if (Status & (1 << SB_128bitmode))
+ DramConfigLo |= 1 << Width128; /* 128-bit mode (normal) */
+
+ word = dct;
+ dword = X4Dimm;
+ while (word < 8) {
+ if (pDCTstat->Dimmx4Present & (1 << word))
+ DramConfigLo |= 1 << dword; /* X4Dimm[3:0] */
+ word++;
+ word++;
+ dword++;
+ }
+
+ if (!(Status & (1 << SB_Registered)))
+ DramConfigLo |= 1 << UnBuffDimm; /* Unbufferd DIMMs */
+
+ if (mctGet_NVbits(NV_ECC_CAP))
+ if (Status & (1 << SB_ECCDIMMs))
+ if ( mctGet_NVbits(NV_ECC))
+ DramConfigLo |= 1 << DimmEcEn;
+
+ DramConfigLo = mct_DisDllShutdownSR(pMCTstat, pDCTstat, DramConfigLo, dct);
+
+ /* Build Dram Config Hi Register Value */
+ dword = pDCTstat->Speed;
+ DramConfigHi |= dword - 1; /* get MemClk encoding */
+ DramConfigHi |= 1 << MemClkFreqVal;
+
+ if (Status & (1 << SB_Registered))
+ if ((pDCTstat->Dimmx4Present != 0) && (pDCTstat->Dimmx8Present != 0))
+ /* set only if x8 Registered DIMMs in System*/
+ DramConfigHi |= 1 << RDqsEn;
+
+ if (mctGet_NVbits(NV_CKE_CTL))
+ /*Chip Select control of CKE*/
+ DramConfigHi |= 1 << 16;
+
+ /* Control Bank Swizzle */
+ if (0) /* call back not needed mctBankSwizzleControl_D()) */
+ DramConfigHi &= ~(1 << BankSwizzleMode);
+ else
+ DramConfigHi |= 1 << BankSwizzleMode; /* recommended setting (default) */
+
+ /* Check for Quadrank DIMM presence */
+ if ( pDCTstat->DimmQRPresent != 0) {
+ byte = mctGet_NVbits(NV_4RANKType);
+ if (byte == 2)
+ DramConfigHi |= 1 << 17; /* S4 (4-Rank SO-DIMMs) */
+ else if (byte == 1)
+ DramConfigHi |= 1 << 18; /* R4 (4-Rank Registered DIMMs) */
+ }
+
+ if (0) /* call back not needed mctOverrideDcqBypMax_D ) */
+ val = mctGet_NVbits(NV_BYPMAX);
+ else
+ val = 0x0f; /* recommended setting (default) */
+ DramConfigHi |= val << 24;
+
+ if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Bx))
+ DramConfigHi |= 1 << DcqArbBypassEn;
+
+ /* Build MemClkDis Value from Dram Timing Lo and
+ Dram Config Misc Registers
+ 1. We will assume that MemClkDis field has been preset prior to this
+ point.
+ 2. We will only set MemClkDis bits if a DIMM is NOT present AND if:
+ NV_AllMemClks <>0 AND SB_DiagClks ==0 */
+
+ /* Dram Timing Low (owns Clock Enable bits) */
+ DramTimingLo = Get_NB32(dev, 0x88 + reg_off);
+ if (mctGet_NVbits(NV_AllMemClks) == 0) {
+ /* Special Jedec SPD diagnostic bit - "enable all clocks" */
+ if (!(pDCTstat->Status & (1<<SB_DiagClks))) {
+ const u8 *p;
+ const u32 *q;
+ p = Tab_ManualCLKDis;
+ q = (u32 *)p;
+
+ byte = mctGet_NVbits(NV_PACK_TYPE);
+ if (byte == PT_L1)
+ p = Tab_L1CLKDis;
+ else if (byte == PT_M2 || byte == PT_AS)
+ p = Tab_AM3CLKDis;
+ else
+ p = Tab_S1CLKDis;
+
+ dword = 0;
+ byte = 0xFF;
+ while(dword < MAX_CS_SUPPORTED) {
+ if (pDCTstat->CSPresent & (1<<dword)){
+ /* re-enable clocks for the enabled CS */
+ val = p[dword];
+ byte &= ~val;
+ }
+ dword++ ;
+ }
+ DramTimingLo |= byte << 24;
+ }
+ }
+
+ printk(BIOS_DEBUG, "AutoConfig_D: DramControl: %x\n", DramControl);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo: %x\n", DramTimingLo);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc: %x\n", DramConfigMisc);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc2: %x\n", DramConfigMisc2);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramConfigLo: %x\n", DramConfigLo);
+ printk(BIOS_DEBUG, "AutoConfig_D: DramConfigHi: %x\n", DramConfigHi);
+
+ /* Write Values to the registers */
+ Set_NB32(dev, 0x78 + reg_off, DramControl);
+ Set_NB32(dev, 0x88 + reg_off, DramTimingLo);
+ Set_NB32(dev, 0xA0 + reg_off, DramConfigMisc);
+ DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, DramConfigMisc2);
+ Set_NB32(dev, 0xA8 + reg_off, DramConfigMisc2);
+ Set_NB32(dev, 0x90 + reg_off, DramConfigLo);
+ ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
+ dword = Get_NB32(dev, 0x94 + reg_off);
+ DramConfigHi |= dword;
+ mct_SetDramConfigHi_D(pDCTstat, dct, DramConfigHi);
+ mct_EarlyArbEn_D(pMCTstat, pDCTstat);
+ mctHookAfterAutoCfg();
+
+ /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+
+ printk(BIOS_DEBUG, "AutoConfig: Status %x\n", pDCTstat->Status);
+ printk(BIOS_DEBUG, "AutoConfig: ErrStatus %x\n", pDCTstat->ErrStatus);
+ printk(BIOS_DEBUG, "AutoConfig: ErrCode %x\n", pDCTstat->ErrCode);
+ printk(BIOS_DEBUG, "AutoConfig: Done\n\n");
+AutoConfig_exit:
+ return pDCTstat->ErrCode;
+}
+
+static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ /* Set bank addressing, program Mask values and build a chip-select
+ * population map. This routine programs PCI 0:24N:2x80 config register
+ * and PCI 0:24N:2x60,64,68,6C config registers (CS Mask 0-3).
+ */
+ u8 ChipSel, Rows, Cols, Ranks, Banks;
+ u32 BankAddrReg, csMask;
+
+ u32 val;
+ u32 reg;
+ u32 dev;
+ u32 reg_off;
+ u8 byte;
+ u16 word;
+ u32 dword;
+ u16 smbaddr;
+
+ dev = pDCTstat->dev_dct;
+ reg_off = 0x100 * dct;
+
+ BankAddrReg = 0;
+ for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel+=2) {
+ byte = ChipSel;
+ if ((pDCTstat->Status & (1 << SB_64MuxedMode)) && ChipSel >=4)
+ byte -= 3;
+
+ if (pDCTstat->DIMMValid & (1<<byte)) {
+ smbaddr = Get_DIMMAddress_D(pDCTstat, (ChipSel + dct));
+
+ byte = mctRead_SPD(smbaddr, SPD_Addressing);
+ Rows = (byte >> 3) & 0x7; /* Rows:0b=12-bit,... */
+ Cols = byte & 0x7; /* Cols:0b=9-bit,... */
+
+ byte = mctRead_SPD(smbaddr, SPD_Density);
+ Banks = (byte >> 4) & 7; /* Banks:0b=3-bit,... */
+
+ byte = mctRead_SPD(smbaddr, SPD_Organization);
+ Ranks = ((byte >> 3) & 7) + 1;
+
+ /* Configure Bank encoding
+ * Use a 6-bit key into a lookup table.
+ * Key (index) = RRRBCC, where CC is the number of Columns minus 9,
+ * RRR is the number of Rows minus 12, and B is the number of banks
+ * minus 3.
+ */
+ byte = Cols;
+ if (Banks == 1)
+ byte |= 4;
+
+ byte |= Rows << 3; /* RRRBCC internal encode */
+
+ for (dword=0; dword < 13; dword++) {
+ if (byte == Tab_BankAddr[dword])
+ break;
+ }
+
+ if (dword > 12)
+ continue;
+
+ /* bit no. of CS field in address mapping reg.*/
+ dword <<= (ChipSel<<1);
+ BankAddrReg |= dword;
+
+ /* Mask value=(2pow(rows+cols+banks+3)-1)>>8,
+ or 2pow(rows+cols+banks-5)-1*/
+ csMask = 0;
+
+ byte = Rows + Cols; /* cl=rows+cols*/
+ byte += 21; /* row:12+col:9 */
+ byte -= 2; /* 3 banks - 5 */
+
+ if (pDCTstat->Status & (1 << SB_128bitmode))
+ byte++; /* double mask size if in 128-bit mode*/
+
+ csMask |= 1 << byte;
+ csMask--;
+
+ /*set ChipSelect population indicator even bits*/
+ pDCTstat->CSPresent |= (1<<ChipSel);
+ if (Ranks >= 2)
+ /*set ChipSelect population indicator odd bits*/
+ pDCTstat->CSPresent |= 1 << (ChipSel + 1);
+
+ reg = 0x60+(ChipSel<<1) + reg_off; /*Dram CS Mask Register */
+ val = csMask;
+ val &= 0x1FF83FE0; /* Mask out reserved bits.*/
+ Set_NB32(dev, reg, val);
+ } else {
+ if (pDCTstat->DIMMSPDCSE & (1<<ChipSel))
+ pDCTstat->CSTestFail |= (1<<ChipSel);
+ } /* if DIMMValid*/
+ } /* while ChipSel*/
+
+ SetCSTriState(pMCTstat, pDCTstat, dct);
+ SetCKETriState(pMCTstat, pDCTstat, dct);
+ SetODTTriState(pMCTstat, pDCTstat, dct);
+
+ if (pDCTstat->Status & (1 << SB_128bitmode)) {
+ SetCSTriState(pMCTstat, pDCTstat, 1); /* force dct1) */
+ SetCKETriState(pMCTstat, pDCTstat, 1); /* force dct1) */
+ SetODTTriState(pMCTstat, pDCTstat, 1); /* force dct1) */
+ }
+
+ word = pDCTstat->CSPresent;
+ mctGetCS_ExcludeMap(); /* mask out specified chip-selects */
+ word ^= pDCTstat->CSPresent;
+ pDCTstat->CSTestFail |= word; /* enable ODT to disabled DIMMs */
+ if (!pDCTstat->CSPresent)
+ pDCTstat->ErrCode = SC_StopError;
+
+ reg = 0x80 + reg_off; /* Bank Addressing Register */
+ Set_NB32(dev, reg, BankAddrReg);
+
+ pDCTstat->CSPresent_DCT[dct] = pDCTstat->CSPresent;
+ /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+
+ printk(BIOS_DEBUG, "SPDSetBanks: CSPresent %x\n", pDCTstat->CSPresent_DCT[dct]);
+ printk(BIOS_DEBUG, "SPDSetBanks: Status %x\n", pDCTstat->Status);
+ printk(BIOS_DEBUG, "SPDSetBanks: ErrStatus %x\n", pDCTstat->ErrStatus);
+ printk(BIOS_DEBUG, "SPDSetBanks: ErrCode %x\n", pDCTstat->ErrCode);
+ printk(BIOS_DEBUG, "SPDSetBanks: Done\n\n");
+}
+
+static void SPDCalcWidth_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ /* Per SPDs, check the symmetry of DIMM pairs (DIMM on Channel A
+ * matching with DIMM on Channel B), the overall DIMM population,
+ * and determine the width mode: 64-bit, 64-bit muxed, 128-bit.
+ */
+ u8 i;
+ u8 smbaddr, smbaddr1;
+ u8 byte, byte1;
+
+ /* Check Symmetry of Channel A and Channel B DIMMs
+ (must be matched for 128-bit mode).*/
+ for (i=0; i < MAX_DIMMS_SUPPORTED; i += 2) {
+ if ((pDCTstat->DIMMValid & (1 << i)) && (pDCTstat->DIMMValid & (1<<(i+1)))) {
+ smbaddr = Get_DIMMAddress_D(pDCTstat, i);
+ smbaddr1 = Get_DIMMAddress_D(pDCTstat, i+1);
+
+ byte = mctRead_SPD(smbaddr, SPD_Addressing) & 0x7;
+ byte1 = mctRead_SPD(smbaddr1, SPD_Addressing) & 0x7;
+ if (byte != byte1) {
+ pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+ break;
+ }
+
+ byte = mctRead_SPD(smbaddr, SPD_Density) & 0x0f;
+ byte1 = mctRead_SPD(smbaddr1, SPD_Density) & 0x0f;
+ if (byte != byte1) {
+ pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+ break;
+ }
+
+ byte = mctRead_SPD(smbaddr, SPD_Organization) & 0x7;
+ byte1 = mctRead_SPD(smbaddr1, SPD_Organization) & 0x7;
+ if (byte != byte1) {
+ pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+ break;
+ }
+
+ byte = (mctRead_SPD(smbaddr, SPD_Organization) >> 3) & 0x7;
+ byte1 = (mctRead_SPD(smbaddr1, SPD_Organization) >> 3) & 0x7;
+ if (byte != byte1) {
+ pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+ break;
+ }
+
+ byte = mctRead_SPD(smbaddr, SPD_DMBANKS) & 7; /* #ranks-1 */
+ byte1 = mctRead_SPD(smbaddr1, SPD_DMBANKS) & 7; /* #ranks-1 */
+ if (byte != byte1) {
+ pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+ break;
+ }
+
+ }
+ }
+
+}
+
+static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ /* Requires that Mask values for each bank be programmed first and that
+ * the chip-select population indicator is correctly set.
+ */
+ u8 b = 0;
+ u32 nxtcsBase, curcsBase;
+ u8 p, q;
+ u32 Sizeq, BiggestBank;
+ u8 _DSpareEn;
+
+ u16 word;
+ u32 dev;
+ u32 reg;
+ u32 reg_off;
+ u32 val;
+
+ dev = pDCTstat->dev_dct;
+ reg_off = 0x100 * dct;
+
+ _DSpareEn = 0;
+
+ /* CS Sparing 1=enabled, 0=disabled */
+ if (mctGet_NVbits(NV_CS_SpareCTL) & 1) {
+ if (MCT_DIMM_SPARE_NO_WARM) {
+ /* Do no warm-reset DIMM spare */
+ if (pMCTstat->GStatus & 1 << GSB_EnDIMMSpareNW) {
+ word = pDCTstat->CSPresent;
+ val = bsf(word);
+ word &= ~(1<<val);
+ if (word)
+ /* Make sure at least two chip-selects are available */
+ _DSpareEn = 1;
+ else
+ pDCTstat->ErrStatus |= 1 << SB_SpareDis;
+ }
+ } else {
+ if (!mctGet_NVbits(NV_DQSTrainCTL)) { /*DQS Training 1=enabled, 0=disabled */
+ word = pDCTstat->CSPresent;
+ val = bsf(word);
+ word &= ~(1 << val);
+ if (word)
+ /* Make sure at least two chip-selects are available */
+ _DSpareEn = 1;
+ else
+ pDCTstat->ErrStatus |= 1 << SB_SpareDis;
+ }
+ }
+ }
+
+ nxtcsBase = 0; /* Next available cs base ADDR[39:8] */
+ for (p=0; p < MAX_DIMMS_SUPPORTED; p++) {
+ BiggestBank = 0;
+ for (q = 0; q < MAX_CS_SUPPORTED; q++) { /* from DIMMS to CS */
+ if (pDCTstat->CSPresent & (1 << q)) { /* bank present? */
+ reg = 0x40 + (q << 2) + reg_off; /* Base[q] reg.*/
+ val = Get_NB32(dev, reg);
+ if (!(val & 3)) { /* (CSEnable|Spare==1)bank is enabled already? */
+ reg = 0x60 + (q << 1) + reg_off; /*Mask[q] reg.*/
+ val = Get_NB32(dev, reg);
+ val >>= 19;
+ val++;
+ val <<= 19;
+ Sizeq = val; /* never used */
+ if (val > BiggestBank) {
+ /*Bingo! possibly Map this chip-select next! */
+ BiggestBank = val;
+ b = q;
+ }
+ }
+ } /*if bank present */
+ } /* while q */
+ if (BiggestBank !=0) {
+ curcsBase = nxtcsBase; /* curcsBase=nxtcsBase*/
+ /* DRAM CS Base b Address Register offset */
+ reg = 0x40 + (b << 2) + reg_off;
+ if (_DSpareEn) {
+ BiggestBank = 0;
+ val = 1 << Spare; /* Spare Enable*/
+ } else {
+ val = curcsBase;
+ val |= 1 << CSEnable; /* Bank Enable */
+ }
+ if (((reg - 0x40) >> 2) & 1) {
+ if (!(pDCTstat->Status & (1 << SB_Registered))) {
+ u16 dimValid;
+ dimValid = pDCTstat->DIMMValid;
+ if (dct & 1)
+ dimValid <<= 1;
+ if ((dimValid & pDCTstat->MirrPresU_NumRegR) != 0) {
+ val |= 1 << onDimmMirror;
+ }
+ }
+ }
+ Set_NB32(dev, reg, val);
+ if (_DSpareEn)
+ _DSpareEn = 0;
+ else
+ /* let nxtcsBase+=Size[b] */
+ nxtcsBase += BiggestBank;
+ }
+
+ /* bank present but disabled?*/
+ if ( pDCTstat->CSTestFail & (1 << p)) {
+ /* DRAM CS Base b Address Register offset */
+ reg = (p << 2) + 0x40 + reg_off;
+ val = 1 << TestFail;
+ Set_NB32(dev, reg, val);
+ }
+ }
+
+ if (nxtcsBase) {
+ pDCTstat->DCTSysLimit = nxtcsBase - 1;
+ mct_AfterStitchMemory(pMCTstat, pDCTstat, dct);
+ }
+
+ /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+
+ printk(BIOS_DEBUG, "StitchMemory: Status %x\n", pDCTstat->Status);
+ printk(BIOS_DEBUG, "StitchMemory: ErrStatus %x\n", pDCTstat->ErrStatus);
+ printk(BIOS_DEBUG, "StitchMemory: ErrCode %x\n", pDCTstat->ErrCode);
+ printk(BIOS_DEBUG, "StitchMemory: Done\n\n");
+}
+
+static u16 Get_Fk_D(u8 k)
+{
+ return Table_F_k[k]; /* FIXME: k or k<<1 ? */
+}
+
+static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ /* Check DIMMs present, verify checksum, flag SDRAM type,
+ * build population indicator bitmaps, and preload bus loading
+ * of DIMMs into DCTStatStruc.
+ * MAAload=number of devices on the "A" bus.
+ * MABload=number of devices on the "B" bus.
+ * MAAdimms=number of DIMMs on the "A" bus slots.
+ * MABdimms=number of DIMMs on the "B" bus slots.
+ * DATAAload=number of ranks on the "A" bus slots.
+ * DATABload=number of ranks on the "B" bus slots.
+ */
+ u16 i, j;
+ u8 smbaddr;
+ u8 SPDCtrl;
+ u16 RegDIMMPresent, MaxDimms;
+ u8 devwidth;
+ u16 DimmSlots;
+ u8 byte = 0, bytex;
+
+ /* preload data structure with addrs */
+ mctGet_DIMMAddr(pDCTstat, pDCTstat->Node_ID);
+
+ DimmSlots = MaxDimms = mctGet_NVbits(NV_MAX_DIMMS);
+
+ SPDCtrl = mctGet_NVbits(NV_SPDCHK_RESTRT);
+
+ RegDIMMPresent = 0;
+ pDCTstat->DimmQRPresent = 0;
+
+ for (i = 0; i< MAX_DIMMS_SUPPORTED; i++) {
+ if (i >= MaxDimms)
+ break;
+
+ if ((pDCTstat->DimmQRPresent & (1 << i)) || (i < DimmSlots)) {
+ int status;
+ smbaddr = Get_DIMMAddress_D(pDCTstat, i);
+ status = mctRead_SPD(smbaddr, SPD_ByteUse);
+ if (status >= 0) { /* SPD access is ok */
+ pDCTstat->DIMMPresent |= 1 << i;
+ if (crcCheck(smbaddr)) { /* CRC is OK */
+ byte = mctRead_SPD(smbaddr, SPD_TYPE);
+ if (byte == JED_DDR3SDRAM) {
+ /*Dimm is 'Present'*/
+ pDCTstat->DIMMValid |= 1 << i;
+ }
+ } else {
+ pDCTstat->DIMMSPDCSE = 1 << i;
+ if (SPDCtrl == 0) {
+ pDCTstat->ErrStatus |= 1 << SB_DIMMChkSum;
+ pDCTstat->ErrCode = SC_StopError;
+ } else {
+ /*if NV_SPDCHK_RESTRT is set to 1, ignore faulty SPD checksum*/
+ pDCTstat->ErrStatus |= 1<<SB_DIMMChkSum;
+ byte = mctRead_SPD(smbaddr, SPD_TYPE);
+ if (byte == JED_DDR3SDRAM)
+ pDCTstat->DIMMValid |= 1 << i;
+ }
+ }
+ /* Check module type */
+ byte = mctRead_SPD(smbaddr, SPD_DIMMTYPE) & 0x7;
+ if (byte == JED_RDIMM || byte == JED_MiniRDIMM)
+ RegDIMMPresent |= 1 << i;
+ /* Check ECC capable */
+ byte = mctRead_SPD(smbaddr, SPD_BusWidth);
+ if (byte & JED_ECC) {
+ /* DIMM is ECC capable */
+ pDCTstat->DimmECCPresent |= 1 << i;
+ }
+ /* Check if x4 device */
+ devwidth = mctRead_SPD(smbaddr, SPD_Organization) & 0x7; /* 0:x4,1:x8,2:x16 */
+ if (devwidth == 0) {
+ /* DIMM is made with x4 or x16 drams */
+ pDCTstat->Dimmx4Present |= 1 << i;
+ } else if (devwidth == 1) {
+ pDCTstat->Dimmx8Present |= 1 << i;
+ } else if (devwidth == 2) {
+ pDCTstat->Dimmx16Present |= 1 << i;
+ }
+
+ byte = (mctRead_SPD(smbaddr, SPD_Organization) >> 3);
+ byte &= 7;
+ if (byte == 3) { /* 4ranks */
+ /* if any DIMMs are QR, we have to make two passes through DIMMs*/
+ if ( pDCTstat->DimmQRPresent == 0) {
+ MaxDimms <<= 1;
+ }
+ if (i < DimmSlots) {
+ pDCTstat->DimmQRPresent |= (1 << i) | (1 << (i+4));
+ } else {
+ pDCTstat->MAdimms[i & 1] --;
+ }
+ byte = 1; /* upper two ranks of QR DIMM will be counted on another DIMM number iteration*/
+ } else if (byte == 1) { /* 2ranks */
+ pDCTstat->DimmDRPresent |= 1 << i;
+ }
+ bytex = devwidth;
+ if (devwidth == 0)
+ bytex = 16;
+ else if (devwidth == 1)
+ bytex = 8;
+ else if (devwidth == 2)
+ bytex = 4;
+
+ byte++; /* al+1=rank# */
+ if (byte == 2)
+ bytex <<= 1; /*double Addr bus load value for dual rank DIMMs*/
+
+ j = i & (1<<0);
+ pDCTstat->DATAload[j] += byte; /*number of ranks on DATA bus*/
+ pDCTstat->MAload[j] += bytex; /*number of devices on CMD/ADDR bus*/
+ pDCTstat->MAdimms[j]++; /*number of DIMMs on A bus */
+
+ /* check address mirror support for unbuffered dimm */
+ /* check number of registers on a dimm for registered dimm */
+ byte = mctRead_SPD(smbaddr, SPD_AddressMirror);
+ if (RegDIMMPresent & (1 << i)) {
+ if ((byte & 3) > 1)
+ pDCTstat->MirrPresU_NumRegR |= 1 << i;
+ } else {
+ if ((byte & 1) == 1)
+ pDCTstat->MirrPresU_NumRegR |= 1 << i;
+ }
+ /* Get byte62: Reference Raw Card information. We dont need it now. */
+ /* byte = mctRead_SPD(smbaddr, 62); */
+ /* Get Control word values for RC3. We dont need it. */
+ byte = mctRead_SPD(smbaddr, 70);
+ pDCTstat->CtrlWrd3 |= (byte >> 4) << (i << 2); /* C3 = SPD byte 70 [7:4] */
+ /* Get Control word values for RC4, and RC5 */
+ byte = mctRead_SPD(smbaddr, 71);
+ pDCTstat->CtrlWrd4 |= (byte & 0xFF) << (i << 2); /* RC4 = SPD byte 71 [3:0] */
+ pDCTstat->CtrlWrd5 |= (byte >> 4) << (i << 2); /* RC5 = SPD byte 71 [7:4] */
+ }
+ }
+ }
+ printk(BIOS_DEBUG, "\t DIMMPresence: DIMMValid=%x\n", pDCTstat->DIMMValid);
+ printk(BIOS_DEBUG, "\t DIMMPresence: DIMMPresent=%x\n", pDCTstat->DIMMPresent);
+ printk(BIOS_DEBUG, "\t DIMMPresence: RegDIMMPresent=%x\n", RegDIMMPresent);
+ printk(BIOS_DEBUG, "\t DIMMPresence: DimmECCPresent=%x\n", pDCTstat->DimmECCPresent);
+ printk(BIOS_DEBUG, "\t DIMMPresence: DimmPARPresent=%x\n", pDCTstat->DimmPARPresent);
+ printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx4Present=%x\n", pDCTstat->Dimmx4Present);
+ printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx8Present=%x\n", pDCTstat->Dimmx8Present);
+ printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx16Present=%x\n", pDCTstat->Dimmx16Present);
+ printk(BIOS_DEBUG, "\t DIMMPresence: DimmPlPresent=%x\n", pDCTstat->DimmPlPresent);
+ printk(BIOS_DEBUG, "\t DIMMPresence: DimmDRPresent=%x\n", pDCTstat->DimmDRPresent);
+ printk(BIOS_DEBUG, "\t DIMMPresence: DimmQRPresent=%x\n", pDCTstat->DimmQRPresent);
+ printk(BIOS_DEBUG, "\t DIMMPresence: DATAload[0]=%x\n", pDCTstat->DATAload[0]);
+ printk(BIOS_DEBUG, "\t DIMMPresence: MAload[0]=%x\n", pDCTstat->MAload[0]);
+ printk(BIOS_DEBUG, "\t DIMMPresence: MAdimms[0]=%x\n", pDCTstat->MAdimms[0]);
+ printk(BIOS_DEBUG, "\t DIMMPresence: DATAload[1]=%x\n", pDCTstat->DATAload[1]);
+ printk(BIOS_DEBUG, "\t DIMMPresence: MAload[1]=%x\n", pDCTstat->MAload[1]);
+ printk(BIOS_DEBUG, "\t DIMMPresence: MAdimms[1]=%x\n", pDCTstat->MAdimms[1]);
+
+ if (pDCTstat->DIMMValid != 0) { /* If any DIMMs are present...*/
+ if (RegDIMMPresent != 0) {
+ if ((RegDIMMPresent ^ pDCTstat->DIMMValid) !=0) {
+ /* module type DIMM mismatch (reg'ed, unbuffered) */
+ pDCTstat->ErrStatus |= 1<<SB_DimmMismatchM;
+ pDCTstat->ErrCode = SC_StopError;
+ } else{
+ /* all DIMMs are registered */
+ pDCTstat->Status |= 1<<SB_Registered;
+ }
+ }
+ if (pDCTstat->DimmECCPresent != 0) {
+ if ((pDCTstat->DimmECCPresent ^ pDCTstat->DIMMValid )== 0) {
+ /* all DIMMs are ECC capable */
+ pDCTstat->Status |= 1<<SB_ECCDIMMs;
+ }
+ }
+ if (pDCTstat->DimmPARPresent != 0) {
+ if ((pDCTstat->DimmPARPresent ^ pDCTstat->DIMMValid) == 0) {
+ /*all DIMMs are Parity capable */
+ pDCTstat->Status |= 1<<SB_PARDIMMs;
+ }
+ }
+ } else {
+ /* no DIMMs present or no DIMMs that qualified. */
+ pDCTstat->ErrStatus |= 1<<SB_NoDimms;
+ pDCTstat->ErrCode = SC_StopError;
+ }
+
+ printk(BIOS_DEBUG, "\t DIMMPresence: Status %x\n", pDCTstat->Status);
+ printk(BIOS_DEBUG, "\t DIMMPresence: ErrStatus %x\n", pDCTstat->ErrStatus);
+ printk(BIOS_DEBUG, "\t DIMMPresence: ErrCode %x\n", pDCTstat->ErrCode);
+ printk(BIOS_DEBUG, "\t DIMMPresence: Done\n\n");
+
+ mctHookAfterDIMMpre();
+
+ return pDCTstat->ErrCode;
+}
+
+static u8 Get_DIMMAddress_D(struct DCTStatStruc *pDCTstat, u8 i)
+{
+ u8 *p;
+
+ p = pDCTstat->DIMMAddr;
+ /* mct_BeforeGetDIMMAddress(); */
+ return p[i];
+}
+
+static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 val;
+ u8 err_code;
+
+ /* Config. DCT0 for Ganged or unganged mode */
+ DCTInit_D(pMCTstat, pDCTstat, 0);
+ if (pDCTstat->ErrCode == SC_FatalErr) {
+ /* Do nothing goto exitDCTInit; any fatal errors? */
+ } else {
+ /* Configure DCT1 if unganged and enabled*/
+ if (!pDCTstat->GangedMode) {
+ if ( pDCTstat->DIMMValidDCT[1] > 0) {
+ err_code = pDCTstat->ErrCode; /* save DCT0 errors */
+ pDCTstat->ErrCode = 0;
+ DCTInit_D(pMCTstat, pDCTstat, 1);
+ if (pDCTstat->ErrCode == 2) /* DCT1 is not Running */
+ pDCTstat->ErrCode = err_code; /* Using DCT0 Error code to update pDCTstat.ErrCode */
+ } else {
+ val = 1 << DisDramInterface;
+ Set_NB32(pDCTstat->dev_dct, 0x100 + 0x94, val);
+ }
+ }
+ }
+/* exitDCTInit: */
+}
+
+static void mct_DramInit(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat);
+ mct_DramInit_Sw_D(pMCTstat, pDCTstat, dct);
+ /* mct_DramInit_Hw_D(pMCTstat, pDCTstat, dct); */
+}
+
+static u8 mct_setMode(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u8 byte;
+ u8 bytex;
+ u32 val;
+ u32 reg;
+
+ byte = bytex = pDCTstat->DIMMValid;
+ bytex &= 0x55; /* CHA DIMM pop */
+ pDCTstat->DIMMValidDCT[0] = bytex;
+
+ byte &= 0xAA; /* CHB DIMM popa */
+ byte >>= 1;
+ pDCTstat->DIMMValidDCT[1] = byte;
+
+ if (byte != bytex) {
+ pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO);
+ } else {
+ byte = mctGet_NVbits(NV_Unganged);
+ if (byte)
+ pDCTstat->ErrStatus |= (1 << SB_DimmMismatchO); /* Set temp. to avoid setting of ganged mode */
+
+ if (!(pDCTstat->ErrStatus & (1 << SB_DimmMismatchO))) {
+ pDCTstat->GangedMode = 1;
+ /* valid 128-bit mode population. */
+ pDCTstat->Status |= 1 << SB_128bitmode;
+ reg = 0x110;
+ val = Get_NB32(pDCTstat->dev_dct, reg);
+ val |= 1 << DctGangEn;
+ Set_NB32(pDCTstat->dev_dct, reg, val);
+ }
+ if (byte) /* NV_Unganged */
+ pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO); /* Clear so that there is no DIMM missmatch error */
+ }
+ return pDCTstat->ErrCode;
+}
+
+u32 Get_NB32(u32 dev, u32 reg)
+{
+ return pci_read_config32(dev, reg);
+}
+
+void Set_NB32(u32 dev, u32 reg, u32 val)
+{
+ pci_write_config32(dev, reg, val);
+}
+
+
+u32 Get_NB32_index(u32 dev, u32 index_reg, u32 index)
+{
+ u32 dword;
+
+ Set_NB32(dev, index_reg, index);
+ dword = Get_NB32(dev, index_reg+0x4);
+
+ return dword;
+}
+
+void Set_NB32_index(u32 dev, u32 index_reg, u32 index, u32 data)
+{
+ Set_NB32(dev, index_reg, index);
+ Set_NB32(dev, index_reg + 0x4, data);
+}
+
+u32 Get_NB32_index_wait(u32 dev, u32 index_reg, u32 index)
+{
+
+ u32 dword;
+
+
+ index &= ~(1 << DctAccessWrite);
+ Set_NB32(dev, index_reg, index);
+ do {
+ dword = Get_NB32(dev, index_reg);
+ } while (!(dword & (1 << DctAccessDone)));
+ dword = Get_NB32(dev, index_reg + 0x4);
+
+ return dword;
+}
+
+void Set_NB32_index_wait(u32 dev, u32 index_reg, u32 index, u32 data)
+{
+ u32 dword;
+
+
+ Set_NB32(dev, index_reg + 0x4, data);
+ index |= (1 << DctAccessWrite);
+ Set_NB32(dev, index_reg, index);
+ do {
+ dword = Get_NB32(dev, index_reg);
+ } while (!(dword & (1 << DctAccessDone)));
+
+}
+
+static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ /* Get platform specific config/timing values from the interface layer
+ * and program them into DCT.
+ */
+
+ u32 dev = pDCTstat->dev_dct;
+ u32 index_reg;
+ u8 i, i_start, i_end;
+
+ if (pDCTstat->GangedMode) {
+ SyncSetting(pDCTstat);
+ /* mct_SetupSync_D */
+ i_start = 0;
+ i_end = 2;
+ } else {
+ i_start = dct;
+ i_end = dct + 1;
+ }
+ for (i=i_start; i<i_end; i++) {
+ index_reg = 0x98 + (i * 0x100);
+ Set_NB32_index_wait(dev, index_reg, 0x00, pDCTstat->CH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */
+ Set_NB32_index_wait(dev, index_reg, 0x04, pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */
+ }
+
+ return pDCTstat->ErrCode;
+
+}
+
+static void mct_SyncDCTsReady(struct DCTStatStruc *pDCTstat)
+{
+ u32 dev;
+ u32 val;
+
+ if (pDCTstat->NodePresent) {
+ dev = pDCTstat->dev_dct;
+
+ if ((pDCTstat->DIMMValidDCT[0] ) || (pDCTstat->DIMMValidDCT[1])) { /* This Node has dram */
+ do {
+ val = Get_NB32(dev, 0x110);
+ } while (!(val & (1 << DramEnabled)));
+ }
+ } /* Node is present */
+}
+
+static void mct_AfterGetCLT(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ if (!pDCTstat->GangedMode) {
+ if (dct == 0 ) {
+ pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
+ if (pDCTstat->DIMMValidDCT[dct] == 0)
+ pDCTstat->ErrCode = SC_StopError;
+ } else {
+ pDCTstat->CSPresent = 0;
+ pDCTstat->CSTestFail = 0;
+ pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
+ if (pDCTstat->DIMMValidDCT[dct] == 0)
+ pDCTstat->ErrCode = SC_StopError;
+ }
+ }
+}
+
+static u8 mct_SPDCalcWidth(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u8 ret;
+ u32 val;
+
+ if ( dct == 0) {
+ SPDCalcWidth_D(pMCTstat, pDCTstat);
+ ret = mct_setMode(pMCTstat, pDCTstat);
+ } else {
+ ret = pDCTstat->ErrCode;
+ }
+
+ if (pDCTstat->DIMMValidDCT[0] == 0) {
+ val = Get_NB32(pDCTstat->dev_dct, 0x94);
+ val |= 1 << DisDramInterface;
+ Set_NB32(pDCTstat->dev_dct, 0x94, val);
+ }
+ if (pDCTstat->DIMMValidDCT[1] == 0) {
+ val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+ val |= 1 << DisDramInterface;
+ Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
+ }
+
+ printk(BIOS_DEBUG, "SPDCalcWidth: Status %x\n", pDCTstat->Status);
+ printk(BIOS_DEBUG, "SPDCalcWidth: ErrStatus %x\n", pDCTstat->ErrStatus);
+ printk(BIOS_DEBUG, "SPDCalcWidth: ErrCode %x\n", pDCTstat->ErrCode);
+ printk(BIOS_DEBUG, "SPDCalcWidth: Done\n");
+ /* Disable dram interface before DRAM init */
+
+ return ret;
+}
+
+static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 val;
+ u32 dword;
+ u32 dev;
+ u32 reg;
+ u8 _MemHoleRemap;
+ u32 DramHoleBase;
+
+ _MemHoleRemap = mctGet_NVbits(NV_MemHole);
+ DramHoleBase = mctGet_NVbits(NV_BottomIO);
+ DramHoleBase <<= 8;
+ /* Increase hole size so;[31:24]to[31:16]
+ * it has granularity of 128MB shl eax,8
+ * Set 'effective' bottom IOmov DramHoleBase,eax
+ */
+ pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8;
+
+ /* In unganged mode, we must add DCT0 and DCT1 to DCTSysLimit */
+ if (!pDCTstat->GangedMode) {
+ dev = pDCTstat->dev_dct;
+ pDCTstat->NodeSysLimit += pDCTstat->DCTSysLimit;
+ /* if DCT0 and DCT1 both exist, set DctSelBaseAddr[47:27] to the top of DCT0 */
+ if (dct == 0) {
+ if (pDCTstat->DIMMValidDCT[1] > 0) {
+ dword = pDCTstat->DCTSysLimit + 1;
+ dword += pDCTstat->NodeSysBase;
+ dword >>= 8; /* scale [39:8] to [47:27],and to F2x110[31:11] */
+ if ((dword >= DramHoleBase) && _MemHoleRemap) {
+ pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8;
+ val = pMCTstat->HoleBase;
+ val >>= 16;
+ val = (((~val) & 0xFF) + 1);
+ val <<= 8;
+ dword += val;
+ }
+ reg = 0x110;
+ val = Get_NB32(dev, reg);
+ val &= 0x7F;
+ val |= dword;
+ val |= 3; /* Set F2x110[DctSelHiRngEn], F2x110[DctSelHi] */
+ Set_NB32(dev, reg, val);
+
+ reg = 0x114;
+ val = dword;
+ Set_NB32(dev, reg, val);
+ }
+ } else {
+ /* Program the DctSelBaseAddr value to 0
+ if DCT 0 is disabled */
+ if (pDCTstat->DIMMValidDCT[0] == 0) {
+ dword = pDCTstat->NodeSysBase;
+ dword >>= 8;
+ if ((dword >= DramHoleBase) && _MemHoleRemap) {
+ pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8;
+ val = pMCTstat->HoleBase;
+ val >>= 8;
+ val &= ~(0xFFFF);
+ val |= (((~val) & 0xFFFF) + 1);
+ dword += val;
+ }
+ reg = 0x114;
+ val = dword;
+ Set_NB32(dev, reg, val);
+
+ reg = 0x110;
+ val |= 3; /* Set F2x110[DctSelHiRngEn], F2x110[DctSelHi] */
+ Set_NB32(dev, reg, val);
+ }
+ }
+ } else {
+ pDCTstat->NodeSysLimit += pDCTstat->DCTSysLimit;
+ }
+ printk(BIOS_DEBUG, "AfterStitch pDCTstat->NodeSysBase = %x\n", pDCTstat->NodeSysBase);
+ printk(BIOS_DEBUG, "mct_AfterStitchMemory: pDCTstat->NodeSysLimit = %x\n", pDCTstat->NodeSysLimit);
+}
+
+static u8 mct_DIMMPresence(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u8 ret;
+
+ if ( dct == 0)
+ ret = DIMMPresence_D(pMCTstat, pDCTstat);
+ else
+ ret = pDCTstat->ErrCode;
+
+ return ret;
+}
+
+/* mct_BeforeGetDIMMAddress inline in C */
+
+static void mct_OtherTiming(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ u8 Node;
+
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+ if (pDCTstat->NodePresent) {
+ if (pDCTstat->DIMMValidDCT[0]) {
+ pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[0];
+ Set_OtherTiming(pMCTstat, pDCTstat, 0);
+ }
+ if (pDCTstat->DIMMValidDCT[1] && !pDCTstat->GangedMode ) {
+ pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[1];
+ Set_OtherTiming(pMCTstat, pDCTstat, 1);
+ }
+ } /* Node is present*/
+ } /* while Node */
+}
+
+static void Set_OtherTiming(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 reg;
+ u32 reg_off = 0x100 * dct;
+ u32 val;
+ u32 dword;
+ u32 dev = pDCTstat->dev_dct;
+
+ Get_DqsRcvEnGross_Diff(pDCTstat, dev, 0x98 + reg_off);
+ Get_WrDatGross_Diff(pDCTstat, dct, dev, 0x98 + reg_off);
+ Get_Trdrd(pMCTstat, pDCTstat, dct);
+ Get_Twrwr(pMCTstat, pDCTstat, dct);
+ Get_Twrrd(pMCTstat, pDCTstat, dct);
+ Get_TrwtTO(pMCTstat, pDCTstat, dct);
+ Get_TrwtWB(pMCTstat, pDCTstat);
+
+ reg = 0x8C + reg_off; /* Dram Timing Hi */
+ val = Get_NB32(dev, reg);
+ val &= 0xffff0300;
+ dword = pDCTstat->TrwtTO;
+ val |= dword << 4;
+ dword = pDCTstat->Twrrd & 3;
+ val |= dword << 10;
+ dword = pDCTstat->Twrwr & 3;
+ val |= dword << 12;
+ dword = pDCTstat->Trdrd & 3;
+ val |= dword << 14;
+ dword = pDCTstat->TrwtWB;
+ val |= dword;
+ Set_NB32(dev, reg, val);
+
+ reg = 0x78 + reg_off;
+ val = Get_NB32(dev, reg);
+ val &= 0xFFFFC0FF;
+ dword = pDCTstat->Twrrd >> 2;
+ val |= dword << 8;
+ dword = pDCTstat->Twrwr >> 2;
+ val |= dword << 10;
+ dword = pDCTstat->Trdrd >> 2;
+ val |= dword << 12;
+ Set_NB32(dev, reg, val);
+}
+
+static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ int8_t Trdrd;
+
+ Trdrd = ((int8_t)(pDCTstat->DqsRcvEnGrossMax - pDCTstat->DqsRcvEnGrossMin) >> 1) + 1;
+ if (Trdrd > 8)
+ Trdrd = 8;
+ pDCTstat->Trdrd = Trdrd;
+}
+
+static void Get_Twrwr(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ int8_t Twrwr = 0;
+
+ Twrwr = ((int8_t)(pDCTstat->WrDatGrossMax - pDCTstat->WrDatGrossMin) >> 1) + 2;
+
+ if (Twrwr < 2)
+ Twrwr = 2;
+ else if (Twrwr > 9)
+ Twrwr = 9;
+
+ pDCTstat->Twrwr = Twrwr;
+}
+
+static void Get_Twrrd(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u8 LDplus1;
+ int8_t Twrrd;
+
+ LDplus1 = Get_Latency_Diff(pMCTstat, pDCTstat, dct);
+
+ Twrrd = ((int8_t)(pDCTstat->WrDatGrossMax - pDCTstat->DqsRcvEnGrossMin) >> 1) + 4 - LDplus1;
+
+ if (Twrrd < 2)
+ Twrrd = 2;
+ else if (Twrrd > 10)
+ Twrrd = 10;
+ pDCTstat->Twrrd = Twrrd;
+}
+
+static void Get_TrwtTO(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u8 LDplus1;
+ int8_t TrwtTO;
+
+ LDplus1 = Get_Latency_Diff(pMCTstat, pDCTstat, dct);
+
+ TrwtTO = ((int8_t)(pDCTstat->DqsRcvEnGrossMax - pDCTstat->WrDatGrossMin) >> 1) + LDplus1;
+
+ pDCTstat->TrwtTO = TrwtTO;
+}
+
+static void Get_TrwtWB(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ /* TrwtWB ensures read-to-write data-bus turnaround.
+ This value should be one more than the programmed TrwtTO.*/
+ pDCTstat->TrwtWB = pDCTstat->TrwtTO;
+}
+
+static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+ u32 val1, val2;
+
+ val1 = Get_NB32(dev, reg_off + 0x88) & 0xF;
+ val2 = (Get_NB32(dev, reg_off + 0x84) >> 20) & 7;
+
+ return val1 - val2;
+}
+
+static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
+ u32 dev, u32 index_reg)
+{
+ u8 Smallest, Largest;
+ u32 val;
+ u8 byte, bytex;
+
+ /* The largest DqsRcvEnGrossDelay of any DIMM minus the
+ DqsRcvEnGrossDelay of any other DIMM is equal to the Critical
+ Gross Delay Difference (CGDD) */
+ /* DqsRcvEn byte 1,0 */
+ val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x10);
+ Largest = val & 0xFF;
+ Smallest = (val >> 8) & 0xFF;
+
+ /* DqsRcvEn byte 3,2 */
+ val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x11);
+ byte = val & 0xFF;
+ bytex = (val >> 8) & 0xFF;
+ if (bytex < Smallest)
+ Smallest = bytex;
+ if (byte > Largest)
+ Largest = byte;
+
+ /* DqsRcvEn byte 5,4 */
+ val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x20);
+ byte = val & 0xFF;
+ bytex = (val >> 8) & 0xFF;
+ if (bytex < Smallest)
+ Smallest = bytex;
+ if (byte > Largest)
+ Largest = byte;
+
+ /* DqsRcvEn byte 7,6 */
+ val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x21);
+ byte = val & 0xFF;
+ bytex = (val >> 8) & 0xFF;
+ if (bytex < Smallest)
+ Smallest = bytex;
+ if (byte > Largest)
+ Largest = byte;
+
+ if (pDCTstat->DimmECCPresent> 0) {
+ /*DqsRcvEn Ecc */
+ val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x12);
+ byte = val & 0xFF;
+ bytex = (val >> 8) & 0xFF;
+ if (bytex < Smallest)
+ Smallest = bytex;
+ if (byte > Largest)
+ Largest = byte;
+ }
+
+ pDCTstat->DqsRcvEnGrossMax = Largest;
+ pDCTstat->DqsRcvEnGrossMin = Smallest;
+}
+
+static void Get_WrDatGross_Diff(struct DCTStatStruc *pDCTstat,
+ u8 dct, u32 dev, u32 index_reg)
+{
+ u8 Smallest, Largest;
+ u32 val;
+ u8 byte, bytex;
+
+ /* The largest WrDatGrossDlyByte of any DIMM minus the
+ WrDatGrossDlyByte of any other DIMM is equal to CGDD */
+ if (pDCTstat->DIMMValid & (1 << 0)) {
+ val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x01); /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM0 */
+ Largest = val & 0xFF;
+ Smallest = (val >> 8) & 0xFF;
+ }
+ if (pDCTstat->DIMMValid & (1 << 2)) {
+ val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x101); /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM1 */
+ byte = val & 0xFF;
+ bytex = (val >> 8) & 0xFF;
+ if (bytex < Smallest)
+ Smallest = bytex;
+ if (byte > Largest)
+ Largest = byte;
+ }
+
+ /* If Cx, 2 more dimm need to be checked to find out the largest and smallest */
+ if (pDCTstat->LogicalCPUID & AMD_DR_Cx) {
+ if (pDCTstat->DIMMValid & (1 << 4)) {
+ val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x201); /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM2 */
+ byte = val & 0xFF;
+ bytex = (val >> 8) & 0xFF;
+ if (bytex < Smallest)
+ Smallest = bytex;
+ if (byte > Largest)
+ Largest = byte;
+ }
+ if (pDCTstat->DIMMValid & (1 << 6)) {
+ val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x301); /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM2 */
+ byte = val & 0xFF;
+ bytex = (val >> 8) & 0xFF;
+ if (bytex < Smallest)
+ Smallest = bytex;
+ if (byte > Largest)
+ Largest = byte;
+ }
+ }
+
+ pDCTstat->WrDatGrossMax = Largest;
+ pDCTstat->WrDatGrossMin = Smallest;
+}
+
+static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
+ u32 dev, u32 index_reg,
+ u32 index)
+{
+ u8 Smallest, Largest;
+ u8 i;
+ u8 byte;
+ u32 val;
+ u16 word;
+ u8 ecc_reg = 0;
+
+ Smallest = 7;
+ Largest = 0;
+
+ if (index == 0x12)
+ ecc_reg = 1;
+
+ for (i=0; i < 8; i+=2) {
+ if ( pDCTstat->DIMMValid & (1 << i)) {
+ val = Get_NB32_index_wait(dev, index_reg, index);
+ val &= 0x00E000E0;
+ byte = (val >> 5) & 0xFF;
+ if (byte < Smallest)
+ Smallest = byte;
+ if (byte > Largest)
+ Largest = byte;
+ if (!(ecc_reg)) {
+ byte = (val >> (16 + 5)) & 0xFF;
+ if (byte < Smallest)
+ Smallest = byte;
+ if (byte > Largest)
+ Largest = byte;
+ }
+ }
+ index += 3;
+ } /* while ++i */
+
+ word = Smallest;
+ word <<= 8;
+ word |= Largest;
+
+ return word;
+}
+
+static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat,
+ u8 dct, u32 dev, u32 index_reg,
+ u32 index)
+{
+ u8 Smallest, Largest;
+ u8 i, j;
+ u32 val;
+ u8 byte;
+ u16 word;
+
+ Smallest = 3;
+ Largest = 0;
+ for (i=0; i < 2; i++) {
+ val = Get_NB32_index_wait(dev, index_reg, index);
+ val &= 0x60606060;
+ val >>= 5;
+ for (j=0; j < 4; j++) {
+ byte = val & 0xFF;
+ if (byte < Smallest)
+ Smallest = byte;
+ if (byte > Largest)
+ Largest = byte;
+ val >>= 8;
+ } /* while ++j */
+ index++;
+ } /*while ++i*/
+
+ if (pDCTstat->DimmECCPresent > 0) {
+ index++;
+ val = Get_NB32_index_wait(dev, index_reg, index);
+ val &= 0x00000060;
+ val >>= 5;
+ byte = val & 0xFF;
+ if (byte < Smallest)
+ Smallest = byte;
+ if (byte > Largest)
+ Largest = byte;
+ }
+
+ word = Smallest;
+ word <<= 8;
+ word |= Largest;
+
+ return word;
+}
+
+static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ mct_ClrClToNB_D(pMCTstat, pDCTstat);
+ mct_ClrWbEnhWsbDis_D(pMCTstat, pDCTstat);
+}
+
+static void mct_InitialMCT_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
+{
+ mct_SetClToNB_D(pMCTstat, pDCTstat);
+ mct_SetWbEnhWsbDis_D(pMCTstat, pDCTstat);
+}
+
+static u32 mct_NodePresent_D(void)
+{
+ u32 val;
+ val = 0x12001022;
+ return val;
+}
+
+static void mct_init(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 lo, hi;
+ u32 addr;
+
+ pDCTstat->GangedMode = 0;
+ pDCTstat->DRPresent = 1;
+
+ /* enable extend PCI configuration access */
+ addr = 0xC001001F;
+ _RDMSR(addr, &lo, &hi);
+ if (hi & (1 << (46-32))) {
+ pDCTstat->Status |= 1 << SB_ExtConfig;
+ } else {
+ hi |= 1 << (46-32);
+ _WRMSR(addr, lo, hi);
+ }
+}
+
+static void clear_legacy_Mode(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 reg;
+ u32 val;
+ u32 dev = pDCTstat->dev_dct;
+
+ /* Clear Legacy BIOS Mode bit */
+ reg = 0x94;
+ val = Get_NB32(dev, reg);
+ val &= ~(1<<LegacyBiosMode);
+ Set_NB32(dev, reg, val);
+
+ reg = 0x94 + 0x100;
+ val = Get_NB32(dev, reg);
+ val &= ~(1<<LegacyBiosMode);
+ Set_NB32(dev, reg, val);
+}
+
+static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ u8 Node;
+ u32 Drambase, Dramlimit;
+ u32 val;
+ u32 reg;
+ u32 dev;
+ u32 devx;
+ u32 dword;
+ struct DCTStatStruc *pDCTstat;
+
+ pDCTstat = pDCTstatA + 0;
+ dev = pDCTstat->dev_map;
+
+ /* Copy dram map from F1x40/44,F1x48/4c,
+ to F1x120/124(Node0),F1x120/124(Node1),...*/
+ for (Node=0; Node < MAX_NODES_SUPPORTED; Node++) {
+ pDCTstat = pDCTstatA + Node;
+ devx = pDCTstat->dev_map;
+
+ /* get base/limit from Node0 */
+ reg = 0x40 + (Node << 3); /* Node0/Dram Base 0 */
+ val = Get_NB32(dev, reg);
+ Drambase = val >> ( 16 + 3);
+
+ reg = 0x44 + (Node << 3); /* Node0/Dram Base 0 */
+ val = Get_NB32(dev, reg);
+ Dramlimit = val >> (16 + 3);
+
+ /* set base/limit to F1x120/124 per Node */
+ if (pDCTstat->NodePresent) {
+ reg = 0x120; /* F1x120,DramBase[47:27] */
+ val = Get_NB32(devx, reg);
+ val &= 0xFFE00000;
+ val |= Drambase;
+ Set_NB32(devx, reg, val);
+
+ reg = 0x124;
+ val = Get_NB32(devx, reg);
+ val &= 0xFFE00000;
+ val |= Dramlimit;
+ Set_NB32(devx, reg, val);
+
+ if ( pMCTstat->GStatus & ( 1 << GSB_HWHole)) {
+ reg = 0xF0;
+ val = Get_NB32(devx, reg);
+ val |= (1 << DramMemHoistValid);
+ val &= ~(0xFF << 24);
+ dword = (pMCTstat->HoleBase >> (24 - 8)) & 0xFF;
+ dword <<= 24;
+ val |= dword;
+ Set_NB32(devx, reg, val);
+ }
+
+ }
+ }
+}
+
+static void SetCSTriState(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 val;
+ u32 dev = pDCTstat->dev_dct;
+ u32 index_reg = 0x98 + 0x100 * dct;
+ u32 index;
+ u16 word;
+
+ /* Tri-state unused chipselects when motherboard
+ termination is available */
+
+ /* FIXME: skip for Ax */
+
+ word = pDCTstat->CSPresent;
+ if (pDCTstat->Status & (1 << SB_Registered)) {
+ word |= (word & 0x55) << 1;
+ }
+ word = (~word) & 0xFF;
+ index = 0x0c;
+ val = Get_NB32_index_wait(dev, index_reg, index);
+ val |= word;
+ Set_NB32_index_wait(dev, index_reg, index, val);
+}
+
+static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 val;
+ u32 dev;
+ u32 index_reg = 0x98 + 0x100 * dct;
+ u32 index;
+ u16 word;
+
+ /* Tri-state unused CKEs when motherboard termination is available */
+
+ /* FIXME: skip for Ax */
+
+ dev = pDCTstat->dev_dct;
+ word = pDCTstat->CSPresent;
+
+ index = 0x0c;
+ val = Get_NB32_index_wait(dev, index_reg, index);
+ if ((word & 0x55) == 0)
+ val |= 1 << 12;
+
+ if ((word & 0xAA) == 0)
+ val |= 1 << 13;
+
+ Set_NB32_index_wait(dev, index_reg, index, val);
+}
+
+static void SetODTTriState(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 val;
+ u32 dev;
+ u32 index_reg = 0x98 + 0x100 * dct;
+ u8 cs;
+ u32 index;
+ u8 odt;
+ u8 max_dimms;
+
+ /* FIXME: skip for Ax */
+
+ dev = pDCTstat->dev_dct;
+
+ /* Tri-state unused ODTs when motherboard termination is available */
+ max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
+ odt = 0x0F; /* ODT tri-state setting */
+
+ if (pDCTstat->Status & (1 <<SB_Registered)) {
+ for (cs = 0; cs < 8; cs += 2) {
+ if (pDCTstat->CSPresent & (1 << cs)) {
+ odt &= ~(1 << (cs / 2));
+ if (mctGet_NVbits(NV_4RANKType) != 0) { /* quad-rank capable platform */
+ if (pDCTstat->CSPresent & (1 << (cs + 1)))
+ odt &= ~(4 << (cs / 2));
+ }
+ }
+ }
+ } else { /* AM3 package */
+ val = ~(pDCTstat->CSPresent);
+ odt = val & 9; /* swap bits 1 and 2 */
+ if (val & (1 << 1))
+ odt |= 1 << 2;
+ if (val & (1 << 2))
+ odt |= 1 << 1;
+ }
+
+ index = 0x0C;
+ val = Get_NB32_index_wait(dev, index_reg, index);
+ val |= ((odt & 0xFF) << 8); /* set bits 11:8 ODTTriState[3:0] */
+ Set_NB32_index_wait(dev, index_reg, index, val);
+
+}
+
+static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u8 i;
+ u32 index_reg = 0x98 + 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+ u32 val;
+ u32 valx = 0;
+ u32 dword;
+ const u8 *p;
+
+ val = Get_NB32_index_wait(dev, index_reg, 0x00);
+ dword = 0;
+ for (i=0; i < 6; i++) {
+ switch (i) {
+ case 0:
+ case 4:
+ p = Table_Comp_Rise_Slew_15x;
+ valx = p[(val >> 16) & 3];
+ break;
+ case 1:
+ case 5:
+ p = Table_Comp_Fall_Slew_15x;
+ valx = p[(val >> 16) & 3];
+ break;
+ case 2:
+ p = Table_Comp_Rise_Slew_20x;
+ valx = p[(val >> 8) & 3];
+ break;
+ case 3:
+ p = Table_Comp_Fall_Slew_20x;
+ valx = p[(val >> 8) & 3];
+ break;
+
+ }
+ dword |= valx << (5 * i);
+ }
+
+ /* Override/Exception */
+ if (!pDCTstat->GangedMode) {
+ i = 0; /* use i for the dct setting required */
+ if (pDCTstat->MAdimms[0] < 4)
+ i = 1;
+ if (((pDCTstat->Speed == 2) || (pDCTstat->Speed == 3)) && (pDCTstat->MAdimms[i] == 4))
+ dword &= 0xF18FFF18;
+ index_reg = 0x98; /* force dct = 0 */
+ }
+
+ Set_NB32_index_wait(dev, index_reg, 0x0a, dword);
+}
+
+static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 reg;
+ u32 val;
+ u32 dev = pDCTstat->dev_dct;
+
+ /* GhEnhancement #18429 modified by askar: For low NB CLK :
+ * Memclk ratio, the DCT may need to arbitrate early to avoid
+ * unnecessary bubbles.
+ * bit 19 of F2x[1,0]78 Dram Control Register, set this bit only when
+ * NB CLK : Memclk ratio is between 3:1 (inclusive) to 4:5 (inclusive)
+ */
+ reg = 0x78;
+ val = Get_NB32(dev, reg);
+
+ if (pDCTstat->LogicalCPUID & (AMD_DR_Bx | AMD_DR_Cx))
+ val |= (1 << EarlyArbEn);
+ else if (CheckNBCOFEarlyArbEn(pMCTstat, pDCTstat))
+ val |= (1 << EarlyArbEn);
+
+ Set_NB32(dev, reg, val);
+}
+
+static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 reg;
+ u32 val;
+ u32 tmp;
+ u32 rem;
+ u32 dev = pDCTstat->dev_dct;
+ u32 hi, lo;
+ u8 NbDid = 0;
+
+ /* Check if NB COF >= 4*Memclk, if it is not, return a fatal error
+ */
+
+ /* 3*(Fn2xD4[NBFid]+4)/(2^NbDid)/(3+Fn2x94[MemClkFreq]) */
+ _RDMSR(0xC0010071, &lo, &hi);
+ if (lo & (1 << 22))
+ NbDid |= 1;
+
+ reg = 0x94;
+ val = Get_NB32(dev, reg);
+ if (!(val & (1 << MemClkFreqVal)))
+ val = Get_NB32(dev, reg + 0x100); /* get the DCT1 value */
+
+ val &= 0x07;
+ val += 3;
+ if (NbDid)
+ val <<= 1;
+ tmp = val;
+
+ dev = pDCTstat->dev_nbmisc;
+ reg = 0xD4;
+ val = Get_NB32(dev, reg);
+ val &= 0x1F;
+ val += 3;
+ val *= 3;
+ val = val / tmp;
+ rem = val % tmp;
+ tmp >>= 1;
+
+ /* Yes this could be nicer but this was how the asm was.... */
+ if (val < 3) { /* NClk:MemClk < 3:1 */
+ return 0;
+ } else if (val > 4) { /* NClk:MemClk >= 5:1 */
+ return 0;
+ } else if ((val == 4) && (rem > tmp)) { /* NClk:MemClk > 4.5:1 */
+ return 0;
+ } else {
+ return 1; /* 3:1 <= NClk:MemClk <= 4.5:1*/
+ }
+}
+
+static void mct_ResetDataStruct_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ u8 Node;
+ u32 i;
+ struct DCTStatStruc *pDCTstat;
+ u32 start, stop;
+ u8 *p;
+ u16 host_serv1, host_serv2;
+
+ /* Initialize Data structures by clearing all entries to 0 */
+ p = (u8 *) pMCTstat;
+ for (i = 0; i < sizeof(struct MCTStatStruc); i++) {
+ p[i] = 0;
+ }
+
+ for (Node = 0; Node < 8; Node++) {
+ pDCTstat = pDCTstatA + Node;
+ host_serv1 = pDCTstat->HostBiosSrvc1;
+ host_serv2 = pDCTstat->HostBiosSrvc2;
+
+ p = (u8 *) pDCTstat;
+ start = 0;
+ stop = ((u32) &((struct DCTStatStruc *)0)->CH_MaxRdLat[2]);
+ for (i = start; i < stop ; i++) {
+ p[i] = 0;
+ }
+
+ start = ((u32) &((struct DCTStatStruc *)0)->CH_D_BC_RCVRDLY[2][4]);
+ stop = sizeof(struct DCTStatStruc);
+ for (i = start; i < stop; i++) {
+ p[i] = 0;
+ }
+ pDCTstat->HostBiosSrvc1 = host_serv1;
+ pDCTstat->HostBiosSrvc2 = host_serv2;
+ }
+}
+
+static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u8 i;
+ u32 reg_off, dword;
+ u32 dev = pDCTstat->dev_dct;
+
+ if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
+ if ((pDCTstat->Speed == 3))
+ dword = 0x00000800;
+ else
+ dword = 0x00000000;
+ for (i=0; i < 2; i++) {
+ reg_off = 0x100 * i;
+ Set_NB32(dev, 0x98 + reg_off, 0x0D000030);
+ Set_NB32(dev, 0x9C + reg_off, dword);
+ Set_NB32(dev, 0x98 + reg_off, 0x4D040F30);
+ }
+ }
+}
+
+static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u32 DramConfigLo, u8 dct)
+{
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+
+ /* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */
+ if (pDCTstat->LogicalCPUID & (AMD_DA_C2 | AMD_RB_C3)) {
+ Set_NB32(dev, 0x9C + reg_off, 0x1c);
+ Set_NB32(dev, 0x98 + reg_off, 0x4D0FE006);
+ Set_NB32(dev, 0x9C + reg_off, 0x13d);
+ Set_NB32(dev, 0x98 + reg_off, 0x4D0FE007);
+ }
+
+ return DramConfigLo | /* DisDllShutdownSR */ 1 << 27;
+}
+
+void mct_SetClToNB_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 lo, hi;
+ u32 msr;
+
+ /* FIXME: Maybe check the CPUID? - not for now. */
+ /* pDCTstat->LogicalCPUID; */
+
+ msr = BU_CFG2;
+ _RDMSR(msr, &lo, &hi);
+ lo |= 1 << ClLinesToNbDis;
+ _WRMSR(msr, lo, hi);
+}
+
+void mct_ClrClToNB_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+
+ u32 lo, hi;
+ u32 msr;
+
+ /* FIXME: Maybe check the CPUID? - not for now. */
+ /* pDCTstat->LogicalCPUID; */
+
+ msr = BU_CFG2;
+ _RDMSR(msr, &lo, &hi);
+ if (!pDCTstat->ClToNB_flag)
+ lo &= ~(1<<ClLinesToNbDis);
+ _WRMSR(msr, lo, hi);
+
+}
+
+void mct_SetWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 lo, hi;
+ u32 msr;
+
+ /* FIXME: Maybe check the CPUID? - not for now. */
+ /* pDCTstat->LogicalCPUID; */
+
+ msr = BU_CFG;
+ _RDMSR(msr, &lo, &hi);
+ hi |= (1 << WbEnhWsbDis_D);
+ _WRMSR(msr, lo, hi);
+}
+
+void mct_ClrWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 lo, hi;
+ u32 msr;
+
+ /* FIXME: Maybe check the CPUID? - not for now. */
+ /* pDCTstat->LogicalCPUID; */
+
+ msr = BU_CFG;
+ _RDMSR(msr, &lo, &hi);
+ hi &= ~(1 << WbEnhWsbDis_D);
+ _WRMSR(msr, lo, hi);
+}
+
+static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dimm)
+{
+ u8 DimmsInstalled = dimm;
+ u32 DramTermDyn = 0;
+ u8 Speed = pDCTstat->Speed;
+
+ if (mctGet_NVbits(NV_MAX_DIMMS) == 4) {
+ if (pDCTstat->CSPresent & 0xF0) {
+ if (DimmsInstalled == 1)
+ if (Speed == 7)
+ DramTermDyn |= 1 << 10;
+ else
+ DramTermDyn |= 1 << 11;
+ else
+ if (Speed == 4)
+ DramTermDyn |= 1 << 11;
+ else
+ DramTermDyn |= 1 << 10;
+ } else {
+ if (DimmsInstalled != 1) {
+ if (Speed == 7)
+ DramTermDyn |= 1 << 10;
+ else
+ DramTermDyn |= 1 << 11;
+ }
+ }
+ } else {
+ if (DimmsInstalled != 1)
+ DramTermDyn |= 1 << 11;
+ }
+ return DramTermDyn;
+}
+
+void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 DramMRS, dword;
+ u8 byte;
+
+ DramMRS = 0;
+
+ /* Set chip select CKE control mode */
+ if (mctGet_NVbits(NV_CKE_CTL)) {
+ if (pDCTstat->CSPresent == 3) {
+ u16 word;
+ word = pDCTstat->DIMMSPDCSE;
+ if (dct == 0)
+ word &= 0b01010100;
+ else
+ word &= 0b10101000;
+ if (word == 0)
+ DramMRS |= 1 << 23;
+ }
+ }
+ /*
+ DRAM MRS Register
+ DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7)
+ */
+ DramMRS |= 1 << 2;
+ /* Dram nominal termination: */
+ byte = pDCTstat->MAdimms[dct];
+ if (!(pDCTstat->Status & (1 << SB_Registered))) {
+ DramMRS |= 1 << 7; /* 60 ohms */
+ if (byte & 2) {
+ if (pDCTstat->Speed < 6)
+ DramMRS |= 1 << 8; /* 40 ohms */
+ else
+ DramMRS |= 1 << 9; /* 30 ohms */
+ }
+ }
+ /* Dram dynamic termination: Disable(1DIMM), 120ohm(>=2DIMM) */
+ if (!(pDCTstat->Status & (1 << SB_Registered))) {
+ if (byte >= 2) {
+ if (pDCTstat->Speed == 7)
+ DramMRS |= 1 << 10;
+ else
+ DramMRS |= 1 << 11;
+ }
+ } else {
+ DramMRS |= mct_DramTermDyn_RDimm(pMCTstat, pDCTstat, byte);
+ }
+
+ /* burst length control */
+ if (pDCTstat->Status & (1 << SB_128bitmode))
+ DramMRS |= 1 << 1;
+ /* Qoff=0, output buffers enabled */
+ /* Tcwl */
+ DramMRS |= (pDCTstat->Speed - 4) << 20;
+ /* ASR=1, auto self refresh */
+ /* SRT=0 */
+ DramMRS |= 1 << 18;
+
+ dword = Get_NB32(pDCTstat->dev_dct, 0x100 * dct + 0x84);
+ dword &= ~0x00FC2F8F;
+ dword |= DramMRS;
+ Set_NB32(pDCTstat->dev_dct, 0x100 * dct + 0x84, dword);
+}
+
+void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct,
+ u32 DramConfigHi)
+{
+ /* Bug#15114: Comp. update interrupted by Freq. change can cause
+ * subsequent update to be invalid during any MemClk frequency change:
+ * Solution: From the bug report:
+ * 1. A software-initiated frequency change should be wrapped into the
+ * following sequence :
+ * - a) Disable Compensation (F2[1, 0]9C_x08[30] )
+ * b) Reset the Begin Compensation bit (D3CMP->COMP_CONFIG[0]) in all the compensation engines
+ * c) Do frequency change
+ * d) Enable Compensation (F2[1, 0]9C_x08[30] )
+ * 2. A software-initiated Disable Compensation should always be
+ * followed by step b) of the above steps.
+ * Silicon Status: Fixed In Rev B0
+ *
+ * Errata#177: DRAM Phy Automatic Compensation Updates May Be Invalid
+ * Solution: BIOS should disable the phy automatic compensation prior
+ * to initiating a memory clock frequency change as follows:
+ * 1. Disable PhyAutoComp by writing 1'b1 to F2x[1, 0]9C_x08[30]
+ * 2. Reset the Begin Compensation bits by writing 32'h0 to
+ * F2x[1, 0]9C_x4D004F00
+ * 3. Perform frequency change
+ * 4. Enable PhyAutoComp by writing 1'b0 to F2x[1, 0]9C_08[30]
+ * In addition, any time software disables the automatic phy
+ * compensation it should reset the begin compensation bit per step 2.
+ * Silicon Status: Fixed in DR-B0
+ */
+
+ u32 dev = pDCTstat->dev_dct;
+ u32 index_reg = 0x98 + 0x100 * dct;
+ u32 index;
+
+ u32 val;
+
+ index = 0x08;
+ val = Get_NB32_index_wait(dev, index_reg, index);
+ if (!(val & (1 << DisAutoComp)))
+ Set_NB32_index_wait(dev, index_reg, index, val | (1 << DisAutoComp));
+
+ mct_Wait(100);
+
+ Set_NB32(dev, 0x94 + 0x100 * dct, DramConfigHi);
+}
+
+static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+{
+ u8 Node;
+ struct DCTStatStruc *pDCTstat;
+
+ /* Errata 178
+ *
+ * Bug#15115: Uncertainty In The Sync Chain Leads To Setup Violations
+ * In TX FIFO
+ * Solution: BIOS should program DRAM Control Register[RdPtrInit] =
+ * 5h, (F2x[1, 0]78[3:0] = 5h).
+ * Silicon Status: Fixed In Rev B0
+ *
+ * Bug#15880: Determine validity of reset settings for DDR PHY timing.
+ * Solutiuon: At least, set WrDqs fine delay to be 0 for DDR3 training.
+ */
+ for (Node = 0; Node < 8; Node++) {
+ pDCTstat = pDCTstatA + Node;
+
+ if (pDCTstat->NodePresent)
+ mct_BeforeDQSTrainSamp(pDCTstat); /* only Bx */
+ mct_ResetDLL_D(pMCTstat, pDCTstat, 0);
+ mct_ResetDLL_D(pMCTstat, pDCTstat, 1);
+ }
+}
+
+static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u8 Receiver;
+ u32 dev = pDCTstat->dev_dct;
+ u32 reg_off = 0x100 * dct;
+ u32 addr;
+ u32 lo, hi;
+ u8 wrap32dis = 0;
+ u8 valid = 0;
+
+ /* Skip reset DLL for B3 */
+ if (pDCTstat->LogicalCPUID & AMD_DR_B3) {
+ return;
+ }
+
+ addr = HWCR;
+ _RDMSR(addr, &lo, &hi);
+ if(lo & (1<<17)) { /* save the old value */
+ wrap32dis = 1;
+ }
+ lo |= (1<<17); /* HWCR.wrap32dis */
+ /* Setting wrap32dis allows 64-bit memory references in 32bit mode */
+ _WRMSR(addr, lo, hi);
+
+ pDCTstat->Channel = dct;
+ Receiver = mct_InitReceiver_D(pDCTstat, dct);
+ /* there are four receiver pairs, loosely associated with chipselects.*/
+ for (; Receiver < 8; Receiver += 2) {
+ if (mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, Receiver)) {
+ addr = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, dct, Receiver, &valid);
+ if (valid) {
+ mct_Read1LTestPattern_D(pMCTstat, pDCTstat, addr); /* cache fills */
+
+ /* Write 0000_8000h to register F2x[1,0]9C_xD080F0C */
+ Set_NB32_index_wait(dev, 0x98 + reg_off, 0x4D080F0C, 0x00008000);
+ mct_Wait(80); /* wait >= 300ns */
+
+ /* Write 0000_0000h to register F2x[1,0]9C_xD080F0C */
+ Set_NB32_index_wait(dev, 0x98 + reg_off, 0x4D080F0C, 0x00000000);
+ mct_Wait(800); /* wait >= 2us */
+ break;
+ }
+ }
+ }
+
+ if(!wrap32dis) {
+ addr = HWCR;
+ _RDMSR(addr, &lo, &hi);
+ lo &= ~(1<<17); /* restore HWCR.wrap32dis */
+ _WRMSR(addr, lo, hi);
+ }
+}
+
+static void mct_EnableDatIntlv_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ u32 dev = pDCTstat->dev_dct;
+ u32 val;
+
+ /* Enable F2x110[DctDatIntlv] */
+ /* Call back not required mctHookBeforeDatIntlv_D() */
+ /* FIXME Skip for Ax */
+ if (!pDCTstat->GangedMode) {
+ val = Get_NB32(dev, 0x110);
+ val |= 1 << 5; /* DctDatIntlv */
+ Set_NB32(dev, 0x110, val);
+
+ /* FIXME Skip for Cx */
+ dev = pDCTstat->dev_nbmisc;
+ val = Get_NB32(dev, 0x8C); /* NB Configuration Hi */
+ val |= 1 << (36-32); /* DisDatMask */
+ Set_NB32(dev, 0x8C, val);
+ }
+}
+
+static void SetDllSpeedUp_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 val;
+ u32 dev = pDCTstat->dev_dct;
+ u32 reg_off = 0x100 * dct;
+
+ if (pDCTstat->Speed >= 7) { /* DDR1600 and above */
+ /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F10 */
+ Set_NB32(dev, reg_off + 0x98, 0x0D080F10);
+ val = Get_NB32(dev, reg_off + 0x9C);
+ val |= 1 < 13;
+ Set_NB32(dev, reg_off + 0x9C, val);
+ Set_NB32(dev, reg_off + 0x98, 0x4D080F10);
+
+ /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F11 */
+ Set_NB32(dev, reg_off + 0x98, 0x0D080F11);
+ val = Get_NB32(dev, reg_off + 0x9C);
+ val |= 1 < 13;
+ Set_NB32(dev, reg_off + 0x9C, val);
+ Set_NB32(dev, reg_off + 0x98, 0x4D080F11);
+
+ /* Set bit13 PowerDown to register F2x[1, 0]98_x0D088F30 */
+ Set_NB32(dev, reg_off + 0x98, 0x0D088F30);
+ val = Get_NB32(dev, reg_off + 0x9C);
+ val |= 1 < 13;
+ Set_NB32(dev, reg_off + 0x9C, val);
+ Set_NB32(dev, reg_off + 0x98, 0x4D088F30);
+
+ /* Set bit13 PowerDown to register F2x[1, 0]98_x0D08CF30 */
+ Set_NB32(dev, reg_off + 0x98, 0x0D08CF30);
+ val = Get_NB32(dev, reg_off + 0x9C);
+ val |= 1 < 13;
+ Set_NB32(dev, reg_off + 0x9C, val);
+ Set_NB32(dev, reg_off + 0x98, 0x4D08CF30);
+
+ }
+}
+
+static void SyncSetting(struct DCTStatStruc *pDCTstat)
+{
+ /* set F2x78[ChSetupSync] when F2x[1, 0]9C_x04[AddrCmdSetup, CsOdtSetup,
+ * CkeSetup] setups for one DCT are all 0s and at least one of the setups,
+ * F2x[1, 0]9C_x04[AddrCmdSetup, CsOdtSetup, CkeSetup], of the other
+ * controller is 1
+ */
+ u32 cha, chb;
+ u32 dev = pDCTstat->dev_dct;
+ u32 val;
+
+ cha = pDCTstat->CH_ADDR_TMG[0] & 0x0202020;
+ chb = pDCTstat->CH_ADDR_TMG[1] & 0x0202020;
+
+ if ((cha != chb) && ((cha == 0) || (chb == 0))) {
+ val = Get_NB32(dev, 0x78);
+ val |= 1 << ChSetupSync;
+ Set_NB32(dev, 0x78, val);
+ }
+}
+
+static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) {
+
+ u32 val;
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+
+ if (pDCTstat->LogicalCPUID & (AMD_DR_B2 | AMD_DR_B3)) {
+ mct_Wait(10000); /* Wait 50 us*/
+ val = Get_NB32(dev, 0x110);
+ if (!(val & (1 << DramEnabled))) {
+ /* If 50 us expires while DramEnable =0 then do the following */
+ val = Get_NB32(dev, 0x90 + reg_off);
+ val &= ~(1 << Width128); /* Program Width128 = 0 */
+ Set_NB32(dev, 0x90 + reg_off, val);
+
+ val = Get_NB32_index_wait(dev, 0x98 + reg_off, 0x05); /* Perform dummy CSR read to F2x09C_x05 */
+
+ if (pDCTstat->GangedMode) {
+ val = Get_NB32(dev, 0x90 + reg_off);
+ val |= 1 << Width128; /* Program Width128 = 0 */
+ Set_NB32(dev, 0x90 + reg_off, val);
+ }
+ }
+ }
+}
+
+/* ==========================================================
+ * 6-bit Bank Addressing Table
+ * RR=rows-13 binary
+ * B=Banks-2 binary
+ * CCC=Columns-9 binary
+ * ==========================================================
+ * DCT CCCBRR Rows Banks Columns 64-bit CS Size
+ * Encoding
+ * 0000 000000 13 2 9 128MB
+ * 0001 001000 13 2 10 256MB
+ * 0010 001001 14 2 10 512MB
+ * 0011 010000 13 2 11 512MB
+ * 0100 001100 13 3 10 512MB
+ * 0101 001101 14 3 10 1GB
+ * 0110 010001 14 2 11 1GB
+ * 0111 001110 15 3 10 2GB
+ * 1000 010101 14 3 11 2GB
+ * 1001 010110 15 3 11 4GB
+ * 1010 001111 16 3 10 4GB
+ * 1011 010111 16 3 11 8GB
+ */
+u8 crcCheck(u8 smbaddr)
+{
+ u8 byte_use;
+ u8 Index;
+ u16 CRC;
+ u8 byte, i;
+
+ byte_use = mctRead_SPD(smbaddr, SPD_ByteUse);
+ if (byte_use & 0x80)
+ byte_use = 117;
+ else
+ byte_use = 126;
+
+ CRC = 0;
+ for (Index = 0; Index < byte_use; Index ++) {
+ byte = mctRead_SPD(smbaddr, Index);
+ CRC ^= byte << 8;
+ for (i=0; i<8; i++) {
+ if (CRC & 0x8000) {
+ CRC <<= 1;
+ CRC ^= 0x1021;
+ } else
+ CRC <<= 1;
+ }
+ }
+ return CRC == (mctRead_SPD(smbaddr, SPD_byte_127) << 8 | mctRead_SPD(smbaddr, SPD_byte_126));
+}