diff --git a/SMCRadeonSensors/AMDCommon.hpp b/SMCRadeonSensors/AMDCommon.hpp index 570aa74..01df47e 100644 --- a/SMCRadeonSensors/AMDCommon.hpp +++ b/SMCRadeonSensors/AMDCommon.hpp @@ -1,5 +1,5 @@ -// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. See LICENSE for -// details. +// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. +// See LICENSE for details. #pragma once #include @@ -25,3 +25,23 @@ constexpr UInt32 CUR_TEMP_RANGE_SEL = 0x80000; constexpr UInt32 mmCG_MULT_THERMAL_STATUS_THM9 = 0x5A; constexpr UInt32 mmCG_MULT_THERMAL_STATUS_THM11 = 0x5F; #define GET_THERMAL_STATUS_CTF_TEMP(v) (((v) & 0x3FE00) >> 9) + +constexpr UInt32 AMDGPU_MAX_USEC_TIMEOUT = 100000; + +constexpr UInt32 MP_BASE_SMU9 = 0x16000; +constexpr UInt32 mmMP1_SMN_C2PMSG_66 = 0x282; +constexpr UInt32 mmMP1_SMN_C2PMSG_82 = 0x292; +constexpr UInt32 mmMP1_SMN_C2PMSG_90 = 0x29A; + +constexpr UInt32 mmSMC_MESSAGE_0_SMU7 = 0x94; +constexpr UInt32 mmSMC_RESP_0_SMU7 = 0x95; +constexpr UInt32 SMC_RESP_0_MASK_SMU7 = 0xFFFF; +constexpr UInt32 mmSMC_MSG_ARG_0_SMU7 = 0xA4; + +constexpr UInt32 ixSMU_PM_STATUS_95 = 0x3FF7C; + +constexpr UInt32 PPSMC_MSG_PmStatusLogStart_SMU7 = 0x170; +constexpr UInt32 PPSMC_MSG_PmStatusLogSample_SMU7 = 0x171; +constexpr UInt32 PPSMC_MSG_GetCurrPkgPwr_SMU7 = 0x282; + +constexpr UInt32 PPSMC_MSG_GetCurrPkgPwr_SMU9 = 0x61; diff --git a/SMCRadeonSensors/KeyImplementations.cpp b/SMCRadeonSensors/KeyImplementations.cpp index 60eb7ef..824f69a 100644 --- a/SMCRadeonSensors/KeyImplementations.cpp +++ b/SMCRadeonSensors/KeyImplementations.cpp @@ -1,10 +1,16 @@ -// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. See LICENSE for -// details. +// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. +// See LICENSE for details. #include "KeyImplementations.hpp" SMC_RESULT RGPUTempValue::readAccess() { auto value = this->provider->getTemperature(this->index); - *reinterpret_cast(this->data) = VirtualSMCAPI::encodeIntSp(SmcKeyTypeSp78, value); + *reinterpret_cast(this->data) = VirtualSMCAPI::encodeIntSp(this->type, value); + return SmcSuccess; +} + +SMC_RESULT RGPUPowerValue::readAccess() { + auto value = this->provider->getPower(this->index); + *reinterpret_cast(data) = VirtualSMCAPI::encodeSp(this->type, static_cast(value)); return SmcSuccess; } diff --git a/SMCRadeonSensors/KeyImplementations.hpp b/SMCRadeonSensors/KeyImplementations.hpp index c42a86a..9774790 100644 --- a/SMCRadeonSensors/KeyImplementations.hpp +++ b/SMCRadeonSensors/KeyImplementations.hpp @@ -20,3 +20,10 @@ class RGPUTempValue : public RadeonSMCValue { protected: SMC_RESULT readAccess() APPLE_KEXT_OVERRIDE; }; + +class RGPUPowerValue : public RadeonSMCValue { + using RadeonSMCValue::RadeonSMCValue; + + protected: + SMC_RESULT readAccess() APPLE_KEXT_OVERRIDE; +}; diff --git a/SMCRadeonSensors/SMCRSCard.cpp b/SMCRadeonSensors/SMCRSCard.cpp index ebcf25d..4dc5e6c 100644 --- a/SMCRadeonSensors/SMCRSCard.cpp +++ b/SMCRadeonSensors/SMCRSCard.cpp @@ -1,5 +1,5 @@ -// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. See LICENSE for -// details. +// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. +// See LICENSE for details. #include "SMCRSCard.hpp" #include "AMDCommon.hpp" @@ -9,93 +9,229 @@ OSDefineMetaClassAndStructors(SMCRSCard, OSObject); IOReturn SMCRSCard::ensureRMMIOMapped() { if (this->rmmio == nullptr) { + IOLockLock(this->regLock); this->dev->setMemoryEnable(true); this->dev->setBusMasterEnable(true); - auto bar5 = this->chipFamily >= ChipFamily::SouthernIslands; + auto bar5 = this->attributes.getFamily() >= SMCRSChipFamily::SouthernIslands; this->rmmio = this->dev->mapDeviceMemoryWithRegister(bar5 ? kIOPCIConfigBaseAddress5 : kIOPCIConfigBaseAddress2); if (this->rmmio == nullptr || !this->rmmio->getLength()) { SYSLOG("RSCard", "Failed to map BAR%d", bar5 ? 5 : 2); OSSafeReleaseNULL(this->rmmio); + IOLockUnlock(this->regLock); return kIOReturnDeviceError; } this->rmmioPtr = reinterpret_cast(this->rmmio->getVirtualAddress()); if (this->rmmioPtr == nullptr) { SYSLOG("RSCard", "Failed to get virtual address for BAR%d", bar5 ? 5 : 2); OSSafeReleaseNULL(this->rmmio); + IOLockUnlock(this->regLock); return kIOReturnDeviceError; } DBGLOG("RSCard", "Using BAR%d, located at %p", bar5 ? 5 : 2, this->rmmioPtr); + IOLockUnlock(this->regLock); } return kIOReturnSuccess; } UInt32 SMCRSCard::readReg32(UInt32 reg) { - if (this->ensureRMMIOMapped() != kIOReturnSuccess) { return 0xFFFFFFFF; } - - bool soc15 = this->chipFamily >= ChipFamily::ArcticIslands; - if ((reg * 4) < this->rmmio->getLength()) { - return this->rmmioPtr[reg]; + IOLockLock(this->regLock); + UInt32 ret; + if ((reg * sizeof(*this->rmmioPtr)) < this->rmmio->getLength()) { + ret = this->rmmioPtr[reg]; } else { - this->rmmioPtr[soc15 ? mmPCIE_INDEX2 : mmPCIE_INDEX] = reg; - return this->rmmioPtr[soc15 ? mmPCIE_DATA2 : mmPCIE_DATA]; + this->rmmioPtr[mmPCIE_INDEX] = reg; + ret = this->rmmioPtr[mmPCIE_DATA]; } + IOLockUnlock(this->regLock); + return ret; } void SMCRSCard::writeReg32(UInt32 reg, UInt32 val) { - if (this->ensureRMMIOMapped() != kIOReturnSuccess) { return; } + IOLockLock(this->regLock); + if ((reg * sizeof(*this->rmmioPtr)) < this->rmmio->getLength()) { + this->rmmioPtr[reg] = val; + } else { + this->rmmioPtr[mmPCIE_INDEX] = reg; + this->rmmioPtr[mmPCIE_DATA] = val; + } + IOLockUnlock(this->regLock); +} + +UInt32 SMCRSCard::soc15ReadReg32(UInt32 reg) { + IOLockLock(this->regLock); + UInt32 ret; + if ((reg * sizeof(*this->rmmioPtr)) < this->rmmio->getLength()) { + ret = this->rmmioPtr[reg]; + } else { + this->rmmioPtr[mmPCIE_INDEX2] = reg; + ret = this->rmmioPtr[mmPCIE_DATA2]; + } + IOLockUnlock(this->regLock); + return ret; +} - bool soc15 = this->chipFamily >= ChipFamily::ArcticIslands; - if ((reg * 4) < this->rmmio->getLength()) { +void SMCRSCard::soc15WriteReg32(UInt32 reg, UInt32 val) { + IOLockLock(this->regLock); + if ((reg * sizeof(*this->rmmioPtr)) < this->rmmio->getLength()) { this->rmmioPtr[reg] = val; } else { - this->rmmioPtr[soc15 ? mmPCIE_INDEX2 : mmPCIE_INDEX] = reg; - this->rmmioPtr[soc15 ? mmPCIE_DATA2 : mmPCIE_DATA] = val; + this->rmmioPtr[mmPCIE_INDEX2] = reg; + this->rmmioPtr[mmPCIE_DATA2] = val; } + IOLockUnlock(this->regLock); } -UInt32 SMCRSCard::readIndirectSMCSI(UInt32 reg) { - this->writeReg32(mmSMC_IND_INDEX_0, reg); - return this->readReg32(mmSMC_IND_DATA_0); +UInt32 SMCRSCard::readIndirectSMC(UInt32 reg) { + IOLockLock(this->indLock); + UInt32 ret; + switch (this->attributes.getFamily()) { + case SMCRSChipFamily::SeaIslands: + case SMCRSChipFamily::SouthernIslands: + this->writeReg32(mmSMC_IND_INDEX_0, reg); + ret = this->readReg32(mmSMC_IND_DATA_0); + case SMCRSChipFamily::VolcanicIslands: + this->writeReg32(mmSMC_IND_INDEX_11, reg); + ret = this->readReg32(mmSMC_IND_DATA_11); + default: + ret = 0xFFFFFFFF; + } + IOLockUnlock(this->indLock); + return ret; } -UInt32 SMCRSCard::readIndirectSMCVI(UInt32 reg) { - this->writeReg32(mmSMC_IND_INDEX_11, reg); - return this->readReg32(mmSMC_IND_DATA_11); +void SMCRSCard::writeIndirectSMC(UInt32 reg, UInt32 val) { + IOLockLock(this->indLock); + switch (this->attributes.getFamily()) { + case SMCRSChipFamily::SeaIslands: + case SMCRSChipFamily::SouthernIslands: + this->writeReg32(mmSMC_IND_INDEX_0, reg); + this->writeReg32(mmSMC_IND_DATA_0, val); + break; + case SMCRSChipFamily::VolcanicIslands: + this->writeReg32(mmSMC_IND_INDEX_11, reg); + this->writeReg32(mmSMC_IND_DATA_11, val); + break; + default: + break; + } + IOLockUnlock(this->indLock); } -IOReturn SMCRSCard::getTempSI(UInt16 *data) { - auto ctfTemp = GET_THERMAL_STATUS_CTF_TEMP(this->readIndirectSMCSI(ixCG_MULT_THERMAL_STATUS)); - *data = (ctfTemp & 0x200) ? 255 : (ctfTemp & 0x1FF); - return kIOReturnSuccess; +UInt32 SMCRSCard::smu7WaitForSMCResp() { + UInt32 ret = 0; + for (UInt32 i = 0; i < AMDGPU_MAX_USEC_TIMEOUT; i++) { + ret = this->readReg32(mmSMC_RESP_0_SMU7) & SMC_RESP_0_MASK_SMU7; + if (ret != 0) { break; } + + IOSleep(1); + } + + return ret; +} + +UInt32 SMCRSCard::smu7SendMessageToSMC(UInt32 message, UInt32 param, UInt32 *outData) { + IOLockLock(this->smcLock); + this->smu7WaitForSMCResp(); + this->writeReg32(mmSMC_MSG_ARG_0_SMU7, param); + this->writeReg32(mmSMC_RESP_0_SMU7, 0); + this->writeReg32(mmSMC_MESSAGE_0_SMU7, message); + + const auto resp = this->smu7WaitForSMCResp(); + + if (outData != nullptr) { *outData = this->readReg32(mmSMC_MSG_ARG_0_SMU7); } + + IOLockUnlock(this->smcLock); + return resp; +} + +UInt32 SMCRSCard::smu9WaitForSMCResp() { + UInt32 ret = 0; + for (UInt32 i = 0; i < AMDGPU_MAX_USEC_TIMEOUT; i++) { + ret = this->readReg32(MP_BASE_SMU9 + mmMP1_SMN_C2PMSG_90); + if (ret != 0) { break; } + + IOSleep(1); + } + + return ret; } -IOReturn SMCRSCard::getTempVI(UInt16 *data) { - auto ctfTemp = GET_THERMAL_STATUS_CTF_TEMP(this->readIndirectSMCVI(ixCG_MULT_THERMAL_STATUS)); +UInt32 SMCRSCard::smu9SendMessageToSMC(UInt32 message, UInt32 param, UInt32 *outData) { + IOLockLock(this->smcLock); + this->smu7WaitForSMCResp(); + this->writeReg32(MP_BASE_SMU9 + mmMP1_SMN_C2PMSG_82, param); + this->writeReg32(MP_BASE_SMU9 + mmMP1_SMN_C2PMSG_90, 0); + this->writeReg32(MP_BASE_SMU9 + mmMP1_SMN_C2PMSG_66, message); + + const auto resp = this->smu7WaitForSMCResp(); + + if (outData != nullptr) { *outData = this->readReg32(mmMP1_SMN_C2PMSG_82); } + + IOLockUnlock(this->smcLock); + return resp; +} + +IOReturn SMCRSCard::smu7GetTemp(UInt16 *data) { + auto ctfTemp = GET_THERMAL_STATUS_CTF_TEMP(this->readIndirectSMC(ixCG_MULT_THERMAL_STATUS)); *data = (ctfTemp & 0x200) ? 255 : (ctfTemp & 0x1FF); return kIOReturnSuccess; } -IOReturn SMCRSCard::getTempTHM9(UInt16 *data) { - auto reg = this->readReg32(THM_BASE + mmCG_MULT_THERMAL_STATUS_THM9); +IOReturn SMCRSCard::thm9GetTemp(UInt16 *data) { + auto reg = this->soc15ReadReg32(THM_BASE + mmCG_MULT_THERMAL_STATUS_THM9); *data = GET_THERMAL_STATUS_CTF_TEMP(reg) & 0x1FF; return kIOReturnSuccess; } -IOReturn SMCRSCard::getTempTHM11(UInt16 *data) { - auto reg = this->readReg32(THM_BASE + mmCG_MULT_THERMAL_STATUS_THM11); +IOReturn SMCRSCard::thm11GetTemp(UInt16 *data) { + auto reg = this->soc15ReadReg32(THM_BASE + mmCG_MULT_THERMAL_STATUS_THM11); *data = GET_THERMAL_STATUS_CTF_TEMP(reg) & 0x1FF; return kIOReturnSuccess; } -IOReturn SMCRSCard::getTempRV(UInt16 *data) { - auto reg = this->readReg32(THM_BASE + mmTHM_TCON_CUR_TMP); +IOReturn SMCRSCard::thm10GetTemp(UInt16 *data) { + auto reg = this->soc15ReadReg32(THM_BASE + mmTHM_TCON_CUR_TMP); *data = GET_TCON_CUR_TEMP(reg) / 8; if (reg & CUR_TEMP_RANGE_SEL) { *data -= 49; } return kIOReturnSuccess; } +static inline float fractional8BitToFloat(UInt32 value) { + return static_cast((value & 0xFFFFFF00) >> 8) + static_cast(value & 0xFF) * 0.001; +} + +IOReturn SMCRSCard::smu7GetPowerPMStatus(float *data) { + this->smu7SendMessageToSMC(PPSMC_MSG_PmStatusLogStart_SMU7); + this->writeIndirectSMC(ixSMU_PM_STATUS_95, 0); + UInt32 value = 0; + for (size_t i = 0; i < 10; i += 1) { + IOSleep(500); + this->smu7SendMessageToSMC(PPSMC_MSG_PmStatusLogSample_SMU7); + value = this->readIndirectSMC(ixSMU_PM_STATUS_95); + if (value != 0) { break; } + } + if (value == 0) { return kIOReturnError; } + *data = fractional8BitToFloat(value); + return kIOReturnSuccess; +} + +IOReturn SMCRSCard::smu7GetPowerSMC(float *data) { + UInt32 value = 0; + if (this->smu7SendMessageToSMC(PPSMC_MSG_GetCurrPkgPwr_SMU7, 0, &value) != 1) { return kIOReturnError; } + if (value == 0) { return this->smu7GetPowerPMStatus(data); } + *data = fractional8BitToFloat(value); + return kIOReturnSuccess; +} + +IOReturn SMCRSCard::smu9GetPower(float *data) { + UInt32 value = 0; + if (this->smu9SendMessageToSMC(PPSMC_MSG_GetCurrPkgPwr_SMU9, 0, &value) != 1) { return kIOReturnError; } + *data = static_cast(value); + return kIOReturnSuccess; +} + bool SMCRSCard::initialise(IOPCIDevice *device) { if (device == nullptr) { return false; } @@ -103,67 +239,111 @@ bool SMCRSCard::initialise(IOPCIDevice *device) { auto deviceID = WIOKit::readPCIConfigValue(this->dev, WIOKit::kIOPCIConfigDeviceID); switch (deviceID) { - case 0x15DD: - case 0x15D8: - case 0x164C: - case 0x1636: - case 0x15E7: - case 0x1638: - this->chipFamily = ChipFamily::Raven; - DBGLOG("RSCard", "Raven"); + case 0x15D8: // Picasso + case 0x15DD: // Raven + case 0x15E7: // Barcelo + case 0x1636: // Renoir + case 0x1638: // Cezanne + case 0x164C: // Lucienne + this->attributes.setFamily(SMCRSChipFamily::Raven); break; - case 0x66A0 ... 0x66AF: - this->chipFamily = ChipFamily::ArcticIslandsTHM11; - DBGLOG("RSCard", "Arctic Islands (THM 11)"); + case 0x66A0 ... 0x66AF: // Vega 20 + this->attributes.setFamily(SMCRSChipFamily::ArcticIslands); + this->attributes.setIsTHM11(); break; - case 0x6860 ... 0x687F: - case 0x69A0 ... 0x69AF: - this->chipFamily = ChipFamily::ArcticIslands; - DBGLOG("RSCard", "Arctic Islands"); + case 0x6860 ... 0x687F: // Vega 10 + this->attributes.setSupportsPower(); + case 0x69A0 ... 0x69AF: // Vega 12 + this->attributes.setFamily(SMCRSChipFamily::ArcticIslands); break; - case 0x67C0 ... 0x67FF: - case 0x6980 ... 0x699F: - this->chipFamily = ChipFamily::VolcanicIslands; - DBGLOG("RSCard", "Volcanic Islands"); + case 0x67C0 ... 0x67FF: // Polaris 10, Polaris 11 + case 0x6980 ... 0x699F: // Polaris 12 + this->attributes.setFamily(SMCRSChipFamily::VolcanicIslands); + this->attributes.setSupportsPower(); break; - case 0x6600 ... 0x666F: - case 0x67A0 ... 0x67BF: - case 0x6900 ... 0x693F: - this->chipFamily = ChipFamily::SouthernIslands; - DBGLOG("RSCard", "Southern Islands"); + case 0x6600 ... 0x666F: // Bonaire + case 0x67A0 ... 0x67BF: // Hawaii + case 0x6900 ... 0x693F: // Tonga + this->attributes.setFamily(SMCRSChipFamily::SouthernIslands); + this->attributes.setSupportsPower(); break; - case 0x6780 ... 0x679F: - case 0x6800 ... 0x683F: - this->chipFamily = ChipFamily::SeaIslands; - DBGLOG("RSCard", "Sea Islands"); + case 0x6780 ... 0x679F: // Tahiti + case 0x6800 ... 0x683F: // Venus, Cape Verde, ... + this->attributes.setFamily(SMCRSChipFamily::SeaIslands); + this->attributes.setSupportsPower(); break; - case 0x7310 ... 0x73FF: - this->chipFamily = ChipFamily::Navi; - DBGLOG("RSCard", "Navi"); + case 0x7310 ... 0x73FF: // Navi 1x, Navi 2x + this->attributes.setFamily(SMCRSChipFamily::Navi); break; default: SYSLOG("RSCard", "Unsupported card 0x%04X", deviceID); return false; } + DBGLOG("RSCard", "Chip Family: %s", stringifyChipFamily(this->attributes.getFamily())); + DBGLOG("RSCard", "Is THM11: %s", this->attributes.isTHM11() ? "Yes" : "No"); + DBGLOG("RSCard", "Power: %s", this->attributes.supportsPower() ? "Supported" : "Unsupported"); + + this->regLock = IOLockAlloc(); + if (regLock == nullptr) { + SYSLOG("RSCard", "Failed to allocate regLock"); + return false; + } + + this->indLock = IOLockAlloc(); + if (indLock == nullptr) { + SYSLOG("RSCard", "Failed to allocate indLock"); + return false; + } + + this->smcLock = IOLockAlloc(); + if (smcLock == nullptr) { + SYSLOG("RSCard", "Failed to allocate smcLock"); + return false; + } + return true; } IOReturn SMCRSCard::getTemperature(UInt16 *data) { - switch (this->chipFamily) { - case ChipFamily::SeaIslands: - case ChipFamily::SouthernIslands: - return this->getTempSI(data); - case ChipFamily::VolcanicIslands: - return this->getTempVI(data); - case ChipFamily::ArcticIslands: - return this->getTempTHM9(data); - case ChipFamily::ArcticIslandsTHM11: - return this->getTempTHM11(data); - case ChipFamily::Raven: - case ChipFamily::Navi: - return this->getTempRV(data); + auto ret = this->ensureRMMIOMapped(); + if (ret != kIOReturnSuccess) { return ret; } + + switch (this->attributes.getFamily()) { + case SMCRSChipFamily::SeaIslands: + case SMCRSChipFamily::SouthernIslands: + case SMCRSChipFamily::VolcanicIslands: + return this->smu7GetTemp(data); + case SMCRSChipFamily::ArcticIslands: + if (this->attributes.isTHM11()) { + return this->thm11GetTemp(data); + } else { + return this->thm9GetTemp(data); + } + case SMCRSChipFamily::Raven: + case SMCRSChipFamily::Navi: + return this->thm10GetTemp(data); + default: + return kIOReturnUnsupported; + } +} + +bool SMCRSCard::supportsPower() { return this->attributes.supportsPower(); } + +IOReturn SMCRSCard::getPower(float *data) { + auto ret = this->ensureRMMIOMapped(); + if (ret != kIOReturnSuccess) { return ret; } + + if (!this->supportsPower()) { return kIOReturnUnsupported; } + switch (this->attributes.getFamily()) { + case SMCRSChipFamily::SeaIslands: + return this->smu7GetPowerPMStatus(data); + case SMCRSChipFamily::SouthernIslands: + case SMCRSChipFamily::VolcanicIslands: + return this->smu7GetPowerSMC(data); + case SMCRSChipFamily::ArcticIslands: + return this->smu9GetPower(data); default: - return kIOReturnError; + return kIOReturnUnsupported; } } diff --git a/SMCRadeonSensors/SMCRSCard.hpp b/SMCRadeonSensors/SMCRSCard.hpp index 479afbc..d741729 100644 --- a/SMCRadeonSensors/SMCRSCard.hpp +++ b/SMCRadeonSensors/SMCRSCard.hpp @@ -1,42 +1,93 @@ -// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. See LICENSE for -// details. +// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. +// See LICENSE for details. #pragma once #include #include -enum struct ChipFamily { +enum struct SMCRSChipFamily { Unknown, SeaIslands, SouthernIslands, VolcanicIslands, ArcticIslands, - ArcticIslandsTHM11, Raven, Navi, }; +#ifdef DEBUG +inline const char *stringifyChipFamily(SMCRSChipFamily value) { + switch (value) { + case SMCRSChipFamily::SeaIslands: + return "Sea Islands"; + case SMCRSChipFamily::SouthernIslands: + return "Southern Islands"; + case SMCRSChipFamily::VolcanicIslands: + return "Volcanic Islands"; + case SMCRSChipFamily::ArcticIslands: + return "Arctic Islands"; + case SMCRSChipFamily::Raven: + return "Raven"; + case SMCRSChipFamily::Navi: + return "Navi"; + default: + return "Unknown"; + } +} +#endif + +class SMCRSAttributes { + static constexpr UInt16 ChipFamilyMask = 7U; + static constexpr UInt16 IsTHM11 = (1U << 3); + static constexpr UInt16 SupportsPower = (1U << 4); + + UInt16 value {0}; + + public: + inline SMCRSChipFamily getFamily() const { return static_cast(this->value & ChipFamilyMask); } + inline bool isTHM11() const { return (this->value & IsTHM11) != 0; } + inline bool supportsPower() const { return (this->value & SupportsPower) != 0; } + + inline void setFamily(SMCRSChipFamily value) { this->value |= static_cast(value); } + inline void setIsTHM11() { this->value |= IsTHM11; } + inline void setSupportsPower() { this->value |= SupportsPower; } +}; + class SMCRSCard : public OSObject { OSDeclareDefaultStructors(SMCRSCard); IOPCIDevice *dev {nullptr}; volatile UInt32 *rmmioPtr {nullptr}; IOMemoryMap *rmmio {nullptr}; - ChipFamily chipFamily {ChipFamily::Unknown}; + SMCRSAttributes attributes {}; + IOLock *regLock {nullptr}; + IOLock *indLock {nullptr}; + IOLock *smcLock {nullptr}; IOReturn ensureRMMIOMapped(); UInt32 readReg32(UInt32 reg); void writeReg32(UInt32 reg, UInt32 val); - UInt32 readIndirectSMCSI(UInt32 reg); - UInt32 readIndirectSMCVI(UInt32 reg); + UInt32 soc15ReadReg32(UInt32 reg); + void soc15WriteReg32(UInt32 reg, UInt32 val); + UInt32 readIndirectSMC(UInt32 reg); + void writeIndirectSMC(UInt32 reg, UInt32 val); + UInt32 smu7WaitForSMCResp(); + UInt32 smu7SendMessageToSMC(UInt32 message, UInt32 param = 0, UInt32 *outData = nullptr); + UInt32 smu9WaitForSMCResp(); + UInt32 smu9SendMessageToSMC(UInt32 message, UInt32 param = 0, UInt32 *outData = nullptr); + + IOReturn smu7GetTemp(UInt16 *data); + IOReturn thm9GetTemp(UInt16 *data); + IOReturn thm11GetTemp(UInt16 *data); + IOReturn thm10GetTemp(UInt16 *data); - IOReturn getTempSI(UInt16 *data); - IOReturn getTempVI(UInt16 *data); - IOReturn getTempTHM9(UInt16 *data); - IOReturn getTempTHM11(UInt16 *data); - IOReturn getTempRV(UInt16 *data); + IOReturn smu7GetPowerPMStatus(float *data); + IOReturn smu7GetPowerSMC(float *data); + IOReturn smu9GetPower(float *data); public: - bool initialise(IOPCIDevice *radeonDevice); + bool initialise(IOPCIDevice *device); IOReturn getTemperature(UInt16 *data); + bool supportsPower(); + IOReturn getPower(float *data); }; diff --git a/SMCRadeonSensors/SMCRadeonSensors.cpp b/SMCRadeonSensors/SMCRadeonSensors.cpp index 1918255..c3b36aa 100644 --- a/SMCRadeonSensors/SMCRadeonSensors.cpp +++ b/SMCRadeonSensors/SMCRadeonSensors.cpp @@ -1,5 +1,5 @@ -// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. See LICENSE for -// details. +// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. +// See LICENSE for details. #include "SMCRadeonSensors.hpp" #include "KeyImplementations.hpp" @@ -61,6 +61,9 @@ IOService *PRODUCT_NAME::probe(IOService *provider, SInt32 *score) { DBGLOG("SMCRS", "Found %u cards", this->cards->getCount()); for (UInt32 i = 0; i < this->cards->getCount(); i++) { + auto *card = this->getCard(i); + if (card == nullptr) { continue; } + VirtualSMCAPI::addKey(KeyTGxD(i), vsmcPlugin.data, VirtualSMCAPI::valueWithSp(0, SmcKeyTypeSp78, new RGPUTempValue(this, i))); VirtualSMCAPI::addKey(KeyTGxP(i), vsmcPlugin.data, @@ -70,11 +73,24 @@ IOService *PRODUCT_NAME::probe(IOService *provider, SInt32 *score) { VirtualSMCAPI::addKey(KeyTGxp(i), vsmcPlugin.data, VirtualSMCAPI::valueWithSp(0, SmcKeyTypeSp78, new RGPUTempValue(this, i))); - if (i != 0) { continue; } - VirtualSMCAPI::addKey(KeyTGDD, vsmcPlugin.data, - VirtualSMCAPI::valueWithSp(0, SmcKeyTypeSp78, new RGPUTempValue(this, i))); + if (card->supportsPower()) { + VirtualSMCAPI::addKey(KeyPGxR(i), vsmcPlugin.data, + VirtualSMCAPI::valueWithSp(0, SmcKeyTypeSp96, new RGPUPowerValue(this, i))); + VirtualSMCAPI::addKey(KeyPGxC(i), vsmcPlugin.data, + VirtualSMCAPI::valueWithSp(0, SmcKeyTypeSp96, new RGPUPowerValue(this, i))); + } + + if (i == 0) { + VirtualSMCAPI::addKey(KeyTGDD, vsmcPlugin.data, + VirtualSMCAPI::valueWithSp(0, SmcKeyTypeSp78, new RGPUTempValue(this, i))); + } } + // VG0C: Voltage + // IG0R: Current + // PG0C: Power + // PG0R: Power + qsort(const_cast(vsmcPlugin.data.data()), vsmcPlugin.data.size(), sizeof(VirtualSMCKeyValue), VirtualSMCKeyValue::compare); @@ -142,6 +158,13 @@ UInt16 PRODUCT_NAME::getTemperature(UInt32 index) { return temp; } +float PRODUCT_NAME::getPower(UInt32 index) { + float power = 0.0; + auto *obj = this->getCard(index); + if (obj != nullptr) { obj->getPower(&power); } + return power; +} + EXPORT extern "C" kern_return_t ADDPR(kern_start)(kmod_info_t *, void *) { lilu_get_boot_args("liludelay", &ADDPR(debugPrintDelay), sizeof(ADDPR(debugPrintDelay))); ADDPR(debugEnabled) = checkKernelArgument("-RSDebug") || checkKernelArgument("-liludbgall"); diff --git a/SMCRadeonSensors/SMCRadeonSensors.hpp b/SMCRadeonSensors/SMCRadeonSensors.hpp index 77ffc52..d01ed21 100644 --- a/SMCRadeonSensors/SMCRadeonSensors.hpp +++ b/SMCRadeonSensors/SMCRadeonSensors.hpp @@ -1,5 +1,5 @@ -// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. See LICENSE for -// details. +// Copyright © 2023-2024 ChefKiss. Licensed under the Thou Shalt Not Profit License version 1.5. +// See LICENSE for details. #pragma once #include "SMCRSCard.hpp" @@ -19,6 +19,8 @@ class EXPORT PRODUCT_NAME : public IOService { static constexpr SMC_KEY KeyTGxp(size_t i) { return SMC_MAKE_IDENTIFIER('T', 'G', KeyIndexes[i], 'p'); } static constexpr SMC_KEY KeyTGxd(size_t i) { return SMC_MAKE_IDENTIFIER('T', 'G', KeyIndexes[i], 'd'); } static constexpr SMC_KEY KeyTGDD = SMC_MAKE_IDENTIFIER('T', 'G', 'D', 'D'); + static constexpr SMC_KEY KeyPGxR(size_t i) { return SMC_MAKE_IDENTIFIER('P', 'G', KeyIndexes[i], 'R'); } + static constexpr SMC_KEY KeyPGxC(size_t i) { return SMC_MAKE_IDENTIFIER('P', 'G', KeyIndexes[i], 'C'); } VirtualSMCAPI::Plugin vsmcPlugin { .product = xStringify(PRODUCT_NAME), @@ -38,6 +40,7 @@ class EXPORT PRODUCT_NAME : public IOService { virtual UInt32 getCardCount(); virtual SMCRSCard *getCard(UInt32 index); virtual UInt16 getTemperature(UInt32 index); + virtual float getPower(UInt32 index); static bool vsmcNotificationHandler(void *target, void *refCon, IOService *newService, IONotifier *notifier); };