Commit 456b0579 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau: use connector events for HPD instead of GPIO watching

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 7a014a87
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <subdev/i2c.h> #include <subdev/i2c.h>
#include <subdev/gpio.h> #include <subdev/gpio.h>
#include <engine/disp.h>
MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); MODULE_PARM_DESC(tv_disable, "Disable TV-out detection");
static int nouveau_tv_disable = 0; static int nouveau_tv_disable = 0;
...@@ -100,7 +101,7 @@ static void ...@@ -100,7 +101,7 @@ static void
nouveau_connector_destroy(struct drm_connector *connector) nouveau_connector_destroy(struct drm_connector *connector)
{ {
struct nouveau_connector *nv_connector = nouveau_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); kfree(nv_connector->edid);
drm_sysfs_connector_remove(connector); drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
...@@ -915,30 +916,34 @@ static void ...@@ -915,30 +916,34 @@ static void
nouveau_connector_hotplug_work(struct work_struct *work) nouveau_connector_hotplug_work(struct work_struct *work)
{ {
struct nouveau_connector *nv_connector = 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_connector *connector = &nv_connector->base;
struct drm_device *dev = connector->dev; struct nouveau_drm *drm = nouveau_drm(connector->dev);
struct nouveau_drm *drm = nouveau_drm(dev); const char *name = connector->name;
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
bool plugged = gpio->get(gpio, 0, nv_connector->hpd.func, 0xff);
NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", if (nv_connector->status & NVKM_HPD_IRQ) {
connector->name); } else {
bool plugged = (nv_connector->status != NVKM_HPD_UNPLUG);
if (plugged) NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name);
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
else
drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
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 static int
nouveau_connector_hotplug(void *data, u32 type, int index) nouveau_connector_hotplug(void *data, u32 type, int index)
{ {
struct nouveau_connector *nv_connector = data; struct nouveau_connector *nv_connector = data;
schedule_work(&nv_connector->hpd_work); nv_connector->status = type;
return NVKM_EVENT_KEEP; schedule_work(&nv_connector->work);
return NVKM_EVENT_DROP;
} }
static int static int
...@@ -974,9 +979,9 @@ nouveau_connector_create(struct drm_device *dev, int index) ...@@ -974,9 +979,9 @@ nouveau_connector_create(struct drm_device *dev, int index)
{ {
const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_connector *nv_connector = NULL; struct nouveau_connector *nv_connector = NULL;
struct nouveau_disp *pdisp = nouveau_disp(drm->device);
struct drm_connector *connector; struct drm_connector *connector;
int type, ret = 0; int type, ret = 0;
bool dummy; bool dummy;
...@@ -992,34 +997,15 @@ nouveau_connector_create(struct drm_device *dev, int index) ...@@ -992,34 +997,15 @@ nouveau_connector_create(struct drm_device *dev, int index)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
connector = &nv_connector->base; connector = &nv_connector->base;
INIT_WORK(&nv_connector->hpd_work, nouveau_connector_hotplug_work);
nv_connector->index = index; nv_connector->index = index;
/* attempt to parse vbios connector type and hotplug gpio */ /* attempt to parse vbios connector type and hotplug gpio */
nv_connector->dcb = olddcb_conn(dev, index); nv_connector->dcb = olddcb_conn(dev, index);
if (nv_connector->dcb) { 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]); u32 entry = ROM16(nv_connector->dcb[0]);
if (olddcb_conntab(dev)[3] >= 4) if (olddcb_conntab(dev)[3] >= 4)
entry |= (u32)ROM16(nv_connector->dcb[2]) << 16; 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]; nv_connector->type = nv_connector->dcb[0];
if (drm_conntype_from_dcb(nv_connector->type) == if (drm_conntype_from_dcb(nv_connector->type) ==
DRM_MODE_CONNECTOR_Unknown) { DRM_MODE_CONNECTOR_Unknown) {
...@@ -1041,7 +1027,6 @@ nouveau_connector_create(struct drm_device *dev, int index) ...@@ -1041,7 +1027,6 @@ nouveau_connector_create(struct drm_device *dev, int index)
} }
} else { } else {
nv_connector->type = DCB_CONNECTOR_NONE; nv_connector->type = DCB_CONNECTOR_NONE;
nv_connector->hpd.func = DCB_GPIO_UNUSED;
} }
/* no vbios data, or an unknown dcb connector type - attempt to /* no vbios data, or an unknown dcb connector type - attempt to
...@@ -1167,10 +1152,16 @@ nouveau_connector_create(struct drm_device *dev, int index) ...@@ -1167,10 +1152,16 @@ nouveau_connector_create(struct drm_device *dev, int index)
break; break;
} }
connector->polled = DRM_CONNECTOR_POLL_CONNECT; ret = nouveau_event_new(pdisp->hpd, NVKM_HPD, index,
if (nv_connector->hpd.func != DCB_GPIO_UNUSED) nouveau_connector_hotplug,
nv_connector, &nv_connector->hpd);
if (ret)
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
else
connector->polled = DRM_CONNECTOR_POLL_HPD; connector->polled = DRM_CONNECTOR_POLL_HPD;
INIT_WORK(&nv_connector->work, nouveau_connector_hotplug_work);
drm_sysfs_connector_add(connector); drm_sysfs_connector_add(connector);
return connector; return connector;
} }
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include <core/event.h> #include <core/event.h>
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/gpio.h>
struct nouveau_i2c_port; struct nouveau_i2c_port;
...@@ -67,9 +66,9 @@ struct nouveau_connector { ...@@ -67,9 +66,9 @@ struct nouveau_connector {
u8 index; u8 index;
u8 *dcb; u8 *dcb;
struct dcb_gpio_func hpd; struct nouveau_eventh *hpd;
struct work_struct hpd_work; u32 status;
struct nouveau_eventh *hpd_func; struct work_struct work;
int dithering_mode; int dithering_mode;
int dithering_depth; int dithering_depth;
......
...@@ -393,7 +393,7 @@ nouveau_display_init(struct drm_device *dev) ...@@ -393,7 +393,7 @@ nouveau_display_init(struct drm_device *dev)
/* enable hotplug interrupts */ /* enable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct nouveau_connector *conn = nouveau_connector(connector); 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; return ret;
...@@ -408,7 +408,7 @@ nouveau_display_fini(struct drm_device *dev) ...@@ -408,7 +408,7 @@ nouveau_display_fini(struct drm_device *dev)
/* disable hotplug interrupts */ /* disable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct nouveau_connector *conn = nouveau_connector(connector); 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); drm_kms_helper_poll_disable(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment