-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Different SMU message IDs for different platforms? #3
Comments
Sorry, my discord account was blocked. So you can nolonger reach me by discord. Email is preferred. SMU Call ID do varied between different platforms. All Raven Ridge share the same interface as I know. I haven't analyze recent SMU update, so I'm not sure if AMD had done that. Probably we can check acpi table to see if IDs have changed? |
Currently my BIOS is 1.06 which Acer updated it. I did try to check SMU version by sending the command but unable to make a sense of it. Seems like the message response is in a reverse order as in the SMU command btw the command that failed me is |
SMU is integrated in processor chip. Probably a arm or LM32 risc core.
|
Do you have any lead on finding the source for at least Raven Ridge mobile AGESA documentation? AMD do provide family 15h AGESA documentation (although a bit scarce) but things are a bit different in family 17h where everything is manufacturer only. Asus Zenstates apparently uses SMU commands to change parameters but the information is useful for Summit Ridge/Pinnacle Ridge. |
They all have different SMU commands. Some CPUs support more than one mailbox and commands for these mailboxes also differ. |
@irusanov my ideapad 5 15 should arrive in 2 weeks max. I more than willing to help/work together with you to go on the hunt for the smu addresses. |
Decided to chime in on this fun. The following information was reverse engineered from Ryzen Master so it's a tad easier than reversing a BIOS and has the benefit of guaranteeing support on all supported models that Ryzen Master also supports. So here we go, tagging @FlyGoat and @irusanov as they've helped me out and might find some of this interesting: List of supported CPU codenames that have SMU capabilities:
And here are the SMU addresses for each of them, a total of three different sets of mailboxes: switch (g_smu.codename) {
case CODENAME_MATISSE:
case CODENAME_CASTLEPEAK:
case CODENAME_ROME:
g_smu.addr_reg_rsp = 0x3B10570;
g_smu.addr_reg_args = 0x3B10A40;
g_smu.addr_reg_cmd = 0x3B10524;
break;
case CODENAME_PINNACLERIDGE:
case CODENAME_COLFAX:
case CODENAME_SUMMITRIDGE:
case CODENAME_THREADRIPPER:
g_smu.addr_reg_rsp = 0x3B10568;
g_smu.addr_reg_args = 0x3B10590;
g_smu.addr_reg_cmd = 0x3B1051C;
break;
case CODENAME_RAVENRIDGE:
case CODENAME_RAVENRIDGE2:
case CODENAME_PICASSO:
case CODENAME_RENOIR:
g_smu.addr_reg_rsp = 0x3B10A80;
g_smu.addr_reg_args = 0x3B10A88;
g_smu.addr_reg_cmd = 0x3B10A20;
break;
default:
return -5;
} Now each CPU class either has completely different function/command IDs for the SMU or they simply do not Here's a few functions and their supported CPU models: int smu_set_ppt(int ppt_watts) {
int args[6] = { ppt_watts * 1000, 0, 0, 0, 0, 0 };
int fn;
if (ppt_watts < 45 || ppt_watts > 511)
return SMU_Return_InvalidArgument;
switch (g_smu.codename) {
case CODENAME_CASTLEPEAK:
case CODENAME_MATISSE:
fn = 0x53;
break;
case CODENAME_COLFAX:
case CODENAME_PINNACLERIDGE:
fn = 0x58;
break;
case CODENAME_PICASSO:
fn = 0x2F;
break;
case CODENAME_RENOIR:
fn = 0x32;
break;
default:
return SMU_Return_Unsupported;
}
return smu_send_command(fn, args, 1);
}
int smu_set_tdc(int tdc_amps) {
int args[6] = { tdc_amps * 1000, 0, 0, 0, 0, 0 };
int fn;
if (tdc_amps < 30 || tdc_amps > 511)
return SMU_Return_InvalidArgument;
switch (g_smu.codename) {
case CODENAME_CASTLEPEAK:
case CODENAME_MATISSE:
fn = 0x54;
break;
case CODENAME_COLFAX:
case CODENAME_PINNACLERIDGE:
fn = 0x65;
break;
default:
return SMU_Return_Unsupported;
}
return smu_send_command(fn, args, 1);
}
int smu_set_edc(int edc_amps) {
int args[6] = { edc_amps * 1000, 0, 0, 0, 0, 0 };
int fn;
if (edc_amps < 30 || edc_amps > 511)
return SMU_Return_InvalidArgument;
switch (g_smu.codename) {
case CODENAME_CASTLEPEAK:
case CODENAME_MATISSE:
fn = 0x55;
break;
case CODENAME_COLFAX:
fn = 0x6C;
break;
case CODENAME_PINNACLERIDGE:
fn = 0x66;
break;
default:
return SMU_Return_Unsupported;
}
return smu_send_command(fn, args, 1);
}
int smu_set_pbo_scalar(int scalar) {
int args[6] = { 1000 - (scalar * 100), 0, 0, 0, 0, 0 };
int fn;
if (scalar < 1 || scalar > 10)
return SMU_Return_InvalidArgument;
switch (g_smu.codename) {
case CODENAME_CASTLEPEAK:
case CODENAME_MATISSE:
fn = 0x58;
break;
case CODENAME_PICASSO:
fn = 0x7C;
break;
case CODENAME_COLFAX:
fn = 0x6F;
break;
case CODENAME_PINNACLERIDGE:
fn = 0x6A;
break;
case CODENAME_RENOIR:
fn = 0x3F;
break;
default:
return SMU_Return_Unsupported;
}
return smu_send_command(fn, args, 1);
}
int smu_get_pbo_scalar() {
int args[6] = { 0x3F800000, 0, 0, 0, 0, 0 }, fn, ret;
switch (g_smu.codename) {
case CODENAME_PICASSO:
fn = 0x62;
break;
case CODENAME_CASTLEPEAK:
case CODENAME_MATISSE:
fn = 0x6C;
break;
case CODENAME_COLFAX:
fn = 0x70;
break;
case CODENAME_PINNACLERIDGE:
fn = 0x6f;
break;
case CODENAME_RAVENRIDGE2:
fn = 0x68;
break;
case CODENAME_RENOIR:
fn = 0xf;
break;
default:
return SMU_Return_Unsupported;
}
ret = smu_send_command(fn, args, 1);
if (ret != 0)
return ret;
return (int)*(float*)&args[0];
}
off_t smu_get_dram_base_address() {
int args[6] = { 0, 0, 0, 0, 0, 0 }, fn[3], ret;
// Matisse and Renoir have a PM table that is mapped to
// the base address that contains interesting stuff like
// the current voltage planes for CCD/IOD (VDDP, VDDG)
// as well as best core rankings, gated cores, how long
// cores were gated for, their average and peak voltage
// over time. Basically all the fun stuff Ryzen Master uses
// that no other application seems to be capable of showing.
//
// And you can bet the entire thing is absolutely undocumented.
switch (g_smu.codename) {
case CODENAME_CASTLEPEAK:
case CODENAME_MATISSE:
fn[0] = 0x06;
goto BASE_ADDR_CLASS_1;
case CODENAME_RENOIR:
fn[0] = 0x66;
goto BASE_ADDR_CLASS_1;
case CODENAME_PINNACLERIDGE:
case CODENAME_COLFAX:
fn[0] = 0x0C;
goto BASE_ADDR_CLASS_2;
case CODENAME_PICASSO:
case CODENAME_RAVENRIDGE:
case CODENAME_RAVENRIDGE2:
// These can be done but provide two results.
// No idea what each translates to for now
// but each contains different sets of info.
default:
return SMU_Return_Unsupported;
}
BASE_ADDR_CLASS_1:
args[0] = args[1] = 1;
ret = smu_send_command(fn[0], args, 2);
if (ret != 0)
return ret;
return ((u64)args[1] << 32) | args[0];
BASE_ADDR_CLASS_2:
ret = smu_send_command(fn[0], args, 1);
if (ret != 0)
return ret;
return args[0];
}
int smu_enable_overclocking() {
int args[6] = { 0, 0, 0, 0, 0, 0 }, fn;
switch (g_smu.codename) {
case CODENAME_CASTLEPEAK:
fn = 0x5A;
break;
default:
return SMU_Return_Unsupported;
}
return smu_send_command(fn, args, 1);
}
int smu_disable_overclocking() {
int args[6] = { 0, 0, 0, 0, 0, 0 }, fn;
switch (g_smu.codename) {
case CODENAME_CASTLEPEAK:
fn = 0x5B;
break;
default:
return SMU_Return_Unsupported;
}
return smu_send_command(fn, args, 1);
}
int smu_disable_prochot() {
int args[6] = { 0, 0, 0, 0, 0, 0 }, fn;
switch (g_smu.codename) {
case CODENAME_CASTLEPEAK:
case CODENAME_MATISSE:
fn = 0x5A;
args[0] = 0x1000000;
break;
case CODENAME_PINNACLERIDGE:
case CODENAME_SUMMITRIDGE:
case CODENAME_THREADRIPPER:
case CODENAME_PICASSO:
case CODENAME_COLFAX:
fn = 0x63;
break;
case CODENAME_RAVENRIDGE2:
fn = 0x69;
break;
default:
return SMU_Return_Unsupported;
}
return smu_send_command(fn, args, 1);
}
int smu_get_version() {
int args[6] = { 1, 0, 0, 0, 0, 0 }, ret;
ret = smu_send_command(2, args, 1);
if (ret != 0)
return ret;
return args[0];
} Bonus SMN stuff: double smn_cpu_hw_vid() {
u32 addr;
switch (g_smu.codename) {
case CODENAME_CASTLEPEAK:
addr = 0x5A054;
break;
case CODENAME_MATISSE:
addr = 0x5A050;
break;
case CODENAME_RENOIR:
addr = 0x6F05C;
break;
case CODENAME_COLFAX:
case CODENAME_PICASSO:
case CODENAME_RAVENRIDGE:
case CODENAME_THREADRIPPER:
case CODENAME_RAVENRIDGE2:
case CODENAME_SUMMITRIDGE:
case CODENAME_PINNACLERIDGE:
addr = 0x5A04C;
break;
default:
return 0;
}
return 1.55 - ((smn_read_address(addr) >> 24) * 0.00625);
}
double smn_get_vddcr_soc() {
u32 addr;
switch (g_smu.codename) {
case CODENAME_CASTLEPEAK:
addr = 0x5A05C;
break;
case CODENAME_MATISSE:
addr = 0x5A058;
break;
case CODENAME_RENOIR:
addr = 0x6F064;
break;
case CODENAME_COLFAX:
case CODENAME_PICASSO:
case CODENAME_RAVENRIDGE:
case CODENAME_THREADRIPPER:
case CODENAME_RAVENRIDGE2:
case CODENAME_SUMMITRIDGE:
case CODENAME_PINNACLERIDGE:
addr = 0x5A054;
break;
default:
return 0;
}
return 1.55 - ((smn_read_address(addr) >> 24) * 0.00625);
}
int smn_cpu_prochot_enabled() {
u32 addr;
switch (g_smu.codename) {
case CODENAME_COLFAX:
case CODENAME_MATISSE:
case CODENAME_PICASSO:
case CODENAME_RAVENRIDGE:
case CODENAME_CASTLEPEAK:
case CODENAME_SUMMITRIDGE:
case CODENAME_THREADRIPPER:
case CODENAME_RAVENRIDGE2:
case CODENAME_PINNACLERIDGE:
addr = 0x59804;
break;
default:
return SMU_Return_Unsupported;
}
return smn_read_address(addr) & 1;
}
int cpu_get_fused_pbo_limits(int* tdp, int* ppt, int* tdc, int* edc, int* tjmax, int *minfreq, int* maxfreq) {
int args[6] = { 0, 0, 0, 0, 0, 0 }, base, ret, tmp;
switch (g_smu.codename) {
case CODENAME_MATISSE:
base = 0x5D2BB;
break;
case CODENAME_CASTLEPEAK:
base = 0x5D31B;
break;
case CODENAME_RAVENRIDGE2:
ret = smu_send_command(0x80, args, 1);
if (ret != 0)
return ret;
*edc = args[0] / 1000;
args[0] = 0;
ret = smu_send_command(0x84, args, 1);
if (ret != 0)
return ret;
*tdc = args[0] / 1000;
args[0] = 0;
ret = smu_send_command(0x82, args, 1);
if (ret != 0)
return ret;
*ppt = args[0] / 1000;
args[0] = 0;
ret = smu_send_command(0x83, args, 1);
if (ret != 0)
return ret;
*tdp = args[0] / 1000;
args[0] = 0;
ret = smu_send_command(0x85, args, 1);
if (ret != 0)
return ret;
*tjmax = args[0] / 1000;
*minfreq = 25 * (smn_read_address(0x5D494) & 0xff);
*maxfreq = 25 * (smn_read_address(0x5D497) >> 24);
return 0;
default:
return SMU_Return_Unsupported;
}
// Castle Peak / Matisse
*edc = (smn_read_address(base) >> 30) | 4 * (smn_read_address(base + 1) & 0x7f);
*tdc = (smn_read_address(base + 3) >> 16) & 0x1ff;
*ppt = (smn_read_address(base - 5) >> 17) & 0x1ff;
*tdp = (smn_read_address(base - 3) >> 3) & 0x1ff;
*tjmax = (smn_read_address(base - 6) >> 10) & 0x7f;
tmp = smn_read_address(base + 11);
*minfreq = 25 * ((tmp >> 25) & 0x7f);
*maxfreq = 25 * ((tmp >> 17) & 0xff);
return 0;
} |
Thanks, here's what I've started to document, although I have more commands as well (found mostly experimentally). https://docs.google.com/spreadsheets/d/15qC2GlLiF3gpW5d9pVMP4npJ14yDv_yP2zT6QGEWseg/edit?usp=sharing |
Alright so I've spent a few more days working on reversing the PM tables the SMU calculates and for the specific models I've listed above, this is the sort of information you can receive:
I've written a Linux driver here that exposes access to the SMU that allows you to execute SMU commands (without needing to mess with mailboxes or have to worry about PCI register race conditions), read the SMN address space as well as access the entire PM table. For a little preview of a bit of info the SMU provides: |
Looks like that's what AMD uProf kernel driver did lol |
Haven't spent any time reversing uProf, might be a worthy investment. Anyways as far as I can tell, MP1_SMU and PSMU differ in the mailbox addresses they use, correct? The info above was simply taken from the "DRAM base" that a specific SMU code triggers to update with power and clock information, which Ryzen Master updates once a second. The mailboxes this driver uses are exactly the same that Ryzen Master itself, which uses 3 different mailboxes across all platforms, each platform only ever using one mailbox address set, for tweaking, overclocking & monitoring. The only functional difference I use is the PCI configuration space registers, which are from Ryzen Master as well. You used [0xB8, 0xBC], Linux's SMN reader uses [0x60, 0x64] and Ryzen Master uses [0xC4, 0xC8]. All these registers seem to function exactly the same, which I can only assume is due to having the need to execute multiple SMU commands at once. Is there functional differences between them PSMU and MP1_SMU? |
As far I can tell PSMU is mainly for drivers to gather perf information and MP1_SMU is mainly for BIOS to set options, they have different calling commands. You can check the source of Linux kernel modules included in AMD uProf SDK, That's publicly available and looks like it's doing exactly what you did. |
You may join discord server ryzenshine https://discord.gg/mzmWkqm, somebody is working on enhance these support. |
I'm now trying to reverse engineering SMUv11 Dxe in BIOS and looks like PPTable is a golden key |
Alright I'll have to make an account so I'll do that this weekend. Extra note: Indeed, I've looked at the source of uPerf and it does seem that it's pretty much what I do except that the performance monitoring tables for 3000 series don't exist in it, as well as in general, most of the tables being undocumented. Thankfully I've managed to reverse quite a bit for the 3000 series, mainly to get the info that Ryzen Master presents, which was my goal. Will definitely look into uPerf more when I have time, thanks for the tip. |
This was what I had started implementing with the information from ryzen_adj with an initial ]AMDuProf.NET](https://github.com/GoelBiju/AMDuProf.NET) library. I know that more people would be willing to create better user interfaces for this and that's why I tried to move what ryzen_adj was doing to C# in order to facilitate it. |
Is it possible this driver could even work with Carrizo/Bristol Ridge SMU? |
I want to say yes but I haven't looked at it. I think it would be fun to mess around with those. Push FX like power draw out of those cores 😄 |
amdmsrtweaker method is not really recommended, it's based on bar edit boost state force trick found in previous AMD CPU models. i just used it at the time i didn't figured out yet about DPM solution: https://www.dell.com/community/Inspiron/Inspiron-5576-CPU-throttling/td-p/7495901 |
@irusanov how likely this would be valid for pre-ryzen series? e.g. carrizo, bristol ridge.. |
Ryzen Master has no support for Carrizo/Bristol Ridge. |
if you can provide compiled executable i can test it on my system. it's cpuid 0x15 model 0x65 |
Pre AM4 have a totally different SMU interface so no way. Maybe we can do sth with Bristol Ridge. |
well i already tried to load @leogx9r driver but it hangs at some point as i haven't defined base dram address - no idea what to put there. i also saw below base dram in code TransferTableSmu2Dram - this seems to be defined in amdgpu driver, but haven't looked much further than that. would it make sense to add a bunch of prints to linux driver and recompile it? for mailbox regs i used those for ravenridge |
In order to support them in the driver, you need to add codenames, model numbers, mailbox addresses and commands for the basic operations, e.g. you need the commands to get dram base address and to transfer the table to dram, so you can then read it. If you have added the mailbox addresses, codename, family and model, then you want to try 0x1 and 0x2 commands first. Haven't worked on the linux version of ZenStates for quite a long time, but can probably work something out. |
just tried loading --smu-test-message from your ZenStates-Linux script with all known mailbox regs. all responses have been 0 |
there is a good explanation in 50742_15h_Models_60h-6Fh_BKDG: The SMU uses two blocks, System Manage-ment Controller (SMC) and Platform Security Processor (PSP), in order to assist with many of these tasks. At the architectural level, PSP is known as MP0 and SMC is known as MP1. |
@FlyGoat is completely right @psyborg55 It seems to be a simplified version of the one for 17h family. page 233
PS: Family 16h extends that with arguments register and the protocol is similar to the one used for 17h and 19h The problem is there are just 3 commands (service index) for the software interrupt. Don't know if other IDs are available,
|
great! i immediately spotted that c210_0000 register and remembered i've seen it in a vbios disassembly:
the code above is The Stilt's patch to disable one of the throttling features on AMD R7 integrated graphics, didn't try it yet but i'm quite sure it will work. nice thing if it will be possible to implement more changes directly into vbios. i am on windows (triple-boot linux,win7,win10) so i can try anything given that i can figure out what exactly to do. |
trying to read the registers in 16h BKDG (e.g. D0F0xBC_x3FDC8) is useless. everything zero. is there suppose to be a write to MP1_C2PMSG_31 reg consisting of service request, request ID, feature ID etc.? |
Stilt's patch didn't work. Further research reveals why: in smu_7_0_0_d.h SMU index/data registers are defined 0x80 and 0x81 (multiple times, different names e.g. mmGCK_SMC_IND_INDEX, mmSMU0_SMU_SMC_IND_INDEX etc.) while comparing it with smu_8_0_d.h here they are 0x180 and 0x181. the problem is i can't verify if the Interrupt Argument and Interrupt Request registers are the same across two families (C210_003C and C210_0000) as they don't appear to be defined in driver at least not in this format. since a lot of stuff is different between the two i'd say these registers differ too. as the 16h documentation list only 3 commands i took BIOSSMC_MSG_NBDPM_Enable as an example and looked for x3F9E8 in smu_7_0_0_d.h, it is there ixNB_DPM_CONFIG_1 as well as many other parameters so definitely a lot more than just 3 commands. same goes for smu_8_0_d.h - a bunch of stuff here, @FlyGoat @irusanov can this be used to tweak system power? |
You can try to check coreboot repo, you have basically everything that isn't the literal SMU firmware sources. Not sure how much the former could be useful, but up to version 4.6 they had north of 100K loc of officially "unused" headers that later got purged. |
Hi, at the time of writing I found another tool called Zenstates. Referring to his readme, I can see that there are a few SMU message IDs that doesn't seem to match yours, notably:
as well as some others. The author didn't mention what CPU he is using when reverse engineering the SMU, but he was on SMU version 64.40.00. Testing his app already send my device (Nitro 5 2500U) to 400MHz hell so I won't step further without proper documentation. So this somehow made me to question:
Sorry that I have to ask using the issues section as for some reason I couldn't contact you over Discord. I tried to ask for explanation from the Zenstates author but seems like he didn't reply
The text was updated successfully, but these errors were encountered: