summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/nouveau_connector.c
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2010-11-11 09:14:56 +0300
committerBen Skeggs <bskeggs@redhat.com>2010-12-03 08:11:45 +0300
commitfce2bad0ee2666d6a10bfeb634b1021469cc3d79 (patch)
treebc66c771c5c27dcd3b59135fb25c39c342ffed71 /drivers/gpu/drm/nouveau/nouveau_connector.c
parente4cbadcaaa4678020e37ca93502942ffdf9aef80 (diff)
downloadlinux-fce2bad0ee2666d6a10bfeb634b1021469cc3d79.tar.xz
drm/nv50: rework PGPIO IRQ handling and hotplug detection
Allows callers to install their own handlers for when a GPIO line changes state (such as for hotplug detect). This also fixes a bug where we weren't acknowledging the GPIO IRQ until after the bottom half had run, causing a severe IRQ storm in some cases. Reviewed-by: Francisco Jerez <currojerez@riseup.net> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_connector.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c54
1 files changed, 48 insertions, 6 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 52c356e9a3d1..a21e00076839 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -37,6 +37,8 @@
#include "nouveau_connector.h"
#include "nouveau_hw.h"
+static void nouveau_connector_hotplug(void *, int);
+
static struct nouveau_encoder *
find_encoder_by_type(struct drm_connector *connector, int type)
{
@@ -94,22 +96,30 @@ nouveau_connector_bpp(struct drm_connector *connector)
}
static void
-nouveau_connector_destroy(struct drm_connector *drm_connector)
+nouveau_connector_destroy(struct drm_connector *connector)
{
- struct nouveau_connector *nv_connector =
- nouveau_connector(drm_connector);
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
+ struct drm_nouveau_private *dev_priv;
+ struct nouveau_gpio_engine *pgpio;
struct drm_device *dev;
if (!nv_connector)
return;
dev = nv_connector->base.dev;
+ dev_priv = dev->dev_private;
NV_DEBUG_KMS(dev, "\n");
+ pgpio = &dev_priv->engine.gpio;
+ if (pgpio->irq_unregister) {
+ pgpio->irq_unregister(dev, nv_connector->dcb->gpio_tag,
+ nouveau_connector_hotplug, connector);
+ }
+
kfree(nv_connector->edid);
- drm_sysfs_connector_remove(drm_connector);
- drm_connector_cleanup(drm_connector);
- kfree(drm_connector);
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+ kfree(connector);
}
static struct nouveau_i2c_chan *
@@ -760,6 +770,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
{
const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
struct nouveau_connector *nv_connector = NULL;
struct dcb_connector_table_entry *dcb = NULL;
struct drm_connector *connector;
@@ -876,6 +887,11 @@ nouveau_connector_create(struct drm_device *dev, int index)
break;
}
+ if (pgpio->irq_register) {
+ pgpio->irq_register(dev, nv_connector->dcb->gpio_tag,
+ nouveau_connector_hotplug, connector);
+ }
+
drm_sysfs_connector_add(connector);
dcb->drm = connector;
return dcb->drm;
@@ -886,3 +902,29 @@ fail:
return ERR_PTR(ret);
}
+
+static void
+nouveau_connector_hotplug(void *data, int plugged)
+{
+ struct drm_connector *connector = data;
+ struct drm_device *dev = connector->dev;
+
+ NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un",
+ drm_get_connector_name(connector));
+
+ if (connector->encoder && connector->encoder->crtc &&
+ connector->encoder->crtc->enabled) {
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(connector->encoder);
+ struct drm_encoder_helper_funcs *helper =
+ connector->encoder->helper_private;
+
+ if (nv_encoder->dcb->type == OUTPUT_DP) {
+ if (plugged)
+ helper->dpms(connector->encoder, DRM_MODE_DPMS_ON);
+ else
+ helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF);
+ }
+ }
+
+ drm_helper_hpd_irq_event(dev);
+}