Macbook Pro 5,x Display Switching Linux

NOTE: This project is not finished, yet. I’ll update this post as soon I have time to fiddle with this again.

idg.c

#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);
    }

int main(int argc, char **argv)
{
if (iopl(3) < 0) {
perror ("No IO permissions");
return 1;
}
mbp_gpu_power(0);
gmux_switch_to_igd();
return 0;
}

dgd.c

#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_dgd()
{
outb(2, PORT_SWITCH_SELECT);
outb(3, PORT_SWITCH_DISPLAY);
outb(3, PORT_SWITCH_DDC);
return 0;
    }

int main(int argc, char **argv)
{
if (iopl(3) < 0) {
perror ("No IO permissions");
return 1;
}
gmux_switch_to_dgd();
return 0;
}

Since we rebooted and the 9600M GT is automatically powered up, we just make sure the Apple GMUX screens the GPU we want.

Compile both and copy them into your /bin directory.

 

Now it gets a bit -not so elegant-. I will have a look for a better solution but since it works for me I share my first try.

  • Create 2 boot options in your bootloader
    one with the parameter gpu=i, and one with gpu=d
  • Create a Shell Script in /bin (like “changegpu.sh”):

#!/bin/sh

gpu=`cat /proc/cmdline|awk '{print match($0,"gpu=i")}'`
if [ $gpu -gt 0 ] ;then
rm /etc/X11/xorg.conf
cp /etc/X11/xorg-i.conf /etc/X11/xorg.conf
/bin/igd
echo "integrated"
exit
fi

gpu=`cat /proc/cmdline|awk '{print match($0,"gpu=d")}'`
if [ $gpu -gt 0 ] ;then
rm /etc/X11/xorg.conf
cp /etc/X11/xorg-d.conf /etc/X11/xorg.conf
/bin/dgd
echo "dedicated"
exit
fi

This captures your bootparameters and searches for your gpu=x string. I don’t know how to create environment variables or something I could work with from the beginning. So it’s unlikely that the string gpu=x will appear somewhere else in the parameters it should do it for now.
The script copies a xorg.conf file as the default one (use symlinks if you prefer) and runs the application that switches the gmux.

  • Make the script executable

Create the xorg-x.conf files (just to be sure – propably not needed):

  • Use nvidia-xconfig to create an xorg.conf for you
  • Edit your xorg.conf and add this Option to your “Device” Section:
    BusID           “PCI:2:0:0″
  • Save the new xorg as xorg-d.conf in the same dir
  • Change the String to:
    BusID           “PCI:3:0:0″
  • And save it as xorg-i.conf

Now we can boot with the GPU we want to be enabled and screened. The last step is to execute the script on resume from sleep/hibernation.

  • Using “systemd” create a file called “nameitlikeyouwantto.service” in your systemd/system where your service files are stored (could be /usr/lib or under /etc):
[Unit]
Description=Root resume actions
After=sysinit.target
After=sleep.target

[Service]
User=root
Type=simple
ExecStart=YOUR PATH TO YOUR CHANGEGPU.SH

[Install]
WantedBy=sysinit.target
WantedBy=sleep.target

This Service runs on boot and after every resume event (hibernation, suspension… everyone will call sleep target in the end).

  • Save and enable your newly created service
    (perhaps a nicer alternative would be to create a new target. instead of booting into graphical-target you could boot into your own target that switches to the desired gpu and then start your display manager so you can avoid the hacky gpu parameter – but again – this is quick and dirty for now.)
  • Reboot and choose your GPU in your bootloader

There is a way to make this work on with vgaswitcheroo but I’m happy with this. Since rebooting my Arch doesn’t take segneficantly longer than logging out in OS X rebooting does not bother me.

to various stuff