Skip to content
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

Open
Road-Drum opened this issue Dec 4, 2019 · 33 comments
Open

Different SMU message IDs for different platforms? #3

Road-Drum opened this issue Dec 4, 2019 · 33 comments

Comments

@Road-Drum
Copy link

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:

  • SetOverclockFreqAllCores (0x26)
  • SetOverclockFreqPerCores (0x27)
  • SetBoostLimitFrequency (0x29)
  • SetBoostLimitFrequencyAllCores (0x2B)

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:

  1. Do SMU message ID differs by platform? As you are testing your code on FP5 platform while the other one seems to be on AM4.
  2. Has AMD updated SMU version to scramble the message ID? Recall that AMD recommends to update to AGESA 1.0.04 even for older Zen/Zen+ which we know that there are no issues like RDRAND on Zen2

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

@FlyGoat
Copy link
Owner

FlyGoat commented Dec 10, 2019

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?

@Road-Drum
Copy link
Author

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 GetNameString returns DMA which supposed to be AMD. Probably different endian as I heard the SMU chip is STM chip.

btw the command that failed me is DisableSMUFeatures and here's how I sent the command through the program: 0x6 39. Seems like not enough arguments from the response message.

@FlyGoat
Copy link
Owner

FlyGoat commented Dec 25, 2019

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 GetNameString returns DMA which supposed to be AMD. Probably different endian as I heard the SMU chip is STM chip.

SMU is integrated in processor chip. Probably a arm or LM32 risc core.

btw the command that failed me is DisableSMUFeatures and here's how I sent the command through the program: 0x6 39. Seems like not enough arguments from the response message.
This is a news to me. But I can't do further investigation as I nolonger own an APU machine.

@Road-Drum
Copy link
Author

This is a news to me. But I can't do further investigation as I nolonger own an APU machine.

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.

@irusanov
Copy link

irusanov commented Jan 11, 2020

They all have different SMU commands. Some CPUs support more than one mailbox and commands for these mailboxes also differ.
ZenStates does not support APUs currently, but I am working on it. The addresses I have are the old SMU commands for Matisse (and similar to those for SummitRidge). The SMU addresses for the APUs seem to be consistent, however I don't have a platform to test myself.
Sadly, no public documentation.
AFAIK "Disable SMU Features" got blocked by AMD since some SMU firmware version, but I don't know which one exactly.

@koriwi
Copy link

koriwi commented Apr 23, 2020

@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.

@leogx9r
Copy link

leogx9r commented May 1, 2020

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:

  • Rome
  • Colfax
  • Renoir
  • Picasso
  • Matisse
  • Threadripper
  • Castle Peak
  • Raven Ridge
  • Raven Ridge 2
  • Summit Ridge
  • Pinnacle Ridge

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
exist at all. In addition, some commands take different arguments across CPU ranges.

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;
}

@irusanov
Copy link

irusanov commented May 1, 2020

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

@leogx9r
Copy link

leogx9r commented May 7, 2020

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:

  • Current PBO Limit ( TjMax, PPT, TDC, EDC )
  • Current Power Usage ( Temperature, PPT, TDC, EDC, Core Power, SoC Power )
  • Voltages ( SoC, VDDP, VDDG, Average + Peak Core Voltage )
  • Clock Rates ( "Real" CPU Core Clocks, Time Spent Asleep, FCLK, UCLK, MCLK )

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:

Preview

@FlyGoat
Copy link
Owner

FlyGoat commented May 8, 2020

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:

* Current PBO Limit ( TjMax, PPT, TDC, EDC )

* Current Power Usage ( Temperature, PPT, TDC, EDC, Core Power, SoC Power )

* Voltages ( SoC, VDDP, VDDG, Average + Peak Core Voltage )

* Clock Rates ( "Real" CPU Core Clocks, Time Spent Asleep, FCLK, UCLK, MCLK )

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:

Preview

Looks like that's what AMD uProf kernel driver did lol
That's PSMU instead of MP1_SMU which we played with.

@leogx9r
Copy link

leogx9r commented May 8, 2020

Looks like that's what AMD uProf kernel driver did lol
That's PSMU instead of MP1_SMU which we played with.

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?

@FlyGoat
Copy link
Owner

FlyGoat commented May 8, 2020

Looks like that's what AMD uProf kernel driver did lol
That's PSMU instead of MP1_SMU which we played with.

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.

@FlyGoat
Copy link
Owner

FlyGoat commented May 8, 2020

You may join discord server ryzenshine https://discord.gg/mzmWkqm, somebody is working on enhance these support.

@FlyGoat
Copy link
Owner

FlyGoat commented May 8, 2020

I'm now trying to reverse engineering SMUv11 Dxe in BIOS and looks like PPTable is a golden key

@leogx9r
Copy link

leogx9r commented May 8, 2020

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.

@GoelBiju
Copy link

GoelBiju commented May 8, 2020

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.

@mirh
Copy link

mirh commented Sep 23, 2020

Is it possible this driver could even work with Carrizo/Bristol Ridge SMU?
I knew The Stilt was planning something like that once upon a time.

@sbski
Copy link

sbski commented Oct 13, 2020

Is it possible this driver could even work with Carrizo/Bristol Ridge SMU?
I knew The Stilt was planning something like that once upon a time.

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 😄

@psyborg55
Copy link

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

@psyborg55
Copy link

The SMU addresses for the APUs seem to be consistent

@irusanov how likely this would be valid for pre-ryzen series? e.g. carrizo, bristol ridge..
also need to figure out how to obtain smu_get_dram_base_address, is there any other way except reversing ryzen master? bristol ridge APU is not supported by any tuning software

@irusanov
Copy link

Ryzen Master has no support for Carrizo/Bristol Ridge.
I can add support for those CPUs in the debug tool and then experiment, but have no such processor,
Might see if I can get a cheap one.

@psyborg55
Copy link

if you can provide compiled executable i can test it on my system. it's cpuid 0x15 model 0x65

@FlyGoat
Copy link
Owner

FlyGoat commented Jan 23, 2021

Pre AM4 have a totally different SMU interface so no way. Maybe we can do sth with Bristol Ridge.

@psyborg55
Copy link

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

@irusanov
Copy link

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.
The PM table structure needs to be defined as well, if you want to get the SMU metrics.

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.

@psyborg55
Copy link

just tried loading --smu-test-message from your ZenStates-Linux script with all known mailbox regs. all responses have been 0
i see you implemented mailbox scan in SMUDebugTool. how reliable that method is in discovering mailbox registers?

@psyborg55
Copy link

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.

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.

@irusanov
Copy link

irusanov commented Jan 24, 2021

@FlyGoat is completely right

@psyborg55
According to that document, it's using the D0F0, basically the same 0x0 PCI bus address as the rest of the cpus.
address offset is 0xBC
data offset is 0xB8
CP2MP (CPU to MP) is 0x1300007C.

It seems to be a simplified version of the one for 17h family.
You can use rweverything for easier testing, but that requires windows.

page 233

The index/data pair registers, D0F0xB8 and D0F0xBC, are used to access the registers at
D0F0xBC_x[FFFF_FFFF:0000_0000]. To access any of these registers, the address is first written into the
index register, D0F0xB8, and then the data is read from or written to the data register, D0F0xBC.

PS: Family 16h extends that with arguments register and the protocol is similar to the one used for 17h and 19h
page 155 from this document: https://www.amd.com/system/files/TechDocs/52740_16h_Models_30h-3Fh_BKDG.pdf

The problem is there are just 3 commands (service index) for the software interrupt. Don't know if other IDs are available,
it would require the usual "poking" the SMU and observing the returned value and how the CPU reacts to each command.
That one can be implemented, although doesn't seem to be very useful if we support just those 3 commands

BIOSSMC_MSG_LCLK_DPM_ENABLE. Enables LCLK DPM.
BIOSSMC_MSG_VDDNB_REQUEST. Request VDDNB voltage.
BIOSSMC_MSG_NBDPM_Enable. Enables NB P-state Adjustments.

@psyborg55
Copy link

PS: Family 16h extends that with arguments register and the protocol is similar to the one used for 17h and 19h
page 155 from this document: https://www.amd.com/system/files/TechDocs/52740_16h_Models_30h-3Fh_BKDG.pdf

great! i immediately spotted that c210_0000 register and remembered i've seen it in a vbios disassembly:

  0006: 370000            SET_ATI_PORT  0000  (INDIRECT_IO_MM)
  0009: 0105000b2100200f  MOVE   reg[0b00]  [XXXX]  <-  0f200021
  0011: 0105cc0b01000000  MOVE   reg[0bcc]  [XXXX]  <-  00000001
  0019: 5c05d30b0000e0ffe01b3200  MASK   reg[0bd3]  [XXXX]  &  ffe00000  |  00321be0
  0025: 01050214a1030300  MOVE   reg[1402]  [XXXX]  <-  000303a1
  002d: 01050314a0030300  MOVE   reg[1403]  [XXXX]  <-  000303a0
  0035: 0105171510c11040  MOVE   reg[1517]  [XXXX]  <-  4010c110
  003d: 661e              SET_DATA_BLOCK  1e  (IntegratedSystemInfo)
  003f: 0324413800        MOVE   WS_REMIND/HI32 [...X]  <-  data[0038] [...X]
  0044: 0925413c          AND    WS_REMIND/HI32 [...X]  <-  3c
  0048: 5c224718c341      MASK   reg[1847]  [...X]  &  c3  |  WS_REMIND/HI32 [...X]
  004e: 370000            SET_ATI_PORT  0000  (INDIRECT_IO_MM)
  0051: 010580003c0010c2  MOVE   reg[0080]  [XXXX]  <-  c210003c
  0059: 5164              DELAY_MicroSec  64
  005b: 0105810080000000  MOVE   reg[0081]  [XXXX]  <-  00000080
  0063: 5164              DELAY_MicroSec  64
  0065: 01058000000010c2  MOVE   reg[0080]  [XXXX]  <-  c2100000
  006d: 5164              DELAY_MicroSec  64
  006f: 0725810001        AND    reg[0081]  [...X]  <-  01
  0074: 5132              DELAY_MicroSec  32
  0076: 0d258100c0        OR     reg[0081]  [...X]  <-  c0
  007b: 5132              DELAY_MicroSec  32
  007d: 6725810001        XOR    reg[0081]  [...X]  <-  01
  0082: 5b                EOT

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.
that 0x1300007C i've noticed already but don't know where to put it in the code

@psyborg55
Copy link

The problem is there are just 3 commands (service index) for the software interrupt. Don't know if other IDs are available,
it would require the usual "poking" the SMU and observing the returned value and how the CPU reacts to each command.
That one can be implemented, although doesn't seem to be very useful if we support just those 3 commands

BIOSSMC_MSG_LCLK_DPM_ENABLE. Enables LCLK DPM.
BIOSSMC_MSG_VDDNB_REQUEST. Request VDDNB voltage.
BIOSSMC_MSG_NBDPM_Enable. Enables NB P-state Adjustments.

trying to read the registers in 16h BKDG (e.g. D0F0xBC_x3FDC8) is useless. everything zero.
reading regs from 15h doc e.g. D0F0xBC_xC001_715 returns some value. but most of these don't look interesting or useful.

is there suppose to be a write to MP1_C2PMSG_31 reg consisting of service request, request ID, feature ID etc.?

@psyborg55
Copy link

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?

@mirh
Copy link

mirh commented Feb 1, 2021

You can try to check coreboot repo, you have basically everything that isn't the literal SMU firmware sources.
You can find older platforms (Ontario, Trinity/Richland and Kabini) in the cpu/southbridges/northbridge folders, while newest (Stoney, Picasso and Cezanne) are in soc. Common folder to both is vendorcode.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants