From 456b0579fb0af095c24fa9e5867bd3983b842b1a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 30 May 2014 12:49:17 +1000 Subject: [PATCH] drm/nouveau: use connector events for HPD instead of GPIO watching Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 67 +++++++++------------ drivers/gpu/drm/nouveau/nouveau_connector.h | 7 +-- drivers/gpu/drm/nouveau/nouveau_display.c | 4 +- 3 files changed, 34 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 4a162a426437..80ab3a1a44c1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -44,6 +44,7 @@ #include #include +#include MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); static int nouveau_tv_disable = 0; @@ -100,7 +101,7 @@ static void nouveau_connector_destroy(struct drm_connector *connector) { struct nouveau_connector *nv_connector = nouveau_connector(connector); - nouveau_event_ref(NULL, &nv_connector->hpd_func); + nouveau_event_ref(NULL, &nv_connector->hpd); kfree(nv_connector->edid); drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); @@ -915,30 +916,34 @@ static void nouveau_connector_hotplug_work(struct work_struct *work) { struct nouveau_connector *nv_connector = - container_of(work, struct nouveau_connector, hpd_work); + container_of(work, typeof(*nv_connector), work); struct drm_connector *connector = &nv_connector->base; - struct drm_device *dev = connector->dev; - struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); - bool plugged = gpio->get(gpio, 0, nv_connector->hpd.func, 0xff); + struct nouveau_drm *drm = nouveau_drm(connector->dev); + const char *name = connector->name; - NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", - connector->name); + if (nv_connector->status & NVKM_HPD_IRQ) { + } else { + bool plugged = (nv_connector->status != NVKM_HPD_UNPLUG); - if (plugged) - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - else - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name); - drm_helper_hpd_irq_event(dev); + if (plugged) + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + else + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + drm_helper_hpd_irq_event(connector->dev); + } + + nouveau_event_get(nv_connector->hpd); } static int nouveau_connector_hotplug(void *data, u32 type, int index) { struct nouveau_connector *nv_connector = data; - schedule_work(&nv_connector->hpd_work); - return NVKM_EVENT_KEEP; + nv_connector->status = type; + schedule_work(&nv_connector->work); + return NVKM_EVENT_DROP; } static int @@ -974,9 +979,9 @@ nouveau_connector_create(struct drm_device *dev, int index) { const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_gpio *gpio = nouveau_gpio(drm->device); struct nouveau_display *disp = nouveau_display(dev); struct nouveau_connector *nv_connector = NULL; + struct nouveau_disp *pdisp = nouveau_disp(drm->device); struct drm_connector *connector; int type, ret = 0; bool dummy; @@ -992,34 +997,15 @@ nouveau_connector_create(struct drm_device *dev, int index) return ERR_PTR(-ENOMEM); connector = &nv_connector->base; - INIT_WORK(&nv_connector->hpd_work, nouveau_connector_hotplug_work); nv_connector->index = index; /* attempt to parse vbios connector type and hotplug gpio */ nv_connector->dcb = olddcb_conn(dev, index); if (nv_connector->dcb) { - static const u8 hpd[16] = { - 0xff, 0x07, 0x08, 0xff, 0xff, 0x51, 0x52, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x5f, 0x60, - }; - u32 entry = ROM16(nv_connector->dcb[0]); if (olddcb_conntab(dev)[3] >= 4) entry |= (u32)ROM16(nv_connector->dcb[2]) << 16; - ret = gpio->find(gpio, 0, hpd[ffs((entry & 0x07033000) >> 12)], - DCB_GPIO_UNUSED, &nv_connector->hpd); - if (ret) - nv_connector->hpd.func = DCB_GPIO_UNUSED; - - if (nv_connector->hpd.func != DCB_GPIO_UNUSED) { - nouveau_event_new(gpio->events, NVKM_GPIO_TOGGLED, - nv_connector->hpd.line, - nouveau_connector_hotplug, - nv_connector, - &nv_connector->hpd_func); - } - nv_connector->type = nv_connector->dcb[0]; if (drm_conntype_from_dcb(nv_connector->type) == DRM_MODE_CONNECTOR_Unknown) { @@ -1041,7 +1027,6 @@ nouveau_connector_create(struct drm_device *dev, int index) } } else { nv_connector->type = DCB_CONNECTOR_NONE; - nv_connector->hpd.func = DCB_GPIO_UNUSED; } /* no vbios data, or an unknown dcb connector type - attempt to @@ -1167,10 +1152,16 @@ nouveau_connector_create(struct drm_device *dev, int index) break; } - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - if (nv_connector->hpd.func != DCB_GPIO_UNUSED) + ret = nouveau_event_new(pdisp->hpd, NVKM_HPD, index, + nouveau_connector_hotplug, + nv_connector, &nv_connector->hpd); + if (ret) + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + else connector->polled = DRM_CONNECTOR_POLL_HPD; + INIT_WORK(&nv_connector->work, nouveau_connector_hotplug_work); + drm_sysfs_connector_add(connector); return connector; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 264a778f473b..7e7682dfa991 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -33,7 +33,6 @@ #include #include -#include struct nouveau_i2c_port; @@ -67,9 +66,9 @@ struct nouveau_connector { u8 index; u8 *dcb; - struct dcb_gpio_func hpd; - struct work_struct hpd_work; - struct nouveau_eventh *hpd_func; + struct nouveau_eventh *hpd; + u32 status; + struct work_struct work; int dithering_mode; int dithering_depth; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 64f9de9b7a56..26b5647188ef 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -393,7 +393,7 @@ nouveau_display_init(struct drm_device *dev) /* enable hotplug interrupts */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct nouveau_connector *conn = nouveau_connector(connector); - if (conn->hpd_func) nouveau_event_get(conn->hpd_func); + if (conn->hpd) nouveau_event_get(conn->hpd); } return ret; @@ -408,7 +408,7 @@ nouveau_display_fini(struct drm_device *dev) /* disable hotplug interrupts */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct nouveau_connector *conn = nouveau_connector(connector); - if (conn->hpd_func) nouveau_event_put(conn->hpd_func); + if (conn->hpd) nouveau_event_put(conn->hpd); } drm_kms_helper_poll_disable(dev); -- 2.20.1