From ced9529bea0ac1db273d74e5d0de8ea2a5ea43f5 Mon Sep 17 00:00:00 2001 From: Sam Demeulemeester <38105886+x86fr@users.noreply.github.com> Date: Mon, 6 Oct 2025 23:01:33 +0200 Subject: [PATCH] DDR5 DIMM Temperature Reporting (#497) * Initial commit for DDR5 Temperature report * Change smbus.h to i2c_x86.h * Change I2C includes defines name to avoid conflict * Add dummy get_ram_temp() function on LA64 * Add menu option for RAM/DDR5 Temperature polling --- app/config.c | 20 ++++--- app/config.h | 4 +- app/display.c | 49 +++++++++++------ app/display.h | 9 ++++ app/main.c | 2 +- system/hwquirks.c | 5 +- system/{smbus.h => i2c_x86.h} | 9 ++-- system/imc/x86/amd_zen.c | 7 +-- system/loongarch/i2c.c | 2 +- system/loongarch/i2c.h | 6 +-- system/loongarch/temperature.c | 11 ++-- system/serial.h | 2 +- system/spd.c | 20 ++++++- system/spd.h | 28 +++++++++- system/temperature.h | 12 +++-- system/x86/cpuinfo.c | 8 +-- system/x86/i2c.c | 99 +++++++++++++++++++++------------- system/x86/temperature.c | 32 +++++++++-- 18 files changed, 229 insertions(+), 96 deletions(-) rename system/{smbus.h => i2c_x86.h} (96%) diff --git a/app/config.c b/app/config.c index 083ea3a..f96c143 100644 --- a/app/config.c +++ b/app/config.c @@ -92,9 +92,11 @@ bool exclude_ecores = true; bool smp_enabled = true; bool enable_big_status = true; -bool enable_temperature = true; bool enable_trace = false; +bool enable_temp_cpu = true; +bool enable_temp_ram = false; // DDR5+ temperature polling + bool enable_sm = true; bool enable_bench = true; bool enable_mch_read = true; @@ -901,11 +903,10 @@ void config_menu(bool initial) if (!smp_enabled) set_foreground_colour(BOLD+BLACK); prints(POP_R+7, POP_LI, " CPU selection"); if (!smp_enabled) set_foreground_colour(WHITE); - //if (no_temperature) set_foreground_colour(BOLD+BLACK); - printf(POP_R+8, POP_LI, " Temperature %s", enable_temperature ? "disable" : "enable "); - //if (no_temperature) set_foreground_colour(WHITE); - printf(POP_R+9, POP_LI, " Boot trace %s", enable_trace ? "disable" : "enable "); - prints(POP_R+10, POP_LI, " Exit menu"); + printf(POP_R+8, POP_LI, " CPU Temperature %s", enable_temp_cpu ? "disable" : "enable "); + printf(POP_R+9, POP_LI, " RAM Temperature %s", enable_temp_ram ? "disable" : "enable "); + printf(POP_R+10, POP_LI, " Boot trace %s", enable_trace ? "disable" : "enable "); + prints(POP_R+11, POP_LI, " Exit menu"); } else { prints(POP_R+7, POP_LI, " Skip current test"); prints(POP_R+8 , POP_LI, " Exit menu"); @@ -942,10 +943,15 @@ void config_menu(bool initial) break; case '6': if (initial) { - enable_temperature = !enable_temperature; + enable_temp_cpu = !enable_temp_cpu; } break; case '7': + if (initial) { + enable_temp_ram = !enable_temp_ram; + } + break; + case '8': if (initial) { enable_trace = !enable_trace; } diff --git a/app/config.h b/app/config.h index b852001..8470841 100644 --- a/app/config.h +++ b/app/config.h @@ -54,9 +54,11 @@ extern bool exclude_ecores; extern bool smp_enabled; extern bool enable_big_status; -extern bool enable_temperature; extern bool enable_trace; +extern bool enable_temp_cpu; +extern bool enable_temp_ram; + extern bool enable_sm; extern bool enable_tty; extern bool enable_bench; diff --git a/app/display.c b/app/display.c index ecc55ca..b7739b3 100644 --- a/app/display.c +++ b/app/display.c @@ -8,13 +8,13 @@ #include "cpuid.h" #include "cpuinfo.h" #include "hwctrl.h" +#include "i2c_x86.h" #include "io.h" #include "keyboard.h" #include "memctrl.h" #include "serial.h" #include "pmem.h" #include "smbios.h" -#include "smbus.h" #include "spd.h" #include "temperature.h" #include "tsc.h" @@ -402,27 +402,42 @@ void display_error_count(void) void display_temperature(void) { - if (!enable_temperature) { - return; - } + if (enable_temp_cpu) { + // Display CPU Temperature + int actual_cpu_temp = get_cpu_temp(); - int actual_cpu_temp = get_cpu_temperature(); - - if (actual_cpu_temp == 0) { - if (max_cpu_temp == 0) { - enable_temperature = false; + if (actual_cpu_temp == 0) { + if (max_cpu_temp == 0) { + enable_temp_cpu = false; + } + return; } - return; + + if (max_cpu_temp < actual_cpu_temp ) { + max_cpu_temp = actual_cpu_temp; + } + + int offset = actual_cpu_temp / 100 + max_cpu_temp / 100; + display_cpu_temperature(actual_cpu_temp, max_cpu_temp, offset); } - if (max_cpu_temp < actual_cpu_temp ) { - max_cpu_temp = actual_cpu_temp; + if (enable_temp_ram) { + // Display RAM Temperature (DDR5+ Only) - LA64 unsupported yet + if (dmi_memory_device->type == DMI_DDR5 && !strstr(cpuid_info.vendor_id.str, "Loongson")) { + + for (int i = 0; i < MAX_SPD_SLOT; i++) { + + if (!ram_slot_info[i].isPopulated || !ram_slot_info[i].hasTempSensor) + continue; + + int ram_temp = get_ram_temp(i); + + if (ram_temp > 0) { + display_ram_temperature(ram_temp, ram_slot_info[i].display_idx) + } + } + } } - - int offset = actual_cpu_temp / 100 + max_cpu_temp / 100; - - clear_screen_region(1, 18, 1, 22); - printf(1, 20-offset, "%2i/%2i%cC", actual_cpu_temp, max_cpu_temp, 0xF8); } void display_big_status(bool pass) diff --git a/app/display.h b/app/display.h index 71b711a..02b5f35 100644 --- a/app/display.h +++ b/app/display.h @@ -47,6 +47,12 @@ typedef enum { #define display_cpu_clk(freq) \ printf(1, 10, "%iMHz", freq) +#define display_cpu_temperature(actual_cpu_temp, max_cpu_temp, offset) \ + { \ + clear_screen_region(1, 18, 1, 22); \ + printf(1, 20-offset, "%2i/%2i%cC", actual_cpu_temp, max_cpu_temp, 0xF8); \ + } + #define display_cpu_addr_mode(str) \ prints(4, 75, str) @@ -74,6 +80,9 @@ typedef enum { #define display_ram_speed(speed) \ printf(5, 18, "%S6kB/s", (uintptr_t)(speed)) +#define display_ram_temperature(ram_temp, idx) \ + printf(idx+ROW_SPD, SCREEN_WIDTH-4, "%i%cC", ram_temp, 0xF8); + #define display_status(status) \ prints(7, 68, status) diff --git a/app/main.c b/app/main.c index 7a2634f..f1a709d 100644 --- a/app/main.c +++ b/app/main.c @@ -260,7 +260,7 @@ static void global_init(void) error_init(); - temperature_init(); + cpu_temp_init(); initial_config(); diff --git a/system/hwquirks.c b/system/hwquirks.c index 7dd749a..359209a 100644 --- a/system/hwquirks.c +++ b/system/hwquirks.c @@ -99,7 +99,7 @@ static void get_vt82c597_mb_cache_size(void) static void disable_temp_reporting(void) { - enable_temperature = false; + enable_temp_cpu = false; } static void amd_k8_revfg_temp(void) @@ -168,7 +168,8 @@ static void unhide_asus_smbus(void) if ((smb_ctrl_reg & 1) == 0) { return; } // Read MMIO at offset 0x3418 - uint32_t *ptr = (uint32_t *)((smb_ctrl_reg & 0xFFFFC000) + 0x3418); + uintptr_t base = (uintptr_t)(smb_ctrl_reg & ~0x3FFFu); + uint32_t *ptr = (uint32_t *)(base + 0x3418u); // Set Bit 3 to 0 to enable SMBUS Controler *ptr &= ~(1u << 3); diff --git a/system/smbus.h b/system/i2c_x86.h similarity index 96% rename from system/smbus.h rename to system/i2c_x86.h index 783f6fe..1b340d5 100644 --- a/system/smbus.h +++ b/system/i2c_x86.h @@ -1,5 +1,5 @@ -#ifndef _SMBUS_H_ -#define _SMBUS_H_ +#ifndef _I2C_X86_H_ +#define _I2C_X86_H_ /** * SPDX-License-Identifier: GPL-2.0 * @@ -13,8 +13,6 @@ #define I2C_WRITE 0 #define I2C_READ 1 -#define SPD5_MR11 11 - /* i801 Hosts Addresses */ #define SMBHSTSTS smbusbase #define SMBHSTCNT smbusbase + 2 @@ -116,5 +114,6 @@ struct pci_smbus_controller { void print_spd_startup_info(void); uint8_t get_spd(uint8_t slot_idx, uint16_t spd_adr); +uint8_t get_spd_hub_register(uint8_t slot_idx, uint8_t spd_hub_adr); -#endif // SMBUS_H +#endif // I2C_X86_H diff --git a/system/imc/x86/amd_zen.c b/system/imc/x86/amd_zen.c index dae9ba2..4d87755 100644 --- a/system/imc/x86/amd_zen.c +++ b/system/imc/x86/amd_zen.c @@ -45,9 +45,6 @@ void get_imc_config_amd_zen(void) uint32_t smn_reg, offset; uint32_t reg_cha, reg_chb; - /* Select UMC MCA MSR base */ - uint32_t mca_ctrl_base = (imc.family >= IMC_K1A_GRG) ? MSR_AMD64_K1A_UMC_MCA_CTRL : MSR_AMD64_K17_UMC_MCA_CTRL; - imc.tCL_dec = 0; // Get Memory Mapped Register Base Address (Enable MMIO if needed) @@ -95,6 +92,10 @@ void get_imc_config_amd_zen(void) // Detect ECC (x64 only) #if TESTWORD_WIDTH > 32 + + /* Select UMC MCA MSR base */ + uint32_t mca_ctrl_base = (imc.family >= IMC_K1A_GRG) ? MSR_AMD64_K1A_UMC_MCA_CTRL : MSR_AMD64_K17_UMC_MCA_CTRL; + if (enable_ecc_polling) { uint32_t regl, regh; diff --git a/system/loongarch/i2c.c b/system/loongarch/i2c.c index 4a9f4bb..d0de089 100644 --- a/system/loongarch/i2c.c +++ b/system/loongarch/i2c.c @@ -9,7 +9,7 @@ #include "cpuid.h" #include "memrw.h" #include "vmem.h" -#include "smbus.h" +#include "i2c_x86.h" #include "i2c.h" #include "spd.h" diff --git a/system/loongarch/i2c.h b/system/loongarch/i2c.h index 3accbdd..aa77013 100644 --- a/system/loongarch/i2c.h +++ b/system/loongarch/i2c.h @@ -8,8 +8,8 @@ * */ -#ifndef _I2C_H_ -#define _I2C_H_ +#ifndef _I2C_LA64_H_ +#define _I2C_LA64_H_ #define PRER_LO_REG 0x0 #define PRER_HI_REG 0x1 @@ -66,4 +66,4 @@ typedef struct { i2c_slot_param i2c_mc[4]; } i2c_param; -#endif // I2C_H +#endif // I2C_LA64_H diff --git a/system/loongarch/temperature.c b/system/loongarch/temperature.c index ca68a9c..8050fa6 100644 --- a/system/loongarch/temperature.c +++ b/system/loongarch/temperature.c @@ -23,9 +23,9 @@ float cpu_temp_offset = 0; // Public Functions //------------------------------------------------------------------------------ -void temperature_init(void) +void cpu_temp_init(void) { - if (!enable_temperature) { + if (!enable_temp_cpu) { return; } @@ -35,7 +35,12 @@ void temperature_init(void) } } -int get_cpu_temperature(void) +int get_cpu_temp(void) { return (int)(__iocsrrd_w(0x428)); } + +int get_ram_temp(uint8_t slot) +{ + return 0; +} diff --git a/system/serial.h b/system/serial.h index df5f97c..f9239aa 100644 --- a/system/serial.h +++ b/system/serial.h @@ -156,7 +156,7 @@ struct serial_port { #define tty_partial_redraw() \ tty_send_region(1, 34, 5, 79); \ tty_send_region(7, 0, 8, 79); \ - if(enable_temperature) tty_send_region(1, 16, 1, 26); + if(enable_temp_cpu) tty_send_region(1, 16, 1, 26); #define tty_error_redraw() \ tty_send_region(10, 0, 23, 79); diff --git a/system/spd.c b/system/spd.c index f53c4dd..666dff5 100644 --- a/system/spd.c +++ b/system/spd.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (C) 2004-2023 Sam Demeulemeester +// Copyright (C) 2004-2025 Sam Demeulemeester #include "stdbool.h" #include "stdint.h" #include "string.h" -#include "smbus.h" +#include "i2c_x86.h" #include "spd.h" #include "jedec_id.h" #include "print.h" @@ -20,6 +20,7 @@ #define ROUNDING_FACTOR 0.9f ram_info_t ram = { 0, 0, 0, 0, 0, 0, "N/A"}; +ram_slot_info_t ram_slot_info[MAX_SPD_SLOT]; static inline uint8_t bcd_to_ui8(uint8_t bcd) { @@ -296,6 +297,9 @@ static void parse_spd_ddr5(spd_info *spdi, uint8_t slot_idx) spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 515)); spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 516)); + // All DDR5s should have temperature sensor. Add a check if proved wrong. + spdi->hasTempSensor = true; + spdi->isValid = true; } @@ -415,6 +419,8 @@ static void parse_spd_ddr4(spd_info *spdi, uint8_t slot_idx) spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 323)); spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 324)); + spdi->hasTempSensor = false; + spdi->isValid = true; } @@ -572,6 +578,8 @@ static void parse_spd_ddr3(spd_info *spdi, uint8_t slot_idx) spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 120)); spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 121)); + spdi->hasTempSensor = false; + spdi->isValid = true; } @@ -709,6 +717,8 @@ static void parse_spd_ddr2(spd_info *spdi, uint8_t slot_idx) spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 93)); spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 94)); + spdi->hasTempSensor = false; + spdi->isValid = true; } @@ -798,6 +808,8 @@ static void parse_spd_ddr(spd_info *spdi, uint8_t slot_idx) spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 93)); spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 94)); + spdi->hasTempSensor = false; + spdi->isValid = true; } @@ -871,6 +883,8 @@ static void parse_spd_rdram(spd_info *spdi, uint8_t slot_idx) spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 93)); spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 94)); + spdi->hasTempSensor = false; + spdi->isValid = true; } @@ -937,6 +951,8 @@ static void parse_spd_sdram(spd_info *spdi, uint8_t slot_idx) spdi->fab_year = bcd_to_ui8(get_spd(slot_idx, 93)); spdi->fab_week = bcd_to_ui8(get_spd(slot_idx, 94)); + spdi->hasTempSensor = false; + spdi->isValid = true; } diff --git a/system/spd.h b/system/spd.h index e6edd23..980f591 100644 --- a/system/spd.h +++ b/system/spd.h @@ -7,10 +7,25 @@ * * Provides access to SPD parsing and printing functions. * - * Copyright (C) 2004-2023 Sam Demeulemeester. + * Copyright (C) 2004-2025 Sam Demeulemeester. */ -#define SPD_SKU_LEN 32 +#define MAX_SPD_SLOT 8 +#define SPD_SKU_LEN 32 + +/* DDR5 SPD Hub Configuration Registers */ + +#define SPD5_HUB_ID_MSB 0x00 // MR0 - Device Type MSB +#define SPD5_HUB_ID_LSB 0x01 // MR1 - Device Type LSB (0x18 = w/ Temp Sensor) +#define SPD5_HUB_CAP 0x05 // MR5 - Device Capability (Bit 1 = Temp Sensor Support) +#define SPD5_HUB_I2C_CONF 0x0B // MR11 - I²C Legacy Mode Device Configuration +#define SPD5_HUB_CONF 0x12 // MR18 - General Device Configuration +#define SPD5_HUB_TS_CONF 0x1A // MR26 - Temperature Sensor Configuration (Bit 0 = 1 for Disable) +#define SPD5_HUB_TS_RES 0x24 // MR36 - TS Resolution (from 9- to 12-bit) +#define SPD5_HUB_STATUS 0x30 // MR48 - Device Status +#define SPD5_HUB_TS_LSB 0x31 // MR49 - TS Current Sensed Temperature - Low Byte +#define SPD5_HUB_TS_MSB 0x32 // MR50 - TS Current Sensed Temperature - High Byte +#define SPD5_HUB_TS_STATUS 0x33 // MR51 - Temperature Sensor Status typedef struct spd_infos { bool isValid; @@ -22,6 +37,7 @@ typedef struct spd_infos { uint8_t XMP; uint16_t freq; bool hasECC; + bool hasTempSensor; uint8_t fab_year; uint8_t fab_week; uint16_t tCL; @@ -42,7 +58,15 @@ typedef struct ram_infos { char *type; } ram_info_t; +typedef struct { + uint8_t slot_idx; + uint8_t display_idx; + bool isPopulated; + bool hasTempSensor; +} ram_slot_info_t; + extern ram_info_t ram; +extern ram_slot_info_t ram_slot_info[MAX_SPD_SLOT]; void print_spdi(spd_info spdi, uint8_t lidx); void parse_spd(spd_info *spdi, uint8_t slot_idx); diff --git a/system/temperature.h b/system/temperature.h index 65cc798..68de57d 100644 --- a/system/temperature.h +++ b/system/temperature.h @@ -8,7 +8,7 @@ * *//* * Copyright (C) 2020-2022 Martin Whitaker. - * Copyright (C) 2003-2023 Sam Demeulemeester. + * Copyright (C) 2003-2025 Sam Demeulemeester. */ #define AMD_TEMP_REG_K8 0xE4 @@ -30,12 +30,18 @@ extern float cpu_temp_offset; /** * Init temperature sensor and compute offsets if needed */ -void temperature_init(void); +void cpu_temp_init(void); /** * Returns the current temperature of the CPU. Returns 0 if * the temperature cannot be read. */ -int get_cpu_temperature(void); +int get_cpu_temp(void); + +/** + * Returns the current temperature of the RAM. Returns 0 if + * the temperature cannot be read. Only for DDR5 + */ +int get_ram_temp(uint8_t slot); #endif // TEMPERATURE_H diff --git a/system/x86/cpuinfo.c b/system/x86/cpuinfo.c index c4d3bf7..f6494e5 100644 --- a/system/x86/cpuinfo.c +++ b/system/x86/cpuinfo.c @@ -396,7 +396,7 @@ static void determine_imc(void) break; case 0x3: imc.family = IMC_CLT; - enable_temperature = false; // Atom Clover Trail + enable_temp_cpu = false; // Atom Clover Trail break; case 0x4: imc.family = IMC_HSW_ULT; // Core 4th Gen (Haswell-ULT) @@ -413,11 +413,11 @@ static void determine_imc(void) switch (cpuid_info.version.extendedModel) { case 0x2: imc.family = IMC_TNC; // Atom Tunnel Creek / Lincroft - enable_temperature = false; + enable_temp_cpu = false; break; case 0x3: imc.family = IMC_CDT; // Atom Cedar Trail - enable_temperature = false; + enable_temp_cpu = false; break; case 0x4: imc.family = IMC_HSW; // Core 4th Gen (Haswell w/ GT3e) @@ -491,7 +491,7 @@ static void determine_imc(void) } else { imc.family = IMC_SLT; // Atom Silverthorne / Diamondvile } - enable_temperature = false; + enable_temp_cpu = false; break; case 0x2: imc.family = IMC_WMR; // Core i7 1st Gen 32 nm (Westmere) diff --git a/system/x86/i2c.c b/system/x86/i2c.c index 97956e6..5639065 100644 --- a/system/x86/i2c.c +++ b/system/x86/i2c.c @@ -11,13 +11,11 @@ #include "macros.h" #include "cpuinfo.h" +#include "hwquirks.h" +#include "i2c_x86.h" #include "memctrl.h" -#include "smbus.h" #include "smbios.h" #include "spd.h" -#include "hwquirks.h" - -#define MAX_SPD_SLOT 8 int smbbus, smbdev, smbfun; unsigned short smbusbase = 0; @@ -60,9 +58,16 @@ void print_spd_startup_info(void) for (spdidx = 0; spdidx < MAX_SPD_SLOT; spdidx++) { parse_spd(&curspd, spdidx); + ram_slot_info[spdidx].slot_idx = spdidx; + ram_slot_info[spdidx].isPopulated = curspd.isValid; + ram_slot_info[spdidx].hasTempSensor = false; + if (!curspd.isValid) continue; + ram_slot_info[spdidx].display_idx = spd_line_idx; + ram_slot_info[spdidx].hasTempSensor = curspd.hasTempSensor; + if (spd_line_idx == 0) { prints(ROW_SPD-2, 0, "Memory SPD Information"); prints(ROW_SPD-1, 0, "----------------------"); @@ -523,9 +528,9 @@ static bool ali_get_smb(uint8_t address) return false; } -// ------------------ -// get_spd() function -// ------------------ +// -------------------- +// SPD Read functions +// -------------------- uint8_t get_spd(uint8_t slot_idx, uint16_t spd_adr) { @@ -542,6 +547,15 @@ uint8_t get_spd(uint8_t slot_idx, uint16_t spd_adr) } } +uint8_t get_spd_hub_register(uint8_t slot_idx, uint8_t spd_hub_adr) +{ + if(dmi_memory_device->type == DMI_DDR5) { + return ich5_read_spd_byte(slot_idx, spd_hub_adr | 0xFF00); + } + + return 0; +} + /************************************************************************************* / ***************************** WARNING ***************************** / ************************************************************************************ @@ -575,44 +589,55 @@ static uint8_t ich5_read_spd_byte(uint8_t smbus_adr, uint16_t spd_adr) spd_adr -= 0x100; } } else if (dmi_memory_device->type == DMI_DDR5) { - // Switch page if needed (DDR5) - uint8_t adr_page = spd_adr / 128; + // For DDR5, choose between reading from the SPD EEPROM (which may require a bank switch) + // and reading from the DDR5 SPD Hub Register (where we added a 0xFF00 offset). - if (adr_page != spd_page || last_adr != smbus_adr) { + if (spd_adr >> 8 != 0xFF) { + // DDR5 SPD Read (7-bit address translated to 0x80-0xFF) + // Switch page if needed (pages are 7-bit/128 bytes wide) + uint8_t adr_page = spd_adr / 128; - // DDR5 SPD Bank switch can be achieved using 2 methods - if(((smbus_id >> 16) & 0xFFFF) == PCI_VID_INTEL) { - // On Intel, we use the process call method because the SMBUS write command - // is sometimes disabled by BIOS to avoid unexpected SPD corruption - __outb((smbus_adr << 1) | I2C_READ, SMBHSTADD); - __outb(SPD5_MR11 & 0x7F, SMBHSTCMD); - __outb(adr_page & 7, SMBHSTDAT0); - __outb(0, SMBHSTDAT1); - __outb(SMBHSTCNT_PROC_CALL, SMBHSTCNT); + if (adr_page != spd_page || last_adr != smbus_adr) { - ich5_process(); + // DDR5 SPD Bank switch can be achieved using 2 methods + if(((smbus_id >> 16) & 0xFFFF) == PCI_VID_INTEL) { + // On Intel, we use the process call method because the SMBUS write command + // is sometimes disabled by BIOS to avoid unexpected SPD corruption + __outb((smbus_adr << 1) | I2C_READ, SMBHSTADD); + __outb(SPD5_HUB_I2C_CONF & 0x7F, SMBHSTCMD); + __outb(adr_page & 7, SMBHSTDAT0); + __outb(0, SMBHSTDAT1); + __outb(SMBHSTCNT_PROC_CALL, SMBHSTCNT); - // These dummy read are mandatory to terminate a Proc Call - __inb(SMBHSTDAT0); - __inb(SMBHSTDAT1); + ich5_process(); - } else { - // On AMD, we continue to use the standard smbus write command as it seems - // more reliable than the process call method. This may be reevaluated later. - __outb((smbus_adr << 1) | I2C_WRITE, SMBHSTADD); - __outb(SPD5_MR11 & 0x7F, SMBHSTCMD); - __outb(adr_page & 7, SMBHSTDAT0); - __outb(SMBHSTCNT_BYTE_DATA, SMBHSTCNT); + // These dummy read are mandatory to terminate a Proc Call + __inb(SMBHSTDAT0); + __inb(SMBHSTDAT1); - ich5_process(); - } + } else { + // On AMD, we continue to use the standard smbus write command as it seems + // more reliable than the process call method. This may be reevaluated later. + __outb((smbus_adr << 1) | I2C_WRITE, SMBHSTADD); + __outb(SPD5_HUB_I2C_CONF & 0x7F, SMBHSTCMD); + __outb(adr_page & 7, SMBHSTDAT0); + __outb(SMBHSTCNT_BYTE_DATA, SMBHSTCNT); - spd_page = adr_page; - last_adr = smbus_adr; - } + ich5_process(); + } - spd_adr -= adr_page * 128; - spd_adr |= 0x80; + spd_page = adr_page; + last_adr = smbus_adr; + } + + // Get final I2C byte address on the current page (0x00-0x7F -> 0x80-0xFF). + spd_adr -= adr_page * 128; + spd_adr |= 0x80; + + } else { + // SPD5 Hub Register Read (7-bit address at 0x00 - 0x7F) + spd_adr &= 0x7F; + } } __outb((smbus_adr << 1) | I2C_READ, SMBHSTADD); diff --git a/system/x86/temperature.c b/system/x86/temperature.c index 7b9ec08..c6d50a9 100644 --- a/system/x86/temperature.c +++ b/system/x86/temperature.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020-2022 Martin Whitaker. -// Copyright (C) 2004-2023 Sam Demeulemeester. +// Copyright (C) 2004-2025 Sam Demeulemeester. #include @@ -8,9 +8,12 @@ #include "cpuid.h" #include "cpuinfo.h" #include "hwquirks.h" +#include "i2c_x86.h" #include "memctrl.h" #include "msr.h" #include "pci.h" +#include "smbios.h" +#include "spd.h" #include "temperature.h" @@ -47,11 +50,11 @@ void get_specific_TjMax(void) } } -void temperature_init(void) +void cpu_temp_init(void) { uint32_t regl, regh; - if (!enable_temperature) { + if (!enable_temp_cpu) { return; } @@ -77,7 +80,7 @@ void temperature_init(void) } } -int get_cpu_temperature(void) +int get_cpu_temp(void) { uint32_t regl, regh; @@ -147,3 +150,24 @@ int get_cpu_temperature(void) return 0; } + +int get_ram_temp(uint8_t slot) +{ + uint16_t temp_reg; + float ram_temp; + + // RAM Temperature is only supported on DDR5 + if (dmi_memory_device->type != DMI_DDR5 || slot >= MAX_SPD_SLOT) + return 0; + + // Check if slot has a temp sensor + if (ram_slot_info[slot].isPopulated == false || ram_slot_info[slot].hasTempSensor == false) + return 0; + + temp_reg = get_spd_hub_register(slot, SPD5_HUB_TS_LSB); + temp_reg |= get_spd_hub_register(slot, SPD5_HUB_TS_MSB) << 8; + + ram_temp = (temp_reg >> 2) / 4.0f; + + return ram_temp; +}