Rework Line 9. Add DDR1->DDR5 Timing Detection to display on this line

This commit is contained in:
Sam Demeulemeester 2022-04-14 01:40:31 +02:00 committed by Sam Demeulemeester
parent 979b85548d
commit 6fca9bedc9
5 changed files with 397 additions and 54 deletions

View File

@ -66,6 +66,8 @@ static bool timed_update_done = false; // update cycle status
int scroll_message_row; int scroll_message_row;
int display_mode = 0; // RAM Info from: 0 = N/A - 1 = SPD - 2 = IMC
int max_cpu_temp = 0; int max_cpu_temp = 0;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -217,6 +219,31 @@ void post_display_init(void)
{ {
print_smbios_startup_info(); print_smbios_startup_info();
print_smbus_startup_info(); print_smbus_startup_info();
if(false) {
// Try to get RAM information from IMC (TODO)
printf(8,0, "IMC: %uMHz (%s-%u) CAS %u-%u-%u-%u", ram.freq / 2
, ram.type
, ram.freq
, ram.tCL
, ram.tRCD
, ram.tRP
, ram.tRAS);
display_mode = 2;
} else if (ram.freq > 0 && ram.tCL > 1) {
// If not available, grab max memory specs from SPD
printf(8,0, "RAM: %uMHz (%s-%u) CAS %u-%u-%u-%u", ram.freq / 2
, ram.type
, ram.freq
, ram.tCL
, ram.tRCD
, ram.tRP
, ram.tRAS);
display_mode = 1;
} else {
// If nothing avilable, fallback to "Using Core" Display
display_mode = 0;
}
} }
void display_start_run(void) void display_start_run(void)

View File

@ -73,7 +73,7 @@
prints(8, 7, "Core #"); \ prints(8, 7, "Core #"); \
printi(8, 13, cpu_num, 3, false, true) printi(8, 13, cpu_num, 3, false, true)
#define display_all_active \ #define display_all_active() \
prints(8, 7, "All Cores") prints(8, 7, "All Cores")
#define display_spinner(spin_state) \ #define display_spinner(spin_state) \
@ -182,6 +182,8 @@
extern int scroll_message_row; extern int scroll_message_row;
extern int display_mode;
void display_init(void); void display_init(void);
void display_cpu_topology(void); void display_cpu_topology(void);

View File

@ -346,9 +346,13 @@ static void test_all_windows(int my_cpu)
if (!dummy_run) { if (!dummy_run) {
if (parallel_test) { if (parallel_test) {
num_active_cpus = num_enabled_cpus; num_active_cpus = num_enabled_cpus;
display_all_active; if(display_mode == 0) {
display_all_active();
}
} else { } else {
display_active_cpu(my_cpu); if(display_mode == 0) {
display_active_cpu(my_cpu);
}
} }
} }
barrier_reset(run_barrier, num_active_cpus); barrier_reset(run_barrier, num_active_cpus);

View File

