diff options
author | Dave Airlie <airlied@gmail.com> | 2012-12-22 12:52:51 +1000 |
---|---|---|
committer | Dave Airlie <airlied@gmail.com> | 2012-12-22 12:52:51 +1000 |
commit | aead3bb72d82bd63149082a2670cc2521f2290a4 (patch) | |
tree | 793138916678971e48564844637c7446c4509451 /drivers/gpu | |
parent | f7acbeae3e997750c3d23a56ad1501d4aeb0d896 (diff) |
WIPswitchy-wip
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 24 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 33 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/vga/vga_switcheroo.c | 59 |
5 files changed, 111 insertions, 25 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 76810eae934d..ce07e7fadd99 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -83,8 +83,6 @@ struct detailed_mode_closure { #define LEVEL_GTF2 2 #define LEVEL_CVT 3 -static DEFINE_MUTEX(drm_edid_mutex); - static struct edid_quirk { char vendor[4]; int product_id; @@ -420,24 +418,14 @@ struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { struct edid *edid = NULL; - struct pci_dev *pdev = connector->dev->pdev; - struct pci_dev *active_pdev = NULL; - - mutex_lock(&drm_edid_mutex); - if (pdev) { - active_pdev = vga_switcheroo_get_active_client(); - if (active_pdev != pdev) - vga_switcheroo_switch_ddc(pdev); - } + vga_switcheroo_lock_ddc(connector->dev->pdev); if (drm_probe_ddc(adapter)) edid = (struct edid *)drm_do_get_edid(connector, adapter); - if (active_pdev && active_pdev != pdev) - vga_switcheroo_switch_ddc(active_pdev); + vga_switcheroo_unlock_ddc(connector->dev->pdev); - mutex_unlock(&drm_edid_mutex); return edid; } EXPORT_SYMBOL(drm_get_edid); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index ffbc9156c792..11580d9df68d 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1279,13 +1279,35 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev) spin_unlock(&dev->count_lock); return can_switch; } +static void i915_switcheroo_reprobe(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_connector *con; + struct intel_encoder *enc; + struct intel_dp *dp; + + list_for_each_entry(con, &dev->mode_config.connector_list, head) { + if (con->connector_type == DRM_MODE_CONNECTOR_eDP) { + enc = intel_attached_encoder(con); + dp = container_of(enc, struct intel_dp, base); + + if (dp->delayed_detect) { + DRM_DEBUG_KMS("have delayed eDP detect\n"); + intel_dp_finish_detect(dev, dp, con); + dp->delayed_detect = false; + } + } + } +} static const struct vga_switcheroo_client_ops i915_switcheroo_ops = { .set_gpu_state = i915_switcheroo_set_state, - .reprobe = NULL, + .reprobe = i915_switcheroo_reprobe, .can_switch = i915_switcheroo_can_switch, }; + static int i915_load_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 088e4c53d07b..753947cc901b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -38,6 +38,8 @@ #include "i915_drm.h" #include "i915_drv.h" +#include <linux/vga_switcheroo.h> + #define DP_LINK_STATUS_SIZE 6 #define DP_LINK_CHECK_TIMEOUT (10 * 1000) @@ -665,9 +667,6 @@ intel_dp_i2c_init(struct intel_dp *intel_dp, intel_dp->adapter.algo_data = &intel_dp->algo; intel_dp->adapter.dev.parent = &intel_connector->base.kdev; - ironlake_edp_panel_vdd_on(intel_dp); - ret = i2c_dp_aux_add_bus(&intel_dp->adapter); - ironlake_edp_panel_vdd_off(intel_dp, false); return ret; } @@ -2625,18 +2624,35 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); - if (force_bl_on) - ironlake_edp_backlight_on(intel_dp); } + if (vga_switcheroo_get_client_mux_active(dev->pdev) == VGA_SWITCHEROO_OFF) + { + DRM_DEBUG_KMS("no mux ownership delay detecting eDP\n"); + intel_dp->delayed_detect = true; + return; + } intel_dp_i2c_init(intel_dp, intel_connector, name); + intel_dp_finish_detect(dev, intel_dp, intel_connector); +} +void intel_dp_finish_detect(struct drm_device *dev, struct intel_dp *intel_dp, + struct intel_connector *intel_connector) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_connector *connector = &intel_connector->base; + int ret; + ironlake_edp_panel_vdd_on(intel_dp); + ret = i2c_dp_aux_add_bus(&intel_dp->adapter); + ironlake_edp_panel_vdd_off(intel_dp, false); if (is_edp(intel_dp)) { bool ret; struct edid *edid; ironlake_edp_panel_vdd_on(intel_dp); + vga_switcheroo_lock_ddc(dev->pdev); ret = intel_dp_get_dpcd(intel_dp); + vga_switcheroo_unlock_ddc(dev->pdev); ironlake_edp_panel_vdd_off(intel_dp, false); if (ret) { @@ -2665,14 +2681,14 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) ironlake_edp_panel_vdd_off(intel_dp, false); } - intel_encoder->hot_plug = intel_dp_hot_plug; + intel_dp->base.hot_plug = intel_dp_hot_plug; if (is_edp(intel_dp)) { - dev_priv->int_edp_connector = connector; + dev_priv->int_edp_connector = &intel_connector->base; intel_panel_setup_backlight(dev); } - intel_dp_add_properties(intel_dp, connector); + intel_dp_add_properties(intel_dp, &intel_connector->base); /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written * 0xd. Failure to do so will result in spurious interrupts being @@ -2683,3 +2699,4 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd); } } + diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 351fd7179cd7..4dc6d79113e9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -360,6 +360,7 @@ struct intel_dp { bool want_panel_vdd; struct edid *edid; /* cached EDID for eDP */ int edid_mode_count; + bool delayed_detect; }; static inline struct drm_crtc * @@ -579,4 +580,7 @@ extern void intel_ddi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); +void intel_dp_finish_detect(struct drm_device *dev, struct intel_dp *intel_dp, + struct intel_connector *conn); + #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index d5cd2747bdc3..89df582262ba 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -56,6 +56,9 @@ struct vgasr_priv { struct list_head clients; struct vga_switcheroo_handler *handler; + + struct mutex ddc_lock; + struct pci_dev *old_ddc_owner; }; #define ID_BIT_AUDIO 0x100 @@ -69,6 +72,7 @@ static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv); /* only one switcheroo per system */ static struct vgasr_priv vgasr_priv = { .clients = LIST_HEAD_INIT(vgasr_priv.clients), + .ddc_lock = __MUTEX_INITIALIZER(vgasr_priv.ddc_lock), }; static BLOCKING_NOTIFIER_HEAD(vga_switcheroo_notifier_list); @@ -252,6 +256,19 @@ struct pci_dev *vga_switcheroo_get_active_client(void) } EXPORT_SYMBOL(vga_switcheroo_get_active_client); +int vga_switcheroo_get_client_mux_active(struct pci_dev *pdev) +{ + struct vga_switcheroo_client *client; + + client = find_client_from_pci(&vgasr_priv.clients, pdev); + if (!client) + return VGA_SWITCHEROO_NOT_FOUND; + if (!vgasr_priv.active) + return VGA_SWITCHEROO_INIT; + return client->active ? VGA_SWITCHEROO_ON : VGA_SWITCHEROO_OFF; +} +EXPORT_SYMBOL(vga_switcheroo_get_client_mux_active); + int vga_switcheroo_get_client_state(struct pci_dev *pdev) { struct vga_switcheroo_client *client; @@ -300,8 +317,9 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev, } EXPORT_SYMBOL(vga_switcheroo_client_fb_set); -int vga_switcheroo_switch_ddc(struct pci_dev *pdev) +int vga_switcheroo_lock_ddc(struct pci_dev *pdev) { + struct vga_switcheroo_client *client; int ret = 0; int id; @@ -313,6 +331,18 @@ int vga_switcheroo_switch_ddc(struct pci_dev *pdev) } if (vgasr_priv.handler->switch_ddc) { + mutex_lock(&vgasr_priv.ddc_lock); + + client = find_active_client(&vgasr_priv.clients); + if (!client) { + mutex_unlock(&vgasr_priv.ddc_lock); + ret = -ENODEV; + goto out; + } + vgasr_priv.old_ddc_owner = client->pdev; + if (client->pdev == pdev) + goto out; + id = vgasr_priv.handler->get_client_id(pdev); ret = vgasr_priv.handler->switch_ddc(id); } @@ -321,7 +351,32 @@ out: mutex_unlock(&vgasr_mutex); return ret; } -EXPORT_SYMBOL(vga_switcheroo_switch_ddc); +EXPORT_SYMBOL(vga_switcheroo_lock_ddc); + +int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) +{ + int ret = 0; + int id; + mutex_lock(&vgasr_mutex); + + if (!vgasr_priv.handler) { + ret = -ENODEV; + goto out; + } + + if (vgasr_priv.handler->switch_ddc) { + if (vgasr_priv.old_ddc_owner != pdev) { + id = vgasr_priv.handler->get_client_id(vgasr_priv.old_ddc_owner); + ret = vgasr_priv.handler->switch_ddc(id); + } + vgasr_priv.old_ddc_owner = NULL; + mutex_unlock(&vgasr_priv.ddc_lock); + } +out: + mutex_unlock(&vgasr_mutex); + return ret; +} +EXPORT_SYMBOL(vga_switcheroo_unlock_ddc); static int vga_switcheroo_show(struct seq_file *m, void *v) { |