Home Mastodon

Disabling the discrete GPU on a Thinkpad T490

I made the error of opting for a model with a discrete GPU, that I never use. Unfortunately, it is impossible to disable by 'conventional' means: Lenovo did not bother to add a BIOS switch, and the usual bbswitch / Optimus / VGA switcheroo are unable to send the proper command to the device.

Someone described how to override the ACPI tables directly, but I put it off while trying to find a better way. It seems there is none. As I will never remember this stuff next time I need it, and because the procedure is slightly different, let's put it all in a memo.

Dump the raw ACPI tables

On Archlinux, the package 'acpica' must be installed to get the ACPI tools.

mkdir dsdt && cd dsdt
acpidump -b
mkdir raw && mv *.dat raw
mkdir dsl && mv *.dsl dsl

Find the GPU reference in the ACPI tables:

grep -rn GPU dsl
...
dsl/ssdt11.dsl:412: TGPU = \_SB.PCI0.LPCB.EC.HKEY.GPTL /* External reference */
dsl/ssdt11.dsl:413: Local0 [0x08] = TGPU /* \_SB_.PCI0.RP09.PEGP.TGPU */

\_SB_.PCI0.RP09.PEGP is the reference we seek. Next search where _ON_: Power On is used in conjunction with the GPU reference.

Edit the table and give it a higher version

I found it in ssdt12.dsl, where I apply the following diff:

diff --git a/dsl/ssdt12.dsl b/dsl/ssdt12.dsl
index 0902ac1..66b9bfe 100644
--- a/dsl/ssdt12.dsl
+++ b/dsl/ssdt12.dsl
@@ -18,7 +18,7 @@
  *     Compiler ID      "INTL"
  *     Compiler Version 0x20160527 (538314023)
  */
-DefinitionBlock ("", "SSDT", 2, "LENOVO", "SgRpSsdt", 0x00001000)
+DefinitionBlock ("", "SSDT", 2, "LENOVO", "SgRpSsdt", 0x00001001)
 {
     External (_SB_.GGIV, MethodObj)    // 1 Arguments
     External (_SB_.GGOV, MethodObj)    // 1 Arguments
@@ -343,7 +343,17 @@ DefinitionBlock ("", "SSDT", 2, "LENOVO", "SgRpSsdt", 0x00001000)
                             PCMR = 0x07
                             PWRS = Zero
                             Sleep (0x10)
-                            \_SB.PCI0.HGON ()
+
+                            // Set this ACPI OSI flag to enable the dGPU.
+                            If (\_OSI ("T490-Hybrid-Graphics"))
+                            {
+                                \_SB.PCI0.HGON ()
+                            }
+                            Else
+                            {
+                                \_SB.PCI0.HGOF ()
+                            }
+
                             _STA = One
                         }

@@ -455,7 +465,15 @@ DefinitionBlock ("", "SSDT", 2, "LENOVO", "SgRpSsdt", 0x00001000)

                     Method (_ON, 0, Serialized)  // _ON_: Power On
                     {
-                        \_SB.PCI0.HGON ()
+                        // Set this ACPI OSI flag to enable the dGPU.
+                        If (\_OSI ("T490-Hybrid-Graphics"))
+                        {
+                            \_SB.PCI0.HGON ()
+                        }
+                        Else
+                        {
+                            \_SB.PCI0.HGOF ()
+                        }
                         Return (Zero)
                     }

Compile the new table:

iasl -tc dsl/ssdt12.dsl

Package and override during boot

mkdir -p img/kernel/firmware/acpi && cd img
cp ../dsl/ssdt12.aml kernel/firmware/acpi/
find kernel | cpio -H newc --create > acpi_override
cp acpi_override /boot

Then read acpi_override during boot in grub using initrd. I put it where Intel / AMD microcode is being loaded.

dmesg | grep -i "ssdt"
[    0.018697] ACPI: SSDT ACPI table found in initrd [kernel/firmware/acpi/ssdt12.aml][0xe3c]
...
[    0.018886] ACPI: Table Upgrade: override [SSDT-LENOVO-SgRpSsdt]