@ -17,6 +17,8 @@
#define LINE_SPD 13 #define LINE_SPD 13
#define MAX_SPD_SLOT 8 #define MAX_SPD_SLOT 8
ram_info ram = { 0, 0, 0, 0, 0, "N/A"};
int smbdev, smbfun; int smbdev, smbfun;
unsigned short smbusbase; unsigned short smbusbase;
@ -106,6 +108,7 @@ void print_smbus_startup_info(void) {
uint8_t spdidx = 0, spd_line_idx = 0; uint8_t spdidx = 0, spd_line_idx = 0;
spd_info curspd; spd_info curspd;
ram.freq = 0;
index = find_smb_controller(); index = find_smb_controller();
@ -140,7 +143,7 @@ void print_smbus_startup_info(void) {
break; break;
} }
if(curspd.isValid) { if (curspd.isValid) {
if(spd_line_idx == 0) { if(spd_line_idx == 0) {
prints(LINE_SPD-2, 0, "Memory SPD Informations"); prints(LINE_SPD-2, 0, "Memory SPD Informations");
prints(LINE_SPD-1, 0, "-----------------------"); prints(LINE_SPD-1, 0, "-----------------------");
@ -166,10 +169,17 @@ static void print_spdi(spd_info spdi, uint8_t lidx)
spdi.freq); spdi.freq);
// Print ECC status // Print ECC status
if(spdi.hasECC) { if (spdi.hasECC) {
curcol = prints(LINE_SPD+lidx, curcol, " ECC"); curcol = prints(LINE_SPD+lidx, curcol, " ECC");
} }
// Print XMP/EPP Status
if (spdi.XMP > 0 && spdi.XMP < 20) {
curcol = prints(LINE_SPD+lidx, curcol, " XMP");
} else if (spdi.XMP == 20) {
curcol = prints(LINE_SPD+lidx, curcol, " EPP");
}
// Print Manufacturer from JEDEC106 // Print Manufacturer from JEDEC106
for (i = 0; i < JEP106_CNT ; i++) { for (i = 0; i < JEP106_CNT ; i++) {
@ -180,7 +190,7 @@ static void print_spdi(spd_info spdi, uint8_t lidx)
} }
// If not present in JEDEC106, display raw JEDEC ID // If not present in JEDEC106, display raw JEDEC ID
if(i == JEP106_CNT && spdi.jedec_code != 0) { if (i == JEP106_CNT && spdi.jedec_code != 0) {
curcol = printf(LINE_SPD+lidx, curcol, " - Unknown (0x%x)", spdi.jedec_code); curcol = printf(LINE_SPD+lidx, curcol, " - Unknown (0x%x)", spdi.jedec_code);
} }
@ -190,13 +200,20 @@ static void print_spdi(spd_info spdi, uint8_t lidx)
} }
// Print Manufacturing date (only if valid) // Print Manufacturing date (only if valid)
if(curcol <= 72 && spdi.fab_year > 1 && spdi.fab_year < 32 && spdi.fab_week < 53) { if (curcol <= 72 && spdi.fab_year > 1 && spdi.fab_year < 32 && spdi.fab_week < 53) {
curcol = printf(LINE_SPD+lidx, curcol, " (W%02i'%02i)", spdi.fab_week, spdi.fab_year); curcol = printf(LINE_SPD+lidx, curcol, " (W%02i'%02i)", spdi.fab_week, spdi.fab_year);
} }
// Print XMP Status // Populate global ram var
if(spdi.XMP > 0) { ram.type = spdi.type;
curcol = prints(LINE_SPD+lidx, curcol, " *XMP*"); if (ram.freq == 0 || ram.freq > spdi.freq) {
ram.freq = spdi.freq;
}
if (ram.tCL < spdi.tCL) {
ram.tCL = spdi.tCL;
ram.tRCD = spdi.tRCD;
ram.tRP = spdi.tRP;
ram.tRAS = spdi.tRAS;
} }
} }
@ -246,7 +263,7 @@ static spd_info parse_spd_ddr5(uint8_t smb_idx, uint8_t slot_idx)
} }
// Die per package // Die per package
if((sbyte >> 5) > 1 && (sbyte >> 5) <= 5) { if ((sbyte >> 5) > 1 && (sbyte >> 5) <= 5) {
cur_rank *= 1 << (((sbyte >> 5) & 7) - 1); cur_rank *= 1 << (((sbyte >> 5) & 7) - 1);
} }
@ -254,7 +271,7 @@ static spd_info parse_spd_ddr5(uint8_t smb_idx, uint8_t slot_idx)
spdi.hasECC = (((sbyte >> 3) & 3) > 0); spdi.hasECC = (((sbyte >> 3) & 3) > 0);
// Channels per DIMM // Channels per DIMM
if(((sbyte >> 5) & 3) == 1) { if (((sbyte >> 5) & 3) == 1) {
cur_rank *= 2; cur_rank *= 2;
} }
@ -269,17 +286,17 @@ static spd_info parse_spd_ddr5(uint8_t smb_idx, uint8_t slot_idx)
spdi.module_size += cur_rank; spdi.module_size += cur_rank;
// If not Asymmetrical, don't process the second rank // If not Asymmetrical, don't process the second rank
if((get_spd(smb_idx, slot_idx, 234) >> 6) == 0) { if ((get_spd(smb_idx, slot_idx, 234) >> 6) == 0) {
break; break;
} }
} }
// Compute Frequency (including XMP) // Compute Frequency (including XMP)
uint16_t tCK; uint16_t tCK, tns;
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
tCK = get_spd(smb_idx, slot_idx, 710) << 8; tCK = get_spd(smb_idx, slot_idx, 710) << 8;
tCK |= get_spd(smb_idx, slot_idx, 709); tCK |= get_spd(smb_idx, slot_idx, 709);
@ -292,16 +309,77 @@ static spd_info parse_spd_ddr5(uint8_t smb_idx, uint8_t slot_idx)
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
if(spdi.XMP == 3) {
// ------------------
// XMP Specifications
// ------------------
// CAS# Latency
tns = (uint16_t)get_spd(smb_idx, slot_idx, 718) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 717);
spdi.tCL = tns / tCK;
// RAS# to CAS# Latency
tns = (uint16_t)get_spd(smb_idx, slot_idx, 720) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 719);
spdi.tRCD = (uint16_t)(tns/tCK);
// RAS# Precharge
tns = (uint16_t)get_spd(smb_idx, slot_idx, 722) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 721);
spdi.tRP= (uint16_t)(tns/tCK);
// Row Active Time
tns = (uint16_t)get_spd(smb_idx, slot_idx, 724) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 723);
spdi.tRAS = (uint16_t)(tns/tCK);
// Row Cycle Time
tns = (uint16_t)get_spd(smb_idx, slot_idx, 726) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 725);
spdi.tRC = (uint16_t)(tns/tCK);
} else {
// --------------------
// JEDEC Specifications
// --------------------
// CAS# Latency
tns = (uint16_t)get_spd(smb_idx, slot_idx, 31) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 30);
spdi.tCL = tns / tCK;
// RAS# to CAS# Latency
tns = (uint16_t)get_spd(smb_idx, slot_idx, 33) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 32);
spdi.tRCD = (uint16_t)(tns/tCK);
// RAS# Precharge
tns = (uint16_t)get_spd(smb_idx, slot_idx, 35) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 34);
spdi.tRP= (uint16_t)(tns/tCK);
// Row Active Time
tns = (uint16_t)get_spd(smb_idx, slot_idx, 37) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 36);
spdi.tRAS = (uint16_t)(tns/tCK);
// Row Cycle Time
tns = (uint16_t)get_spd(smb_idx, slot_idx, 39) << 8 |
(uint16_t)get_spd(smb_idx, slot_idx, 38);
spdi.tRC = (uint16_t)(tns/tCK);
}
// 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 SKU // Module Timings
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--; spdi.sku_len--;
break; break;
} else { } else {
@ -341,47 +419,92 @@ static spd_info parse_spd_ddr4(uint8_t smb_idx, uint8_t slot_idx)
spdi.hasECC = (((get_spd(smb_idx, slot_idx, 13) >> 3) & 1) == 1); spdi.hasECC = (((get_spd(smb_idx, slot_idx, 13) >> 3) & 1) == 1);
uint8_t tck = get_spd(smb_idx, slot_idx, 18); // Module max clock
float tns, tckns, ramfreq;
if(get_spd(smb_idx, slot_idx, 384) == 0x0C && get_spd(smb_idx, slot_idx, 385) == 0x4A) { if (get_spd(smb_idx, slot_idx, 384) == 0x0C && get_spd(smb_idx, slot_idx, 385) == 0x4A) {
// Max XMP // Max XMP
uint8_t tck_mtb = get_spd(smb_idx, slot_idx, 396); tckns = (uint8_t)get_spd(smb_idx, slot_idx, 396) * 0.125f +
int8_t tck_ftb = get_spd(smb_idx, slot_idx, 431); (int8_t)get_spd(smb_idx, slot_idx, 431) * 0.001f;
float tckavg = 1.0f / ((tck_mtb * 0.125f) + (tck_ftb * 0.001f)) * 2.0f * 1000.0f; ramfreq = 1.0f / tckns * 2.0f * 1000.0f;
spdi.freq = (tckavg+50)/100; spdi.freq = (ramfreq+50)/100;
spdi.freq *= 100; spdi.freq *= 100;
spdi.XMP = 2; spdi.XMP = 2;
} else { } else {
// Max JEDEC // Max JEDEC
spdi.XMP = 0; tckns = (uint8_t)get_spd(smb_idx, slot_idx, 18) * 0.125f +
(int8_t)get_spd(smb_idx, slot_idx, 125) * 0.001f;
switch(tck) { ramfreq = 1.0f / tckns * 2.0f * 1000.0f;
default: spdi.freq = (uint16_t)ramfreq;
spdi.freq = 0;
break; spdi.XMP = 0;
case 10: }
spdi.freq = 1600;
break; // Module Timings
case 9: if (spdi.XMP == 2) {
spdi.freq = 1866; // ------------------
break; // XMP Specifications
case 8: // ------------------
spdi.freq = 2133;
break; // CAS# Latency
case 7: tns = (uint8_t)get_spd(smb_idx, slot_idx, 401) * 0.125f +
spdi.freq = 2400; (int8_t)get_spd(smb_idx, slot_idx, 430) * 0.001f;
break; spdi.tCL = (uint16_t)(tns/tckns);
case 6:
spdi.freq = 2666; // RAS# to CAS# Latency
break; tns = (uint8_t)get_spd(smb_idx, slot_idx, 402) * 0.125f +
case 5: (int8_t)get_spd(smb_idx, slot_idx, 429) * 0.001f;
spdi.freq = 3200; spdi.tRCD = (uint16_t)(tns/tckns);
break;
} // RAS# Precharge
tns = (uint8_t)get_spd(smb_idx, slot_idx, 403) * 0.125f +
(int8_t)get_spd(smb_idx, slot_idx, 428) * 0.001f;
spdi.tRP= (uint16_t)(tns/tckns);
// Row Active Time
tns = (uint8_t)get_spd(smb_idx, slot_idx, 405) * 0.125f +
(int8_t)get_spd(smb_idx, slot_idx, 427) * 0.001f +
(uint8_t)(get_spd(smb_idx, slot_idx, 404) & 0x0F) * 32.0f;
spdi.tRAS = (uint16_t)(tns/tckns);
// Row Cycle Time
tns = (uint8_t)get_spd(smb_idx, slot_idx, 406) * 0.125f +
(uint8_t)(get_spd(smb_idx, slot_idx, 404) >> 4) * 32.0f;
spdi.tRC = (uint16_t)(tns/tckns);
} else {
// --------------------
// JEDEC Specifications
// --------------------
// CAS# Latency
tns = (uint8_t)get_spd(smb_idx, slot_idx, 24) * 0.125f +
(int8_t)get_spd(smb_idx, slot_idx, 123) * 0.001f;
spdi.tCL = (uint16_t)(tns/tckns);
// RAS# to CAS# Latency
tns = (uint8_t)get_spd(smb_idx, slot_idx, 25) * 0.125f +
(int8_t)get_spd(smb_idx, slot_idx, 122) * 0.001f;
spdi.tRCD = (uint16_t)(tns/tckns);
// RAS# Precharge
tns = (uint8_t)get_spd(smb_idx, slot_idx, 26) * 0.125f +
(int8_t)get_spd(smb_idx, slot_idx, 121) * 0.001f;
spdi.tRP= (uint16_t)(tns/tckns);
// Row Active Time
tns = (uint8_t)get_spd(smb_idx, slot_idx, 28) * 0.125f +
(uint8_t)(get_spd(smb_idx, slot_idx, 27) & 0x0F) * 32.0f;
spdi.tRAS = (uint16_t)(tns/tckns);
// Row Cycle Time
tns = (uint8_t)get_spd(smb_idx, slot_idx, 29) * 0.125f +
(uint8_t)(get_spd(smb_idx, slot_idx, 27) >> 4) * 32.0f;
spdi.tRC = (uint16_t)(tns/tckns);
} }
// Module manufacturer // Module manufacturer
@ -393,7 +516,7 @@ static spd_info parse_spd_ddr4(uint8_t smb_idx, uint8_t slot_idx)
for (int j = 0; j <= 20; j++) { for (int j = 0; j <= 20; j++) {
sku_byte = get_spd(smb_idx, slot_idx, 329+j); sku_byte = get_spd(smb_idx, slot_idx, 329+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--; spdi.sku_len--;
break; break;
} else { } else {
@ -435,13 +558,13 @@ static spd_info parse_spd_ddr3(uint8_t smb_idx, uint8_t slot_idx)
uint8_t tck = get_spd(smb_idx, slot_idx, 12); uint8_t tck = get_spd(smb_idx, slot_idx, 12);
if(get_spd(smb_idx, slot_idx, 176) == 0x0C && get_spd(smb_idx, slot_idx, 177) == 0x4A) { if (get_spd(smb_idx, slot_idx, 176) == 0x0C && get_spd(smb_idx, slot_idx, 177) == 0x4A) {
tck = get_spd(smb_idx, slot_idx, 186); tck = get_spd(smb_idx, slot_idx, 186);
spdi.XMP = 1; spdi.XMP = 1;
} }
// Module jedec speed // Module jedec speed
switch(tck) { switch (tck) {
default: default:
spdi.freq = 0; spdi.freq = 0;
break; break;
@ -471,6 +594,69 @@ static spd_info parse_spd_ddr3(uint8_t smb_idx, uint8_t slot_idx)
break; break;
} }
// Module Timings
float tckns, tns;
if (spdi.XMP == 1) {
// ------------------
// XMP Specifications
// ------------------
tckns = get_spd(smb_idx, slot_idx, 186);
// CAS# Latency
tns = get_spd(smb_idx, slot_idx, 187);
spdi.tCL = (uint16_t)(tns/tckns);
// RAS# to CAS# Latency
tns = get_spd(smb_idx, slot_idx, 192);
spdi.tRCD = (uint16_t)(tns/tckns);
// RAS# Precharge
tns = get_spd(smb_idx, slot_idx, 191);
spdi.tRP= (uint16_t)(tns/tckns);
// Row Active Time
tns = (uint16_t)(get_spd(smb_idx, slot_idx, 194) & 0xF0) << 4 |
get_spd(smb_idx, slot_idx, 195);
;
spdi.tRAS = (uint16_t)(tns/tckns);
// Row Cycle Time
tns = (uint16_t)(get_spd(smb_idx, slot_idx, 194) & 0x0F) << 8 |
get_spd(smb_idx, slot_idx, 196);
spdi.tRC = (uint16_t)(tns/tckns);
} else {
// --------------------
// JEDEC Specifications
// --------------------
tckns = (uint8_t)get_spd(smb_idx, slot_idx, 12) * 0.125f +
(int8_t)get_spd(smb_idx, slot_idx, 134) * 0.001f;
// CAS# Latency
tns = (uint8_t)get_spd(smb_idx, slot_idx, 16) * 0.125f +
(int8_t)get_spd(smb_idx, slot_idx, 35) * 0.001f;
spdi.tCL = (uint16_t)(tns/tckns);
// RAS# to CAS# Latency
tns = (uint8_t)get_spd(smb_idx, slot_idx, 18) * 0.125f +
(int8_t)get_spd(smb_idx, slot_idx, 36) * 0.001f;
spdi.tRCD = (uint16_t)(tns/tckns);
// RAS# Precharge
tns = (uint8_t)get_spd(smb_idx, slot_idx, 20) * 0.125f +
(int8_t)get_spd(smb_idx, slot_idx, 37) * 0.001f;
spdi.tRP= (uint16_t)(tns/tckns);
// Row Active Time
tns = (uint8_t)get_spd(smb_idx, slot_idx, 22) * 0.125f +
(uint8_t)(get_spd(smb_idx, slot_idx, 21) & 0x0F) * 32.0f;
spdi.tRAS = (uint16_t)(tns/tckns);
// Row Cycle Time
tns = (uint8_t)get_spd(smb_idx, slot_idx, 23) * 0.125f +
(uint8_t)(get_spd(smb_idx, slot_idx, 21) >> 4) * 32.0f;
spdi.tRC = (uint16_t)(tns/tckns);
}
// Module manufacturer // Module manufacturer
spdi.jedec_code= (get_spd(smb_idx, slot_idx, 117) & 0x1F) << 8; spdi.jedec_code= (get_spd(smb_idx, slot_idx, 117) & 0x1F) << 8;
spdi.jedec_code |= get_spd(smb_idx, slot_idx, 118) & 0x7F; spdi.jedec_code |= get_spd(smb_idx, slot_idx, 118) & 0x7F;
@ -542,9 +728,94 @@ static spd_info parse_spd_ddr2(uint8_t smb_idx, uint8_t slot_idx)
spdi.hasECC = ((get_spd(smb_idx, slot_idx, 11) >> 1) == 1); spdi.hasECC = ((get_spd(smb_idx, slot_idx, 11) >> 1) == 1);
float tckns, tns;
uint8_t tbyte;
// Module EPP Detection (we only support Full profiles
uint8_t epp_offset = 0;
if (get_spd(smb_idx, slot_idx, 99) == 0x6D && get_spd(smb_idx, slot_idx, 102) == 0xB1) {
epp_offset = (get_spd(smb_idx, slot_idx, 103) & 0x3) * 12;
tbyte = get_spd(smb_idx, slot_idx, 109 + epp_offset);
spdi.XMP = 20;
} else {
tbyte = get_spd(smb_idx, slot_idx, 9);
}
// Module speed // Module speed
uint8_t spd_byte9 = get_spd(smb_idx, slot_idx, 9); tckns = (tbyte & 0xF0) >> 4;
spdi.freq = (float)(1.0f / (((spd_byte9 >> 4) * 10.0f) + (spd_byte9 & 0xF)) * 10000.0f * 2.0f); tbyte &= 0xF;
if (tbyte < 10) {
tckns += (tbyte & 0xF) * 0.1f;
} else if (tbyte == 10) {
tckns += 0.25f;
} else if (tbyte == 11) {
tckns += 0.33f;
} else if (tbyte == 12) {
tckns += 0.66f;
} else if (tbyte == 13) {
tckns += 0.75f;
} else if (tbyte == 14) { // EPP Specific
tckns += 0.875f;
}
spdi.freq = (float)(1.0f / tckns * 1000.0f * 2.0f);
if (spdi.XMP == 20) {
// Module Timings (EPP)
// CAS# Latency
tbyte = get_spd(smb_idx, slot_idx, 110 + epp_offset);
for (int shft = 0; shft < 7; shft++) {
if ((tbyte >> shft) & 1) {
spdi.tCL = shft;
break;
}
}
// RAS# to CAS# Latency
tbyte = get_spd(smb_idx, slot_idx, 111 + epp_offset);
tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f;
spdi.tRCD = (uint16_t)(tns/tckns);
// RAS# Precharge
tbyte = get_spd(smb_idx, slot_idx, 112 + epp_offset);
tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f;
spdi.tRP= (uint16_t)(tns/tckns);
// Row Active Time
tns = get_spd(smb_idx, slot_idx, 113 + epp_offset);
spdi.tRAS = (uint16_t)(tns/tckns);
// Row Cycle Time
tns = 0;
} else {
// Module Timings (JEDEC)
// CAS# Latency
tbyte = get_spd(smb_idx, slot_idx, 18);
for (int shft = 0; shft < 7; shft++) {
if ((tbyte >> shft) & 1) {
spdi.tCL = shft;
break;
}
}
// RAS# to CAS# Latency
tbyte = get_spd(smb_idx, slot_idx, 29);
tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f;
spdi.tRCD = (uint16_t)(tns/tckns);
// RAS# Precharge
tbyte = get_spd(smb_idx, slot_idx, 27);
tns = ((tbyte & 0xFC) >> 2) + (tbyte & 0x3) * 0.25f;
spdi.tRP= (uint16_t)(tns/tckns);
// Row Active Time
tns = get_spd(smb_idx, slot_idx, 30);
spdi.tRAS = (uint16_t)(tns/tckns);
// Row Cycle Time
tns = 0;
}
// Module manufacturer // Module manufacturer
uint8_t contcode; uint8_t contcode;
@ -627,8 +898,31 @@ static spd_info parse_spd_ddr(uint8_t smb_idx, uint8_t slot_idx)
spdi.hasECC = ((get_spd(smb_idx, slot_idx, 11) >> 1) == 1); spdi.hasECC = ((get_spd(smb_idx, slot_idx, 11) >> 1) == 1);
// Module speed // Module speed
float tns, tckns;
uint8_t spd_byte9 = get_spd(smb_idx, slot_idx, 9); uint8_t spd_byte9 = get_spd(smb_idx, slot_idx, 9);
spdi.freq = (float)(1.0f / (((spd_byte9 >> 4) * 10.0f) + (spd_byte9 & 0xF)) * 10000.0f * 2.0f); tckns = (spd_byte9 >> 4) + (spd_byte9 & 0xF) * 0.1f;
spdi.freq = (uint16_t)(1.0f / tckns* 1000.0f * 2.0f );
// Module Timings
uint8_t spd_byte18 = get_spd(smb_idx, slot_idx, 18);
for (int shft = 0; shft < 7; shft++) {
if ((spd_byte18 >> shft) & 1) {
spdi.tCL = 1.0f + shft * 0.5f; // TODO: .5 CAS
break;
}
}
tns = (get_spd(smb_idx, slot_idx, 29) >> 2) +
(get_spd(smb_idx, slot_idx, 29) & 0x3) * 0.25f;
spdi.tRCD = (uint16_t)(tns/tckns);
tns = (get_spd(smb_idx, slot_idx, 27) >> 2) +
(get_spd(smb_idx, slot_idx, 27) & 0x3) * 0.25f;
spdi.tRP= (uint16_t)(tns/tckns);
spdi.tRAS = (uint16_t)(get_spd(smb_idx, slot_idx, 30)/tckns);
spdi.tRC = 0;
// Module manufacturer // Module manufacturer
uint8_t contcode; uint8_t contcode;

View File

@ -63,7 +63,6 @@ typedef struct spd_infos {
bool isValid; bool isValid;
uint32_t module_size; uint32_t module_size;
uint8_t slot_num; uint8_t slot_num;
char *type;
uint16_t jedec_code; uint16_t jedec_code;
char sku[32]; char sku[32];
uint8_t sku_len; uint8_t sku_len;
@ -72,8 +71,25 @@ typedef struct spd_infos {
bool hasECC; bool hasECC;
uint8_t fab_year; uint8_t fab_year;
uint8_t fab_week; uint8_t fab_week;
uint16_t tCL;
uint16_t tRCD;
uint16_t tRP;
uint16_t tRAS;
uint16_t tRC;
char *type;
} spd_info; } spd_info;
typedef struct ram_infos {
uint16_t freq;
uint16_t tCL;
uint16_t tRCD;
uint16_t tRP;
uint16_t tRAS;
char *type;
} ram_info;
extern ram_info ram;
#define get_spd(smb_idx, slot_idx, spd_adr) \ #define get_spd(smb_idx, slot_idx, spd_adr) \
smbcontrollers[smb_idx].read_spd_byte(slot_idx, spd_adr) smbcontrollers[smb_idx].read_spd_byte(slot_idx, spd_adr)