first commit
This commit is contained in:
@@ -0,0 +1,775 @@
|
||||
// ported from: https://gitlab.com/leogx9r/ryzen_smu
|
||||
// and: https://github.com/irusanov/SMUDebugTool
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware;
|
||||
|
||||
internal class RyzenSMU
|
||||
{
|
||||
private const byte SMU_PCI_ADDR_REG = 0xC4;
|
||||
private const byte SMU_PCI_DATA_REG = 0xC8;
|
||||
private const uint SMU_REQ_MAX_ARGS = 6;
|
||||
private const uint SMU_RETRIES_MAX = 8096;
|
||||
|
||||
private readonly CpuCodeName _cpuCodeName;
|
||||
private readonly bool _supportedCPU;
|
||||
|
||||
private readonly Dictionary<uint, Dictionary<uint, SmuSensorType>> _supportedPmTableVersions = new()
|
||||
{
|
||||
{
|
||||
// Zen Raven Ridge APU.
|
||||
0x001E0004, new Dictionary<uint, SmuSensorType>
|
||||
{
|
||||
{ 7, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } },
|
||||
{ 11, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } },
|
||||
//{ 61, new SmuSensorType { Name = "Core", Type = SensorType.Voltage } },
|
||||
//{ 62, new SmuSensorType { Name = "Core", Type = SensorType.Current, Scale = 1} },
|
||||
//{ 63, new SmuSensorType { Name = "Core", Type = SensorType.Power, Scale = 1 } },
|
||||
//{ 65, new SmuSensorType { Name = "SoC", Type = SensorType.Voltage } },
|
||||
{ 66, new SmuSensorType { Name = "SoC", Type = SensorType.Current, Scale = 1 } },
|
||||
{ 67, new SmuSensorType { Name = "SoC", Type = SensorType.Power, Scale = 1 } },
|
||||
//{ 96, new SmuSensorType { Name = "Core #1", Type = SensorType.Power } },
|
||||
//{ 97, new SmuSensorType { Name = "Core #2", Type = SensorType.Power } },
|
||||
//{ 98, new SmuSensorType { Name = "Core #3", Type = SensorType.Power } },
|
||||
//{ 99, new SmuSensorType { Name = "Core #4", Type = SensorType.Power } },
|
||||
{ 108, new SmuSensorType { Name = "Core #1", Type = SensorType.Temperature, Scale = 1 } },
|
||||
{ 109, new SmuSensorType { Name = "Core #2", Type = SensorType.Temperature, Scale = 1 } },
|
||||
{ 110, new SmuSensorType { Name = "Core #3", Type = SensorType.Temperature, Scale = 1 } },
|
||||
{ 111, new SmuSensorType { Name = "Core #4", Type = SensorType.Temperature, Scale = 1 } },
|
||||
{ 150, new SmuSensorType { Name = "GFX", Type = SensorType.Voltage, Scale = 1 } },
|
||||
{ 151, new SmuSensorType { Name = "GFX", Type = SensorType.Temperature, Scale = 1 } },
|
||||
{ 154, new SmuSensorType { Name = "GFX", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 156, new SmuSensorType { Name = "GFX", Type = SensorType.Load, Scale = 1 } },
|
||||
{ 166, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 177, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 178, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 342, new SmuSensorType { Name = "Displays", Type = SensorType.Factor, Scale = 1 } }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Zen 2.
|
||||
0x00240903, new Dictionary<uint, SmuSensorType>
|
||||
{
|
||||
{ 15, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } },
|
||||
{ 21, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } },
|
||||
{ 48, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 50, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 51, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 115, new SmuSensorType { Name = "SoC", Type = SensorType.Temperature, Scale = 1 } }
|
||||
//{ 66, new SmuSensorType { Name = "Bus Speed", Type = SensorType.Clock, Scale = 1 } },
|
||||
//{ 188, new SmuSensorType { Name = "Core #1", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 189, new SmuSensorType { Name = "Core #2", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 190, new SmuSensorType { Name = "Core #3", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 191, new SmuSensorType { Name = "Core #4", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 192, new SmuSensorType { Name = "Core #5", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 193, new SmuSensorType { Name = "Core #6", Type = SensorType.Clock, Scale = 1000 } },
|
||||
}
|
||||
},
|
||||
{
|
||||
// Zen 3.
|
||||
0x00380805, new Dictionary<uint, SmuSensorType>
|
||||
{
|
||||
{ 3, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } },
|
||||
// TODO: requires some post-processing
|
||||
// see: https://gitlab.com/leogx9r/ryzen_smu/-/blob/master/userspace/monitor_cpu.c#L577
|
||||
// { 9, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } },
|
||||
{ 48, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 50, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 51, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 127, new SmuSensorType { Name = "SoC", Type = SensorType.Temperature, Scale = 1 } },
|
||||
{ 268, new SmuSensorType { Name = "Core #1 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 269, new SmuSensorType { Name = "Core #2 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 270, new SmuSensorType { Name = "Core #3 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 271, new SmuSensorType { Name = "Core #4 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 272, new SmuSensorType { Name = "Core #5 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 273, new SmuSensorType { Name = "Core #6 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 274, new SmuSensorType { Name = "Core #7 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 275, new SmuSensorType { Name = "Core #8 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 276, new SmuSensorType { Name = "Core #9 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 277, new SmuSensorType { Name = "Core #10 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 278, new SmuSensorType { Name = "Core #11 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 279, new SmuSensorType { Name = "Core #12 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 280, new SmuSensorType { Name = "Core #13 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 281, new SmuSensorType { Name = "Core #14 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 282, new SmuSensorType { Name = "Core #15 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
{ 283, new SmuSensorType { Name = "Core #16 (Effective)", Type = SensorType.Clock, Scale = 1000 } }
|
||||
}
|
||||
},
|
||||
{
|
||||
// Zen 4.
|
||||
0x00540004, new Dictionary<uint, SmuSensorType>
|
||||
{
|
||||
{ 3, new SmuSensorType { Name = "CPU PPT", Type = SensorType.Power, Scale = 1 } },
|
||||
{ 11, new SmuSensorType { Name = "Package", Type = SensorType.Temperature, Scale = 1 } },
|
||||
{ 20, new SmuSensorType { Name = "Core Power", Type = SensorType.Power, Scale = 1 } },
|
||||
{ 21, new SmuSensorType { Name = "SOC Power", Type = SensorType.Power, Scale = 1 } },
|
||||
{ 22, new SmuSensorType { Name = "Misc Power", Type = SensorType.Power, Scale = 1 } },
|
||||
{ 26, new SmuSensorType { Name = "Total Power", Type = SensorType.Power, Scale = 1 } },
|
||||
{ 47, new SmuSensorType { Name = "VDDCR", Type = SensorType.Voltage, Scale = 1 } },
|
||||
{ 48, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } },
|
||||
{ 49, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } },
|
||||
{ 52, new SmuSensorType { Name = "VDDCR SoC", Type = SensorType.Voltage, Scale = 1 } },
|
||||
{ 57, new SmuSensorType { Name = "VDD Misc", Type = SensorType.Voltage, Scale = 1 } },
|
||||
{ 70, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 74, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 78, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } },
|
||||
{ 211, new SmuSensorType { Name = "IOD Hotspot", Type = SensorType.Temperature, Scale = 1 } },
|
||||
{ 539, new SmuSensorType { Name = "L3 (CCD1)", Type = SensorType.Temperature, Scale = 1 } },
|
||||
{ 540, new SmuSensorType { Name = "L3 (CCD2)", Type = SensorType.Temperature, Scale = 1 } },
|
||||
{ 268, new SmuSensorType { Name = "LDO VDD", Type = SensorType.Voltage, Scale = 1 } },
|
||||
|
||||
// This is not working, some cores can be deactivated with the core disabled map.
|
||||
// When Core 2 is disabled and Core 3 is enabled, the name of Core 3 == "Core 2".
|
||||
//{ 357, new SmuSensorType { Name = "Core #1 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 358, new SmuSensorType { Name = "Core #2 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 359, new SmuSensorType { Name = "Core #3 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 360, new SmuSensorType { Name = "Core #4 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 361, new SmuSensorType { Name = "Core #5 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 362, new SmuSensorType { Name = "Core #6 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 363, new SmuSensorType { Name = "Core #7 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 364, new SmuSensorType { Name = "Core #8 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 365, new SmuSensorType { Name = "Core #9 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 366, new SmuSensorType { Name = "Core #10 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 367, new SmuSensorType { Name = "Core #11 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 368, new SmuSensorType { Name = "Core #12 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 369, new SmuSensorType { Name = "Core #13 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 370, new SmuSensorType { Name = "Core #14 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 371, new SmuSensorType { Name = "Core #15 (Effective)", Type = SensorType.Clock, Scale = 1000 } },
|
||||
//{ 372, new SmuSensorType { Name = "Core #16 (Effective)", Type = SensorType.Clock, Scale = 1000 } }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private uint _argsAddr;
|
||||
private uint _cmdAddr;
|
||||
private uint _dramAddrHi;
|
||||
private uint _dramBaseAddr;
|
||||
private uint _pmTableSize;
|
||||
private uint _pmTableSizeAlt;
|
||||
private uint _pmTableVersion;
|
||||
private uint _rspAddr;
|
||||
|
||||
public RyzenSMU(uint family, uint model, uint packageType)
|
||||
{
|
||||
_cpuCodeName = GetCpuCodeName(family, model, packageType);
|
||||
|
||||
_supportedCPU = Environment.Is64BitOperatingSystem == Environment.Is64BitProcess && SetAddresses(_cpuCodeName);
|
||||
|
||||
if (_supportedCPU && InpOut.Open())
|
||||
SetupPmTableAddrAndSize();
|
||||
}
|
||||
|
||||
private static CpuCodeName GetCpuCodeName(uint family, uint model, uint packageType)
|
||||
{
|
||||
return family switch
|
||||
{
|
||||
0x17 => model switch
|
||||
{
|
||||
0x01 => packageType == 7 ? CpuCodeName.Threadripper : CpuCodeName.SummitRidge,
|
||||
0x08 => packageType == 7 ? CpuCodeName.Colfax : CpuCodeName.PinnacleRidge,
|
||||
0x11 => CpuCodeName.RavenRidge,
|
||||
0x18 => packageType == 2 ? CpuCodeName.RavenRidge2 : CpuCodeName.Picasso,
|
||||
0x20 => CpuCodeName.Dali,
|
||||
0x31 => CpuCodeName.CastlePeak,
|
||||
0x60 => CpuCodeName.Renoir,
|
||||
0x71 => CpuCodeName.Matisse,
|
||||
0x90 => CpuCodeName.Vangogh,
|
||||
_ => CpuCodeName.Undefined
|
||||
},
|
||||
0x19 => model switch
|
||||
{
|
||||
0x00 => CpuCodeName.Milan,
|
||||
0x20 or 0x21 => CpuCodeName.Vermeer,
|
||||
0x40 => CpuCodeName.Rembrandt,
|
||||
0x50 => CpuCodeName.Cezanne,
|
||||
0x61 => CpuCodeName.Raphael,
|
||||
_ => CpuCodeName.Undefined
|
||||
},
|
||||
0x1A => model switch
|
||||
{
|
||||
0x44 => CpuCodeName.GraniteRidge,
|
||||
_ => CpuCodeName.Undefined
|
||||
},
|
||||
_ => CpuCodeName.Undefined
|
||||
};
|
||||
}
|
||||
|
||||
public string GetReport()
|
||||
{
|
||||
StringBuilder r = new();
|
||||
|
||||
r.AppendLine("Ryzen SMU");
|
||||
r.AppendLine();
|
||||
r.AppendLine($" PM table version: 0x{_pmTableVersion:X8}");
|
||||
r.AppendLine($" PM table supported: {_supportedCPU}");
|
||||
r.AppendLine($" PM table layout defined: {IsPmTableLayoutDefined()}");
|
||||
|
||||
if (_supportedCPU)
|
||||
{
|
||||
r.AppendLine($" PM table size: 0x{_pmTableSize:X3}");
|
||||
r.AppendLine($" PM table start address: 0x{_dramBaseAddr:X8}");
|
||||
r.AppendLine();
|
||||
r.AppendLine(" PM table dump:");
|
||||
r.AppendLine(" Idx Offset Value");
|
||||
r.AppendLine(" ------------------------");
|
||||
|
||||
float[] pm_values = GetPmTable();
|
||||
for (int i = 0; i < pm_values.Length; i++)
|
||||
{
|
||||
r.AppendLine($" {i,4} 0x{i * 4:X3} {pm_values[i]}");
|
||||
}
|
||||
}
|
||||
|
||||
return r.ToString();
|
||||
}
|
||||
|
||||
private bool SetAddresses(CpuCodeName codeName)
|
||||
{
|
||||
switch (codeName)
|
||||
{
|
||||
case CpuCodeName.CastlePeak:
|
||||
case CpuCodeName.Matisse:
|
||||
case CpuCodeName.Vermeer:
|
||||
case CpuCodeName.Raphael:
|
||||
case CpuCodeName.GraniteRidge:
|
||||
_cmdAddr = 0x3B10524;
|
||||
_rspAddr = 0x3B10570;
|
||||
_argsAddr = 0x3B10A40;
|
||||
return true;
|
||||
|
||||
case CpuCodeName.Colfax:
|
||||
case CpuCodeName.SummitRidge:
|
||||
case CpuCodeName.Threadripper:
|
||||
case CpuCodeName.PinnacleRidge:
|
||||
_cmdAddr = 0x3B1051C;
|
||||
_rspAddr = 0x3B10568;
|
||||
_argsAddr = 0x3B10590;
|
||||
return true;
|
||||
|
||||
case CpuCodeName.Renoir:
|
||||
case CpuCodeName.Picasso:
|
||||
case CpuCodeName.RavenRidge:
|
||||
case CpuCodeName.RavenRidge2:
|
||||
case CpuCodeName.Dali:
|
||||
_cmdAddr = 0x3B10A20;
|
||||
_rspAddr = 0x3B10A80;
|
||||
_argsAddr = 0x3B10A88;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetSmuVersion()
|
||||
{
|
||||
uint[] args = [1];
|
||||
|
||||
return SendCommand(0x02, ref args) ? args[0] : 0;
|
||||
}
|
||||
|
||||
public Dictionary<uint, SmuSensorType> GetPmTableStructure()
|
||||
{
|
||||
if (!IsPmTableLayoutDefined())
|
||||
return new Dictionary<uint, SmuSensorType>();
|
||||
|
||||
return _supportedPmTableVersions[_pmTableVersion];
|
||||
}
|
||||
|
||||
public bool IsPmTableLayoutDefined()
|
||||
{
|
||||
return _supportedPmTableVersions.ContainsKey(_pmTableVersion);
|
||||
}
|
||||
|
||||
public float[] GetPmTable()
|
||||
{
|
||||
if (!_supportedCPU || !TransferTableToDram())
|
||||
return [0];
|
||||
|
||||
float[] table = ReadDramToArray();
|
||||
|
||||
// Fix for Zen+ empty values on first call.
|
||||
if (table.Length == 0 || table[0] == 0)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
TransferTableToDram();
|
||||
table = ReadDramToArray();
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
private float[] ReadDramToArray()
|
||||
{
|
||||
float[] table = new float[_pmTableSize / 4];
|
||||
|
||||
IntPtr pMemory = Environment.Is64BitProcess ? new IntPtr(_dramBaseAddr | (long)_dramAddrHi << 32) : new IntPtr(_dramBaseAddr);
|
||||
|
||||
byte[] bytes = InpOut.ReadMemory(pMemory, _pmTableSize);
|
||||
if (bytes != null)
|
||||
Buffer.BlockCopy(bytes, 0, table, 0, bytes.Length);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
private bool SetupPmTableAddrAndSize()
|
||||
{
|
||||
if (_pmTableSize == 0)
|
||||
SetupPmTableSize();
|
||||
|
||||
if (_dramBaseAddr == 0)
|
||||
SetupDramBaseAddr();
|
||||
|
||||
return _dramBaseAddr != 0 && _pmTableSize != 0;
|
||||
}
|
||||
|
||||
private void SetupPmTableSize()
|
||||
{
|
||||
if (!GetPmTableVersion(ref _pmTableVersion))
|
||||
return;
|
||||
|
||||
switch (_cpuCodeName)
|
||||
{
|
||||
case CpuCodeName.Matisse:
|
||||
switch (_pmTableVersion)
|
||||
{
|
||||
case 0x240902:
|
||||
_pmTableSize = 0x514;
|
||||
break;
|
||||
case 0x240903:
|
||||
_pmTableSize = 0x518;
|
||||
break;
|
||||
case 0x240802:
|
||||
_pmTableSize = 0x7E0;
|
||||
break;
|
||||
case 0x240803:
|
||||
_pmTableSize = 0x7E4;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CpuCodeName.Vermeer:
|
||||
switch (_pmTableVersion)
|
||||
{
|
||||
case 0x2D0903:
|
||||
_pmTableSize = 0x594;
|
||||
break;
|
||||
case 0x380904:
|
||||
_pmTableSize = 0x5A4;
|
||||
break;
|
||||
case 0x380905:
|
||||
_pmTableSize = 0x5D0;
|
||||
break;
|
||||
case 0x2D0803:
|
||||
_pmTableSize = 0x894;
|
||||
break;
|
||||
case 0x380804:
|
||||
_pmTableSize = 0x8A4;
|
||||
break;
|
||||
case 0x380805:
|
||||
_pmTableSize = 0x8F0;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CpuCodeName.Renoir:
|
||||
switch (_pmTableVersion)
|
||||
{
|
||||
case 0x370000:
|
||||
_pmTableSize = 0x794;
|
||||
break;
|
||||
case 0x370001:
|
||||
_pmTableSize = 0x884;
|
||||
break;
|
||||
case 0x370002:
|
||||
case 0x370003:
|
||||
_pmTableSize = 0x88C;
|
||||
break;
|
||||
case 0x370004:
|
||||
_pmTableSize = 0x8AC;
|
||||
break;
|
||||
case 0x370005:
|
||||
_pmTableSize = 0x8C8;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CpuCodeName.Cezanne:
|
||||
switch (_pmTableVersion)
|
||||
{
|
||||
case 0x400005:
|
||||
_pmTableSize = 0x944;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CpuCodeName.Picasso:
|
||||
case CpuCodeName.RavenRidge:
|
||||
case CpuCodeName.RavenRidge2:
|
||||
_pmTableSizeAlt = 0xA4;
|
||||
_pmTableSize = 0x608 + _pmTableSizeAlt;
|
||||
break;
|
||||
|
||||
case CpuCodeName.Raphael:
|
||||
case CpuCodeName.GraniteRidge:
|
||||
switch (_pmTableVersion)
|
||||
{
|
||||
case 0x00540004:
|
||||
_pmTableSize = 0x948;
|
||||
break;
|
||||
|
||||
case 0x00540104:
|
||||
_pmTableSize = 0x950;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private bool GetPmTableVersion(ref uint version)
|
||||
{
|
||||
uint[] args = [0];
|
||||
uint fn;
|
||||
|
||||
switch (_cpuCodeName)
|
||||
{
|
||||
case CpuCodeName.RavenRidge:
|
||||
case CpuCodeName.Picasso:
|
||||
fn = 0x0c;
|
||||
break;
|
||||
case CpuCodeName.Matisse:
|
||||
case CpuCodeName.Vermeer:
|
||||
fn = 0x08;
|
||||
break;
|
||||
case CpuCodeName.Renoir:
|
||||
fn = 0x06;
|
||||
break;
|
||||
case CpuCodeName.Raphael:
|
||||
case CpuCodeName.GraniteRidge:
|
||||
fn = 0x05;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = SendCommand(fn, ref args);
|
||||
version = args[0];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void SetupAddrClass1(uint[] fn)
|
||||
{
|
||||
uint[] args = [1, 1];
|
||||
|
||||
bool command = SendCommand(fn[0], ref args);
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
_dramBaseAddr = args[0];
|
||||
_dramAddrHi = args[1];
|
||||
}
|
||||
|
||||
private void SetupAddrClass2(uint[] fn)
|
||||
{
|
||||
uint[] args = [0, 0, 0, 0, 0, 0];
|
||||
|
||||
bool command = SendCommand(fn[0], ref args);
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
args = [0];
|
||||
command = SendCommand(fn[1], ref args);
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
_dramBaseAddr = args[0];
|
||||
}
|
||||
|
||||
private void SetupAddrClass3(uint[] fn)
|
||||
{
|
||||
uint[] parts = [0, 0];
|
||||
|
||||
// == Part 1 ==
|
||||
uint[] args = [3];
|
||||
bool command = SendCommand(fn[0], ref args);
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
args = [3];
|
||||
command = SendCommand(fn[2], ref args);
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
// 1st Base.
|
||||
parts[0] = args[0];
|
||||
// == Part 1 End ==
|
||||
|
||||
// == Part 2 ==
|
||||
args = [3];
|
||||
command = SendCommand(fn[1], ref args);
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
args = [5];
|
||||
command = SendCommand(fn[0], ref args);
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
args = [5];
|
||||
command = SendCommand(fn[2], ref args);
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
// 2nd base.
|
||||
parts[1] = args[0];
|
||||
// == Part 2 End ==
|
||||
|
||||
_dramBaseAddr = parts[0] & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
private void SetupDramBaseAddr()
|
||||
{
|
||||
uint[] fn = [0, 0, 0];
|
||||
|
||||
switch (_cpuCodeName)
|
||||
{
|
||||
case CpuCodeName.Raphael:
|
||||
case CpuCodeName.GraniteRidge:
|
||||
fn[0] = 0x04;
|
||||
SetupAddrClass1(fn);
|
||||
return;
|
||||
case CpuCodeName.Vermeer:
|
||||
case CpuCodeName.Matisse:
|
||||
case CpuCodeName.CastlePeak:
|
||||
fn[0] = 0x06;
|
||||
SetupAddrClass1(fn);
|
||||
return;
|
||||
case CpuCodeName.Renoir:
|
||||
fn[0] = 0x66;
|
||||
SetupAddrClass1(fn);
|
||||
return;
|
||||
case CpuCodeName.Colfax:
|
||||
case CpuCodeName.PinnacleRidge:
|
||||
fn[0] = 0x0b;
|
||||
fn[1] = 0x0c;
|
||||
SetupAddrClass2(fn);
|
||||
return;
|
||||
case CpuCodeName.Dali:
|
||||
case CpuCodeName.Picasso:
|
||||
case CpuCodeName.RavenRidge:
|
||||
case CpuCodeName.RavenRidge2:
|
||||
fn[0] = 0x0a;
|
||||
fn[1] = 0x3d;
|
||||
fn[2] = 0x0b;
|
||||
SetupAddrClass3(fn);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TransferTableToDram()
|
||||
{
|
||||
uint[] args = [0];
|
||||
uint fn;
|
||||
|
||||
switch (_cpuCodeName)
|
||||
{
|
||||
case CpuCodeName.Raphael:
|
||||
case CpuCodeName.GraniteRidge:
|
||||
fn = 0x03;
|
||||
break;
|
||||
case CpuCodeName.Matisse:
|
||||
case CpuCodeName.Vermeer:
|
||||
fn = 0x05;
|
||||
break;
|
||||
case CpuCodeName.Renoir:
|
||||
args[0] = 3;
|
||||
fn = 0x65;
|
||||
break;
|
||||
case CpuCodeName.Picasso:
|
||||
case CpuCodeName.RavenRidge:
|
||||
case CpuCodeName.RavenRidge2:
|
||||
args[0] = 3;
|
||||
fn = 0x3d;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return SendCommand(fn, ref args);
|
||||
}
|
||||
|
||||
private bool SendCommand(uint msg, ref uint[] args)
|
||||
{
|
||||
uint[] cmdArgs = new uint[SMU_REQ_MAX_ARGS];
|
||||
int argsLength = Math.Min(args.Length, cmdArgs.Length);
|
||||
|
||||
for (int i = 0; i < argsLength; ++i)
|
||||
cmdArgs[i] = args[i];
|
||||
|
||||
uint tmp = 0;
|
||||
if (Mutexes.WaitPciBus(5000))
|
||||
{
|
||||
// Step 1: Wait until the RSP register is non-zero.
|
||||
|
||||
tmp = 0;
|
||||
uint retries = SMU_RETRIES_MAX;
|
||||
do
|
||||
{
|
||||
if (!ReadReg(_rspAddr, ref tmp))
|
||||
{
|
||||
Mutexes.ReleasePciBus();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (tmp == 0 && retries-- != 0);
|
||||
|
||||
// Step 1.b: A command is still being processed meaning a new command cannot be issued.
|
||||
|
||||
if (retries == 0 && tmp == 0)
|
||||
{
|
||||
Mutexes.ReleasePciBus();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 2: Write zero (0) to the RSP register
|
||||
WriteReg(_rspAddr, 0);
|
||||
|
||||
// Step 3: Write the argument(s) into the argument register(s)
|
||||
for (int i = 0; i < cmdArgs.Length; ++i)
|
||||
WriteReg(_argsAddr + (uint)(i * 4), cmdArgs[i]);
|
||||
|
||||
// Step 4: Write the message Id into the Message ID register
|
||||
WriteReg(_cmdAddr, msg);
|
||||
|
||||
// Step 5: Wait until the Response register is non-zero.
|
||||
tmp = 0;
|
||||
retries = SMU_RETRIES_MAX;
|
||||
do
|
||||
{
|
||||
if (!ReadReg(_rspAddr, ref tmp))
|
||||
{
|
||||
Mutexes.ReleasePciBus();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (tmp == 0 && retries-- != 0);
|
||||
|
||||
if (retries == 0 && tmp != (uint)Status.OK)
|
||||
{
|
||||
Mutexes.ReleasePciBus();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Step 6: If the Response register contains OK, then SMU has finished processing the message.
|
||||
|
||||
args = new uint[SMU_REQ_MAX_ARGS];
|
||||
for (byte i = 0; i < SMU_REQ_MAX_ARGS; i++)
|
||||
{
|
||||
if (!ReadReg(_argsAddr + (uint)(i * 4), ref args[i]))
|
||||
{
|
||||
Mutexes.ReleasePciBus();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ReadReg(_rspAddr, ref tmp);
|
||||
Mutexes.ReleasePciBus();
|
||||
}
|
||||
|
||||
return tmp == (uint)Status.OK;
|
||||
}
|
||||
|
||||
private static void WriteReg(uint addr, uint data)
|
||||
{
|
||||
if (Mutexes.WaitPciBus(10))
|
||||
{
|
||||
if (Ring0.WritePciConfig(0x00, SMU_PCI_ADDR_REG, addr))
|
||||
Ring0.WritePciConfig(0x00, SMU_PCI_DATA_REG, data);
|
||||
|
||||
Mutexes.ReleasePciBus();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ReadReg(uint addr, ref uint data)
|
||||
{
|
||||
bool read = false;
|
||||
|
||||
if (Mutexes.WaitPciBus(10))
|
||||
{
|
||||
if (Ring0.WritePciConfig(0x00, SMU_PCI_ADDR_REG, addr))
|
||||
read = Ring0.ReadPciConfig(0x00, SMU_PCI_DATA_REG, out data);
|
||||
|
||||
Mutexes.ReleasePciBus();
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
public struct SmuSensorType
|
||||
{
|
||||
public string Name;
|
||||
public SensorType Type;
|
||||
public float Scale;
|
||||
}
|
||||
|
||||
private enum Status : uint
|
||||
{
|
||||
OK = 0x01,
|
||||
CmdRejectedBusy = 0xFC,
|
||||
CmdRejectedPrereq = 0xFD,
|
||||
UnknownCmd = 0xFE,
|
||||
Failed = 0xFF
|
||||
}
|
||||
|
||||
private enum CpuCodeName
|
||||
{
|
||||
Undefined,
|
||||
Colfax,
|
||||
Renoir,
|
||||
Picasso,
|
||||
Matisse,
|
||||
Threadripper,
|
||||
CastlePeak,
|
||||
RavenRidge,
|
||||
RavenRidge2,
|
||||
SummitRidge,
|
||||
PinnacleRidge,
|
||||
Rembrandt,
|
||||
Vermeer,
|
||||
Vangogh,
|
||||
Cezanne,
|
||||
Milan,
|
||||
Dali,
|
||||
Raphael,
|
||||
GraniteRidge
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user