summaryrefslogtreecommitdiffstats
path: root/resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
diff options
context:
space:
mode:
authorFrancis Rowe <info@gluglug.org.uk>2016-01-02 17:10:32 (EST)
committer Francis Rowe <info@gluglug.org.uk>2016-01-04 15:28:39 (EST)
commitd1f408f3725aa02bc1d76c4c6aadb4697bd073c0 (patch)
tree7eed036543ae1f8c57b56825880a722a8efbedf1 /resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
parent91aec7e72005dcda72d19f2d024a02d8c0f86590 (diff)
downloadlibreboot-d1f408f3725aa02bc1d76c4c6aadb4697bd073c0.zip
libreboot-d1f408f3725aa02bc1d76c4c6aadb4697bd073c0.tar.gz
libreboot-d1f408f3725aa02bc1d76c4c6aadb4697bd073c0.tar.bz2
Use different coreboot revisions and patches per board
The release archives will be bigger, but this is a necessary change that makes libreboot development easier. At present, there are boards maintained in libreboot by different people. By doing it this way, that becomes much easier. This is in contrast to the present situation, where a change to one board potentially affects all other boards, especially when updating to a new version of coreboot. Coreboot-libre scripts, download scripts, build scripts - everything. The entire build system has been modified to reflect this change of development. For reasons of consistency, cbfstool and nvramtool are no longer included in the util archives.
Diffstat (limited to 'resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch')
-rw-r--r--resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch461
1 files changed, 461 insertions, 0 deletions
diff --git a/resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch b/resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
new file mode 100644
index 0000000..23c1b3d
--- /dev/null
+++ b/resources/libreboot/patch/coreboot/33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f/grub/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
@@ -0,0 +1,461 @@
+From 6f89a93a630dac9cd6588c69040f81c9ddebb0df Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <tpearson@raptorengineeringinc.com>
+Date: Tue, 2 Jun 2015 20:51:59 -0500
+Subject: [PATCH 041/143] northbridge/amd/amdmct: Read SPD data into cache to
+ decrease bootup time
+
+Change-Id: Ic16a927a3f1fc6f7cb1aea36a8abe8cc1999cb52
+Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 161 ++++++++++++++-------------
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h | 7 ++
+ 2 files changed, 92 insertions(+), 76 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 4677c73..5344ff9 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -180,7 +180,7 @@ static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
+ static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+ static void SyncSetting(struct DCTStatStruc *pDCTstat);
+-static u8 crcCheck(u8 smbaddr);
++static uint8_t crcCheck(struct DCTStatStruc *pDCTstat, uint8_t dimm);
+ static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat);
+ static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat);
+
+@@ -1170,6 +1170,20 @@ static void precise_memclk_delay_fam15(struct MCTStatStruc *pMCTstat, struct DCT
+ precise_ndelay_fam15(pMCTstat, delay_ns);
+ }
+
++static void read_spd_bytes(struct MCTStatStruc *pMCTstat,
++ struct DCTStatStruc *pDCTstat, uint8_t dimm)
++{
++ uint16_t addr;
++ uint16_t byte;
++
++ addr = Get_DIMMAddress_D(pDCTstat, dimm);
++ pDCTstat->spd_data.spd_address[dimm] = addr;
++
++ for (byte = 0; byte < 256; byte++) {
++ pDCTstat->spd_data.spd_bytes[dimm][byte] = mctRead_SPD(addr, byte);
++ }
++}
++
+ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstatA)
+ {
+@@ -1275,7 +1289,7 @@ restartinit:
+ mct_InitialMCT_D(pMCTstat, pDCTstat);
+
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: mctSMBhub_Init\n");
+- mctSMBhub_Init(Node); /* Switch SMBUS crossbar to proper node*/
++ mctSMBhub_Init(Node); /* Switch SMBUS crossbar to proper node */
+
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_preInitDCT\n");
+ mct_preInitDCT(pMCTstat, pDCTstat);
+@@ -2435,7 +2449,6 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+ u32 dword;
+ u32 dev;
+ u32 val;
+- u16 smbaddr;
+
+ printk(BIOS_DEBUG, "%s: Start\n", __func__);
+
+@@ -2455,64 +2468,62 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+ 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);
++ val = pDCTstat->spd_data.spd_bytes[dct + i][SPD_MTBDivisor]; /* MTB=Dividend/Divisor */
++ MTB16x = ((pDCTstat->spd_data.spd_bytes[dct + i][SPD_MTBDividend] & 0xff) << 4);
+ MTB16x /= val; /* transfer to MTB*16 */
+
+- byte = mctRead_SPD(smbaddr, SPD_tRPmin);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRPmin];
+ val = byte * MTB16x;
+ if (Trp < val)
+ Trp = val;
+
+- byte = mctRead_SPD(smbaddr, SPD_tRRDmin);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRRDmin];
+ val = byte * MTB16x;
+ if (Trrd < val)
+ Trrd = val;
+
+- byte = mctRead_SPD(smbaddr, SPD_tRCDmin);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRCDmin];
+ val = byte * MTB16x;
+ if (Trcd < val)
+ Trcd = val;
+
+- byte = mctRead_SPD(smbaddr, SPD_tRTPmin);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRTPmin];
+ val = byte * MTB16x;
+ if (Trtp < val)
+ Trtp = val;
+
+- byte = mctRead_SPD(smbaddr, SPD_tWRmin);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tWRmin];
+ val = byte * MTB16x;
+ if (Twr < val)
+ Twr = val;
+
+- byte = mctRead_SPD(smbaddr, SPD_tWTRmin);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tWTRmin];
+ val = byte * MTB16x;
+ if (Twtr < val)
+ Twtr = val;
+
+- val = mctRead_SPD(smbaddr, SPD_Upper_tRAS_tRC) & 0xFF;
++ val = pDCTstat->spd_data.spd_bytes[dct + i][SPD_Upper_tRAS_tRC] & 0xFF;
+ val >>= 4;
+ val <<= 8;
+- val |= mctRead_SPD(smbaddr, SPD_tRCmin) & 0xFF;
++ val |= pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRCmin] & 0xFF;
+ val *= MTB16x;
+ if (Trc < val)
+ Trc = val;
+
+- byte = mctRead_SPD(smbaddr, SPD_Density) & 0xF;
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_Density] & 0xF;
+ if (Trfc[LDIMM] < byte)
+ Trfc[LDIMM] = byte;
+
+- val = mctRead_SPD(smbaddr, SPD_Upper_tRAS_tRC) & 0xF;
++ val = pDCTstat->spd_data.spd_bytes[dct + i][SPD_Upper_tRAS_tRC] & 0xF;
+ val <<= 8;
+- val |= (mctRead_SPD(smbaddr, SPD_tRASmin) & 0xFF);
++ val |= (pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRASmin] & 0xFF);
+ val *= MTB16x;
+ if (Tras < val)
+ Tras = val;
+
+- val = mctRead_SPD(smbaddr, SPD_Upper_tFAW) & 0xF;
++ val = pDCTstat->spd_data.spd_bytes[dct + i][SPD_Upper_tFAW] & 0xF;
+ val <<= 8;
+- val |= mctRead_SPD(smbaddr, SPD_tFAWmin) & 0xFF;
++ val |= pDCTstat->spd_data.spd_bytes[dct + i][SPD_tFAWmin] & 0xFF;
+ val *= MTB16x;
+ if (Tfaw < val)
+ Tfaw = val;
+@@ -2928,7 +2939,7 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+ u8 CLactual, CLdesired, CLT_Fail;
+ uint16_t min_frequency_tck16x;
+
+- u8 smbaddr, byte = 0, bytex = 0;
++ u8 byte = 0, bytex = 0;
+
+ CASLatLow = 0xFF;
+ CASLatHigh = 0xFF;
+@@ -2949,28 +2960,27 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+
+ 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);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_CASLow];
+ CASLatLow &= byte;
+- byte = mctRead_SPD(smbaddr, SPD_CASHigh);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][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);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_MTBDivisor];
+
+- MTB16x = ((mctRead_SPD(smbaddr, SPD_MTBDividend) & 0xFF)<<4);
++ MTB16x = ((pDCTstat->spd_data.spd_bytes[dct + i][SPD_MTBDividend] & 0xFF)<<4);
+ MTB16x /= byte; /* transfer to MTB*16 */
+
+- byte = mctRead_SPD(smbaddr, SPD_tAAmin);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][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);
++ byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tCKmin];
+
+ if (tCKmin16x < byte * MTB16x)
+ tCKmin16x = byte * MTB16x;
+@@ -3341,7 +3351,6 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
+ u8 byte;
+ u16 word;
+ u32 dword;
+- u16 smbaddr;
+
+ dev = pDCTstat->dev_dct;
+
+@@ -3352,16 +3361,14 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
+ byte -= 3;
+
+ if (pDCTstat->DIMMValid & (1<<byte)) {
+- smbaddr = Get_DIMMAddress_D(pDCTstat, (ChipSel + dct));
+-
+- byte = mctRead_SPD(smbaddr, SPD_Addressing);
++ byte = pDCTstat->spd_data.spd_bytes[ChipSel + dct][SPD_Addressing];
+ Rows = (byte >> 3) & 0x7; /* Rows:0b=12-bit,... */
+ Cols = byte & 0x7; /* Cols:0b=9-bit,... */
+
+- byte = mctRead_SPD(smbaddr, SPD_Density);
++ byte = pDCTstat->spd_data.spd_bytes[ChipSel + dct][SPD_Density];
+ Banks = (byte >> 4) & 7; /* Banks:0b=3-bit,... */
+
+- byte = mctRead_SPD(smbaddr, SPD_Organization);
++ byte = pDCTstat->spd_data.spd_bytes[ChipSel + dct][SPD_Organization];
+ Ranks = ((byte >> 3) & 7) + 1;
+
+ /* Configure Bank encoding
+@@ -3456,46 +3463,42 @@ static void SPDCalcWidth_D(struct MCTStatStruc *pMCTstat,
+ * 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;
++ byte = pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] & 0x7;
++ byte1 = pDCTstat->spd_data.spd_bytes[i + 1][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;
++ byte = pDCTstat->spd_data.spd_bytes[i][SPD_Density] & 0x0f;
++ byte1 = pDCTstat->spd_data.spd_bytes[i + 1][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;
++ byte = pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x7;
++ byte1 = pDCTstat->spd_data.spd_bytes[i + 1][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;
++ byte = (pDCTstat->spd_data.spd_bytes[i][SPD_Organization] >> 3) & 0x7;
++ byte1 = (pDCTstat->spd_data.spd_bytes[i + 1][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 */
++ byte = pDCTstat->spd_data.spd_bytes[i][SPD_DMBANKS] & 7; /* #ranks-1 */
++ byte1 = pDCTstat->spd_data.spd_bytes[i + 1][SPD_DMBANKS] & 7; /* #ranks-1 */
+ if (byte != byte1) {
+ pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+ break;
+@@ -3676,8 +3679,9 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+ 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);
++ read_spd_bytes(pMCTstat, pDCTstat, i);
++ if (crcCheck(pDCTstat, i)) { /* CRC is OK */
++ byte = pDCTstat->spd_data.spd_bytes[i][SPD_TYPE];
+ if (byte == JED_DDR3SDRAM) {
+ /*Dimm is 'Present'*/
+ pDCTstat->DIMMValid |= 1 << i;
+@@ -3690,36 +3694,41 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+ } else {
+ /*if NV_SPDCHK_RESTRT is set to 1, ignore faulty SPD checksum*/
+ pDCTstat->ErrStatus |= 1<<SB_DIMMChkSum;
+- byte = mctRead_SPD(smbaddr, SPD_TYPE);
++ byte = pDCTstat->spd_data.spd_bytes[i][SPD_TYPE];
+ if (byte == JED_DDR3SDRAM)
+ pDCTstat->DIMMValid |= 1 << i;
+ }
+ }
++
++ /* Zero DIMM SPD data cache if DIMM not present / valid */
++ if (!(pDCTstat->DIMMValid & (1 << i)))
++ memset(pDCTstat->spd_data.spd_bytes[i], 0, 256);
++
+ /* Get module information for SMBIOS */
+ if (pDCTstat->DIMMValid & (1 << i)) {
+ pDCTstat->DimmManufacturerID[i] = 0;
+ for (k = 0; k < 8; k++)
+- pDCTstat->DimmManufacturerID[i] |= ((uint64_t)mctRead_SPD(smbaddr, SPD_MANID_START + k)) << (k * 8);
++ pDCTstat->DimmManufacturerID[i] |= ((uint64_t)pDCTstat->spd_data.spd_bytes[i][SPD_MANID_START + k]) << (k * 8);
+ for (k = 0; k < SPD_PARTN_LENGTH; k++)
+- pDCTstat->DimmPartNumber[i][k] = mctRead_SPD(smbaddr, SPD_PARTN_START + k);
++ pDCTstat->DimmPartNumber[i][k] = pDCTstat->spd_data.spd_bytes[i][SPD_PARTN_START + k];
+ pDCTstat->DimmPartNumber[i][SPD_PARTN_LENGTH] = 0;
+ pDCTstat->DimmRevisionNumber[i] = 0;
+ for (k = 0; k < 2; k++)
+- pDCTstat->DimmRevisionNumber[i] |= ((uint16_t)mctRead_SPD(smbaddr, SPD_REVNO_START + k)) << (k * 8);
++ pDCTstat->DimmRevisionNumber[i] |= ((uint16_t)pDCTstat->spd_data.spd_bytes[i][SPD_REVNO_START + k]) << (k * 8);
+ pDCTstat->DimmSerialNumber[i] = 0;
+ for (k = 0; k < 4; k++)
+- pDCTstat->DimmSerialNumber[i] |= ((uint32_t)mctRead_SPD(smbaddr, SPD_SERIAL_START + k)) << (k * 8);
+- pDCTstat->DimmRows[i] = (mctRead_SPD(smbaddr, SPD_Addressing) & 0x38) >> 3;
+- pDCTstat->DimmCols[i] = mctRead_SPD(smbaddr, SPD_Addressing) & 0x7;
+- pDCTstat->DimmRanks[i] = ((mctRead_SPD(smbaddr, SPD_Organization) & 0x38) >> 3) + 1;
+- pDCTstat->DimmBanks[i] = 1ULL << (((mctRead_SPD(smbaddr, SPD_Density) & 0x70) >> 4) + 3);
+- pDCTstat->DimmWidth[i] = 1ULL << ((mctRead_SPD(smbaddr, SPD_BusWidth) & 0x7) + 3);
++ pDCTstat->DimmSerialNumber[i] |= ((uint32_t)pDCTstat->spd_data.spd_bytes[i][SPD_SERIAL_START + k]) << (k * 8);
++ pDCTstat->DimmRows[i] = (pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] & 0x38) >> 3;
++ pDCTstat->DimmCols[i] = pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] & 0x7;
++ pDCTstat->DimmRanks[i] = ((pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x38) >> 3) + 1;
++ pDCTstat->DimmBanks[i] = 1ULL << (((pDCTstat->spd_data.spd_bytes[i][SPD_Density] & 0x70) >> 4) + 3);
++ pDCTstat->DimmWidth[i] = 1ULL << ((pDCTstat->spd_data.spd_bytes[i][SPD_BusWidth] & 0x7) + 3);
+ }
+ /* Check supported voltage(s) */
+- pDCTstat->DimmSupportedVoltages[i] = mctRead_SPD(smbaddr, SPD_Voltage) & 0x7;
++ pDCTstat->DimmSupportedVoltages[i] = pDCTstat->spd_data.spd_bytes[i][SPD_Voltage] & 0x7;
+ pDCTstat->DimmSupportedVoltages[i] ^= 0x1; /* Invert LSB to convert from SPD format to internal bitmap format */
+ /* Check module type */
+- byte = mctRead_SPD(smbaddr, SPD_DIMMTYPE) & 0x7;
++ byte = pDCTstat->spd_data.spd_bytes[i][SPD_DIMMTYPE] & 0x7;
+ if (byte == JED_RDIMM || byte == JED_MiniRDIMM) {
+ RegDIMMPresent |= 1 << i;
+ pDCTstat->DimmRegistered[i] = 1;
+@@ -3733,13 +3742,13 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+ pDCTstat->DimmLoadReduced[i] = 0;
+ }
+ /* Check ECC capable */
+- byte = mctRead_SPD(smbaddr, SPD_BusWidth);
++ byte = pDCTstat->spd_data.spd_bytes[i][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 */
++ devwidth = pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x7; /* 0:x4,1:x8,2:x16 */
+ if (devwidth == 0) {
+ /* DIMM is made with x4 or x16 drams */
+ pDCTstat->Dimmx4Present |= 1 << i;
+@@ -3749,7 +3758,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+ pDCTstat->Dimmx16Present |= 1 << i;
+ }
+
+- byte = (mctRead_SPD(smbaddr, SPD_Organization) >> 3);
++ byte = (pDCTstat->spd_data.spd_bytes[i][SPD_Organization] >> 3);
+ byte &= 7;
+ if (byte == 3) { /* 4ranks */
+ /* if any DIMMs are QR, we have to make two passes through DIMMs*/
+@@ -3784,7 +3793,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+
+ /* check address mirror support for unbuffered dimm */
+ /* check number of registers on a dimm for registered dimm */
+- byte = mctRead_SPD(smbaddr, SPD_AddressMirror);
++ byte = pDCTstat->spd_data.spd_bytes[i][SPD_AddressMirror];
+ if (RegDIMMPresent & (1 << i)) {
+ if ((byte & 3) > 1)
+ pDCTstat->MirrPresU_NumRegR |= 1 << i;
+@@ -3793,20 +3802,20 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+ pDCTstat->MirrPresU_NumRegR |= 1 << i;
+ }
+ /* Get byte62: Reference Raw Card information. We dont need it now. */
+- /* byte = mctRead_SPD(smbaddr, SPD_RefRawCard); */
++ /* byte = pDCTstat->spd_data.spd_bytes[i][SPD_RefRawCard]; */
+ /* Get Byte65/66 for register manufacture ID code */
+- if ((0x97 == mctRead_SPD(smbaddr, SPD_RegManufactureID_H)) &&
+- (0x80 == mctRead_SPD(smbaddr, SPD_RegManufactureID_L))) {
+- if (0x16 == mctRead_SPD(smbaddr, SPD_RegManRevID))
++ if ((0x97 == pDCTstat->spd_data.spd_bytes[i][SPD_RegManufactureID_H]) &&
++ (0x80 == pDCTstat->spd_data.spd_bytes[i][SPD_RegManufactureID_L])) {
++ if (0x16 == pDCTstat->spd_data.spd_bytes[i][SPD_RegManRevID])
+ pDCTstat->RegMan2Present |= 1 << i;
+ else
+ pDCTstat->RegMan1Present |= 1 << i;
+ }
+ /* Get Control word values for RC3. We dont need it. */
+- byte = mctRead_SPD(smbaddr, 70);
++ byte = pDCTstat->spd_data.spd_bytes[i][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);
++ byte = pDCTstat->spd_data.spd_bytes[i][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] */
+ }
+@@ -6184,14 +6193,14 @@ static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) {
+ * 1010 001111 16 3 10 4GB
+ * 1011 010111 16 3 11 8GB
+ */
+-u8 crcCheck(u8 smbaddr)
++uint8_t crcCheck(struct DCTStatStruc *pDCTstat, uint8_t dimm)
+ {
+ u8 byte_use;
+ u8 Index;
+ u16 CRC;
+ u8 byte, i;
+
+- byte_use = mctRead_SPD(smbaddr, SPD_ByteUse);
++ byte_use = pDCTstat->spd_data.spd_bytes[dimm][SPD_ByteUse];
+ if (byte_use & 0x80)
+ byte_use = 117;
+ else
+@@ -6199,7 +6208,7 @@ u8 crcCheck(u8 smbaddr)
+
+ CRC = 0;
+ for (Index = 0; Index < byte_use; Index ++) {
+- byte = mctRead_SPD(smbaddr, Index);
++ byte = pDCTstat->spd_data.spd_bytes[dimm][Index];
+ CRC ^= byte << 8;
+ for (i=0; i<8; i++) {
+ if (CRC & 0x8000) {
+@@ -6209,5 +6218,5 @@ u8 crcCheck(u8 smbaddr)
+ CRC <<= 1;
+ }
+ }
+- return CRC == (mctRead_SPD(smbaddr, SPD_byte_127) << 8 | mctRead_SPD(smbaddr, SPD_byte_126));
++ return CRC == (pDCTstat->spd_data.spd_bytes[dimm][SPD_byte_127] << 8 | pDCTstat->spd_data.spd_bytes[dimm][SPD_byte_126]);
+ }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index 50fbff7..5bb09b4 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -322,6 +322,11 @@ struct MCTStatStruc {
+ ===============================================================================*/
+ #include "mwlc_d.h" /* I have to */
+
++struct amd_spd_node_data {
++ uint8_t spd_bytes[MAX_DIMMS_SUPPORTED][256]; /* [DIMM][byte] */
++ uint8_t spd_address[MAX_DIMMS_SUPPORTED]; /* [DIMM] */
++} __attribute__((packed));
++
+ struct DCTStatStruc { /* A per Node structure*/
+ /* DCTStatStruct_F - start */
+ u8 Node_ID; /* Node ID of current controller */
+@@ -615,6 +620,8 @@ struct DCTStatStruc { /* A per Node structure*/
+ char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH+1];
+ uint16_t DimmRevisionNumber[MAX_DIMMS_SUPPORTED];
+ uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
++
++ struct amd_spd_node_data spd_data;
+ } __attribute__((packed));
+
+ struct amd_s3_persistent_mct_channel_data {
+--
+1.7.9.5
+