mirror of
https://github.com/ayufan/steam-deck-tools.git
synced 2026-01-03 23:30:16 +01:00
219 lines
5.5 KiB
C#
219 lines
5.5 KiB
C#
using CommonHelpers;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace PowerControl.Helpers.AMD
|
|
{
|
|
public class RyzenSMU : IDisposable
|
|
{
|
|
public IntPtr MMIO_ADDR;
|
|
public uint MMIO_SIZE;
|
|
public uint RES_ADDR, MSG_ADDR, PARAM_ADDR;
|
|
public uint INDEX_ADDR, DATA_ADDR;
|
|
|
|
IntPtr mappedAddress;
|
|
IntPtr physicalHandle;
|
|
InpOut? inpOut;
|
|
|
|
public RyzenSMU()
|
|
{
|
|
}
|
|
|
|
~RyzenSMU()
|
|
{
|
|
Dispose();
|
|
}
|
|
|
|
public bool Opened
|
|
{
|
|
get { return physicalHandle != IntPtr.Zero && mappedAddress != IntPtr.Zero; }
|
|
}
|
|
|
|
public bool Open()
|
|
{
|
|
if (physicalHandle != IntPtr.Zero)
|
|
return true;
|
|
if (MMIO_ADDR == IntPtr.Zero || MMIO_SIZE == 0)
|
|
return false;
|
|
|
|
try
|
|
{
|
|
inpOut = new InpOut();
|
|
mappedAddress = inpOut.MapPhysToLin(MMIO_ADDR, MMIO_SIZE, out physicalHandle);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
TraceLine("RyzenSMU: {0}", e);
|
|
return false;
|
|
}
|
|
|
|
return Opened;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (physicalHandle == IntPtr.Zero)
|
|
return;
|
|
|
|
GC.SuppressFinalize(this);
|
|
inpOut?.UnmapPhysicalMemory(physicalHandle, mappedAddress);
|
|
mappedAddress = IntPtr.Zero;
|
|
physicalHandle = IntPtr.Zero;
|
|
using (inpOut) { }
|
|
inpOut = null;
|
|
}
|
|
|
|
private uint RregRaw(uint reg)
|
|
{
|
|
return (uint)Marshal.ReadInt32(mappedAddress, (int)reg);
|
|
}
|
|
|
|
private void WregRaw(uint reg, uint value)
|
|
{
|
|
Marshal.WriteInt32(mappedAddress, (int)reg, (int)value);
|
|
}
|
|
|
|
private bool WregCheckedRaw(uint reg, uint value)
|
|
{
|
|
WregRaw(reg, value);
|
|
return RregRaw(reg) == value;
|
|
}
|
|
|
|
private bool Wreg(uint reg, uint value)
|
|
{
|
|
if (!Opened)
|
|
return false;
|
|
|
|
bool success = false;
|
|
|
|
try
|
|
{
|
|
if (reg < MMIO_SIZE)
|
|
{
|
|
return success = WregCheckedRaw(reg, value);
|
|
}
|
|
else
|
|
{
|
|
if (!WregCheckedRaw(INDEX_ADDR, reg))
|
|
return false;
|
|
if (!WregCheckedRaw(DATA_ADDR, value))
|
|
return false;
|
|
}
|
|
|
|
return success = true;
|
|
}
|
|
finally
|
|
{
|
|
TraceLine("Wreg: reg={0:X}, value={1:X} => success={2}",
|
|
reg, value, success);
|
|
}
|
|
}
|
|
|
|
private bool Rreg(uint reg, out uint value)
|
|
{
|
|
value = default;
|
|
|
|
if (!Opened)
|
|
return false;
|
|
|
|
bool success = false;
|
|
|
|
try
|
|
{
|
|
if (reg < MMIO_SIZE)
|
|
{
|
|
value = RregRaw(reg);
|
|
}
|
|
else
|
|
{
|
|
if (!WregCheckedRaw(INDEX_ADDR, reg))
|
|
return false;
|
|
value = RregRaw(DATA_ADDR);
|
|
}
|
|
|
|
return success = true;
|
|
}
|
|
finally
|
|
{
|
|
TraceLine("Rreg: reg={0:X} => read={1}/{1:X}, success={2}",
|
|
reg, value, success);
|
|
}
|
|
}
|
|
|
|
private uint WaitForResponse()
|
|
{
|
|
const int timeout = 20;
|
|
for (int i = 0; i < timeout; i++)
|
|
{
|
|
uint value;
|
|
if (!Rreg(RES_ADDR, out value))
|
|
return 0;
|
|
if (value != 0)
|
|
return value;
|
|
Thread.SpinWait(100);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public bool SendMsg(ushort msg, uint param)
|
|
{
|
|
return SendMsg(msg, param, out _);
|
|
}
|
|
|
|
public bool SendMsg(ushort msg, uint param, out uint arg)
|
|
{
|
|
bool success = false;
|
|
|
|
arg = 0;
|
|
|
|
try
|
|
{
|
|
var res = WaitForResponse();
|
|
if (res != 0x1)
|
|
{
|
|
// Reset SMU state
|
|
if (res != 0)
|
|
Wreg(RES_ADDR, 1);
|
|
return false;
|
|
}
|
|
|
|
Wreg(RES_ADDR, 0);
|
|
Wreg(PARAM_ADDR, param);
|
|
Wreg(MSG_ADDR, msg);
|
|
|
|
res = WaitForResponse();
|
|
if (res != 0x1)
|
|
return false;
|
|
|
|
success = Rreg(PARAM_ADDR, out arg);
|
|
return success;
|
|
}
|
|
finally
|
|
{
|
|
TraceLine(">> SendMsg: msg={0:X}, param={1:X} => arg={2}/{2:X}, success={3}",
|
|
msg, param, arg, success);
|
|
}
|
|
}
|
|
|
|
public bool SendMsg<T>(T msg, uint param)
|
|
{
|
|
return SendMsg((ushort)(object)msg, param, out _);
|
|
}
|
|
|
|
public bool SendMsg<T>(T msg, uint param, out uint arg) where T : unmanaged
|
|
{
|
|
return SendMsg((ushort)(object)msg, param, out arg);
|
|
}
|
|
|
|
private static void TraceLine(string format, params object?[]? arg)
|
|
{
|
|
Trace.WriteLine(string.Format(format, arg));
|
|
}
|
|
}
|
|
}
|