diff --git a/app/display.c b/app/display.c index 055de39..ce23f7a 100644 --- a/app/display.c +++ b/app/display.c @@ -66,6 +66,8 @@ static bool timed_update_done = false; // update cycle status int scroll_message_row; +int display_mode = 0; // RAM Info from: 0 = N/A - 1 = SPD - 2 = IMC + int max_cpu_temp = 0; //------------------------------------------------------------------------------ @@ -217,6 +219,31 @@ void post_display_init(void) { print_smbios_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) diff --git a/app/display.h b/app/display.h index 3905078..fa415e8 100644 --- a/app/display.h +++ b/app/display.h @@ -73,7 +73,7 @@ prints(8, 7, "Core #"); \ printi(8, 13, cpu_num, 3, false, true) -#define display_all_active \ +#define display_all_active() \ prints(8, 7, "All Cores") #define display_spinner(spin_state) \ @@ -182,6 +182,8 @@ extern int scroll_message_row; +extern int display_mode; + void display_init(void); void display_cpu_topology(void); diff --git a/app/main.c b/app/main.c index 8769668..aed66e7 100644 --- a/app/main.c +++ b/app/main.c @@ -346,9 +346,13 @@ static void test_all_windows(int my_cpu) if (!dummy_run) { if (parallel_test) { num_active_cpus = num_enabled_cpus; - display_all_active; + if(display_mode == 0) { + display_all_active(); + } } else { - display_active_cpu(my_cpu); + if(display_mode == 0) { + display_active_cpu(my_cpu); + } } } barrier_reset(run_barrier, num_active_cpus); diff --git a/system/smbus.c b/system/smbus.c index f2b7645..75eaf86 100644 --- a/system/smbus.c +++ b/system/smbus.c @@ -17,6 +17,8 @@ #define LINE_SPD 13 #define MAX_SPD_SLOT 8 +ram_info ram = { 0, 0, 0, 0, 0, "N/A"}; + int smbdev, smbfun; unsigned short smbusbase; @@ -106,6 +108,7 @@ void print_smbus_startup_info(void) { uint8_t spdidx = 0, spd_line_idx = 0; spd_info curspd; + ram.freq = 0; index = find_smb_controller(); @@ -140,7 +143,7 @@ void print_smbus_startup_info(void) { break; } - if(curspd.isValid) { + if (curspd.isValid) { if(spd_line_idx == 0) { prints(LINE_SPD-2, 0, "Memory SPD Informations"); prints(LINE_SPD-1, 0, "-----------------------"); @@ -166,10 +169,17 @@ static void print_spdi(spd_info spdi, uint8_t lidx) spdi.freq); // Print ECC status - if(spdi.hasECC) { + if (spdi.hasECC) { 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 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(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); } @@ -190,13 +200,20 @@ static void print_spdi(spd_info spdi, uint8_t lidx) } // 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); } - // Print XMP Status - if(spdi.XMP > 0) { - curcol = prints(LINE_SPD+lidx, curcol, " *XMP*"); + // Populate global ram var + ram.type = spdi.type; + 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 - if((sbyte >> 5) > 1 && (sbyte >> 5) <= 5) { + if ((sbyte >> 5) > 1 && (sbyte >> 5) <= 5) { 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); // Channels per DIMM - if(((sbyte >> 5) & 3) == 1) { + if (((sbyte >> 5) & 3) == 1) { 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; // 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; } } // 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; - if(spdi.XMP == 3) { + if (spdi.XMP == 3) { // XMP 3.0 tCK = get_spd(smb_idx, slot_idx, 710) << 8; 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 = (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 spdi.jedec_code = (get_spd(smb_idx, slot_idx, 512) & 0x1F) << 8; spdi.jedec_code |= get_spd(smb_idx, slot_idx, 513) & 0x7F; - // Module SKU + // Module Timings uint8_t sku_byte; for (int j = 0; j <= 29; 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; } 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); - 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 - uint8_t tck_mtb = get_spd(smb_idx, slot_idx, 396); - int8_t tck_ftb = get_spd(smb_idx, slot_idx, 431); + tckns = (uint8_t)get_spd(smb_idx, slot_idx, 396) * 0.125f + + (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.XMP = 2; } else { // 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) { - default: - spdi.freq = 0; - break; - case 10: - spdi.freq = 1600; - break; - case 9: - spdi.freq = 1866; - break; - case 8: - spdi.freq = 2133; - break; - case 7: - spdi.freq = 2400; - break; - case 6: - spdi.freq = 2666; - break; - case 5: - spdi.freq = 3200; - break; - } + ramfreq = 1.0f / tckns * 2.0f * 1000.0f; + spdi.freq = (uint16_t)ramfreq; + + spdi.XMP = 0; + } + + // Module Timings + if (spdi.XMP == 2) { + // ------------------ + // XMP Specifications + // ------------------ + + // CAS# Latency + tns = (uint8_t)get_spd(smb_idx, slot_idx, 401) * 0.125f + + (int8_t)get_spd(smb_idx, slot_idx, 430) * 0.001f; + spdi.tCL = (uint16_t)(tns/tckns); + + // RAS# to CAS# Latency + tns = (uint8_t)get_spd(smb_idx, slot_idx, 402) * 0.125f + + (int8_t)get_spd(smb_idx, slot_idx, 429) * 0.001f; + spdi.tRCD = (uint16_t)(tns/tckns); + + // 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 @@ -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++) { 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--; break; } 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); - 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); spdi.XMP = 1; } // Module jedec speed - switch(tck) { + switch (tck) { default: spdi.freq = 0; break; @@ -471,6 +594,69 @@ static spd_info parse_spd_ddr3(uint8_t smb_idx, uint8_t slot_idx) 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 spdi.jedec_code= (get_spd(smb_idx, slot_idx, 117) & 0x1F) << 8; 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); + 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 - 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 = (tbyte & 0xF0) >> 4; + 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 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); // Module speed + float tns, tckns; 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 uint8_t contcode; diff --git a/system/smbus.h b/system/smbus.h index f564e50..55305b3 100644 --- a/system/smbus.h +++ b/system/smbus.h @@ -63,7 +63,6 @@ typedef struct spd_infos { bool isValid; uint32_t module_size; uint8_t slot_num; - char *type; uint16_t jedec_code; char sku[32]; uint8_t sku_len; @@ -72,8 +71,25 @@ typedef struct spd_infos { bool hasECC; uint8_t fab_year; uint8_t fab_week; + uint16_t tCL; + uint16_t tRCD; + uint16_t tRP; + uint16_t tRAS; + uint16_t tRC; + char *type; } 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) \ smbcontrollers[smb_idx].read_spd_byte(slot_idx, spd_adr)