Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 185639
b: refs/heads/master
c: 6a9ee8a
h: refs/heads/master
i:
  185637: 9c9a852
  185635: 9836204
  185631: 238b8c3
v: v3
  • Loading branch information
Dave Airlie authored and Dave Airlie committed Mar 1, 2010
1 parent d6756be commit a7738fd
Show file tree
Hide file tree
Showing 25 changed files with 1,105 additions and 71 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9fd1de52945e06ed88a440c99ca92dab74b9b33c
refs/heads/master: 6a9ee8af344e3bd7dbd61e67037096cdf7f83289
35 changes: 35 additions & 0 deletions trunk/drivers/gpu/drm/i915/i915_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "i915_drv.h"
#include "i915_trace.h"
#include <linux/vgaarb.h>
#include <linux/vga_switcheroo.h>

/* Really want an OS-independent resettable timer. Would like to have
* this loop run for (eg) 3 sec, but have the timer reset every time
Expand Down Expand Up @@ -1199,6 +1200,32 @@ static unsigned int i915_vga_set_decode(void *cookie, bool state)
return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
}

static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_INFO "i915: switched off\n");
/* i915 resume handler doesn't set to D0 */
pci_set_power_state(dev->pdev, PCI_D0);
i915_resume(dev);
} else {
printk(KERN_ERR "i915: switched off\n");
i915_suspend(dev, pmm);
}
}

static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
bool can_switch;

spin_lock(&dev->count_lock);
can_switch = (dev->open_count == 0);
spin_unlock(&dev->count_lock);
return can_switch;
}

static int i915_load_modeset_init(struct drm_device *dev,
unsigned long prealloc_start,
unsigned long prealloc_size,
Expand Down Expand Up @@ -1260,6 +1287,12 @@ static int i915_load_modeset_init(struct drm_device *dev,
if (ret)
goto destroy_ringbuffer;

ret = vga_switcheroo_register_client(dev->pdev,
i915_switcheroo_set_state,
i915_switcheroo_can_switch);
if (ret)
goto destroy_ringbuffer;

intel_modeset_init(dev);

ret = drm_irq_install(dev);
Expand Down Expand Up @@ -1544,6 +1577,7 @@ int i915_driver_unload(struct drm_device *dev)
dev_priv->child_dev_num = 0;
}
drm_irq_uninstall(dev);
vga_switcheroo_unregister_client(dev->pdev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
}

Expand Down Expand Up @@ -1611,6 +1645,7 @@ void i915_driver_lastclose(struct drm_device * dev)

if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
drm_fb_helper_restore();
vga_switcheroo_process_delayed_switch();
return;
}

Expand Down
4 changes: 2 additions & 2 deletions trunk/drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ static int i915_drm_freeze(struct drm_device *dev)
return 0;
}

static int i915_suspend(struct drm_device *dev, pm_message_t state)
int i915_suspend(struct drm_device *dev, pm_message_t state)
{
int error;

Expand Down Expand Up @@ -255,7 +255,7 @@ static int i915_drm_thaw(struct drm_device *dev)
return error;
}

static int i915_resume(struct drm_device *dev)
int i915_resume(struct drm_device *dev)
{
if (pci_enable_device(dev->pdev))
return -EIO;
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,8 @@ extern unsigned int i915_fbpercrtc;
extern unsigned int i915_powersave;
extern unsigned int i915_lvds_downclock;

extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev);
extern void i915_save_display(struct drm_device *dev);
extern void i915_restore_display(struct drm_device *dev);
extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/gpu/drm/i915/intel_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/vga_switcheroo.h>

#include "drmP.h"
#include "drm.h"
Expand Down Expand Up @@ -235,6 +236,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
obj_priv->gtt_offset, fbo);

mutex_unlock(&dev->struct_mutex);
vga_switcheroo_client_fb_set(dev->pdev, info);
return 0;

out_unpin:
Expand Down
160 changes: 120 additions & 40 deletions trunk/drivers/gpu/drm/nouveau/nouveau_acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "nouveau_drm.h"
#include "nv50_display.h"

#include <linux/vga_switcheroo.h>

#define NOUVEAU_DSM_SUPPORTED 0x00
#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00

Expand All @@ -28,31 +30,30 @@
#define NOUVEAU_DSM_POWER_SPEED 0x01
#define NOUVEAU_DSM_POWER_STAMINA 0x02

static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
{
static char muid[] = {
0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
};
static struct nouveau_dsm_priv {
bool dsm_detected;
acpi_handle dhandle;
acpi_handle dsm_handle;
} nouveau_dsm_priv;

static const char nouveau_dsm_muid[] = {
0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
};

struct pci_dev *pdev = dev->pdev;
struct acpi_handle *handle;
static int nouveau_dsm(acpi_handle handle, int func, int arg, int *result)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_object_list input;
union acpi_object params[4];
union acpi_object *obj;
int err;

handle = DEVICE_ACPI_HANDLE(&pdev->dev);

if (!handle)
return -ENODEV;

input.count = 4;
input.pointer = params;
params[0].type = ACPI_TYPE_BUFFER;
params[0].buffer.length = sizeof(muid);
params[0].buffer.pointer = (char *)muid;
params[0].buffer.length = sizeof(nouveau_dsm_muid);
params[0].buffer.pointer = (char *)nouveau_dsm_muid;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = 0x00000102;
params[2].type = ACPI_TYPE_INTEGER;
Expand All @@ -62,7 +63,7 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)

err = acpi_evaluate_object(handle, "_DSM", &input, &output);
if (err) {
NV_INFO(dev, "failed to evaluate _DSM: %d\n", err);
printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
return err;
}

Expand All @@ -86,40 +87,119 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
return 0;
}

int nouveau_hybrid_setup(struct drm_device *dev)
static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
{
int result;

if (nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STATE,
&result))
return -ENODEV;

NV_INFO(dev, "_DSM hardware status gave 0x%x\n", result);

if (result) { /* Ensure that the external GPU is enabled */
nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL);
nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED,
NULL);
} else { /* Stamina mode - disable the external GPU */
nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_STAMINA,
NULL);
nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STAMINA,
NULL);
}
return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
}

static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state)
{
int arg;
if (state == VGA_SWITCHEROO_ON)
arg = NOUVEAU_DSM_POWER_SPEED;
else
arg = NOUVEAU_DSM_POWER_STAMINA;
nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL);
return 0;
}

static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
{
if (id == VGA_SWITCHEROO_IGD)
return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_STAMINA);
else
return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_SPEED);
}

static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
enum vga_switcheroo_state state)
{
if (id == VGA_SWITCHEROO_IGD)
return 0;

return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dsm_handle, state);
}

static int nouveau_dsm_init(void)
{
return 0;
}

bool nouveau_dsm_probe(struct drm_device *dev)
static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
{
int support = 0;
if (nouveau_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
return VGA_SWITCHEROO_IGD;
else
return VGA_SWITCHEROO_DIS;
}

static struct vga_switcheroo_handler nouveau_dsm_handler = {
.switchto = nouveau_dsm_switchto,
.power_state = nouveau_dsm_power_state,
.init = nouveau_dsm_init,
.get_client_id = nouveau_dsm_get_client_id,
};

if (nouveau_dsm(dev, NOUVEAU_DSM_SUPPORTED,
NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &support))
static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
{
acpi_handle dhandle, nvidia_handle;
acpi_status status;
int ret;
uint32_t result;

dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
if (!dhandle)
return false;
status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle);
if (ACPI_FAILURE(status)) {
return false;
}

if (!support)
ret= nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED,
NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
if (ret < 0)
return false;

nouveau_dsm_priv.dhandle = dhandle;
nouveau_dsm_priv.dsm_handle = nvidia_handle;
return true;
}

static bool nouveau_dsm_detect(void)
{
char acpi_method_name[255] = { 0 };
struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
struct pci_dev *pdev = NULL;
int has_dsm = 0;
int vga_count = 0;
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
vga_count++;

has_dsm |= (nouveau_dsm_pci_probe(pdev) == true);
}

if (vga_count == 2 && has_dsm) {
acpi_get_name(nouveau_dsm_priv.dsm_handle, ACPI_FULL_PATHNAME, &buffer);
printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
acpi_method_name);
nouveau_dsm_priv.dsm_detected = true;
return true;
}
return false;
}

void nouveau_register_dsm_handler(void)
{
bool r;

r = nouveau_dsm_detect();
if (!r)
return;

vga_switcheroo_register_handler(&nouveau_dsm_handler);
}

void nouveau_unregister_dsm_handler(void)
{
vga_switcheroo_unregister_handler();
}
9 changes: 6 additions & 3 deletions trunk/drivers/gpu/drm/nouveau/nouveau_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ nouveau_pci_remove(struct pci_dev *pdev)
drm_put_dev(dev);
}

static int
int
nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
Expand Down Expand Up @@ -233,7 +233,7 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
return ret;
}

static int
int
nouveau_pci_resume(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
Expand Down Expand Up @@ -402,15 +402,18 @@ static int __init nouveau_init(void)
nouveau_modeset = 1;
}

if (nouveau_modeset == 1)
if (nouveau_modeset == 1) {
driver.driver_features |= DRIVER_MODESET;
nouveau_register_dsm_handler();
}

return drm_init(&driver);
}

static void __exit nouveau_exit(void)
{
drm_exit(&driver);
nouveau_unregister_dsm_handler();
}

module_init(nouveau_init);
Expand Down
Loading

0 comments on commit a7738fd

Please sign in to comment.