forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-06 08f87f769b595151be1afeff53e144f543faa614
kernel/drivers/gpu/drm/nouveau/nouveau_dp.c
....@@ -22,7 +22,6 @@
2222 * Authors: Ben Skeggs
2323 */
2424
25
-#include <drm/drmP.h>
2625 #include <drm/drm_dp_helper.h>
2726
2827 #include "nouveau_drv.h"
....@@ -37,50 +36,123 @@
3736 static int nouveau_mst = 1;
3837 module_param_named(mst, nouveau_mst, int, 0400);
3938
40
-static void
41
-nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_aux *aux, u8 *dpcd)
39
+static bool
40
+nouveau_dp_has_sink_count(struct drm_connector *connector,
41
+ struct nouveau_encoder *outp)
4242 {
43
- struct nouveau_drm *drm = nouveau_drm(dev);
44
- u8 buf[3];
43
+ return drm_dp_read_sink_count_cap(connector, outp->dp.dpcd, &outp->dp.desc);
44
+}
4545
46
- if (!(dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
47
- return;
46
+static enum drm_connector_status
47
+nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector,
48
+ struct nouveau_encoder *outp)
49
+{
50
+ struct drm_connector *connector = &nv_connector->base;
51
+ struct drm_dp_aux *aux = &nv_connector->aux;
52
+ struct nv50_mstm *mstm = NULL;
53
+ enum drm_connector_status status = connector_status_disconnected;
54
+ int ret;
55
+ u8 *dpcd = outp->dp.dpcd;
4856
49
- if (!nvkm_rdaux(aux, DP_SINK_OUI, buf, 3))
50
- NV_DEBUG(drm, "Sink OUI: %02hx%02hx%02hx\n",
51
- buf[0], buf[1], buf[2]);
57
+ ret = drm_dp_read_dpcd_caps(aux, dpcd);
58
+ if (ret < 0)
59
+ goto out;
5260
53
- if (!nvkm_rdaux(aux, DP_BRANCH_OUI, buf, 3))
54
- NV_DEBUG(drm, "Branch OUI: %02hx%02hx%02hx\n",
55
- buf[0], buf[1], buf[2]);
61
+ ret = drm_dp_read_desc(aux, &outp->dp.desc, drm_dp_is_branch(dpcd));
62
+ if (ret < 0)
63
+ goto out;
5664
65
+ if (nouveau_mst) {
66
+ mstm = outp->dp.mstm;
67
+ if (mstm)
68
+ mstm->can_mst = drm_dp_read_mst_cap(aux, dpcd);
69
+ }
70
+
71
+ if (nouveau_dp_has_sink_count(connector, outp)) {
72
+ ret = drm_dp_read_sink_count(aux);
73
+ if (ret < 0)
74
+ goto out;
75
+
76
+ outp->dp.sink_count = ret;
77
+
78
+ /*
79
+ * Dongle connected, but no display. Don't bother reading
80
+ * downstream port info
81
+ */
82
+ if (!outp->dp.sink_count)
83
+ return connector_status_disconnected;
84
+ }
85
+
86
+ ret = drm_dp_read_downstream_info(aux, dpcd,
87
+ outp->dp.downstream_ports);
88
+ if (ret < 0)
89
+ goto out;
90
+
91
+ status = connector_status_connected;
92
+out:
93
+ if (status != connector_status_connected) {
94
+ /* Clear any cached info */
95
+ outp->dp.sink_count = 0;
96
+ }
97
+ return status;
5798 }
5899
59100 int
60
-nouveau_dp_detect(struct nouveau_encoder *nv_encoder)
101
+nouveau_dp_detect(struct nouveau_connector *nv_connector,
102
+ struct nouveau_encoder *nv_encoder)
61103 {
62104 struct drm_device *dev = nv_encoder->base.base.dev;
63105 struct nouveau_drm *drm = nouveau_drm(dev);
64
- struct nvkm_i2c_aux *aux;
65
- u8 dpcd[8];
66
- int ret;
106
+ struct drm_connector *connector = &nv_connector->base;
107
+ struct nv50_mstm *mstm = nv_encoder->dp.mstm;
108
+ enum drm_connector_status status;
109
+ u8 *dpcd = nv_encoder->dp.dpcd;
110
+ int ret = NOUVEAU_DP_NONE;
67111
68
- aux = nv_encoder->aux;
69
- if (!aux)
70
- return -ENODEV;
112
+ /* If we've already read the DPCD on an eDP device, we don't need to
113
+ * reread it as it won't change
114
+ */
115
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
116
+ dpcd[DP_DPCD_REV] != 0)
117
+ return NOUVEAU_DP_SST;
71118
72
- ret = nvkm_rdaux(aux, DP_DPCD_REV, dpcd, sizeof(dpcd));
73
- if (ret)
74
- return ret;
119
+ mutex_lock(&nv_encoder->dp.hpd_irq_lock);
120
+ if (mstm) {
121
+ /* If we're not ready to handle MST state changes yet, just
122
+ * report the last status of the connector. We'll reprobe it
123
+ * once we've resumed.
124
+ */
125
+ if (mstm->suspended) {
126
+ if (mstm->is_mst)
127
+ ret = NOUVEAU_DP_MST;
128
+ else if (connector->status ==
129
+ connector_status_connected)
130
+ ret = NOUVEAU_DP_SST;
75131
76
- nv_encoder->dp.link_bw = 27000 * dpcd[1];
77
- nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
132
+ goto out;
133
+ }
134
+ }
135
+
136
+ status = nouveau_dp_probe_dpcd(nv_connector, nv_encoder);
137
+ if (status == connector_status_disconnected)
138
+ goto out;
139
+
140
+ /* If we're in MST mode, we're done here */
141
+ if (mstm && mstm->can_mst && mstm->is_mst) {
142
+ ret = NOUVEAU_DP_MST;
143
+ goto out;
144
+ }
145
+
146
+ nv_encoder->dp.link_bw = 27000 * dpcd[DP_MAX_LINK_RATE];
147
+ nv_encoder->dp.link_nr =
148
+ dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
78149
79150 NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n",
80
- nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, dpcd[0]);
151
+ nv_encoder->dp.link_nr, nv_encoder->dp.link_bw,
152
+ dpcd[DP_DPCD_REV]);
81153 NV_DEBUG(drm, "encoder: %dx%d\n",
82
- nv_encoder->dcb->dpconf.link_nr,
83
- nv_encoder->dcb->dpconf.link_bw);
154
+ nv_encoder->dcb->dpconf.link_nr,
155
+ nv_encoder->dcb->dpconf.link_bw);
84156
85157 if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr)
86158 nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr;
....@@ -88,14 +160,101 @@
88160 nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw;
89161
90162 NV_DEBUG(drm, "maximum: %dx%d\n",
91
- nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
163
+ nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
92164
93
- nouveau_dp_probe_oui(dev, aux, dpcd);
165
+ if (mstm && mstm->can_mst) {
166
+ ret = nv50_mstm_detect(nv_encoder);
167
+ if (ret == 1) {
168
+ ret = NOUVEAU_DP_MST;
169
+ goto out;
170
+ } else if (ret != 0) {
171
+ goto out;
172
+ }
173
+ }
174
+ ret = NOUVEAU_DP_SST;
94175
95
- ret = nv50_mstm_detect(nv_encoder->dp.mstm, dpcd, nouveau_mst);
96
- if (ret == 1)
97
- return NOUVEAU_DP_MST;
98
- if (ret == 0)
99
- return NOUVEAU_DP_SST;
176
+out:
177
+ if (mstm && !mstm->suspended && ret != NOUVEAU_DP_MST)
178
+ nv50_mstm_remove(mstm);
179
+
180
+ mutex_unlock(&nv_encoder->dp.hpd_irq_lock);
100181 return ret;
101182 }
183
+
184
+void nouveau_dp_irq(struct nouveau_drm *drm,
185
+ struct nouveau_connector *nv_connector)
186
+{
187
+ struct drm_connector *connector = &nv_connector->base;
188
+ struct nouveau_encoder *outp = find_encoder(connector, DCB_OUTPUT_DP);
189
+ struct nv50_mstm *mstm;
190
+ int ret;
191
+ bool send_hpd = false;
192
+
193
+ if (!outp)
194
+ return;
195
+
196
+ mstm = outp->dp.mstm;
197
+ NV_DEBUG(drm, "service %s\n", connector->name);
198
+
199
+ mutex_lock(&outp->dp.hpd_irq_lock);
200
+
201
+ if (mstm && mstm->is_mst) {
202
+ if (!nv50_mstm_service(drm, nv_connector, mstm))
203
+ send_hpd = true;
204
+ } else {
205
+ drm_dp_cec_irq(&nv_connector->aux);
206
+
207
+ if (nouveau_dp_has_sink_count(connector, outp)) {
208
+ ret = drm_dp_read_sink_count(&nv_connector->aux);
209
+ if (ret != outp->dp.sink_count)
210
+ send_hpd = true;
211
+ if (ret >= 0)
212
+ outp->dp.sink_count = ret;
213
+ }
214
+ }
215
+
216
+ mutex_unlock(&outp->dp.hpd_irq_lock);
217
+
218
+ if (send_hpd)
219
+ nouveau_connector_hpd(connector);
220
+}
221
+
222
+/* TODO:
223
+ * - Use the minimum possible BPC here, once we add support for the max bpc
224
+ * property.
225
+ * - Validate against the DP caps advertised by the GPU (we don't check these
226
+ * yet)
227
+ */
228
+enum drm_mode_status
229
+nv50_dp_mode_valid(struct drm_connector *connector,
230
+ struct nouveau_encoder *outp,
231
+ const struct drm_display_mode *mode,
232
+ unsigned *out_clock)
233
+{
234
+ const unsigned int min_clock = 25000;
235
+ unsigned int max_rate, mode_rate, ds_max_dotclock, clock = mode->clock;
236
+ const u8 bpp = connector->display_info.bpc * 3;
237
+
238
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE && !outp->caps.dp_interlace)
239
+ return MODE_NO_INTERLACE;
240
+
241
+ if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
242
+ clock *= 2;
243
+
244
+ max_rate = outp->dp.link_nr * outp->dp.link_bw;
245
+ mode_rate = DIV_ROUND_UP(clock * bpp, 8);
246
+ if (mode_rate > max_rate)
247
+ return MODE_CLOCK_HIGH;
248
+
249
+ ds_max_dotclock = drm_dp_downstream_max_dotclock(outp->dp.dpcd, outp->dp.downstream_ports);
250
+ if (ds_max_dotclock && clock > ds_max_dotclock)
251
+ return MODE_CLOCK_HIGH;
252
+
253
+ if (clock < min_clock)
254
+ return MODE_CLOCK_LOW;
255
+
256
+ if (out_clock)
257
+ *out_clock = clock;
258
+
259
+ return MODE_OK;
260
+}