This article is a collection of caveats necessary to get Arch Linux up and running on old Intel MacBooks with AMD GPUs.
Steps here are based on various articles and hours of painful debugging.
Article skips full Arch setup process, focusing only on MacBook-specific steps.
This article assumes that you’re using:
- PipeWire as audio server.
- Wayland with Hyprland as a compositor.
Information in this article is based on following sources:
- https://wiki.t2linux.org/guides/hybrid-graphics/
- https://github.com/Dunedan/mbp-2016-linux
- https://wiki.archlinux.org/title/MacBookPro11,x
- https://github.com/pandeiro/arch-on-air
Apple introduces certain limitations for non-macOS systems, such as inability to use Intel GPU.
The most convenient way to bypass them is using rEFInd bootloader. rEFInd handles MacOS version spoofing, SIP and other stuff out of the box.
Install rEFInd by following instructions from ArchWiki.
Important
Don’t forget to add Linux boot configuration into rEFInd config file /boot/EFI/refind/refind.conf
Apple blocks access to integrated Intel GPU for any non-macOS operating system.
rEFInd provides a way to workaround this with spoof_osx_version
config parameter.
Open /boot/EFI/refind/refind.conf
and add a following parameter:
spoof_osx_version 12.7
Add following options to your Arch Linux menu entry in rEFInd config:
data=writeback libata.force=1:noncq acpi_mask_gpe=0x06 acpi_osi=Darwin i915.modeset=1 amdgpu.modeset=0 amdgpu.runpm=1
Unlike Grub or systemd-boot, rEFInd places itself into a non-standard directory inside EFI partition.
Use efibootmgr
to add rEFInd as boot entry:
efibootmgr -c -L 'rEFInd Boot Manager' -l '\EFI\refind\refind_x64.efi'
Important
Remove old macOS boot entries using efibootmgr
to avoid having long boot delays.
NetworkManager won’t let you to connect to a WiFI without a proper dbus session and keychain provider.
The simplest and most reliable way is to use iwd
instead:
pacman -S iwd
systemctl disable --now NetworkManager
systemctl enable --now systemd-resolved
systemctl enable --now systemd-networkd
systemctl enable --now iwd
Tip
Check this ArchWiki page for instructions how to connect to a WiFi network.
You might encounter issues related to missing Broadcom firmware.
In that case, installing broadcom-wl
might help:
paru broadcom-wl-dmks
Then, create /etc/modprobe.d/broadcom-wl-dkms.conf
:
blacklist brcm80211
Unfortunately AMD Cape-Verde gGPUs don’t support dynamic power management. This means, dGPU has to be shut down manually in order to save battery.
Create /etc/udev/rules.d/30-amdgpu-pm.rules
ACTION=="add", SUBSYSTEM=="drm", DRIVERS=="amdgpu", ATTR{device/power/control}="auto"
ACTION=="add", SUBSYSTEM=="drm", DRIVERS=="amdgpu", ATTR{device/power_dpm_force_performance_level}="low"
Go to /etc/modprobe.d
and create a couple of files.
amdgpu.conf
options amdgpu modeset=0
options amdgpu enable_psr=1
options amdgpu si_support=1
options amdgpu cik_support=1
options amdgpu runpm=1
radeon.conf
options radeon si_support=0
options radeon cik_support=0
options radeon runpm=1
Then run sudo mkinitcpio -P
to apply changes.
Use integrated GPU on boot using gpu-switch
Install gpu-switch
tool from AUR using Paru.
Then, use a following command to set iGPU as a primary GPU to drive display:
sudo gpu-switch -i
Note
Operation takes affect only after reboot.
WirePlumber is using /dev/snd/controlC2
which is AMD GPU's HDMI Audio.
This prevents AMDGPU to put a device into D3 cold state.
Make ~/.config/wireplumber/wireplumber.conf.d/50-disable-dgpu-hdmi.conf
:
# disable the HDA function on the Radeon R9 M370X (PCI 01:00.1)
monitor.alsa.rules = [
{
matches = [
{ "device.name" = "alsa_card.pci-0000_01_00.1" }
]
actions = { update-props = { device.disabled = true } }
}
]
After:
- restart wireplumber:
systemctl --user restart wireplumber
- check if
DIS-Audio
isDynOff
:sudo cat /sys/kernel/debug/vgaswitcheroo/switch
Both GPUs are controlled using Apple's GMUX. It is responsible for turning on and off discrete AMD GPU.
The vga-switcheroo kernel module is responsible for controlling a mux.
# set to integrated
sudo sh -c 'echo IDG > /sys/kernel/debug/vgaswitcheroo/switch'
# turn off dGPU
sudo sh -c 'echo OFF > /sys/kernel/debug/vgaswitcheroo/switch'
# print mux state.
# ensure that "DIS" is "OFF" and "DIS-Audio" is "DynOff"
sudo cat /sys/kernel/debug/vgaswitcheroo/switch
Output of /sys/kernel/vgaswitcheroo/switch
should look like this:
0:IGD:+:Pwr:0000:00:02.0
1:DIS: :Off:0000:01:00.0
2:DIS-Audio: :DynOff:0000:01:00.1
Create oneshot systemd unit file /etc/systemd/system/dgpu-poweroff.service
:
[Unit]
Description=Disable discrete GPU (vgaswitcheroo OFF)
Requires=sys-kernel-debug.mount
After=sys-kernel-debug.mount
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo OFF > /sys/kernel/debug/vgaswitcheroo/switch'
[Install]
WantedBy=multi-user.target suspend.target # run at boot *and* after resume
Then, start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now dgpu-poweroff.service
Find GPU PCI of integrated GPU:
$ lspci | grep VGA
00:02.0 VGA compatible controller: Intel Corporation Crystal Well Integrated Graphics Controller (rev 08)
01:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Venus XT [Radeon HD 8870M / R9 M270X/M370X] (rev 83)
Check what DRI card maps to PCI ID:
$ ls -l /dev/dri/by-path
total 0
lrwxrwxrwx 1 root root 8 Apr 23 03:14 pci-0000:00:02.0-card -> ../card1
lrwxrwxrwx 1 root root 13 Apr 23 03:14 pci-0000:00:02.0-render -> ../renderD128
lrwxrwxrwx 1 root root 8 Apr 23 03:14 pci-0000:01:00.0-card -> ../card0
lrwxrwxrwx 1 root root 13 Apr 23 03:14 pci-0000:01:00.0-render -> ../renderD129
In my case, card1
is Intel and card0
is AMD.
To make Intel GPU a preferred GPU for Hyprland, add following into a ~/.config/hypr/hyprland.conf
:
# Prefer iGPU
env = AQ_DRM_DEVICES,/dev/dri/card1
Even with disabled AMD GPU, MacBook still consumes about 15–20 watts (which is a lot).
Although there are a lot of things that can be tweaked, the most basic thing to address is setting a correct CPU power profile.
I recommend using battop tool to monitor power consumption during power optimization.
PSR (panel self-refresh) and FBC (frame-buffer compression) save ~0.3-0.5 W when the screen shows static content.
Create /etc/modprobe.d/i915.conf
:
options i915 enable_psr=1
options i915 enable_fbc=1
options i915 enable_dc=1
The auto-cpufreq
daemon allows automatic CPU power profile configuration based on battery capacity and charging status.
Pros:
- Automatic power profile management based on charging state.
Cons:
- By default it will put CPU into a power save mode when not connected to a charger. This will cause a drastic performance decrease.
- Written in Python and consumes 20MB of RAM which is quite a lot for a simple CPU frequency daemon.
Install auto-cpufreq
daemon to automatically control CPU frequency:
paru auto-cpufreq
sudo systemctl enable --now auto-cpufreq
Important
Don't install auto-cpufreq-git
as it's broken.
power-profiles-deamon
package provides DBus service and a tool to switch CPU profiles.
sudo pacman -S power-profiles-daemon
sudo systemctl enable --now power-profiles-daemon.service
Later, you can change power profile to power saver, performance or balanced:
powerprofilesctl set power-saver
powerprofilesctl set balanced