summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-05-30 16:20:58 +1000
committerBen Skeggs <bskeggs@redhat.com>2014-06-11 16:02:09 +1000
commitc8b8d211e9ba7462a773ff4deca636933198a00f (patch)
tree8ede5345f3e39c91e8fd0fc33e5d41dc8d68cfa3
parentab1ab09a691374dde112088638d5d68a52419e93 (diff)
kms: register a drm_dp_aux channel for each dp connector
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drm/nouveau_connector.c55
-rw-r--r--drm/nouveau_connector.h3
2 files changed, 55 insertions, 3 deletions
diff --git a/drm/nouveau_connector.c b/drm/nouveau_connector.c
index 80ab3a1a..7535a870 100644
--- a/drm/nouveau_connector.c
+++ b/drm/nouveau_connector.c
@@ -105,6 +105,8 @@ nouveau_connector_destroy(struct drm_connector *connector)
kfree(nv_connector->edid);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
+ if (nv_connector->aux.transfer)
+ drm_dp_aux_unregister(&nv_connector->aux);
kfree(connector);
}
@@ -946,6 +948,38 @@ nouveau_connector_hotplug(void *data, u32 type, int index)
return NVKM_EVENT_DROP;
}
+static ssize_t
+nouveau_connector_aux_xfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+ struct nouveau_connector *nv_connector =
+ container_of(aux, typeof(*nv_connector), aux);
+ struct nouveau_encoder *nv_encoder;
+ struct nouveau_i2c_port *port;
+ int ret;
+
+ nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
+ if (!nv_encoder || !(port = nv_encoder->i2c))
+ return -ENODEV;
+ if (WARN_ON(msg->size > 16))
+ return -E2BIG;
+ if (msg->size == 0)
+ return msg->size;
+
+ ret = nouveau_i2c(port)->acquire(port, 0);
+ if (ret)
+ return ret;
+
+ ret = port->func->aux(port, false, msg->request, msg->address,
+ msg->buffer, msg->size);
+ nouveau_i2c(port)->release(port);
+ if (ret >= 0) {
+ msg->reply = ret;
+ return msg->size;
+ }
+
+ return ret;
+}
+
static int
drm_conntype_from_dcb(enum dcb_connector_type dcb)
{
@@ -1066,8 +1100,8 @@ nouveau_connector_create(struct drm_device *dev, int index)
}
}
- type = drm_conntype_from_dcb(nv_connector->type);
- if (type == DRM_MODE_CONNECTOR_LVDS) {
+ switch ((type = drm_conntype_from_dcb(nv_connector->type))) {
+ case DRM_MODE_CONNECTOR_LVDS:
ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy);
if (ret) {
NV_ERROR(drm, "Error parsing LVDS table, disabling\n");
@@ -1076,8 +1110,23 @@ nouveau_connector_create(struct drm_device *dev, int index)
}
funcs = &nouveau_connector_funcs_lvds;
- } else {
+ break;
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ case DRM_MODE_CONNECTOR_eDP:
+ nv_connector->aux.dev = dev->dev;
+ nv_connector->aux.transfer = nouveau_connector_aux_xfer;
+ ret = drm_dp_aux_register(&nv_connector->aux);
+ if (ret) {
+ NV_ERROR(drm, "failed to register aux channel\n");
+ kfree(nv_connector);
+ return ERR_PTR(ret);
+ }
+
funcs = &nouveau_connector_funcs;
+ break;
+ default:
+ funcs = &nouveau_connector_funcs;
+ break;
}
/* defaults, will get overridden in detect() */
diff --git a/drm/nouveau_connector.h b/drm/nouveau_connector.h
index 7e7682df..8861b6c5 100644
--- a/drm/nouveau_connector.h
+++ b/drm/nouveau_connector.h
@@ -28,6 +28,7 @@
#define __NOUVEAU_CONNECTOR_H__
#include <drm/drm_edid.h>
+#include <drm/drm_dp_helper.h>
#include "nouveau_crtc.h"
#include <core/event.h>
@@ -70,6 +71,8 @@ struct nouveau_connector {
u32 status;
struct work_struct work;
+ struct drm_dp_aux aux;
+
int dithering_mode;
int dithering_depth;
int scaling_mode;