diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/gpu/vga/vga_switcheroo.c')
-rw-r--r-- | ANDROID_3.4.5/drivers/gpu/vga/vga_switcheroo.c | 492 |
1 files changed, 0 insertions, 492 deletions
diff --git a/ANDROID_3.4.5/drivers/gpu/vga/vga_switcheroo.c b/ANDROID_3.4.5/drivers/gpu/vga/vga_switcheroo.c deleted file mode 100644 index 58434e80..00000000 --- a/ANDROID_3.4.5/drivers/gpu/vga/vga_switcheroo.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright (c) 2010 Red Hat Inc. - * Author : Dave Airlie <airlied@redhat.com> - * - * - * Licensed under GPLv2 - * - * vga_switcheroo.c - Support for laptop with dual GPU using one set of outputs - - Switcher interface - methods require for ATPX and DCM - - switchto - this throws the output MUX switch - - discrete_set_power - sets the power state for the discrete card - - GPU driver interface - - set_gpu_state - this should do the equiv of s/r for the card - - this should *not* set the discrete power state - - switch_check - check if the device is in a position to switch now - */ - -#include <linux/module.h> -#include <linux/dmi.h> -#include <linux/seq_file.h> -#include <linux/uaccess.h> -#include <linux/fs.h> -#include <linux/debugfs.h> -#include <linux/fb.h> - -#include <linux/pci.h> -#include <linux/vga_switcheroo.h> - -struct vga_switcheroo_client { - struct pci_dev *pdev; - struct fb_info *fb_info; - int pwr_state; - void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state); - void (*reprobe)(struct pci_dev *pdev); - bool (*can_switch)(struct pci_dev *pdev); - int id; - bool active; -}; - -static DEFINE_MUTEX(vgasr_mutex); - -struct vgasr_priv { - - bool active; - bool delayed_switch_active; - enum vga_switcheroo_client_id delayed_client_id; - - struct dentry *debugfs_root; - struct dentry *switch_file; - - int registered_clients; - struct vga_switcheroo_client clients[VGA_SWITCHEROO_MAX_CLIENTS]; - - struct vga_switcheroo_handler *handler; -}; - -static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv); -static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv); - -/* only one switcheroo per system */ -static struct vgasr_priv vgasr_priv; - -int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) -{ - mutex_lock(&vgasr_mutex); - if (vgasr_priv.handler) { - mutex_unlock(&vgasr_mutex); - return -EINVAL; - } - - vgasr_priv.handler = handler; - mutex_unlock(&vgasr_mutex); - return 0; -} -EXPORT_SYMBOL(vga_switcheroo_register_handler); - -void vga_switcheroo_unregister_handler(void) -{ - mutex_lock(&vgasr_mutex); - vgasr_priv.handler = NULL; - mutex_unlock(&vgasr_mutex); -} -EXPORT_SYMBOL(vga_switcheroo_unregister_handler); - -static void vga_switcheroo_enable(void) -{ - int i; - int ret; - /* call the handler to init */ - vgasr_priv.handler->init(); - - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - ret = vgasr_priv.handler->get_client_id(vgasr_priv.clients[i].pdev); - if (ret < 0) - return; - - vgasr_priv.clients[i].id = ret; - } - vga_switcheroo_debugfs_init(&vgasr_priv); - vgasr_priv.active = true; -} - -int vga_switcheroo_register_client(struct pci_dev *pdev, - void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state), - void (*reprobe)(struct pci_dev *pdev), - bool (*can_switch)(struct pci_dev *pdev)) -{ - int index; - - mutex_lock(&vgasr_mutex); - /* don't do IGD vs DIS here */ - if (vgasr_priv.registered_clients & 1) - index = 1; - else - index = 0; - - vgasr_priv.clients[index].pwr_state = VGA_SWITCHEROO_ON; - vgasr_priv.clients[index].pdev = pdev; - vgasr_priv.clients[index].set_gpu_state = set_gpu_state; - vgasr_priv.clients[index].reprobe = reprobe; - vgasr_priv.clients[index].can_switch = can_switch; - vgasr_priv.clients[index].id = -1; - if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) - vgasr_priv.clients[index].active = true; - - vgasr_priv.registered_clients |= (1 << index); - - /* 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; -} -EXPORT_SYMBOL(vga_switcheroo_register_client); - -void vga_switcheroo_unregister_client(struct pci_dev *pdev) -{ - int i; - - mutex_lock(&vgasr_mutex); - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - if (vgasr_priv.clients[i].pdev == pdev) { - vgasr_priv.registered_clients &= ~(1 << i); - break; - } - } - - printk(KERN_INFO "vga_switcheroo: disabled\n"); - vga_switcheroo_debugfs_fini(&vgasr_priv); - vgasr_priv.active = false; - mutex_unlock(&vgasr_mutex); -} -EXPORT_SYMBOL(vga_switcheroo_unregister_client); - -void vga_switcheroo_client_fb_set(struct pci_dev *pdev, - struct fb_info *info) -{ - int i; - - mutex_lock(&vgasr_mutex); - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - if (vgasr_priv.clients[i].pdev == pdev) { - vgasr_priv.clients[i].fb_info = info; - break; - } - } - mutex_unlock(&vgasr_mutex); -} -EXPORT_SYMBOL(vga_switcheroo_client_fb_set); - -static int vga_switcheroo_show(struct seq_file *m, void *v) -{ - int i; - mutex_lock(&vgasr_mutex); - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - seq_printf(m, "%d:%s:%c:%s:%s\n", i, - vgasr_priv.clients[i].id == VGA_SWITCHEROO_DIS ? "DIS" : "IGD", - vgasr_priv.clients[i].active ? '+' : ' ', - vgasr_priv.clients[i].pwr_state ? "Pwr" : "Off", - pci_name(vgasr_priv.clients[i].pdev)); - } - mutex_unlock(&vgasr_mutex); - return 0; -} - -static int vga_switcheroo_debugfs_open(struct inode *inode, struct file *file) -{ - return single_open(file, vga_switcheroo_show, NULL); -} - -static int vga_switchon(struct vga_switcheroo_client *client) -{ - if (vgasr_priv.handler->power_state) - vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON); - /* call the driver callback to turn on device */ - client->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON); - client->pwr_state = VGA_SWITCHEROO_ON; - return 0; -} - -static int vga_switchoff(struct vga_switcheroo_client *client) -{ - /* call the driver callback to turn off device */ - client->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF); - if (vgasr_priv.handler->power_state) - vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF); - client->pwr_state = VGA_SWITCHEROO_OFF; - return 0; -} - -/* stage one happens before delay */ -static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) -{ - int i; - struct vga_switcheroo_client *active = NULL; - - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - if (vgasr_priv.clients[i].active == true) { - active = &vgasr_priv.clients[i]; - break; - } - } - if (!active) - return 0; - - if (new_client->pwr_state == VGA_SWITCHEROO_OFF) - vga_switchon(new_client); - - /* swap shadow resource to denote boot VGA device has changed so X starts on new device */ - active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW; - new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; - return 0; -} - -/* post delay */ -static int vga_switchto_stage2(struct vga_switcheroo_client *new_client) -{ - int ret; - int i; - struct vga_switcheroo_client *active = NULL; - - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - if (vgasr_priv.clients[i].active == true) { - active = &vgasr_priv.clients[i]; - break; - } - } - if (!active) - return 0; - - active->active = false; - - if (new_client->fb_info) { - struct fb_event event; - event.info = new_client->fb_info; - fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event); - } - - ret = vgasr_priv.handler->switchto(new_client->id); - if (ret) - return ret; - - if (new_client->reprobe) - new_client->reprobe(new_client->pdev); - - if (active->pwr_state == VGA_SWITCHEROO_ON) - vga_switchoff(active); - - new_client->active = true; - return 0; -} - -static ssize_t -vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, - size_t cnt, loff_t *ppos) -{ - char usercmd[64]; - const char *pdev_name; - int i, ret; - bool delay = false, can_switch; - bool just_mux = false; - int client_id = -1; - struct vga_switcheroo_client *client = NULL; - - if (cnt > 63) - cnt = 63; - - if (copy_from_user(usercmd, ubuf, cnt)) - return -EFAULT; - - mutex_lock(&vgasr_mutex); - - if (!vgasr_priv.active) { - cnt = -EINVAL; - goto out; - } - - /* pwr off the device not in use */ - if (strncmp(usercmd, "OFF", 3) == 0) { - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - if (vgasr_priv.clients[i].active) - continue; - if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_ON) - vga_switchoff(&vgasr_priv.clients[i]); - } - goto out; - } - /* pwr on the device not in use */ - if (strncmp(usercmd, "ON", 2) == 0) { - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - if (vgasr_priv.clients[i].active) - continue; - if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_OFF) - vga_switchon(&vgasr_priv.clients[i]); - } - goto out; - } - - /* request a delayed switch - test can we switch now */ - if (strncmp(usercmd, "DIGD", 4) == 0) { - client_id = VGA_SWITCHEROO_IGD; - delay = true; - } - - if (strncmp(usercmd, "DDIS", 4) == 0) { - client_id = VGA_SWITCHEROO_DIS; - delay = true; - } - - if (strncmp(usercmd, "IGD", 3) == 0) - client_id = VGA_SWITCHEROO_IGD; - - if (strncmp(usercmd, "DIS", 3) == 0) - client_id = VGA_SWITCHEROO_DIS; - - if (strncmp(usercmd, "MIGD", 4) == 0) { - just_mux = true; - client_id = VGA_SWITCHEROO_IGD; - } - if (strncmp(usercmd, "MDIS", 4) == 0) { - just_mux = true; - client_id = VGA_SWITCHEROO_DIS; - } - - if (client_id == -1) - goto out; - - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - if (vgasr_priv.clients[i].id == client_id) { - client = &vgasr_priv.clients[i]; - break; - } - } - - vgasr_priv.delayed_switch_active = false; - - if (just_mux) { - ret = vgasr_priv.handler->switchto(client_id); - goto out; - } - - if (client->active == true) - goto out; - - /* okay we want a switch - test if devices are willing to switch */ - can_switch = true; - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev); - if (can_switch == false) { - printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i); - break; - } - } - - if (can_switch == false && delay == false) - goto out; - - if (can_switch == true) { - pdev_name = pci_name(client->pdev); - ret = vga_switchto_stage1(client); - if (ret) - printk(KERN_ERR "vga_switcheroo: switching failed stage 1 %d\n", ret); - - ret = vga_switchto_stage2(client); - if (ret) - printk(KERN_ERR "vga_switcheroo: switching failed stage 2 %d\n", ret); - - } else { - printk(KERN_INFO "vga_switcheroo: setting delayed switch to client %d\n", client->id); - vgasr_priv.delayed_switch_active = true; - vgasr_priv.delayed_client_id = client_id; - - ret = vga_switchto_stage1(client); - if (ret) - printk(KERN_ERR "vga_switcheroo: delayed switching stage 1 failed %d\n", ret); - } - -out: - mutex_unlock(&vgasr_mutex); - return cnt; -} - -static const struct file_operations vga_switcheroo_debugfs_fops = { - .owner = THIS_MODULE, - .open = vga_switcheroo_debugfs_open, - .write = vga_switcheroo_debugfs_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv) -{ - if (priv->switch_file) { - debugfs_remove(priv->switch_file); - priv->switch_file = NULL; - } - if (priv->debugfs_root) { - debugfs_remove(priv->debugfs_root); - priv->debugfs_root = NULL; - } -} - -static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv) -{ - /* already initialised */ - if (priv->debugfs_root) - return 0; - priv->debugfs_root = debugfs_create_dir("vgaswitcheroo", NULL); - - if (!priv->debugfs_root) { - printk(KERN_ERR "vga_switcheroo: Cannot create /sys/kernel/debug/vgaswitcheroo\n"); - goto fail; - } - - priv->switch_file = debugfs_create_file("switch", 0644, - priv->debugfs_root, NULL, &vga_switcheroo_debugfs_fops); - if (!priv->switch_file) { - printk(KERN_ERR "vga_switcheroo: cannot create /sys/kernel/debug/vgaswitcheroo/switch\n"); - goto fail; - } - return 0; -fail: - vga_switcheroo_debugfs_fini(priv); - return -1; -} - -int vga_switcheroo_process_delayed_switch(void) -{ - struct vga_switcheroo_client *client = NULL; - const char *pdev_name; - bool can_switch = true; - int i; - int ret; - int err = -EINVAL; - - mutex_lock(&vgasr_mutex); - if (!vgasr_priv.delayed_switch_active) - goto err; - - printk(KERN_INFO "vga_switcheroo: processing delayed switch to %d\n", vgasr_priv.delayed_client_id); - - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { - if (vgasr_priv.clients[i].id == vgasr_priv.delayed_client_id) - client = &vgasr_priv.clients[i]; - can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev); - if (can_switch == false) { - printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i); - break; - } - } - - if (can_switch == false || client == NULL) - goto err; - - pdev_name = pci_name(client->pdev); - ret = vga_switchto_stage2(client); - if (ret) - printk(KERN_ERR "vga_switcheroo: delayed switching failed stage 2 %d\n", ret); - - vgasr_priv.delayed_switch_active = false; - err = 0; -err: - mutex_unlock(&vgasr_mutex); - return err; -} -EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch); - |