summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c53
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h2
2 files changed, 50 insertions, 5 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index ad852e572cfe..59be357b17e0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -36,12 +36,21 @@ MODULE_PARM_DESC(mst, "Enable DisplayPort multi-stream (default: enabled)");
static int nouveau_mst = 1;
module_param_named(mst, nouveau_mst, int, 0400);
+static bool
+nouveau_dp_has_sink_count(struct drm_connector *connector,
+ struct nouveau_encoder *outp)
+{
+ return drm_dp_read_sink_count_cap(connector, outp->dp.dpcd, &outp->dp.desc);
+}
+
static enum drm_connector_status
nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector,
struct nouveau_encoder *outp)
{
+ struct drm_connector *connector = &nv_connector->base;
struct drm_dp_aux *aux = &nv_connector->aux;
struct nv50_mstm *mstm = NULL;
+ enum drm_connector_status status = connector_status_disconnected;
int ret;
u8 *dpcd = outp->dp.dpcd;
@@ -50,9 +59,9 @@ nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector,
ret = drm_dp_read_desc(aux, &outp->dp.desc,
drm_dp_is_branch(dpcd));
if (ret < 0)
- return connector_status_disconnected;
+ goto out;
} else {
- return connector_status_disconnected;
+ goto out;
}
if (nouveau_mst) {
@@ -61,12 +70,33 @@ nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector,
mstm->can_mst = drm_dp_read_mst_cap(aux, dpcd);
}
+ if (nouveau_dp_has_sink_count(connector, outp)) {
+ ret = drm_dp_read_sink_count(aux);
+ if (ret < 0)
+ goto out;
+
+ outp->dp.sink_count = ret;
+
+ /*
+ * Dongle connected, but no display. Don't bother reading
+ * downstream port info
+ */
+ if (!outp->dp.sink_count)
+ return connector_status_disconnected;
+ }
+
ret = drm_dp_read_downstream_info(aux, dpcd,
outp->dp.downstream_ports);
if (ret < 0)
- return connector_status_disconnected;
+ goto out;
- return connector_status_connected;
+ status = connector_status_connected;
+out:
+ if (status != connector_status_connected) {
+ /* Clear any cached info */
+ outp->dp.sink_count = 0;
+ }
+ return status;
}
int
@@ -159,6 +189,8 @@ void nouveau_dp_irq(struct nouveau_drm *drm,
struct drm_connector *connector = &nv_connector->base;
struct nouveau_encoder *outp = find_encoder(connector, DCB_OUTPUT_DP);
struct nv50_mstm *mstm;
+ int ret;
+ bool send_hpd = false;
if (!outp)
return;
@@ -170,12 +202,23 @@ void nouveau_dp_irq(struct nouveau_drm *drm,
if (mstm && mstm->is_mst) {
if (!nv50_mstm_service(drm, nv_connector, mstm))
- nouveau_connector_hpd(connector);
+ send_hpd = true;
} else {
drm_dp_cec_irq(&nv_connector->aux);
+
+ if (nouveau_dp_has_sink_count(connector, outp)) {
+ ret = drm_dp_read_sink_count(&nv_connector->aux);
+ if (ret != outp->dp.sink_count)
+ send_hpd = true;
+ if (ret >= 0)
+ outp->dp.sink_count = ret;
+ }
}
mutex_unlock(&outp->dp.hpd_irq_lock);
+
+ if (send_hpd)
+ nouveau_connector_hpd(connector);
}
/* TODO:
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index c1924a4529a7..21937f1c7dd9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -74,6 +74,8 @@ struct nouveau_encoder {
u8 dpcd[DP_RECEIVER_CAP_SIZE];
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
struct drm_dp_desc desc;
+
+ u8 sink_count;
} dp;
};