Contribute
Register

[Guide] Disabling discrete graphics in dual-GPU laptops

Hi all, My Laptop is T440p Thinkpad i7 4600M, I followed this guide but I was stuck when finding correct position for _INI and _OFF methods.
Code:
MacBook-Pro:patchmatic bangdc$ grep -l Method.*_INI *.dsl
DSDT.dsl
SSDT-5-SaSsdt .dsl
And
Code:
MacBook-Pro:patchmatic bangdc$ grep -l Method.*_OFF *.dsl
DSDT.dsl
In both files, I can not find out :
Code:
\_SB.PCI0.RP05.PEGP
I used IORegistryExplorer to check NV card and saw it is: PCI0@0 -> PEG@1,1 ->IOPP ->GFX0@0, but I also did not find anything look like in _INI method :
Code:
\_SB.PCI0.PEG.IOPP.GFX0
So I don't know how to continue follow guideline, Has anyone ever fixed this for T440p Thinkpad, please help me.
And how to check whether discrete card display was disabled or not?
I attached original DSDT-SSDT files.
Thank you very much.
 

Attachments

  • origin_DSDT-SSDT.zip
    39.3 KB · Views: 189
  • IORegistry.png
    IORegistry.png
    71.6 KB · Views: 145
  • debug_28961.zip
    2.6 MB · Views: 126
If someone owns a HP Envy 13T the patch for deactivating the Nvidia is quite simple. The _INI and the _OFF methods can be found in the SSDT-12-INSYDE.dsl Scope (\_SB.PCI0.RP01.PXSX):

Code:
Method (_INI, 0, NotSerialized)  // _INI: Initialize
        {
            Store (Zero, \_SB.PCI0.RP01.PXSX._ADR)
            Store (Zero, \_SB.PCI0.RP01.PXSX.DHPS)
            //added to turn nvidia/radeon off - EDI by RHM
            External(\_SB.PCI0.RP01.PXSX._OFF, MethodObj)
            _OFF()
        }

That's it, two lines patch and NVidia is gone! Have fun!
 
It seems like I've correctly applied this via hotpatch in my SSDT-DDGPU, as I no longer need to inject a dummy device-ID through Clover, but I'm concerned that the _STA in IOReg's IOACPIPlane is still 0xFFFFFFFF and my battery life is still pretty bad. Is _STA something to worry about? Is something wrong here?

Thanks in advance.
 

Attachments

  • debug_3641.zip
    3.4 MB · Views: 177
Hello,
someone have any good idea about old laptop without _OFF method? I try the solution to look for _PS3, but I cannot reach the solution.
 
Not sure if anyone is still helping folks here but I am having a tough time compiling clean on SSDT-6 (30 errors/this is where SGOF/INI is), SSDT-7 has OFF.... Please assist if at all possible. Thanks!
 

Attachments

  • origin.zip
    92.2 KB · Views: 174
Hi @Feartech

I've successfully patched my rig to allow disabling my RTX2060.
Issue is my current hackintosh was running a GTX960 (Maxwell architecture) won't boot up when these GPUs are attached. I swapped the GTX960 with a GT 640 (Kepler architecture) then it works.

Is there for some reason while disabling the RTX, it also disabled my GTX?
works fine with the GT 640 tho
 
I've updated the logitech control center, but when I saw that it won't see anymore my trackball so I've uninstalled it. I had to reboot to make the uninstall effective and then it stopped working. now I can't access mac os anymore. looked at verbose mode with some help, I saw that the problem was with the graphic card, 'cause it tries to power up something that is unauthorized to work, and the only thing in this status is the discrete GPU. Is there any possibility to solve the problem without reinstalling macOS?
I'm attaching verbose log to make it clear
Overview

The purpose of this guide is to show you how to disable the discrete graphics device with DSDT/SSDT edits in "switched" dual-GPU laptops (eg. Intel+Nvidia[Optimus] and Intel+Radeon).

