[Guide] Disabling discrete graphics in dual-GPU laptops

Discussion in 'Mojave Laptop Support' started by RehabMan, May 12, 2015.

  1. RehabMan

    RehabMan Moderator

    Joined:
    May 3, 2012
    Messages:
    188,339
    Motherboard:
    Intel DH67BL
    CPU:
    Core i7-2600K
    Graphics:
    Intel HD 3000
    Mac:
    MacBook Air
    Mobile Phone:
    iOS
    May 12, 2015 at 3:12 AM #1
    RehabMan

    RehabMan Moderator

    Joined:
    May 3, 2012
    Messages:
    188,339
    Motherboard:
    Intel DH67BL
    CPU:
    Core i7-2600K
    Graphics:
    Intel HD 3000
    Mac:
    MacBook Air
    Mobile Phone:
    iOS
    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:
     

    Attached Files:

    Last edited: Apr 19, 2018
  2. daxuenj

    daxuenj

    Joined:
    Nov 13, 2013
    Messages:
    62
    Motherboard:
    OS X 10.9.5
    CPU:
    intel core 2 duo T6570
    Graphics:
    Nvidia Geforce G 105m
    May 12, 2015 at 4:06 AM #2
    daxuenj

    daxuenj

    Joined:
    Nov 13, 2013
    Messages:
    62
    Motherboard:
    OS X 10.9.5
    CPU:
    intel core 2 duo T6570
    Graphics:
    Nvidia Geforce G 105m
    Wow, wonderful !!
    :thumbup:

    Can I translate this post and publish on a Chinese forum ?
     
  3. RehabMan

    RehabMan Moderator

    Joined:
    May 3, 2012
    Messages:
    188,339
    Motherboard:
    Intel DH67BL
    CPU:
    Core i7-2600K
    Graphics:
    Intel HD 3000
    Mac:
    MacBook Air
    Mobile Phone:
    iOS
    May 12, 2015 at 4:19 AM #3
    RehabMan

    RehabMan Moderator

    Joined:
    May 3, 2012
    Messages:
    188,339
    Motherboard:
    Intel DH67BL
    CPU:
    Core i7-2600K
    Graphics:
    Intel HD 3000
    Mac:
    MacBook Air
    Mobile Phone:
    iOS
    I was wondering how long it would be before you asked... Not long!

    As long as the original is linked, and credit given, I'm ok with it...
     
  4. daxuenj

    daxuenj

    Joined:
    Nov 13, 2013
    Messages:
    62
    Motherboard:
    OS X 10.9.5
    CPU:
    intel core 2 duo T6570
    Graphics:
    Nvidia Geforce G 105m
    May 12, 2015 at 4:24 AM #4
    daxuenj

    daxuenj

    Joined:
    Nov 13, 2013
    Messages:
    62
    Motherboard:
    OS X 10.9.5
    CPU:
    intel core 2 duo T6570
    Graphics:
    Nvidia Geforce G 105m
    Yeah, of course. :) I will give credits to you and link the original post. :)
     
  5. s.prashant

    s.prashant

    Joined:
    May 17, 2015
    Messages:
    55
    Motherboard:
    Sony SVF14A15SN
    CPU:
    i5-3337U
    Graphics:
    HD4000/GT735M
    May 23, 2015 at 6:15 PM #5
    s.prashant

    s.prashant

    Joined:
    May 17, 2015
    Messages:
    55
    Motherboard:
    Sony SVF14A15SN
    CPU:
    i5-3337U
    Graphics:
    HD4000/GT735M
    I tried the patches on both SSDT and DSDT from your repo to disable Nvidia. I have attached the patched SSDT and DSDT.

    But it didn't got disabled.
     

    Attached Files:

  6. RehabMan

    RehabMan Moderator

    Joined:
    May 3, 2012
    Messages:
    188,339
    Motherboard:
    Intel DH67BL
    CPU:
    Core i7-2600K
    Graphics:
    Intel HD 3000
    Mac:
    MacBook Air
    Mobile Phone:
    iOS
    May 23, 2015 at 6:28 PM #6
    RehabMan

    RehabMan Moderator

    Joined:
    May 3, 2012
    Messages:
    188,339
    Motherboard:
    Intel DH67BL
    CPU:
    Core i7-2600K
    Graphics:
    Intel HD 3000
    Mac:
    MacBook Air
    Mobile Phone:
    iOS
    Please read post #1, "Problem reporting"
     
  7. s.prashant

    s.prashant

    Joined:
    May 17, 2015
    Messages:
    55
    Motherboard:
    Sony SVF14A15SN
    CPU:
    i5-3337U
    Graphics:
    HD4000/GT735M
    May 23, 2015 at 6:40 PM #7
    s.prashant

    s.prashant

    Joined:
    May 17, 2015
    Messages:
    55
    Motherboard:
    Sony SVF14A15SN
    CPU:
    i5-3337U
    Graphics:
    HD4000/GT735M
     

    Attached Files:

  8. RehabMan

    RehabMan Moderator

    Joined:
    May 3, 2012
    Messages:
    188,339
    Motherboard:
    Intel DH67BL
    CPU:
    Core i7-2600K
    Graphics:
    Intel HD 3000
    Mac:
    MacBook Air
    Mobile Phone:
    iOS
    May 23, 2015 at 6:59 PM #8
    RehabMan

    RehabMan Moderator

    Joined:
    May 3, 2012
    Messages:
    188,339
    Motherboard:
    Intel DH67BL
    CPU:
    Core i7-2600K
    Graphics:
    Intel HD 3000
    Mac:
    MacBook Air
    Mobile Phone:
    iOS
    You did not follow the guide. Note that there is still GFX0 references in SSDT-1.aml (patchmatic output), although it has been renamed to IGPU in DSDT. Renames must always be balanced.

    Also, make sure you haven't dropped any SSDTs that are required (my guess is you have them all, but not possible to verify without seeing native files).

    Also, not a good idea to call _OFF from both _REG and _INI. Call from _INI first, and only call from _REG if you think it is necessary (and them remove call from _INI).
     
  9. s.prashant

    s.prashant

    Joined:
    May 17, 2015
    Messages:
    55
    Motherboard:
    Sony SVF14A15SN
    CPU:
    i5-3337U
    Graphics:
    HD4000/GT735M
    May 23, 2015 at 7:35 PM #9
    s.prashant

    s.prashant

    Joined:
    May 17, 2015
    Messages:
    55
    Motherboard:
    Sony SVF14A15SN
    CPU:
    i5-3337U
    Graphics:
    HD4000/GT735M
    I think it got disabled. Not sure though but it can't be seen in system information.
     

    Attached Files:

  10. RehabMan

    RehabMan Moderator

    Joined:
    May 3, 2012
    Messages:
    188,339
    Motherboard:
    Intel DH67BL
    CPU:
    Core i7-2600K
    Graphics:
    Intel HD 3000
    Mac:
    MacBook Air
    Mobile Phone:
    iOS
    May 24, 2015 at 5:14 AM #10
    RehabMan

    RehabMan Moderator

    Joined:
    May 3, 2012
    Messages:
    188,339
    Motherboard:
    Intel DH67BL
    CPU:
    Core i7-2600K
    Graphics:
    Intel HD 3000
    Mac:
    MacBook Air
    Mobile Phone:
    iOS
    Yup.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice