mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2026-08-13 06:24:53 -05:00
Enumerate all XMP 3.0 profiles on DDR5 to find the fastest. Solve a rounding issue with DDR5 timings
This commit is contained in:
+1
-1
@@ -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
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user