Because only the Intel device can be used in these laptops, the discrete device is generally left active and using power, contributing to heat, noise, and battery usage. Although the device can usually be disabled in BIOS, it is better to disable it with a custom ACPI setup so the device can still be used when booting Windows.

Although it is a relatively simple patch (sometimes only a one line change), because of the fact that the patch is done to one or more SSDTs, there are many pitfalls to fall into. Also, certain machine/ACPI configurations require different approaches, leading to more complexity. The example DSDT/SSDT set that this guide uses is one of the more complex setups, so it covers most of the issues you might run into with your own.

You should follow this walkthrough with the example before patching your own.

The laptop being used for this guide/example is an "Asus UX303LN" with Intel HD4400 + Nvidia. The Clover F4 extracted tables (ACPI/origin directory) are provided in an attachment to this post.

Note: There is also a full hotpatch guide (for this same computer) here: https://www.tonymacx86.com/threads/guide-using-clover-to-hotpatch-acpi.200137/


Patching requirements

The goal is quite simple. These machines provide an _OFF method, usually in an SSDT, that can be called to power down the discrete device. The easiest fix is to call _OFF from the corresponding _INI method. Note that the _OFF method may be in DSDT or may have a different name (GPOF, OPOF, _PS3, etc.)

Certain implementations of _OFF cannot be called from _INI as they access the EC (Embedded Controller) space. For these machines, _OFF (or a portion of it) must be delayed until _REG (when Arg0==3 and Arg1==1, see ACPI spec for more information regarding _REG). In some cases, calling from _REG is too late and it is either not effective or leads to a crash. In such a case, editing _OFF to remove EC dependencies is necessary, so it can be called from _INI. The code that was removed from _OFF is then inserted into _REG so the effect is the same although the EC work is done later. This is the case with the example ACPI setup in this guide.

Note #1: Not all _OFF implementations have EC related code. In that case, no need to move any such code to _REG as it simply didn't exist in the first place.

Note: #2: Not all ACPI sets have an _INI at the _OFF path. In that case, you simply add an _INI that calls off. Easiest to add it just before the _OFF method:
Code:
Method(_INI) { _OFF() }


Basic patching

It is important to understand how to extract, disassemble and patch your DSDT/SSDT files, and how to install them for your bootloader, etc. This subject is covered in my guide: http://www.tonymacx86.com/yosemite-laptop-support/152573-guide-patching-laptop-dsdt-ssdts.html. You should be familiar with it before attempting this guide.

Because patching for the basics is important, we'll do that first here before getting started on the patching required for disabling the Nvidia card in the example.

This guide will assume that most common rename patches are done in config.plist/ACPI/DSDT/Patches. And it will assume that AutoMerge=true (relatively new Clover feature, added by RehabMan). These patches and settings are default in the guide plists: https://www.tonymacx86.com/threads/guide-booting-the-os-x-installer-on-laptops-with-clover.148093/

In the ACPI patching guide (linked above), the kind of ACPI configuration assumed by this guide is "Partial hotpatch with patched SSDTs", as described in "Recommended configurations".

First, the files are extracted (you can simply download the example files), then disassembled with iasl:
Code:
iasl -da -dl *.aml

After disassembly we can proceed to patch the various files. Because we have common renames in config.plist, and are using AutoMerge=true, we only need to apply functional patches not covered by the defaults from config.plist. And there is no need to correct errors in a file when it requires no patching. The file is, instead, simply omitted from ACPI/patched.

For DSDT.dsl:
"Fix PARSEOP_ZERO Error (agressive)"
"Fix ADBG Error"
"Rename _DSM methods to XDSM"
"IRQ Fix"
"SMBUS Fix"
"OS Check Fix (Windows 8)"
"Add IMEI"
"RTC Fix"
"Fix _WAK Arg0 v2"
"ASUS N55SL/VivoBook"
"USB3 _PRW 0x6D (instant wake)"
"Audio Layout 12"

Since our config.plist has the common renames, none of the SSDTs need any patching, except those required to disable the discrete graphics device. At this point, we are ready to look at the SSDTs to determine the patches needed to disable the device.


Patching for discrete disable

Remember the goal? Call _OFF from _INI...

Now... how to find the SSDT that has _OFF. We can use grep:
Code:
grep -l Method.*_OFF *.dsl

Which shows:
Code:
SSDT-7.dsl
SSDT-8.dsl

Also, it is nice to know where the _INI methods are:
Code:
grep -l Method.*_INI *.dsl

Which shows:
Code:
DSDT.dsl
SSDT-6.dsl
SSDT-7.dsl
SSDT-8.dsl

Note: SSDT-7 and SSDT-8 are listed again. This is likely where the _OFF and associated _INI are located...

We could also open each file individually into MaciASL and search for _OFF and _INI, but using grep is a bit easier and faster.

When we open SSDT-7.dsl and look for "Method (_INI", we find this:
Code:
        Method (_INI, 0, NotSerialized)  // _INI: Initialize
        {
            Store (Zero, \_SB.PCI0.RP05.PEGP._ADR)
        }

This is a typical _INI method for a discrete device, and one that we want to patch so it calls _OFF.

If we click in the method body, we can see the ACPI "path" that this method lives in. MaciASL shows it on the status bar: SSDT -> \_SB.PCI0.RP05.PEGP -> _INI. Now we know that the path to _OFF should also be \_SB.PCI0.RP05.PEGP._OFF.

So, we know that _OFF is either in SSDT-7.dsl or SSDT-8.dsl. If you open SSDT-7.dsl and look for _OFF, you find it is a method inside a PowerResource macro. This is not the _OFF method we want. Open SSDT-8.dsl and look for _OFF there and you'll find a regular _OFF method, which is what we are looking for. So now we know where _OFF is. We need to know, as it is necessary to review the code for potential EC access.

In SSDT-8.dsl, _OFF is defined as follows:
Code:
        Method (_OFF, 0, Serialized)  // _OFF: Power Off
        {
            If (LEqual (CTXT, Zero))
            {
                \_SB.PCI0.LPCB.EC0.SPIN (0x96, Zero)
                If (LNotEqual (GPRF, One))
                {
                    Store (VGAR, VGAB)
                }

                Store (One, CTXT)
            }

            SGOF ()
        }

If you examine the code, you can see it accesses the EC (\_SB.PCI0.LPCB.EC0.SPIN (0x96, Zero). This is going to be a problem and will prevent _OFF from executing fully when called from _INI. Keep in mind it is not always this obvious. The code could have called a method not directly related to the EC, which in turn calls a method in the EC (indirect access). So you may need to do some digging. This example was obvious as the method path includes EC0.

The best way to deal with the EC access is to remove the offending code from _OFF.

We can do it manually, or use a patch like this:
Code:
into method label _OFF parent_label \_SB.PCI0.RP05.PEGP code_regex .*EC.* removeall_matched;

The modified _OFF method is this:
Code:
        Method (_OFF, 0, Serialized)  // _OFF: Power Off
        {
            If (LEqual (CTXT, Zero))
            {
                If (LNotEqual (GPRF, One))
                {
                    Store (VGAR, VGAB)
                }

                Store (One, CTXT)
            }

            SGOF ()
        }

After making this change, attempt to compile SSDT-8.dsl. You will notice it has errors. Really, we should have taken care of these errors before making changes. But we can fix them now by applying the "Cleanup/Fix Errors (SSDT)" patch. That removes some of the errors, but there is still one additional error at line 620:
Code:
       Store (TCAP, \_PR.CPU0._PTC ())

This code is invalid, and in fact will be skipped by the ACPI runtime. \_PR.CPU0._PTC is a method, and of course it is not valid to store something "into" a method. We can simply comment this code:
Code:
//       Store (TCAP, \_PR.CPU0._PTC ())

We should still have the line that we removed, \_SB.PCI0.LPCB.EC0.SPIN (0x96, Zero), executed in _REG, so keep that in mind.

Now that we have fixed _OFF, let's call it from _INI, defined in SSDT-7.dsl.

We can apply patch "Disable from _INI (SSDT)". But our method's path is slightly different from what is common, so we need to modify the patch. Also, we are calling to _OFF which is defined in SSDT-8.dsl, so we need the External declaration.

The modified patch follows:
Code:
into method label _INI parent_label \_SB.PCI0.RP05.PEGP insert
begin
//added to turn nvidia/radeon off\n
External(\_SB.PCI0.RP05.PEGP._OFF, MethodObj)\n
_OFF()\n
end;

After applying this patch, the patched _INI now reads:
Code:
        Method (_INI, 0, NotSerialized)  // _INI: Initialize
        {
            Store (Zero, \_SB.PCI0.RP05.PEGP._ADR)
            //added to turn nvidia/radeon off
            External(\_SB.PCI0.RP05.PEGP._OFF, MethodObj)
            _OFF()
        }

Now we need to turn our attention to DSDT _REG. The _REG method needs to do the EC work that _OFF used to do before we patched it.

Here is the original _REG (for EC0) in DSDT:
Code:
            Method (_REG, 2, NotSerialized)  // _REG: Region Availability
            {
                If (LEqual (Arg0, 0x03))
                {
                    Store (Arg1, ECFL)
                }
            }

There is a patch in my repo to call _OFF from _REG. We can use it as a base for what we need:
Code:
into method label _REG parent_hid PNP0C09 insert
begin
//added to turn nvidia/radeon off\n
If (LAnd(LEqual(Arg0,3),LEqual(Arg1,1)))\n
{\n
    External(\_SB.PCI0.PEG0.PEGP._OFF, MethodObj)\n
    \_SB.PCI0.PEG0.PEGP._OFF()\n
}\n
end;

Instead of calling _OFF, we want it to call SPIN as the original _OFF did.

The modified patch is:
Code:
into method label _REG parent_hid PNP0C09 insert
begin
//added to turn nvidia/radeon off\n
If (LAnd(LEqual(Arg0,3),LEqual(Arg1,1)))\n
{\n
    \_SB.PCI0.LPCB.EC0.SPIN (0x96, Zero)\n
}\n
end;

The modified _REG after patching:
Code:
            Method (_REG, 2, NotSerialized)  // _REG: Region Availability
            {
                If (LEqual (Arg0, 0x03))
                {
                    Store (Arg1, ECFL)
                }
                //added to turn nvidia/radeon off
                If (LAnd(LEqual(Arg0,3),LEqual(Arg1,1)))
                {
                    \_SB.PCI0.LPCB.EC0.SPIN (0x96, Zero)
                }
            }

And that concludes patching. At this point all the patched files can be compiled and placed in ACPI/patched.

Only the patched files are placed in ACPI/patched:
DSDT.aml (has core patches, _REG patch)
SSDT-7.aml (has _INI patch)
SSDT-8.aml (has _OFF patch)

Note that this example is complex and not all laptops will have the same configuration. For most, the _INI and _OFF associated with the discrete device are in the same SSDT. In that case it is not necessary to use the External declaration. You can use the "Call _OFF from _INI (SSDT)" patch directly. Some even have it in DSDT (again you can use the patch directly). And not all _OFF methods access the EC, so the movement of the EC related code to _REG is not needed.

It is also possible that the EC related code is more than one line. All such code should be moved to _REG.


Sleep/Wake Problems

Some laptops have issues with sleep/wake or even shutdown/restart with this patch in place. This was the case with the HP ProBook (with Radeon). The fix is to re-enable the card before sleeping and disable it on wake.

There is a patch in the repository to accomplish this. It is called "Disable/Enable on _WAK/_PTS (DSDT)".

But since this DSDT has _OFF/_ON at a different path than the patch expects, we need to modify it.

Original patch:
Code:
into method label _PTS code_regex ([\s\S]*) replace_matched
begin
External(\\_SB.PCI0.PEG0.PEGP._ON, MethodObj)\n
If (CondRefOf(\\_SB.PCI0.PEG0.PEGP._ON)) { \\_SB.PCI0.PEG0.PEGP._ON() }\n
%1
end;

into method label _WAK code_regex (Return\s+\(.*) replace_matched
begin
External(\\_SB.PCI0.PEG0.PEGP._OFF, MethodObj)\n
If (CondRefOf(\\_SB.PCI0.PEG0.PEGP._OFF)) { \\_SB.PCI0.PEG0.PEGP._OFF() }\n
%1
end;

Modified patch (PEG0 changed to RP05):
Code:
into method label _PTS code_regex ([\s\S]*) replace_matched
begin
External(\\_SB.PCI0.RP05.PEGP._ON, MethodObj)\n
If (CondRefOf(\\_SB.PCI0.RP05.PEGP._ON)) { \\_SB.PCI0.RP05.PEGP._ON() }\n
%1
end;

into method label _WAK code_regex (Return\s+\(.*) replace_matched
begin
External(\\_SB.PCI0.RP05.PEGP._OFF, MethodObj)\n
If (CondRefOf(\\_SB.PCI0.RP05.PEGP._OFF)) { \\_SB.PCI0.RP05.PEGP._OFF() }\n
%1
end;

If your laptop doesn't have problems with sleep/wake/restart/shutdown with the discrete device disabled, then you do not need this patch. You need to test your laptop first to determine if it is needed.

Note: If you patched _OFF to remove EC related code, and you're calling _OFF from _WAK, you may need to also execute that removed code in _WAK. One way to do that is to have an XOFF that is the original/un-patched _OFF that you can call from _WAK instead of calling the (patched) _OFF.


Older laptops

You will notice that older laptops may not have _OFF, or may have an empty _OFF. In such cases, you may notice that _PS3 is required. In some cases, _PS3 will not work unless the invoke the associated _DSM with appropriate params. Details are in post #96 of this thread: http://www.tonymacx86.com/yosemite-...graphics-dual-gpu-laptops-10.html#post1056748


Problem Reporting

If you have problems with your DSDT/SSDTs in patching or fixing errors, please provide all the native files that you're working with.

If you attempt to disable your discrete card according to this guide and it is not working, please provide "Problem Reporting" data as per FAQ.

Read FAQ, "Problem Reporting". Carefully. Attach all requested files/output.
https://www.tonymacx86.com/threads/faq-read-first-laptop-frequent-questions.164990/



Sample Attachment

The following files are used as the example ACPI set in this guide:
 

Attachments

  • WhatsApp Image 2019-12-09 at 22.01.57.jpeg
    WhatsApp Image 2019-12-09 at 22.01.57.jpeg
    281.9 KB · Views: 181
Hello,

Is this guide suitable for desktops PCs?

I have disassembled ACPI files however I can only find a somewhat relevant _INI method but not the _OFF method. I have read that _OFF method can be called differently... And the _INI method I have found looks similar to the one in the guide but not quite..

I found it in SSDT-4-A M I.dsl SB.PCI0.PEG0-2 sections:
Code:
Method (_INI, 0, NotSerialized)  // _INI: Initialize
        {
            If (PRES ())
            {
                Store (LTRX, LTRS)
                Store (OBFX, OBFS)
                If (CondRefOf (PINI))
                {
                    PINI ()
                }
            }
        }
Can you please advise whether I am attempting to use the correct approach to disable my Nvidia GPU?

If I have missed any info apologies in advance.

Many thanks,
Archie
 

Attachments

  • debug_25777.zip
    2.8 MB · Views: 179
Last edited:
@tchemiy
IOReg file is missing. (the txt file is useless)
Carefully follow the below guide
 
@tchemiy
IOReg file is missing. (the txt file is useless)
Carefully follow the below guide
Apologies, please find the proper IOReg file attached.
 

Attachments

  • AD’s iMac.ioreg
    4.3 MB · Views: 228
Back
Top