Disclaimer: Please follow this guide being aware of the fact that I'm not an expert regarding the things outlined below, however I made my best attempt.
NVIDIA driver since version 435.17 supports this method. xf86-video-modesetting, xf86-video-amdgpu (450.57), and xf86-video-intel (455.38) are officially supported as iGPU drivers.
For Turing generation cards with Intel Coffee Lake or above CPUs (as well as the Ryzen 5800H Acer Nitro 5 that im using maybe other ryzens too?), it is possible to fully power down the GPU when not in use.
nvidia gpus 1650 and up is supposedly working with this?.
Acer Nitro 5 AN515-45:
- AMD Ryzen 7 5800H
- AMD ATI 06:00.0 Cezanne
- NVIDIA GeForce RTX 3060 Mobile
- Intel Corporation Wi-Fi 6 AX200
- Realtek Semiconductor Co., Ltd. Device 2600
- 2x8GB (16GB) Micron Technology 4ATF1G64HZ-3G2B2
im using archlinux, so all the packages exist in the repos.
pacman -S nvidia-dkms nvidia-utils nvidia-prime
we have to mark the nvidia gpu as Inactive to get it listed in xrandr --listproviders and get the hdmi output showing aswell. also to remedy certain opengl/vulkan application barfing about X BadAlloc errors. probably race to finish and trying to output to a non existant display.
im also using "IgnoreABI" because nvidia fails to load without it on xorg-git which i compile.
the BusID's need to be tweaked for your system. can be grabbed from lspci. https://unix.stackexchange.com/a/585911
/etc/X11/xorg.conf.d/02-amdgpu.conf
Section "ServerFlags"
Option "IgnoreABI" "1"
Option "AutoAddGPU" "false"
Option "AutoBindGPU" "false"
EndSection
Section "ServerLayout"
Identifier "default"
Screen 0 "amdgpu"
Inactive "nvidia"
Option "AllowNVIDIAGPUScreens"
EndSection
Section "Device"
Identifier "amdgpu"
Driver "amdgpu"
BusID "PCI:6:0:0"
Option "TearFree" "true"
Option "DRI" "3"
Option "VariableRefresh" "true"
EndSection
Section "Device"
Identifier "nvidia"
Driver "nvidia"
BusID "PCI:1:0:0"
Option "SidebandSocketPath" "/var/run/nvidia-xdriver"
Option "ProbeAllGpus" "false"
EndSection
Section "Screen"
Identifier "amdgpu"
Device "amdgpu"
EndSection
we also need a few environment variables set to not iterate over the nvidia gpu in certain tasks to activate it randomly for a few moments. in one of the various ways to set them, .pam_environment / .bash_profile / .zprofile etc.
to get the MESA_VK_DEVICE_SELECT id, just run MESA_VK_DEVICE_SELECT=list vkcube
in a terminal.
VK_ICD_FILENAMES="/usr/share/vulkan/icd.d/radeon_icd.i686.json:/usr/share/vulkan/icd.d/radeon_icd.x86_64.json"
DXVK_FILTER_DEVICE_NAME="AMD"
VKD3D_FILTER_DEVICE_NAME="AMD"
MESA_VK_DEVICE_SELECT="1002:1638"
__GLX_VENDOR_LIBRARY_NAME="mesa"
__EGL_VENDOR_LIBRARY_FILENAMES="/usr/share/glvnd/egl_vendor.d/50_mesa.json"
then modify your /usr/bin/prime-run so it uses nvidia with those env vars.
_EGL_VENDOR_LIBRARY_FILENAMES="/usr/share/glvnd/egl_vendor.d/10_nvidia.json" DXVK_FILTER_DEVICE_NAME="NVIDIA" VKD3D_FILTER_DEVICE_NAME="NVIDIA" VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/nvidia_icd.json __NV_PRIME_RENDER_OFFLOAD=1 __VK_LAYER_NV_optimus=NVIDIA_only __GLX_VENDOR_LIBRARY_NAME=nvidia "$@"
then you need udev rules to setup appropiate paths in /dev and just because nvidia sucks.
/etc/udev/rules.d/70-nvidia_uvm.rules
ACTION=="add", DEVPATH=="/bus/pci/drivers/nvidia", RUN+="/usr/bin/nvidia-modprobe -c0 -u"
to get PRIME synchronisation working. https://us.download.nvidia.com/XFree86/Linux-x86_64/470.63.01/README/randr14.html
/etc/modprobed.d/nvidia-prime.conf
options nvidia-drm modeset=1
This makes the dGPU power on/off when the nvidia driver detects usage on the gpu.
i mainly use it with prime-run <application>
and it powers on/off upon exit.
now we can enable the powermanagement option in the nvidia driver. set NVreg_DynamicPowerManagement=0x02 with a modprobe.d/nvidia.conf
/etc/modprobed.d/nvidia.conf
options nvidia "NVreg_DynamicPowerManagement=0x02"
now we can make an udev rule to enable power management, as according to nvidia readme.
/etc/udev/rules.d/80-nvidia_pm.rules
# Remove NVIDIA USB xHCI Host Controller devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1"
# Remove NVIDIA USB Type-C UCSI devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1"
# Remove NVIDIA Audio devices, if present
ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1"
# Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"
# Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on"
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on"
we also need nvidia-persistenced to run to not make the "kernel tear down the device state whenever the NVIDIA device resources are no longer in use". More information here https://download.nvidia.com/XFree86/Linux-x86_64/396.51/README/nvidia-persistenced.html
systemctl enable nvidia-persistenced
reboot and we are good to go.
to check the nvidia gpu state you can cat /proc/driver/nvidia/gpus/0000:01:00.0/power
if its powered off and everything is working as intended you get an output like this.
Runtime D3 status: Enabled (fine-grained)
Video Memory: Off
GPU Hardware Support:
Video Memory Self Refresh: Supported
Video Memory Off: Supported
Power Limits:
Default: N/A milliwatts
GPU Boost: N/A milliwatts
and when its powered on you get an output like this.
Runtime D3 status: Enabled (fine-grained)
Video Memory: Active
GPU Hardware Support:
Video Memory Self Refresh: Supported
Video Memory Off: Supported
Power Limits:
Default: 80000 milliwatts
GPU Boost: 4294967295 milliwatts