mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2026-10-16 10:52:02 -05:00
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
This commit is contained in:
1 parent
2b51351ab7
commit
ced9529bea
18 files changed
+229
-96
No files matched your search
+13
-7
@@ -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, "<F5> CPU selection");
|
||||
if (!smp_enabled) set_foreground_colour(WHITE);
|
||||
//if (no_temperature) set_foreground_colour(BOLD+BLACK);
|
||||
printf(POP_R+8, POP_LI, "<F6> Temperature %s", enable_temperature ? "disable" : "enable ");
|
||||
//if (no_temperature) set_foreground_colour(WHITE);
|
||||
printf(POP_R+9, POP_LI, "<F7> Boot trace %s", enable_trace ? "disable" : "enable ");
|
||||
prints(POP_R+10, POP_LI, "<F10> Exit menu");
|
||||
printf(POP_R+8, POP_LI, "<F6> CPU Temperature %s", enable_temp_cpu ? "disable" : "enable ");
|
||||
printf(POP_R+9, POP_LI, "<F7> RAM Temperature %s", enable_temp_ram ? "disable" : "enable ");
|
||||
printf(POP_R+10, POP_LI, "<F8> Boot trace %s", enable_trace ? "disable" : "enable ");
|
||||
prints(POP_R+11, POP_LI, "<F10> Exit menu");
|
||||
} else {
|
||||
prints(POP_R+7, POP_LI, "<F5> Skip current test");
|
||||
prints(POP_R+8 , POP_LI, "<F10> 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;
|
||||
}
|
||||
|
||||
+3
-1
@@ -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;
|
||||
|
||||
+32
-17
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
+1
-1
@@ -260,7 +260,7 @@ static void global_init(void)
|
||||
|
||||
error_init();
|
||||
|
||||
temperature_init();
|
||||
cpu_temp_init();
|
||||
|
||||
initial_config();
|
||||
|
||||
|
||||
+3
-2
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+18
-2
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+26
-2
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
+62
-37
@@ -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);
|
||||
|
||||
@@ -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 <stdint.h>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user