Skip to content

Instantly share code, notes, and snippets.

@sp3c73r2038
Created July 4, 2013 15:26
Show Gist options
  • Save sp3c73r2038/5928611 to your computer and use it in GitHub Desktop.
Save sp3c73r2038/5928611 to your computer and use it in GitHub Desktop.
patches to make macbookpro 8,2 (2011 early) work under (Gentoo) Linux
--- a/drivers/video/backlight/apple_bl.c
+++ b/drivers/video/backlight/apple_bl.c
@@ -31,6 +31,8 @@ struct hw_data {
/* I/O resource to allocate. */
unsigned long iostart;
unsigned long iolen;
+ unsigned long io_1_start;
+ unsigned long io_1_len;
/* Backlight operations structure. */
const struct backlight_ops backlight_ops;
void (*set_brightness)(int);
@@ -44,6 +46,12 @@ static const struct hw_data *hw_data;
static int debug;
module_param_named(debug, debug, int, 0644);
MODULE_PARM_DESC(debug, "Set to one to enable debugging messages.");
+static int use_gmux;
+module_param_named(use_gmux, use_gmux, int, 0644);
+MODULE_PARM_DESC(use_gmux, "Set to one to use gmux backlight method");
+static int max_brightness = 132000;
+module_param_named(max_brightness, max_brightness, int, 0644);
+MODULE_PARM_DESC(max_brightness, "Set to max allowable brightness");
/*
* Implementation for machines with Intel chipset.
@@ -139,6 +147,53 @@ static const struct hw_data nvidia_chipset_data = {
.set_brightness = nvidia_chipset_set_brightness,
};
+#define PORT_BACKLIGHT_1 0x774
+#define PORT_BACKLIGHT_2 0x10724
+
+static void gmux_set_brightness(int intensity)
+{
+ outw(0x2f, PORT_BACKLIGHT_2);
+ outl(intensity, PORT_BACKLIGHT_1);
+}
+
+static int gmux_send_intensity(struct backlight_device *bd)
+{
+ int intensity = bd->props.brightness;
+
+ if (debug)
+ printk(KERN_DEBUG "setting brightness to %d\n",
+ intensity);
+
+ gmux_set_brightness(intensity);
+ return 0;
+}
+
+static int gmux_get_intensity(struct backlight_device *bd)
+{
+ int intensity;
+ intensity = inl(PORT_BACKLIGHT_1);
+
+ if (debug)
+ printk(KERN_DEBUG "read brightness of %d\n",
+ intensity);
+
+ return intensity;
+}
+
+static const struct hw_data gmux_data = {
+ .iostart = PORT_BACKLIGHT_1,
+ .iolen = 4,
+ .io_1_start = PORT_BACKLIGHT_2,
+ .io_1_len = 2,
+ .backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .get_brightness = gmux_get_intensity,
+ .update_status = gmux_send_intensity
+ },
+ .set_brightness = gmux_set_brightness,
+};
+
+
static int __devinit apple_bl_add(struct acpi_device *dev)
{
struct backlight_properties props;
@@ -152,10 +207,16 @@ static int __devinit apple_bl_add(struct acpi_device *dev)
return -ENODEV;
}
- if (host->vendor == PCI_VENDOR_ID_INTEL)
- hw_data = &intel_chipset_data;
- else if (host->vendor == PCI_VENDOR_ID_NVIDIA)
- hw_data = &nvidia_chipset_data;
+ if(use_gmux == 0) {
+ if (host->vendor == PCI_VENDOR_ID_INTEL)
+ hw_data = &intel_chipset_data;
+ else if (host->vendor == PCI_VENDOR_ID_NVIDIA)
+ hw_data = &nvidia_chipset_data;
+ }
+ else
+ hw_data = &gmux_data;
+
+ printk(KERN_ERR "host->vendor == %x gmux = %d", host->vendor, use_gmux);
pci_dev_put(host);
@@ -170,24 +231,38 @@ static int __devinit apple_bl_add(struct acpi_device *dev)
if (!intensity) {
hw_data->set_brightness(1);
- if (!hw_data->backlight_ops.get_brightness(NULL))
+ if (!hw_data->backlight_ops.get_brightness(NULL)) {
+ printk(KERN_ERR "cannot set brightness - no device found\n");
return -ENODEV;
+ }
+
hw_data->set_brightness(0);
}
-
+
if (!request_region(hw_data->iostart, hw_data->iolen,
- "Apple backlight"))
- return -ENXIO;
+ "Apple backlight")) {
+ printk(KERN_ERR "cannot request backlight region\n");
+ // return -ENXIO;
+ }
+ if (hw_data->io_1_start != 0 && !request_region(hw_data->io_1_start, hw_data->io_1_len,
+ "Apple backlight1")) {
+ printk(KERN_ERR "cannot request backlight region 1\n");
+ // return -ENXIO;
+ }
+
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_PLATFORM;
- props.max_brightness = 15;
- apple_backlight_device = backlight_device_register("apple_backlight",
+ props.max_brightness = use_gmux ? max_brightness : 15;
+ apple_backlight_device = backlight_device_register("acpi_video0",
NULL, NULL, &hw_data->backlight_ops, &props);
if (IS_ERR(apple_backlight_device)) {
release_region(hw_data->iostart, hw_data->iolen);
+ if(hw_data->io_1_start)
+ release_region(hw_data->io_1_start, hw_data->io_1_len);
+ printk(KERN_ERR "cannot register device\n");
return PTR_ERR(apple_backlight_device);
}
@@ -203,6 +278,8 @@ static int __devexit apple_bl_remove(struct acpi_device *dev, int type)
backlight_device_unregister(apple_backlight_device);
release_region(hw_data->iostart, hw_data->iolen);
+ if(hw_data->io_1_start)
+ release_region(hw_data->io_1_start, hw_data->io_1_len);
hw_data = NULL;
return 0;
}
diff -rupN a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
--- a/drivers/gpu/drm/radeon/radeon_bios.c 2013-05-30 21:16:40.470096575 +0800
+++ b/drivers/gpu/drm/radeon/radeon_bios.c 2013-05-26 22:13:21.724928639 +0800
@@ -30,6 +30,7 @@
#include "radeon.h"
#include "atom.h"
+#include <linux/firmware.h>
#include <linux/vga_switcheroo.h>
#include <linux/slab.h>
#include <linux/acpi.h>
@@ -57,6 +58,7 @@ static bool igp_read_bios_from_vram(stru
vram_base = pci_resource_start(rdev->pdev, 0);
bios = ioremap(vram_base, size);
if (!bios) {
+ DRM_ERROR("No bios\n");
return false;
}
@@ -66,6 +68,7 @@ static bool igp_read_bios_from_vram(stru
}
rdev->bios = kmalloc(size, GFP_KERNEL);
if (rdev->bios == NULL) {
+ DRM_ERROR("alloc fail\n");
iounmap(bios);
return false;
}
@@ -74,6 +77,42 @@ static bool igp_read_bios_from_vram(stru
return true;
}
+static bool radeon_read_bios_from_firmware(struct radeon_device *rdev)
+{
+ const uint8_t __iomem *bios;
+ resource_size_t size;
+ const struct firmware *fw = NULL;
+
+ request_firmware(&fw, "radeon/vbios.bin", rdev->dev);
+ if (!fw) {
+ DRM_ERROR("No firmware file\n");
+ return false;
+ }
+ size = fw->size;
+ bios = fw->data;
+
+ if (!bios) {
+ DRM_ERROR("No bios\n");
+ return false;
+ }
+
+ if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+ DRM_ERROR("wrong sig\n");
+ release_firmware(fw);
+ return false;
+ }
+ rdev->bios = kmalloc(size, GFP_KERNEL);
+ if (rdev->bios == NULL) {
+ DRM_ERROR("alloc fail\n");
+ release_firmware(fw);
+ return false;
+ }
+ memcpy(rdev->bios, bios, size);
+ release_firmware(fw);
+ return true;
+}
+
+
static bool radeon_read_bios(struct radeon_device *rdev)
{
uint8_t __iomem *bios;
@@ -633,7 +672,9 @@ bool radeon_get_bios(struct radeon_devic
bool r;
uint16_t tmp;
- r = radeon_atrm_get_bios(rdev);
+ r = radeon_read_bios_from_firmware(rdev);
+ if (r == false)
+ r = radeon_atrm_get_bios(rdev);
if (r == false)
r = radeon_acpi_vfct_bios(rdev);
if (r == false)
diff -rupN a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig
--- a/drivers/gpu/vga/Kconfig 2013-05-30 21:16:35.694096497 +0800
+++ b/drivers/gpu/vga/Kconfig 2013-05-26 22:17:16.869920785 +0800
@@ -28,3 +28,9 @@ config VGA_SWITCHEROO
X isn't running and delayed switching until the next logoff. This
feature is called hybrid graphics, ATI PowerXpress, and Nvidia
HybridPower.
+
+config VGA_APPLE_GMUX
+ bool "Apple GMUX handler for Hybrid Graphics"
+ depends on VGA_SWITCHEROO
+ help
+ Include GMUX handler for switching hybrid graphics on newer MacBookPros
diff -rupN a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
--- a/drivers/gpu/vga/vga_switcheroo.c 2013-05-30 21:16:35.683096497 +0800
+++ b/drivers/gpu/vga/vga_switcheroo.c 2013-05-26 22:19:21.617916619 +0800
@@ -99,6 +99,8 @@ static void vga_switcheroo_enable(void)
vgasr_priv.active = true;
}
+static void vga_switcheroo_enable(void);
+
int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
{
mutex_lock(&vgasr_mutex);
@@ -108,10 +110,15 @@ int vga_switcheroo_register_handler(stru
}
vgasr_priv.handler = handler;
- if (vga_switcheroo_ready()) {
+ /* if we get two clients + handler */
+ if (vgasr_priv.registered_clients == 0x3 && vgasr_priv.handler) {
printk(KERN_INFO "vga_switcheroo: enabled\n");
vga_switcheroo_enable();
}
+ // if (vga_switcheroo_ready()) {
+ // printk(KERN_INFO "vga_switcheroo: enabled\n");
+ // vga_switcheroo_enable();
+ // }
mutex_unlock(&vgasr_mutex);
return 0;
}
diff -rupN a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c
--- a/drivers/video/backlight/apple_bl.c 2013-05-30 21:16:24.562096315 +0800
+++ b/drivers/video/backlight/apple_bl.c 2013-05-26 22:24:10.231906980 +0800
@@ -35,6 +35,8 @@ struct hw_data {
/* I/O resource to allocate. */
unsigned long iostart;
unsigned long iolen;
+ unsigned long io_1_start;
+ unsigned long io_1_len;
/* Backlight operations structure. */
const struct backlight_ops backlight_ops;
void (*set_brightness)(int);
@@ -46,6 +48,12 @@ static const struct hw_data *hw_data;
static int debug;
module_param_named(debug, debug, int, 0644);
MODULE_PARM_DESC(debug, "Set to one to enable debugging messages.");
+static int use_gmux;
+module_param_named(use_gmux, use_gmux, int, 0644);
+MODULE_PARM_DESC(use_gmux, "Set to one to use gmux backlight method");
+static int max_brightness = 132000;
+module_param_named(max_brightness, max_brightness, int, 0644);
+MODULE_PARM_DESC(max_brightness, "Set to max allowable brightness");
/*
* Implementation for machines with Intel chipset.
@@ -137,6 +145,53 @@ static const struct hw_data nvidia_chips
.set_brightness = nvidia_chipset_set_brightness,
};
+#define PORT_BACKLIGHT_1 0x774
+#define PORT_BACKLIGHT_2 0x10724
+
+static void gmux_set_brightness(int intensity)
+{
+ outw(0x2f, PORT_BACKLIGHT_2);
+ outl(intensity, PORT_BACKLIGHT_1);
+}
+
+static int gmux_send_intensity(struct backlight_device *bd)
+{
+ int intensity = bd->props.brightness;
+
+ if (debug)
+ printk(KERN_DEBUG "setting brightness to %d\n",
+ intensity);
+
+ gmux_set_brightness(intensity);
+ return 0;
+}
+
+static int gmux_get_intensity(struct backlight_device *bd)
+{
+ int intensity;
+ intensity = inl(PORT_BACKLIGHT_1);
+
+ if (debug)
+ printk(KERN_DEBUG "read brightness of %d\n",
+ intensity);
+
+ return intensity;
+}
+
+static const struct hw_data gmux_data = {
+ .iostart = PORT_BACKLIGHT_1,
+ .iolen = 4,
+ .io_1_start = PORT_BACKLIGHT_2,
+ .io_1_len = 2,
+ .backlight_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .get_brightness = gmux_get_intensity,
+ .update_status = gmux_send_intensity
+ },
+ .set_brightness = gmux_set_brightness,
+};
+
+
static int apple_bl_add(struct acpi_device *dev)
{
struct backlight_properties props;
@@ -150,10 +205,16 @@ static int apple_bl_add(struct acpi_devi
return -ENODEV;
}
- if (host->vendor == PCI_VENDOR_ID_INTEL)
- hw_data = &intel_chipset_data;
- else if (host->vendor == PCI_VENDOR_ID_NVIDIA)
- hw_data = &nvidia_chipset_data;
+ if(use_gmux == 0) {
+ if (host->vendor == PCI_VENDOR_ID_INTEL)
+ hw_data = &intel_chipset_data;
+ else if (host->vendor == PCI_VENDOR_ID_NVIDIA)
+ hw_data = &nvidia_chipset_data;
+ }
+ else
+ hw_data = &gmux_data;
+
+ printk(KERN_ERR "host->vendor == %x gmux = %d", host->vendor, use_gmux);
pci_dev_put(host);
@@ -168,24 +229,38 @@ static int apple_bl_add(struct acpi_devi
if (!intensity) {
hw_data->set_brightness(1);
- if (!hw_data->backlight_ops.get_brightness(NULL))
+ if (!hw_data->backlight_ops.get_brightness(NULL)) {
+ printk(KERN_ERR "cannot set brightness - no device found\n");
return -ENODEV;
+ }
+
hw_data->set_brightness(0);
}
-
+
if (!request_region(hw_data->iostart, hw_data->iolen,
- "Apple backlight"))
- return -ENXIO;
+ "Apple backlight")) {
+ printk(KERN_ERR "cannot request backlight region\n");
+ // return -ENXIO;
+ }
+ if (hw_data->io_1_start != 0 && !request_region(hw_data->io_1_start, hw_data->io_1_len,
+ "Apple backlight1")) {
+ printk(KERN_ERR "cannot request backlight region 1\n");
+ // return -ENXIO;
+ }
+
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_PLATFORM;
- props.max_brightness = 15;
- apple_backlight_device = backlight_device_register("apple_backlight",
+ props.max_brightness = use_gmux ? max_brightness : 15;
+ apple_backlight_device = backlight_device_register("acpi_video0",
NULL, NULL, &hw_data->backlight_ops, &props);
if (IS_ERR(apple_backlight_device)) {
release_region(hw_data->iostart, hw_data->iolen);
+ if(hw_data->io_1_start)
+ release_region(hw_data->io_1_start, hw_data->io_1_len);
+ printk(KERN_ERR "cannot register device\n");
return PTR_ERR(apple_backlight_device);
}
@@ -201,6 +276,8 @@ static int apple_bl_remove(struct acpi_d
backlight_device_unregister(apple_backlight_device);
release_region(hw_data->iostart, hw_data->iolen);
+ if(hw_data->io_1_start)
+ release_region(hw_data->io_1_start, hw_data->io_1_len);
hw_data = NULL;
return 0;
}
diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig
index 96c83a9..46ee883 100644
--- a/drivers/gpu/vga/Kconfig
+++ b/drivers/gpu/vga/Kconfig
@@ -27,3 +27,10 @@ config VGA_SWITCHEROO
X isn't running and delayed switching until the next logoff. This
feature is called hybrid graphics, ATI PowerXpress, and Nvidia
HybridPower.
+
+config VGA_APPLE_GMUX
+ bool "Apple GMUX handler for Hybrid Graphics"
+ depends on VGA_SWITCHEROO
+ help
+ Include GMUX handler for switching hybrid graphics on newer MacBookPros
+
diff --git a/drivers/gpu/vga/Makefile b/drivers/gpu/vga/Makefile
index 14ca30b..921b70b 100644
--- a/drivers/gpu/vga/Makefile
+++ b/drivers/gpu/vga/Makefile
@@ -1,2 +1,4 @@
obj-$(CONFIG_VGA_ARB) += vgaarb.o
obj-$(CONFIG_VGA_SWITCHEROO) += vga_switcheroo.o
+obj-$(CONFIG_VGA_APPLE_GMUX) += apple_gmux.o
+
diff --git a/drivers/gpu/vga/apple_gmux.c b/drivers/gpu/vga/apple_gmux.c
new file mode 100644
index 0000000..b003d69
--- /dev/null
+++ b/drivers/gpu/vga/apple_gmux.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2010 Andreas Heider
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/pnp.h>
+#include <linux/vga_switcheroo.h>
+#include <linux/backlight.h>
+#include <acpi/acpi.h>
+#include <acpi/actypes.h>
+
+struct gmux_priv {
+ acpi_handle gmux_handle;
+
+ struct backlight_device *gmux_backlight_device;
+ struct backlight_properties props;
+};
+
+static struct gmux_priv gmux_priv;
+
+DECLARE_COMPLETION(powerchange_done);
+
+#define PORT_VER_MAJOR 0x704
+#define PORT_VER_MINOR 0x705
+#define PORT_VER_RELEASE 0x706
+
+#define PORT_SWITCH_DISPLAY 0x710
+#define PORT_SWITCH_UNK 0x728
+#define PORT_SWITCH_DDC 0x740
+
+#define PORT_DISCRETE_POWER 0x750
+
+#define PORT_BACKLIGHT 0x774
+#define MAX_BRIGHTNESS 0x1af40
+#define BRIGHTNESS_STEPS 20
+
+#define PORT_INTERRUPT_ENABLE 0x714
+#define PORT_INTERRUPT_STATUS 0x716
+
+#define INTERRUPT_ENABLE 0xFF
+#define INTERRUPT_DISABLE 0x0
+
+#define INTERRUPT_STATUS_ACTIVE 0
+/* display switch complete */
+#define INTERRUPT_STATUS_DISPLAY 1
+/* dedicated card powered up/down */
+#define INTERRUPT_STATUS_POWER 4
+/* unknown, set after boot */
+#define INTERRUPT_STATUS_UNK 5
+
+static int gmux_switchto(enum vga_switcheroo_client_id id)
+{
+ if (id == VGA_SWITCHEROO_IGD) {
+ outb(1, PORT_SWITCH_UNK);
+ outb(2, PORT_SWITCH_DISPLAY);
+ outb(2, PORT_SWITCH_DDC);
+ } else {
+ outb(2, PORT_SWITCH_UNK);
+ outb(3, PORT_SWITCH_DISPLAY);
+ outb(3, PORT_SWITCH_DDC);
+ }
+
+ return 0;
+}
+
+//static int gmux_switchddc(enum vga_switcheroo_client_id id)
+//{
+// if (id == VGA_SWITCHEROO_IGD) {
+// outb(1, PORT_SWITCH_UNK);
+// outb(2, PORT_SWITCH_DDC);
+// } else {
+// outb(2, PORT_SWITCH_UNK);
+// outb(3, PORT_SWITCH_DDC);
+// }
+//
+// return 0;
+//}
+
+static int gmux_set_discrete_state(enum vga_switcheroo_state state)
+{
+ /* TODO: locking for completions needed? */
+ init_completion(&powerchange_done);
+
+ if (state == VGA_SWITCHEROO_ON) {
+ outb(1, PORT_DISCRETE_POWER);
+ outb(3, PORT_DISCRETE_POWER);
+ printk("gmux: discrete powered up\n");
+ } else {
+ outb(0, PORT_DISCRETE_POWER);
+ printk("gmux: discrete powered down\n");
+ }
+
+ /* TODO: add timeout */
+ printk("vga_switcheroo: before completion\n");
+ wait_for_completion(&powerchange_done);
+ printk("vga_switcheroo: after completion\n");
+
+ return 0;
+}
+
+
+static int gmux_set_power_state(enum vga_switcheroo_client_id id,
+ enum vga_switcheroo_state state)
+{
+ if (id == VGA_SWITCHEROO_IGD)
+ return 0;
+
+ return gmux_set_discrete_state(state);
+}
+
+static int gmux_init(void)
+{
+ return 0;
+}
+
+static int gmux_get_client_id(struct pci_dev *pdev)
+{
+ if (pdev->vendor == 0x8086) /* TODO: better detection */
+ return VGA_SWITCHEROO_IGD;
+ else
+ return VGA_SWITCHEROO_DIS;
+}
+
+static struct vga_switcheroo_handler gmux_handler = {
+ .switchto = gmux_switchto,
+// .switchddc = gmux_switchddc,
+ .power_state = gmux_set_power_state,
+ .init = gmux_init,
+ .get_client_id = gmux_get_client_id,
+};
+
+static void disable_interrupts(void)
+{
+ outb(INTERRUPT_DISABLE, PORT_INTERRUPT_ENABLE);
+}
+
+static void enable_interrupts(void)
+{
+ outb(INTERRUPT_ENABLE, PORT_INTERRUPT_ENABLE);
+}
+
+static int interrupt_get_status(void)
+{
+ return inb(PORT_INTERRUPT_STATUS);
+}
+
+static void interrupt_activate_status(void)
+{
+ int old_status;
+ int new_status;
+
+ /* to reactivate interrupts write back current status */
+ old_status = inb(PORT_INTERRUPT_STATUS);
+ outb(old_status, PORT_INTERRUPT_STATUS);
+ new_status = inb(PORT_INTERRUPT_STATUS);
+
+ /* status = 0 indicates active interrupts */
+ if (new_status)
+ printk("gmux: error: activate_status, old_status %d new_status %d\n", old_status, new_status);
+}
+
+static u32 gpe_handler(acpi_handle gpe_device, u32 gpe_number, void *context)
+{
+ int status;
+
+ status = interrupt_get_status();
+ disable_interrupts();
+ printk("gmux: gpe handler called: status %d\n", status);
+
+ interrupt_activate_status();
+ enable_interrupts();
+
+ if (status == INTERRUPT_STATUS_POWER)
+ complete(&powerchange_done);
+
+ return 0;
+}
+
+static bool gmux_detect(void)
+{
+ int ver_major, ver_minor, ver_release;
+
+ ver_major = inb(PORT_VER_MAJOR);
+ ver_minor = inb(PORT_VER_MINOR);
+ ver_release = inb(PORT_VER_RELEASE);
+
+ if (!(ver_major == 0x1 && ver_minor == 0x9)) {
+ printk(KERN_INFO "gmux: detected unknown gmux HW version: %x.%x.%x\n", ver_major, ver_minor, ver_release);
+ return false;
+ }
+ else {
+ printk(KERN_INFO "gmux: detected gmux HW version: %x.%x.%x\n", ver_major, ver_minor, ver_release);
+ return true;
+ }
+}
+
+//static int set_brightness(struct backlight_device *bd)
+//{
+// int brightness = bd->props.brightness;
+//
+// if (bd->props.state & BL_CORE_FBBLANK)
+// brightness = 0;
+// else if (bd->props.state & BL_CORE_SUSPENDED)
+// brightness = 0;
+//
+// outl((MAX_BRIGHTNESS / BRIGHTNESS_STEPS) * brightness, PORT_BACKLIGHT);
+//
+// printk("gmux: set brightness %d\n", brightness);
+// return 0;
+//}
+//
+//static int get_brightness(struct backlight_device *bd)
+//{
+// printk("gmux: get brightness\n");
+// return inl(PORT_BACKLIGHT) / (MAX_BRIGHTNESS / BRIGHTNESS_STEPS);
+//}
+//
+//const struct backlight_ops backlight_ops = {
+// .options = BL_CORE_SUSPENDRESUME,
+// .get_brightness = get_brightness,
+// .update_status = set_brightness
+//};
+//
+//int init_backlight(void)
+//{
+// memset(&gmux_priv.props, 0, sizeof(struct backlight_properties));
+// gmux_priv.props.max_brightness = BRIGHTNESS_STEPS;
+// gmux_priv.gmux_backlight_device = backlight_device_register("gmux", NULL,
+// NULL,
+// &backlight_ops,
+// &gmux_priv.props);
+//
+// if (IS_ERR(gmux_priv.gmux_backlight_device)) {
+// return PTR_ERR(gmux_priv.gmux_backlight_device);
+// }
+//
+// gmux_priv.gmux_backlight_device->props.brightness =
+// backlight_ops.get_brightness(gmux_priv.gmux_backlight_device);
+// backlight_update_status(gmux_priv.gmux_backlight_device);
+//
+// return 0;
+//}
+
+static int __devinit gmux_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+{
+ acpi_status status;
+
+ /* TODO: get ioport region and gpe num from acpi */
+// if (! request_region(0x700, 0xff, "gmux")) {
+ if (! request_region(0x700, 0x51, "gmux")) {
+ printk("gmux: request ioport region failed\n");
+ goto err;
+ }
+
+
+ /* TODO: add more checks if it's really a gmux */
+
+ if (! gmux_detect())
+ goto err;
+
+ status = acpi_install_gpe_handler(NULL, 0x16, ACPI_GPE_LEVEL_TRIGGERED, &gpe_handler, &gmux_priv.gmux_handle);
+ if (ACPI_FAILURE(status)) {
+ printk("gmux: install gpe handler failed: %s\n", acpi_format_exception(status));
+ goto err_detect;
+ }
+
+// if (init_backlight())
+// goto err_backlight;
+
+ status = acpi_enable_gpe(NULL, 0x16);
+ if (ACPI_FAILURE(status)) {
+ printk("gmux: enable gpe failed: %s\n", acpi_format_exception(status));
+ goto err_enable_gpe;
+ }
+
+ enable_interrupts();
+
+ if (vga_switcheroo_register_handler(&gmux_handler))
+ goto err_switcheroo;
+
+ printk("gmux: loaded successfully\n");
+ return 0;
+
+err_switcheroo:
+ acpi_disable_gpe(NULL, 0x16);
+err_enable_gpe:
+// backlight_device_unregister(gmux_priv.gmux_backlight_device);
+//err_backlight:
+ acpi_remove_gpe_handler(NULL, 0x16, &gpe_handler);
+err_detect:
+// release_region(0x700, 0xff);
+ release_region(0x700, 0x51);
+err:
+ return -ENODEV;
+}
+
+static void gmux_pnp_remove(struct pnp_dev * dev)
+{
+ vga_switcheroo_unregister_handler();
+
+// backlight_device_unregister(gmux_priv.gmux_backlight_device);
+
+ disable_interrupts();
+
+ acpi_remove_gpe_handler(NULL, 0x16, &gpe_handler);
+
+ acpi_disable_gpe(NULL, 0x16);
+
+// release_region(0x700, 0xff);
+ release_region(0x700, 0x51);
+
+ printk("gmux: unloaded\n");
+}
+
+static const struct pnp_device_id pnp_dev_table[] = {
+ { "APP000b", 0 },
+ { "", 0 }
+};
+
+static struct pnp_driver gmux_pnp_driver = {
+ .name = "gmux",
+ .id_table = pnp_dev_table,
+ .probe = gmux_pnp_probe,
+ .remove = gmux_pnp_remove,
+};
+
+static int __init init_gmux(void)
+{
+ return pnp_register_driver(&gmux_pnp_driver);
+}
+
+
+static void unload_gmux(void)
+{
+ pnp_unregister_driver(&gmux_pnp_driver);
+}
+
+module_init(init_gmux);
+module_exit(unload_gmux);
+
+MODULE_AUTHOR("Andreas Heider");
+MODULE_DESCRIPTION("Support for Macbook Pro graphics switching");
+MODULE_LICENSE("GPL and additional rights");
+
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 498b284..afc412d 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -62,6 +62,8 @@ static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
/* only one switcheroo per system */
static struct vgasr_priv vgasr_priv;
+static void vga_switcheroo_enable(void);
+
int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
{
mutex_lock(&vgasr_mutex);
@@ -71,6 +73,11 @@ int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
}
vgasr_priv.handler = handler;
+ /* if we get two clients + handler */
+ if (vgasr_priv.registered_clients == 0x3 && vgasr_priv.handler) {
+ printk(KERN_INFO "vga_switcheroo: enabled\n");
+ vga_switcheroo_enable();
+ }
mutex_unlock(&vgasr_mutex);
return 0;
}
--
commit f4f37b555846e4559874d39d849ed195b8bcc261
Author: Petar Radosevic <[email protected]>
Date: Wed Apr 11 16:03:00 2012 +0200
Radeon force load firmware
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 501f488..67e3452 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -30,6 +30,7 @@
#include "radeon.h"
#include "atom.h"
+#include <linux/firmware.h>
#include <linux/vga_switcheroo.h>
#include <linux/slab.h>
/*
@@ -56,6 +57,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
vram_base = pci_resource_start(rdev->pdev, 0);
bios = ioremap(vram_base, size);
if (!bios) {
+ DRM_ERROR("No bios\n");
return false;
}
@@ -65,6 +67,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
}
rdev->bios = kmalloc(size, GFP_KERNEL);
if (rdev->bios == NULL) {
+ DRM_ERROR("alloc fail\n");
iounmap(bios);
return false;
}
@@ -73,6 +76,42 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
return true;
}
+static bool radeon_read_bios_from_firmware(struct radeon_device *rdev)
+{
+ const uint8_t __iomem *bios;
+ resource_size_t size;
+ const struct firmware *fw = NULL;
+
+ request_firmware(&fw, "radeon/vbios.bin", rdev->dev);
+ if (!fw) {
+ DRM_ERROR("No firmware file\n");
+ return false;
+ }
+ size = fw->size;
+ bios = fw->data;
+
+ if (!bios) {
+ DRM_ERROR("No bios\n");
+ return false;
+ }
+
+ if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+ DRM_ERROR("wrong sig\n");
+ release_firmware(fw);
+ return false;
+ }
+ rdev->bios = kmalloc(size, GFP_KERNEL);
+ if (rdev->bios == NULL) {
+ DRM_ERROR("alloc fail\n");
+ release_firmware(fw);
+ return false;
+ }
+ memcpy(rdev->bios, bios, size);
+ release_firmware(fw);
+ return true;
+}
+
+
static bool radeon_read_bios(struct radeon_device *rdev)
{
uint8_t __iomem *bios;
@@ -482,7 +521,9 @@ bool radeon_get_bios(struct radeon_device *rdev)
bool r;
uint16_t tmp;
- r = radeon_atrm_get_bios(rdev);
+ r = radeon_read_bios_from_firmware(rdev);
+ if (r == false)
+ r = radeon_atrm_get_bios(rdev);
if (r == false)
r = igp_read_bios_from_vram(rdev);
if (r == false)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment