Skip to content

Commit a4efad3

Browse files
committed
drm/nouveau/kms/nv50-: Add support for DP_SINK_COUNT
This is another bit that we never implemented for nouveau: dongle detection. When a "dongle", e.g. an active display adaptor, is hooked up to the system and causes an HPD to be fired, we don't actually know whether or not there's anything plugged into the dongle without checking the sink count. As a result, plugging in a dongle without anything plugged into it currently results in a bogus EDID retrieval error in the kernel log. Additionally, most dongles won't send another long HPD signal if the user suddenly plugs something in, they'll only send a short HPD IRQ with the expectation that the source will check the sink count and reprobe the connector if it's changed - something we don't actually do. As a result, nothing will happen if the user plugs the dongle in before plugging something into the dongle. So, let's fix this by checking the sink count in both nouveau_dp_probe_dpcd() and nouveau_dp_irq(), and reprobing the connector if things change. Signed-off-by: Lyude Paul <[email protected]> Reviewed-by: Ben Skeggs <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 4778ff0 commit a4efad3

File tree

2 files changed

+50
-5
lines changed

2 files changed

+50
-5
lines changed

drivers/gpu/drm/nouveau/nouveau_dp.c

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,21 @@ MODULE_PARM_DESC(mst, "Enable DisplayPort multi-stream (default: enabled)");
3636
static int nouveau_mst = 1;
3737
module_param_named(mst, nouveau_mst, int, 0400);
3838

39+
static bool
40+
nouveau_dp_has_sink_count(struct drm_connector *connector,
41+
struct nouveau_encoder *outp)
42+
{
43+
return drm_dp_read_sink_count_cap(connector, outp->dp.dpcd, &outp->dp.desc);
44+
}
45+
3946
static enum drm_connector_status
4047
nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector,
4148
struct nouveau_encoder *outp)
4249
{
50+
struct drm_connector *connector = &nv_connector->base;
4351
struct drm_dp_aux *aux = &nv_connector->aux;
4452
struct nv50_mstm *mstm = NULL;
53+
enum drm_connector_status status = connector_status_disconnected;
4554
int ret;
4655
u8 *dpcd = outp->dp.dpcd;
4756

@@ -50,9 +59,9 @@ nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector,
5059
ret = drm_dp_read_desc(aux, &outp->dp.desc,
5160
drm_dp_is_branch(dpcd));
5261
if (ret < 0)
53-
return connector_status_disconnected;
62+
goto out;
5463
} else {
55-
return connector_status_disconnected;
64+
goto out;
5665
}
5766

5867
if (nouveau_mst) {
@@ -61,12 +70,33 @@ nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector,
6170
mstm->can_mst = drm_dp_read_mst_cap(aux, dpcd);
6271
}
6372

73+
if (nouveau_dp_has_sink_count(connector, outp)) {
74+
ret = drm_dp_read_sink_count(aux);
75+
if (ret < 0)
76+
goto out;
77+
78+
outp->dp.sink_count = ret;
79+
80+
/*
81+
* Dongle connected, but no display. Don't bother reading
82+
* downstream port info
83+
*/
84+
if (!outp->dp.sink_count)
85+
return connector_status_disconnected;
86+
}
87+
6488
ret = drm_dp_read_downstream_info(aux, dpcd,
6589
outp->dp.downstream_ports);
6690
if (ret < 0)
67-
return connector_status_disconnected;
91+
goto out;
6892

69-
return connector_status_connected;
93+
status = connector_status_connected;
94+
out:
95+
if (status != connector_status_connected) {
96+
/* Clear any cached info */
97+
outp->dp.sink_count = 0;
98+
}
99+
return status;
70100
}
71101

72102
int
@@ -159,6 +189,8 @@ void nouveau_dp_irq(struct nouveau_drm *drm,
159189
struct drm_connector *connector = &nv_connector->base;
160190
struct nouveau_encoder *outp = find_encoder(connector, DCB_OUTPUT_DP);
161191
struct nv50_mstm *mstm;
192+
int ret;
193+
bool send_hpd = false;
162194

163195
if (!outp)
164196
return;
@@ -170,12 +202,23 @@ void nouveau_dp_irq(struct nouveau_drm *drm,
170202

171203
if (mstm && mstm->is_mst) {
172204
if (!nv50_mstm_service(drm, nv_connector, mstm))
173-
nouveau_connector_hpd(connector);
205+
send_hpd = true;
174206
} else {
175207
drm_dp_cec_irq(&nv_connector->aux);
208+
209+
if (nouveau_dp_has_sink_count(connector, outp)) {
210+
ret = drm_dp_read_sink_count(&nv_connector->aux);
211+
if (ret != outp->dp.sink_count)
212+
send_hpd = true;
213+
if (ret >= 0)
214+
outp->dp.sink_count = ret;
215+
}
176216
}
177217

178218
mutex_unlock(&outp->dp.hpd_irq_lock);
219+
220+
if (send_hpd)
221+
nouveau_connector_hpd(connector);
179222
}
180223

181224
/* TODO:

drivers/gpu/drm/nouveau/nouveau_encoder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ struct nouveau_encoder {
7474
u8 dpcd[DP_RECEIVER_CAP_SIZE];
7575
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
7676
struct drm_dp_desc desc;
77+
78+
u8 sink_count;
7779
} dp;
7880
};
7981

0 commit comments

Comments
 (0)