Enumerate all XMP 3.0 profiles on DDR5 to find the fastest. Solve a rounding issue with DDR5 timings

This commit is contained in:
Sam Demeulemeester
2022-04-22 00:49:54 +02:00
parent 66c6dfa357
commit 2a7631daab
2 changed files with 43 additions and 30 deletions
+1 -1
View File
@@ -1541,7 +1541,7 @@ static const struct spd_jedec_manufacturer jep106[] = {
// { 0x0C14, "NeuMem Co Ltd" }, // { 0x0C14, "NeuMem Co Ltd" },
// { 0x0C15, "Lifelong" }, // { 0x0C15, "Lifelong" },
// { 0x0C16, "Beijing Oitech Technology Co Ltd" }, // { 0x0C16, "Beijing Oitech Technology Co Ltd" },
{ 0x0C17, "Groupe LDLC" }, { 0x0C17, "LDLC" },
// { 0x0C18, "Semidynamics Technology Services SLU" }, // { 0x0C18, "Semidynamics Technology Services SLU" },
// { 0x0C19, "swordbill" }, // { 0x0C19, "swordbill" },
// { 0x0C1A, "YIREN" }, // { 0x0C1A, "YIREN" },
+42 -29
View File
@@ -231,6 +231,7 @@ static spd_info parse_spd_ddr5(uint8_t smb_idx, uint8_t slot_idx)
{ {
spd_info spdi; spd_info spdi;
spdi.isValid = false;
spdi.type = "DDR5"; spdi.type = "DDR5";
spdi.slot_num = slot_idx; spdi.slot_num = slot_idx;
spdi.sku_len = 0; spdi.sku_len = 0;
@@ -302,53 +303,66 @@ static spd_info parse_spd_ddr5(uint8_t smb_idx, uint8_t slot_idx)
} }
// Compute Frequency (including XMP) // Compute Frequency (including XMP)
uint16_t tCK, tns; uint16_t tCK, tCKtmp, tns;
int xmp_offset = 0;
spdi.XMP = ((get_spd(smb_idx, slot_idx, 640) == 0x0C && get_spd(smb_idx, slot_idx, 641) == 0x4A)) ? 3 : 0; spdi.XMP = ((get_spd(smb_idx, slot_idx, 640) == 0x0C && get_spd(smb_idx, slot_idx, 641) == 0x4A)) ? 3 : 0;
if (spdi.XMP == 3) { if (spdi.XMP == 3) {
// XMP 3.0 // XMP 3.0 (enumerate all profiles to find the fastest)
tCK = get_spd(smb_idx, slot_idx, 710) << 8; tCK = 0;
tCK |= get_spd(smb_idx, slot_idx, 709); for (int offset = 0; offset < 3*64; offset += 64) {
tCKtmp = get_spd(smb_idx, slot_idx, 710 + offset) << 8 |
get_spd(smb_idx, slot_idx, 709 + offset);
if (tCKtmp != 0 && (tCK == 0 || tCKtmp < tCK)) {
xmp_offset = offset;
tCK = tCKtmp;
}
}
} else { } else {
// JEDEC // JEDEC
tCK = get_spd(smb_idx, slot_idx, 21) << 8; tCK = get_spd(smb_idx, slot_idx, 21) << 8 |
tCK |= get_spd(smb_idx, slot_idx, 20); get_spd(smb_idx, slot_idx, 20);
}
if (tCK == 0) {
return spdi;
} }
spdi.freq = (float)(1.0f / tCK * 2.0f * 1000.0f * 1000.0f); spdi.freq = (float)(1.0f / tCK * 2.0f * 1000.0f * 1000.0f);
spdi.freq = (spdi.freq + 50) / 100 * 100; spdi.freq = (spdi.freq + 50) / 100 * 100;
// Module Timings // Module Timings
if(spdi.XMP == 3) { if (spdi.XMP == 3) {
// ------------------ // ------------------
// XMP Specifications // XMP Specifications
// ------------------ // ------------------
// CAS# Latency // CAS# Latency
tns = (uint16_t)get_spd(smb_idx, slot_idx, 718) << 8 | tns = (uint16_t)get_spd(smb_idx, slot_idx, 718 + xmp_offset) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 717); (uint16_t)get_spd(smb_idx, slot_idx, 717 + xmp_offset);
spdi.tCL = tns / tCK; spdi.tCL = (uint16_t)(tns/tCK + 0.5f);
// RAS# to CAS# Latency // RAS# to CAS# Latency
tns = (uint16_t)get_spd(smb_idx, slot_idx, 720) << 8 | tns = (uint16_t)get_spd(smb_idx, slot_idx, 720 + xmp_offset) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 719); (uint16_t)get_spd(smb_idx, slot_idx, 719 + xmp_offset);
spdi.tRCD = (uint16_t)(tns/tCK); spdi.tRCD = (uint16_t)(tns/tCK + 0.5f);
// RAS# Precharge // RAS# Precharge
tns = (uint16_t)get_spd(smb_idx, slot_idx, 722) << 8 | tns = (uint16_t)get_spd(smb_idx, slot_idx, 722 + xmp_offset) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 721); (uint16_t)get_spd(smb_idx, slot_idx, 721 + xmp_offset);
spdi.tRP= (uint16_t)(tns/tCK); spdi.tRP= (uint16_t)(tns/tCK + 0.5f);
// Row Active Time // Row Active Time
tns = (uint16_t)get_spd(smb_idx, slot_idx, 724) << 8 | tns = (uint16_t)get_spd(smb_idx, slot_idx, 724 + xmp_offset) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 723); (uint16_t)get_spd(smb_idx, slot_idx, 723 + xmp_offset);
spdi.tRAS = (uint16_t)(tns/tCK); spdi.tRAS = (uint16_t)(tns/tCK + 0.5f);
// Row Cycle Time // Row Cycle Time
tns = (uint16_t)get_spd(smb_idx, slot_idx, 726) << 8 | tns = (uint16_t)get_spd(smb_idx, slot_idx, 726 + xmp_offset) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 725); (uint16_t)get_spd(smb_idx, slot_idx, 725 + xmp_offset);
spdi.tRC = (uint16_t)(tns/tCK); spdi.tRC = (uint16_t)(tns/tCK + 0.5f);
} else { } else {
// -------------------- // --------------------
// JEDEC Specifications // JEDEC Specifications
@@ -357,40 +371,39 @@ static spd_info parse_spd_ddr5(uint8_t smb_idx, uint8_t slot_idx)
// CAS# Latency // CAS# Latency
tns = (uint16_t)get_spd(smb_idx, slot_idx, 31) << 8 | tns = (uint16_t)get_spd(smb_idx, slot_idx, 31) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 30); (uint16_t)get_spd(smb_idx, slot_idx, 30);
spdi.tCL = tns / tCK; spdi.tCL = (uint16_t)(tns/tCK + 0.5f);
// RAS# to CAS# Latency // RAS# to CAS# Latency
tns = (uint16_t)get_spd(smb_idx, slot_idx, 33) << 8 | tns = (uint16_t)get_spd(smb_idx, slot_idx, 33) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 32); (uint16_t)get_spd(smb_idx, slot_idx, 32);
spdi.tRCD = (uint16_t)(tns/tCK); spdi.tRCD = (uint16_t)(tns/tCK + 0.5f);
// RAS# Precharge // RAS# Precharge
tns = (uint16_t)get_spd(smb_idx, slot_idx, 35) << 8 | tns = (uint16_t)get_spd(smb_idx, slot_idx, 35) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 34); (uint16_t)get_spd(smb_idx, slot_idx, 34);
spdi.tRP= (uint16_t)(tns/tCK); spdi.tRP= (uint16_t)(tns/tCK + 0.5f);
// Row Active Time // Row Active Time
tns = (uint16_t)get_spd(smb_idx, slot_idx, 37) << 8 | tns = (uint16_t)get_spd(smb_idx, slot_idx, 37) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 36); (uint16_t)get_spd(smb_idx, slot_idx, 36);
spdi.tRAS = (uint16_t)(tns/tCK); spdi.tRAS = (uint16_t)(tns/tCK + 0.5f);
// Row Cycle Time // Row Cycle Time
tns = (uint16_t)get_spd(smb_idx, slot_idx, 39) << 8 | tns = (uint16_t)get_spd(smb_idx, slot_idx, 39) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 38); (uint16_t)get_spd(smb_idx, slot_idx, 38);
spdi.tRC = (uint16_t)(tns/tCK); spdi.tRC = (uint16_t)(tns/tCK + 0.5f);
} }
// Module manufacturer // Module manufacturer
spdi.jedec_code = (get_spd(smb_idx, slot_idx, 512) & 0x1F) << 8; spdi.jedec_code = (get_spd(smb_idx, slot_idx, 512) & 0x1F) << 8;
spdi.jedec_code |= get_spd(smb_idx, slot_idx, 513) & 0x7F; spdi.jedec_code |= get_spd(smb_idx, slot_idx, 513) & 0x7F;
// Module Timings // Module SKU
uint8_t sku_byte; uint8_t sku_byte;
for (int j = 0; j <= 29; j++) { for (int j = 0; j <= 29; j++) {
sku_byte = get_spd(smb_idx, slot_idx, 521+j); sku_byte = get_spd(smb_idx, slot_idx, 521+j);
if (sku_byte <= 0x20 && j > 1 && spdi.sku[j-1] <= 0x20) { if (sku_byte <= 0x20 && j > 1 && spdi.sku[j-1] <= 0x20) {
spdi.sku_len--;
break; break;
} else { } else {
spdi.sku[j] = sku_byte; spdi.sku[j] = sku_byte;