Created
July 4, 2013 15:26
-
-
Save sp3c73r2038/5928611 to your computer and use it in GitHub Desktop.
patches to make macbookpro 8,2 (2011 early) work under (Gentoo) Linux
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 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; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
-- | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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