Installing Debian Wheezy (7.0) on an Apple MacbookPro9,1 (15", June 2012)

The biggest difficulty presented by this device is the presence of a two graphics cards: an Intel integrated device and an additional discrete nVidia card.

Getting a MacBookPro to install and boot in text console mode is fairly easy (instructions for older MacBook Pros apply). However, if you carelessly install a graphical desktop, you may end-up with a blank screen. The system boots, but you have no feedback. If that happens, don't worry too much: network access is possible, as well as booting in rescue mode or booting from the installation medium and chrooting to the installed partition.

The 3.2 kernel has several bugs or limitations which affect this Macbook. Patches are available on the net, but I preferred switching to the 3.8 kernel packaged in Debian experimental, which solved all the problems I noticed.

I have not investigated very long how to make this machine work with BIOS emulation booting because it hides the Intel card (the low power-consumption one which is physically attached to the screen, as far as I understand).

I installed grub-efi to boot in EFI mode instead. For some reason video mode was not set and the system failed to boot. To avoid this problem, you can add this to /etc/default/grub:

GRUB_PRELOAD_MODULES="efi_gap efi_vga video_bochs video_cirrus"

and use grub-mkconfig to regenerate /boot/grub/grub.cfg. As a temporary solution, you can also use insmod from the grub command line to load those modules before booting:

insmod efi_gap
insmod efi_vga
insmod video_bochs
insmod video_cirrus

From then on, you can easily get a working environment by removing all the xserver-xorg-video-* packages safe for xserver-xorg-video-fbdev. This is far from perfect though. To be able to use the Intel card, I had to make sure those few lines were added to the linux section in grub.cfg:

        outb 0x728 1
        outb 0x710 2
        outb 0x740 2
        outb 0x750 0

This enables the Intel card and disables the nVidia card. I put those lines in /etc/grub.d/10_linux, right after the "insmod gzio" line, then used grub-mkconfig again:

grub-mkconfig > /boot/grub/grub.cfg

I then installed the xserver-xorg-video-intel package. With this setup, the nVidia GPU should be off and not consume battery, while the display is quite fine, with 3D acceleration. However, the nvidia card gets powered on again after suspend: read on for a solution below.

Fan control

I installed the macfanctld package to avoid overheating. I simply took the Ubuntu raring package, but I'll try and package it properly for Debian soon.

LCD brightness

The LCD brightness buttons don't work out of the box.

Solution 1: pommed+mouseemu

To be able to adjust the LCD backlight brightness using the relevant keyboard buttons, you may install pommed, but as of writing you will need to patch it: #708150. As mentioned in this bug report, you will also need to modify /etc/pommed.conf:

lcd_sysfs {
        init = -1
        step = 1000
        on_batt = 4000
}

mouseemu was installed by default. It is tempting to remove it, as it is not useful for what it's meant (providing right and middle click), which can be achieved just as well by configuring the synaptics driver by copying /usr/share/X11/xorg.conf.d/50-synaptics.conf into /etc/X11/xorg.conf.d/ and editing this file. In addition, mouseemu has several drawbacks: it disables the Caps Lock green LED as well as the F11 and F12 keyboard buttons (at least by default). However, I found that backlight brightness adjustement with pommed (under GNOME 3) required mouseemu.

Solution 2: gnome-settings-daemon + xbindkeys | input-event-daemon

I wrote this little script that I installed as /usr/local/bin/lcd_brightness:

# Copyright 2013 Thibaut Paumard
# You may use, modify and distribute this file freely, including
# modified versions.
set -e
CMD=/usr/lib/gnome-settings-daemon/gsd-backlight-helper
NSTEPS=20

maxbr=`${CMD} --get-max-brightness`
delta=`expr ${maxbr} / ${NSTEPS}`
curbr=`${CMD} --get-brightness`

op=$1

if [ "x$op" != "x+" -a "x$op" != "x-" ] ; then
    echo "Usage: $0 +/-"
    exit 1
fi

br=$(( ${curbr} ${op} ${delta} ))

[[ $br -le $maxbr ]] || br=$maxbr
[[ $br -ge 0 ]] || br=0

${CMD} --set-brightness ${br}

exit 0

I added this line to sudoers:

ALL     ALL=NOPASSWD: /usr/local/bin/lcd_brightness *

Now we need to bind the key events to this script. For X11 only, the xbindkeys package can do that. Install it and create ~/.xbindkeysrc:

"sudo lcd_brightness - &"
XF86MonBrightnessDown

"sudo lcd_brightness + &"
XF86MonBrightnessUp

Make sure "xbindkeys -f $HOME/.xbindkeysrc" is started with your session. gdm does that automatically. Caveat: this works only in x, not in a virtual console, where you can manually call the script.

input-event-daemon is an lower level alternative to xbindkeys which works also on the virtual console. That's what I use now. How to launch it at boot time is left as an exercise to the reader.

You may keep pommed which allows adjusting LCD brightness depending on AC status.

Suspend / hibernate: uswsusp

s2ram, s2disk, s2both from uswsusp work from the command line and GNOME 3 (menus and lid closing for instance).

Sound in Skype libasound2-plugins

This is probably not macbook specific, but I installed skype on my amd64 installation using there i386 package (after activating the i386 arch in dpkg). To get the internal microphone to work, I had to manually install the libasound2-plugins i386 package.

Wireless

The computer is equipped with a BCM4331 wireless adapter for WiFi. When using the (almost) free b43 driver, I experience frequent disconnections, and I'm not the only one. I'm saying "almost" free because the driver needs a firmware, which isn't free. The solution, as found elsewhere on the web, is to use the proprietary driver from Broadcom. The module itself is called "wl" and can be found in the non-free Debian package broadcom-sta-dkms or the Ubuntu package bcmwl-source. Both need dkms and the headers for your current kernel. Since we use a recent kernel (I use 3.10), we need a recent version of either package. For 3.10, as of writing, the Ubuntu package works. The Debian package in SID works for 3.9.

Swithing graphics

Some background first. This computer comes with and Intel integrated (in the motherboard) graphics device and a NVidia discrete graphical power unit (GPU). The is a graphics multiplexer (gmux) to switch between the two. Which card(s) are on and active is selected by writing certain values to certain ports using "outb", either from a C program or directly from grub.

At the moment, I have succeeded in running with three setups:

However, I have not been able to switch at runtime, and if you need to use the nvidia card, it must remain powered up all the time. The only way I have found to use the nvidia proprietary driver is through bumblebee.

The Arch Linux wiki has a useful page about bumblebee: https://wiki.archlinux.org/index.php/Bumblebee.

Note: this is all pretty experimental. This section is merely some notes about what I believe is fundamental to get each setup running, but these are not complete instructions (yet).

Intel only

This is the simplest solution, and gives you longer battery life, at the expense of performance.

As explained above, you need to switch the GPU off at boot time and switch the gmux to the IGD. This is done by adding those lines in grub.conf:

        outb 0x728 1
        outb 0x710 2
        outb 0x740 2
        outb 0x750 0

At boot time, the screen remains black for about 15s, then you start seeing the boot up messages, and X starts up automatically with the correct driver. The GPU is off, promising extended battery life. However, it come up again after suspend. To switch it off again, compile (with gcc -O2) the following program (borrowed from http://blog.tkassembled.com/364/intel-graphics-on-a-2011-macbook-pro-in-linux/):

//http://blog.tkassembled.com/364/intel-graphics-on-a-2011-macbook-pro-in-linux/

#include <stdio.h> 
#include <sys/io.h>

#define PORT_SWITCH_DISPLAY 0x710
#define PORT_SWITCH_SELECT 0x728
#define PORT_SWITCH_DDC 0x740
#define PORT_DISCRETE_POWER 0x750

static int gmux_switch_to_igd()
{
    outb(1, PORT_SWITCH_SELECT);
    outb(2, PORT_SWITCH_DISPLAY);
    outb(2, PORT_SWITCH_DDC);
    return 0;
}

static void mbp_gpu_power(int state)
{
    outb(state, PORT_DISCRETE_POWER);
}

static void mb_gpu_print()
{
    printf("SELECT:  %hhu\n", inb(PORT_SWITCH_SELECT));
    printf("DISPLAY: %hhu\n", inb(PORT_SWITCH_DISPLAY));
    printf("DDC:     %hhu\n", inb(PORT_SWITCH_DDC));
    printf("POWER:   %hhu\n", inb(PORT_DISCRETE_POWER));
}

int main(int argc, char **argv)
{
    if (iopl(3) < 0) {
        perror ("No IO permissions");
        return 1;
    }
    int state=0;
    if (argc > 1) state = atoi(argv[1]);
    printf("Before:\n");
    mb_gpu_print();
    mbp_gpu_power(state);
    gmux_switch_to_igd();
    printf("After:\n");
    mb_gpu_print();
    return 0;
}

Install it somewhere, for instance /usr/local/bin/mbp_power and make sure it is called whenever the computer wakes up from suspend by adding this script as /etc/pm/sleep.d/10_disable_nvidia.sh:

#
# turn off the ATI card

case "${1}" in
    hibernate|suspend)
        # this is called when going to hibernate or to sleep
            ;;
    resume|thaw)
        # this is called when waking up
        /usr/local/bin/mbp_power
            ;;
esac

Using the GPU only

Using only the GPU should simply be a matter of using outb in grub to turn off the IGD, on the GPU and switch the gmux to the GPU:

        outb 0x728 2
        outb 0x710 3
        outb 0x740 3
        outb 0x750 3

Remember to update-grub whenever you edit /etc/default/grub or /etc/grub.d/*.

However this works only with the nouveau driver. Indeed, the screen seems to be physically connected to the IGD. Apparently the nouveau driver manages to access it nevertheless, but the proprietary nvidia driver fails with a message like "no screens found".

Of course, remove the script 10_disable_nvidia.sh above if you installed it previously.

Using both

Finally, the only solution if you need to be able to use the nvidia driver, is to install bumblebee and primus. These packages allow running specific applications on the GPU while the desktop runs on the IGD. The packages should be on backports, else grab the source from SID (or experimental) and recompile them.

Unfortunately, with this setup, I get a blank screen after suspend or hybernate.

For this setup, you need to switch to the IGD, but power on both the GPU and the IGD:

        outb 0x728 1
        outb 0x710 2
        outb 0x740 2
        outb 0x750 3

You will need at least a small xorg.conf to instruct X11 to use the IGD, else it tries to use the GPU and you get a black screen. By the way, the virtual consoles are not usable with this setup: the screen remains black until X starts up.

Normally, bumblee comes with a companion program, bbswitch, to turn the GPU down when it's not in use (to save battery). On this computer, bbswitch does nothing. Of course, you can use a program like mbp_power above to turn the GPU off manually. Unfortunately, if you do that, you won't be able to use the GPU again until you reboot. I'm 95% cetain a solution exists, but I didn't manage yet.

This is my xorg.conf (for this setup).

Status

Almost everything works. I cannot connect (yet) use an external monitor, although the information here looks promising: