2020-05-24 21:30:55 +01:00
// SPDX-License-Identifier: GPL-2.0
2022-01-31 22:59:14 +00:00
// Copyright (C) 2020-2022 Martin Whitaker.
2023-02-13 22:29:17 +01:00
// Copyright (C) 2004-2023 Sam Demeulemeester.
2020-05-24 21:30:55 +01:00
# include <stdint.h>
2023-05-18 16:03:48 +02:00
# include "config.h"
2020-05-24 21:30:55 +01:00
# include "cpuid.h"
# include "cpuinfo.h"
2023-02-13 22:29:17 +01:00
# include "hwquirks.h"
2023-05-18 16:03:48 +02:00
# include "memctrl.h"
2020-05-24 21:30:55 +01:00
# include "msr.h"
# include "pci.h"
# include "temperature.h"
2023-02-13 22:29:17 +01:00
//------------------------------------------------------------------------------
// Public Variables
//------------------------------------------------------------------------------
float cpu_temp_offset = 0 ;
2020-05-24 21:30:55 +01:00
//------------------------------------------------------------------------------
// Public Functions
//------------------------------------------------------------------------------
2023-02-18 18:43:38 +01:00
static int TjMax = 0 ;
void get_specific_TjMax ( void )
{
// The TjMax value for some Mobile/Embedded CPUs must be read from a fixed
// table according to their CPUID, PCI Root DID/VID or PNS.
// Trying to read the MSR 0x1A2 on some of them trigger a reboot.
if ( cpuid_info . version . raw [ 0 ] = = 0x6E8 ) {
2023-05-18 16:03:48 +02:00
// Yonah C0 Step (Pentium/Core Duo T2000 & Celeron M 200/400)
TjMax = 100 ;
} else if ( imc . family = = IMC_SLT | | imc . family = = IMC_CLT | | imc . family = = IMC_TNC ) {
// Atom Silverthorne / Diamondvile
// Atom Clover Trail/Cloverview
// Atom Tunnel Creek / Lincroft
TjMax = 90 ;
} else if ( imc . family = = IMC_CDT | | imc . family = = IMC_PNV ) {
// Atom Silverthorne / Diamondvile
// Atom Cedar Trail/Cedarview
2023-02-18 18:43:38 +01:00
TjMax = 100 ;
}
}
2023-02-13 22:29:17 +01:00
void temperature_init ( void )
2020-05-24 21:30:55 +01:00
{
2023-02-18 18:43:38 +01:00
uint32_t regl , regh ;
2023-05-18 16:03:48 +02:00
if ( ! enable_temperature ) {
return ;
}
2023-02-13 22:29:17 +01:00
// Process temperature-related quirks
if ( quirk . type & QUIRK_TYPE_TEMP ) {
quirk . process ( ) ;
}
2023-02-18 18:43:38 +01:00
// Get TjMax for Intel CPU
if ( cpuid_info . vendor_id . str [ 0 ] = = ' G ' & & cpuid_info . max_cpuid > = 6 & & ( cpuid_info . dts_pmp & 1 ) ) {
get_specific_TjMax ( ) ;
if ( TjMax = = 0 ) {
// Generic Method using MSR 0x1A2
rdmsr ( MSR_IA32_TEMPERATURE_TARGET , regl , regh ) ;
TjMax = ( regl > > 16 ) & 0x7F ;
if ( TjMax < 50 | | TjMax > 125 ) {
TjMax = 100 ;
}
}
}
2023-02-13 22:29:17 +01:00
}
2020-05-24 21:30:55 +01:00
2023-02-13 22:29:17 +01:00
int get_cpu_temperature ( void )
{
2023-02-18 18:43:38 +01:00
uint32_t regl , regh ;
2020-05-24 21:30:55 +01:00
2023-02-18 18:43:38 +01:00
// Intel CPU
if ( cpuid_info . vendor_id . str [ 0 ] = = ' G ' & & cpuid_info . max_cpuid > = 6 & & ( cpuid_info . dts_pmp & 1 ) ) {
2020-05-24 21:30:55 +01:00
2023-02-18 18:43:38 +01:00
rdmsr ( MSR_IA32_THERM_STATUS , regl , regh ) ;
int Tabs = ( regl > > 16 ) & 0x7F ;
2020-05-24 21:30:55 +01:00
2023-02-18 18:43:38 +01:00
return TjMax - Tabs ;
2020-05-24 21:30:55 +01:00
}
// AMD CPU
2023-02-13 22:29:17 +01:00
else if ( cpuid_info . vendor_id . str [ 0 ] = = ' A ' & & cpuid_info . version . family = = 0xF ) { // Target only K8 & newer
if ( cpuid_info . version . extendedFamily > = 8 ) { // Target Zen µarch and newer. Use SMN to get temperature.
2022-03-10 01:23:29 +01:00
2023-02-18 18:43:38 +01:00
regl = amd_smn_read ( SMN_THM_TCON_CUR_TMP ) ;
2022-03-10 01:23:29 +01:00
2023-02-18 18:43:38 +01:00
if ( ( regl > > 19 ) & 0x01 ) {
cpu_temp_offset = - 49.0f ;
2023-02-13 22:29:17 +01:00
}
2022-03-10 01:23:29 +01:00
2023-02-18 18:43:38 +01:00
return cpu_temp_offset + 0.125f * ( float ) ( ( regl > > 21 ) & 0x7FF ) ;
2022-03-10 01:23:29 +01:00
2024-11-11 22:49:31 +00:00
} else if ( cpuid_info . version . extendedFamily = = 6 & & ( cpuid_info . version . extendedModel = = 6 | | cpuid_info . version . extendedModel = = 7 ) ) { // Target family 15h (Excavator)
pci_config_write32 ( 0 , 0 , 0 , AMD_SMU_INDEX_ADDR_REG , AMD_F15_M60H_TEMP_CTRL_OFFSET ) ;
regl = pci_config_read32 ( 0 , 0 , 0 , AMD_SMU_INDEX_DATA_REG ) ;
int raw_temp = ( ( regl > > 21 ) & 0x7FF ) / 8 ;
return ( raw_temp > 0 ) ? raw_temp : 0 ;
2023-02-13 22:29:17 +01:00
} else if ( cpuid_info . version . extendedFamily > 0 ) { // Target K10 to K15 (Bulldozer)
2022-03-10 01:23:29 +01:00
2023-02-18 18:43:38 +01:00
regl = pci_config_read32 ( 0 , 24 , 3 , AMD_TEMP_REG_K10 ) ;
int raw_temp = ( ( regl > > 21 ) & 0x7FF ) / 8 ;
2022-03-10 01:23:29 +01:00
2023-02-13 22:29:17 +01:00
return ( raw_temp > 0 ) ? raw_temp : 0 ;
2022-03-10 01:23:29 +01:00
2023-02-13 22:29:17 +01:00
} else { // Target K8 (CPUID ExtFamily = 0)
2023-02-18 18:43:38 +01:00
regl = pci_config_read32 ( 0 , 24 , 3 , AMD_TEMP_REG_K8 ) ;
int raw_temp = ( ( regl > > 16 ) & 0xFF ) - 49 + cpu_temp_offset ;
2023-02-13 22:29:17 +01:00
return ( raw_temp > 0 ) ? raw_temp : 0 ;
}
2020-05-24 21:30:55 +01:00
}
2023-02-10 21:32:31 +00:00
// VIA/Centaur/Zhaoxin CPU
else if ( cpuid_info . vendor_id . str [ 0 ] = = ' C ' & & cpuid_info . vendor_id . str [ 1 ] = = ' e '
& & ( cpuid_info . version . family = = 6 | | cpuid_info . version . family = = 7 ) ) {
2023-02-18 18:43:38 +01:00
uint32_t msr_temp ;
2023-02-10 21:32:31 +00:00
if ( cpuid_info . version . family = = 7 | | cpuid_info . version . model = = 0xF ) {
2023-02-13 22:29:17 +01:00
msr_temp = MSR_VIA_TEMP_NANO ; // Zhaoxin, Nano
2023-02-10 21:32:31 +00:00
} else if ( cpuid_info . version . model = = 0xA | | cpuid_info . version . model = = 0xD ) {
2023-02-13 22:29:17 +01:00
msr_temp = MSR_VIA_TEMP_C7 ; // C7 A/D
2023-02-10 21:32:31 +00:00
} else {
return 0 ;
}
2023-02-18 18:43:38 +01:00
rdmsr ( msr_temp , regl , regh ) ;
return ( int ) ( regl & 0xffffff ) ;
2023-02-10 21:32:31 +00:00
}
2020-05-24 21:30:55 +01:00
return 0 ;
}