Commit | Line | Data |
---|---|---|
6ee73861 BS |
1 | /* |
2 | * Copyright (C) 2008 Maarten Maathuis. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * Permission is hereby granted, free of charge, to any person obtaining | |
6 | * a copy of this software and associated documentation files (the | |
7 | * "Software"), to deal in the Software without restriction, including | |
8 | * without limitation the rights to use, copy, modify, merge, publish, | |
9 | * distribute, sublicense, and/or sell copies of the Software, and to | |
10 | * permit persons to whom the Software is furnished to do so, subject to | |
11 | * the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice (including the | |
14 | * next paragraph) shall be included in all copies or substantial | |
15 | * portions of the Software. | |
16 | * | |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
20 | * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE | |
21 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
22 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
23 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
24 | * | |
25 | */ | |
26 | ||
a1470890 BS |
27 | #include <acpi/button.h> |
28 | ||
5addcf0a | 29 | #include <linux/pm_runtime.h> |
39c1c901 | 30 | #include <linux/vga_switcheroo.h> |
5addcf0a | 31 | |
616915ec | 32 | #include <drm/drm_atomic_helper.h> |
760285e7 DH |
33 | #include <drm/drm_edid.h> |
34 | #include <drm/drm_crtc_helper.h> | |
fcd70cd3 | 35 | #include <drm/drm_probe_helper.h> |
a743d758 | 36 | #include <drm/drm_atomic.h> |
a1470890 | 37 | |
6ee73861 | 38 | #include "nouveau_reg.h" |
4dc28134 | 39 | #include "nouveau_drv.h" |
1a646342 | 40 | #include "dispnv04/hw.h" |
d6a9efec | 41 | #include "dispnv50/disp.h" |
c0077061 | 42 | #include "nouveau_acpi.h" |
6ee73861 | 43 | |
77145f1c BS |
44 | #include "nouveau_display.h" |
45 | #include "nouveau_connector.h" | |
6ee73861 BS |
46 | #include "nouveau_encoder.h" |
47 | #include "nouveau_crtc.h" | |
77145f1c | 48 | |
923bc416 | 49 | #include <nvif/class.h> |
773eb04d | 50 | #include <nvif/if0011.h> |
79ca2770 | 51 | |
616915ec BS |
52 | struct drm_display_mode * |
53 | nouveau_conn_native_mode(struct drm_connector *connector) | |
54 | { | |
55 | const struct drm_connector_helper_funcs *helper = connector->helper_private; | |
56 | struct nouveau_drm *drm = nouveau_drm(connector->dev); | |
57 | struct drm_device *dev = connector->dev; | |
58 | struct drm_display_mode *mode, *largest = NULL; | |
59 | int high_w = 0, high_h = 0, high_v = 0; | |
60 | ||
61 | list_for_each_entry(mode, &connector->probed_modes, head) { | |
616915ec BS |
62 | if (helper->mode_valid(connector, mode) != MODE_OK || |
63 | (mode->flags & DRM_MODE_FLAG_INTERLACE)) | |
64 | continue; | |
65 | ||
66 | /* Use preferred mode if there is one.. */ | |
67 | if (mode->type & DRM_MODE_TYPE_PREFERRED) { | |
68 | NV_DEBUG(drm, "native mode from preferred\n"); | |
69 | return drm_mode_duplicate(dev, mode); | |
70 | } | |
71 | ||
72 | /* Otherwise, take the resolution with the largest width, then | |
73 | * height, then vertical refresh | |
74 | */ | |
75 | if (mode->hdisplay < high_w) | |
76 | continue; | |
77 | ||
78 | if (mode->hdisplay == high_w && mode->vdisplay < high_h) | |
79 | continue; | |
80 | ||
81 | if (mode->hdisplay == high_w && mode->vdisplay == high_h && | |
0425662f | 82 | drm_mode_vrefresh(mode) < high_v) |
616915ec BS |
83 | continue; |
84 | ||
85 | high_w = mode->hdisplay; | |
86 | high_h = mode->vdisplay; | |
0425662f | 87 | high_v = drm_mode_vrefresh(mode); |
616915ec BS |
88 | largest = mode; |
89 | } | |
90 | ||
91 | NV_DEBUG(drm, "native mode from largest: %dx%d@%d\n", | |
92 | high_w, high_h, high_v); | |
93 | return largest ? drm_mode_duplicate(dev, largest) : NULL; | |
94 | } | |
95 | ||
96 | int | |
97 | nouveau_conn_atomic_get_property(struct drm_connector *connector, | |
98 | const struct drm_connector_state *state, | |
99 | struct drm_property *property, u64 *val) | |
100 | { | |
101 | struct nouveau_conn_atom *asyc = nouveau_conn_atom(state); | |
102 | struct nouveau_display *disp = nouveau_display(connector->dev); | |
103 | struct drm_device *dev = connector->dev; | |
104 | ||
105 | if (property == dev->mode_config.scaling_mode_property) | |
106 | *val = asyc->scaler.mode; | |
107 | else if (property == disp->underscan_property) | |
108 | *val = asyc->scaler.underscan.mode; | |
109 | else if (property == disp->underscan_hborder_property) | |
110 | *val = asyc->scaler.underscan.hborder; | |
111 | else if (property == disp->underscan_vborder_property) | |
112 | *val = asyc->scaler.underscan.vborder; | |
113 | else if (property == disp->dithering_mode) | |
114 | *val = asyc->dither.mode; | |
115 | else if (property == disp->dithering_depth) | |
116 | *val = asyc->dither.depth; | |
117 | else if (property == disp->vibrant_hue_property) | |
118 | *val = asyc->procamp.vibrant_hue; | |
119 | else if (property == disp->color_vibrance_property) | |
120 | *val = asyc->procamp.color_vibrance; | |
121 | else | |
122 | return -EINVAL; | |
123 | ||
124 | return 0; | |
125 | } | |
126 | ||
127 | int | |
128 | nouveau_conn_atomic_set_property(struct drm_connector *connector, | |
129 | struct drm_connector_state *state, | |
130 | struct drm_property *property, u64 val) | |
131 | { | |
132 | struct drm_device *dev = connector->dev; | |
133 | struct nouveau_conn_atom *asyc = nouveau_conn_atom(state); | |
134 | struct nouveau_display *disp = nouveau_display(dev); | |
135 | ||
136 | if (property == dev->mode_config.scaling_mode_property) { | |
137 | switch (val) { | |
138 | case DRM_MODE_SCALE_NONE: | |
139 | /* We allow 'None' for EDID modes, even on a fixed | |
140 | * panel (some exist with support for lower refresh | |
141 | * rates, which people might want to use for power- | |
142 | * saving purposes). | |
143 | * | |
144 | * Non-EDID modes will force the use of GPU scaling | |
145 | * to the native mode regardless of this setting. | |
146 | */ | |
147 | switch (connector->connector_type) { | |
148 | case DRM_MODE_CONNECTOR_LVDS: | |
149 | case DRM_MODE_CONNECTOR_eDP: | |
150 | /* ... except prior to G80, where the code | |
151 | * doesn't support such things. | |
152 | */ | |
0d4a2c57 | 153 | if (disp->disp.object.oclass < NV50_DISP) |
616915ec BS |
154 | return -EINVAL; |
155 | break; | |
156 | default: | |
157 | break; | |
158 | } | |
f49efb10 | 159 | break; |
616915ec BS |
160 | case DRM_MODE_SCALE_FULLSCREEN: |
161 | case DRM_MODE_SCALE_CENTER: | |
162 | case DRM_MODE_SCALE_ASPECT: | |
163 | break; | |
164 | default: | |
165 | return -EINVAL; | |
166 | } | |
167 | ||
168 | if (asyc->scaler.mode != val) { | |
169 | asyc->scaler.mode = val; | |
170 | asyc->set.scaler = true; | |
171 | } | |
172 | } else | |
173 | if (property == disp->underscan_property) { | |
174 | if (asyc->scaler.underscan.mode != val) { | |
175 | asyc->scaler.underscan.mode = val; | |
176 | asyc->set.scaler = true; | |
177 | } | |
178 | } else | |
179 | if (property == disp->underscan_hborder_property) { | |
180 | if (asyc->scaler.underscan.hborder != val) { | |
181 | asyc->scaler.underscan.hborder = val; | |
182 | asyc->set.scaler = true; | |
183 | } | |
184 | } else | |
185 | if (property == disp->underscan_vborder_property) { | |
186 | if (asyc->scaler.underscan.vborder != val) { | |
187 | asyc->scaler.underscan.vborder = val; | |
188 | asyc->set.scaler = true; | |
189 | } | |
190 | } else | |
191 | if (property == disp->dithering_mode) { | |
192 | if (asyc->dither.mode != val) { | |
193 | asyc->dither.mode = val; | |
194 | asyc->set.dither = true; | |
195 | } | |
196 | } else | |
197 | if (property == disp->dithering_depth) { | |
198 | if (asyc->dither.mode != val) { | |
199 | asyc->dither.depth = val; | |
200 | asyc->set.dither = true; | |
201 | } | |
202 | } else | |
203 | if (property == disp->vibrant_hue_property) { | |
204 | if (asyc->procamp.vibrant_hue != val) { | |
205 | asyc->procamp.vibrant_hue = val; | |
206 | asyc->set.procamp = true; | |
207 | } | |
208 | } else | |
209 | if (property == disp->color_vibrance_property) { | |
210 | if (asyc->procamp.color_vibrance != val) { | |
211 | asyc->procamp.color_vibrance = val; | |
212 | asyc->set.procamp = true; | |
213 | } | |
214 | } else { | |
215 | return -EINVAL; | |
216 | } | |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
221 | void | |
222 | nouveau_conn_atomic_destroy_state(struct drm_connector *connector, | |
223 | struct drm_connector_state *state) | |
224 | { | |
225 | struct nouveau_conn_atom *asyc = nouveau_conn_atom(state); | |
226 | __drm_atomic_helper_connector_destroy_state(&asyc->state); | |
227 | kfree(asyc); | |
228 | } | |
229 | ||
230 | struct drm_connector_state * | |
231 | nouveau_conn_atomic_duplicate_state(struct drm_connector *connector) | |
232 | { | |
233 | struct nouveau_conn_atom *armc = nouveau_conn_atom(connector->state); | |
234 | struct nouveau_conn_atom *asyc; | |
235 | if (!(asyc = kmalloc(sizeof(*asyc), GFP_KERNEL))) | |
236 | return NULL; | |
237 | __drm_atomic_helper_connector_duplicate_state(connector, &asyc->state); | |
238 | asyc->dither = armc->dither; | |
239 | asyc->scaler = armc->scaler; | |
240 | asyc->procamp = armc->procamp; | |
241 | asyc->set.mask = 0; | |
242 | return &asyc->state; | |
243 | } | |
244 | ||
245 | void | |
246 | nouveau_conn_reset(struct drm_connector *connector) | |
247 | { | |
64d17f25 | 248 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
616915ec BS |
249 | struct nouveau_conn_atom *asyc; |
250 | ||
64d17f25 HG |
251 | if (drm_drv_uses_atomic_modeset(connector->dev)) { |
252 | if (WARN_ON(!(asyc = kzalloc(sizeof(*asyc), GFP_KERNEL)))) | |
253 | return; | |
254 | ||
255 | if (connector->state) | |
256 | nouveau_conn_atomic_destroy_state(connector, | |
257 | connector->state); | |
258 | ||
259 | __drm_atomic_helper_connector_reset(connector, &asyc->state); | |
260 | } else { | |
261 | asyc = &nv_connector->properties_state; | |
262 | } | |
616915ec | 263 | |
616915ec BS |
264 | asyc->dither.mode = DITHERING_MODE_AUTO; |
265 | asyc->dither.depth = DITHERING_DEPTH_AUTO; | |
266 | asyc->scaler.mode = DRM_MODE_SCALE_NONE; | |
267 | asyc->scaler.underscan.mode = UNDERSCAN_OFF; | |
268 | asyc->procamp.color_vibrance = 150; | |
269 | asyc->procamp.vibrant_hue = 90; | |
270 | ||
0d4a2c57 | 271 | if (nouveau_display(connector->dev)->disp.object.oclass < NV50_DISP) { |
616915ec BS |
272 | switch (connector->connector_type) { |
273 | case DRM_MODE_CONNECTOR_LVDS: | |
274 | /* See note in nouveau_conn_atomic_set_property(). */ | |
275 | asyc->scaler.mode = DRM_MODE_SCALE_FULLSCREEN; | |
276 | break; | |
277 | default: | |
278 | break; | |
279 | } | |
280 | } | |
281 | } | |
282 | ||
56182b8b BS |
283 | void |
284 | nouveau_conn_attach_properties(struct drm_connector *connector) | |
285 | { | |
286 | struct drm_device *dev = connector->dev; | |
56182b8b | 287 | struct nouveau_display *disp = nouveau_display(dev); |
64d17f25 HG |
288 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
289 | struct nouveau_conn_atom *armc; | |
290 | ||
291 | if (drm_drv_uses_atomic_modeset(connector->dev)) | |
292 | armc = nouveau_conn_atom(connector->state); | |
293 | else | |
294 | armc = &nv_connector->properties_state; | |
56182b8b BS |
295 | |
296 | /* Init DVI-I specific properties. */ | |
297 | if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) | |
298 | drm_object_attach_property(&connector->base, dev->mode_config. | |
299 | dvi_i_subconnector_property, 0); | |
300 | ||
301 | /* Add overscan compensation options to digital outputs. */ | |
302 | if (disp->underscan_property && | |
303 | (connector->connector_type == DRM_MODE_CONNECTOR_DVID || | |
304 | connector->connector_type == DRM_MODE_CONNECTOR_DVII || | |
305 | connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || | |
306 | connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)) { | |
307 | drm_object_attach_property(&connector->base, | |
308 | disp->underscan_property, | |
309 | UNDERSCAN_OFF); | |
310 | drm_object_attach_property(&connector->base, | |
311 | disp->underscan_hborder_property, 0); | |
312 | drm_object_attach_property(&connector->base, | |
313 | disp->underscan_vborder_property, 0); | |
314 | } | |
315 | ||
316 | /* Add hue and saturation options. */ | |
317 | if (disp->vibrant_hue_property) | |
318 | drm_object_attach_property(&connector->base, | |
319 | disp->vibrant_hue_property, | |
320 | armc->procamp.vibrant_hue); | |
321 | if (disp->color_vibrance_property) | |
322 | drm_object_attach_property(&connector->base, | |
323 | disp->color_vibrance_property, | |
324 | armc->procamp.color_vibrance); | |
325 | ||
326 | /* Scaling mode property. */ | |
327 | switch (connector->connector_type) { | |
328 | case DRM_MODE_CONNECTOR_TV: | |
329 | break; | |
330 | case DRM_MODE_CONNECTOR_VGA: | |
0d4a2c57 | 331 | if (disp->disp.object.oclass < NV50_DISP) |
56182b8b | 332 | break; /* Can only scale on DFPs. */ |
f6e7393e | 333 | fallthrough; |
56182b8b BS |
334 | default: |
335 | drm_object_attach_property(&connector->base, dev->mode_config. | |
336 | scaling_mode_property, | |
337 | armc->scaler.mode); | |
338 | break; | |
339 | } | |
340 | ||
341 | /* Dithering properties. */ | |
342 | switch (connector->connector_type) { | |
343 | case DRM_MODE_CONNECTOR_TV: | |
344 | case DRM_MODE_CONNECTOR_VGA: | |
345 | break; | |
346 | default: | |
347 | if (disp->dithering_mode) { | |
348 | drm_object_attach_property(&connector->base, | |
349 | disp->dithering_mode, | |
350 | armc->dither.mode); | |
351 | } | |
352 | if (disp->dithering_depth) { | |
353 | drm_object_attach_property(&connector->base, | |
354 | disp->dithering_depth, | |
355 | armc->dither.depth); | |
356 | } | |
357 | break; | |
358 | } | |
359 | } | |
360 | ||
77145f1c | 361 | MODULE_PARM_DESC(tv_disable, "Disable TV-out detection"); |
703fa264 | 362 | int nouveau_tv_disable = 0; |
77145f1c BS |
363 | module_param_named(tv_disable, nouveau_tv_disable, int, 0400); |
364 | ||
365 | MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status"); | |
703fa264 | 366 | int nouveau_ignorelid = 0; |
77145f1c BS |
367 | module_param_named(ignorelid, nouveau_ignorelid, int, 0400); |
368 | ||
369 | MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (default: enabled)"); | |
703fa264 | 370 | int nouveau_duallink = 1; |
77145f1c | 371 | module_param_named(duallink, nouveau_duallink, int, 0400); |
6ee73861 | 372 | |
1a0c96c0 IM |
373 | MODULE_PARM_DESC(hdmimhz, "Force a maximum HDMI pixel clock (in MHz)"); |
374 | int nouveau_hdmimhz = 0; | |
375 | module_param_named(hdmimhz, nouveau_hdmimhz, int, 0400); | |
376 | ||
10b461e4 | 377 | struct nouveau_encoder * |
e19b20bb | 378 | find_encoder(struct drm_connector *connector, int type) |
6ee73861 | 379 | { |
6ee73861 | 380 | struct nouveau_encoder *nv_encoder; |
6d385c0a | 381 | struct drm_encoder *enc; |
6ee73861 | 382 | |
62afb4ad | 383 | drm_connector_for_each_possible_encoder(connector, enc) { |
6d385c0a | 384 | nv_encoder = nouveau_encoder(enc); |
6ee73861 | 385 | |
4874322e BS |
386 | if (type == DCB_OUTPUT_ANY || |
387 | (nv_encoder->dcb && nv_encoder->dcb->type == type)) | |
6ee73861 BS |
388 | return nv_encoder; |
389 | } | |
390 | ||
391 | return NULL; | |
392 | } | |
393 | ||
6ee73861 | 394 | static void |
fce2bad0 | 395 | nouveau_connector_destroy(struct drm_connector *connector) |
6ee73861 | 396 | { |
fce2bad0 | 397 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
773eb04d BS |
398 | nvif_event_dtor(&nv_connector->irq); |
399 | nvif_event_dtor(&nv_connector->hpd); | |
c8ebe275 | 400 | kfree(nv_connector->edid); |
34ea3d38 | 401 | drm_connector_unregister(connector); |
fce2bad0 | 402 | drm_connector_cleanup(connector); |
9c3361de | 403 | if (nv_connector->aux.transfer) |
46094b2b | 404 | drm_dp_cec_unregister_connector(&nv_connector->aux); |
95983aea | 405 | nvif_conn_dtor(&nv_connector->conn); |
fce2bad0 | 406 | kfree(connector); |
6ee73861 BS |
407 | } |
408 | ||
8777c5c1 BS |
409 | static struct nouveau_encoder * |
410 | nouveau_connector_ddc_detect(struct drm_connector *connector) | |
6ee73861 BS |
411 | { |
412 | struct drm_device *dev = connector->dev; | |
4c0d42f7 | 413 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
a69eeb37 | 414 | struct nouveau_connector *conn = nouveau_connector(connector); |
d5986a1c | 415 | struct nouveau_encoder *nv_encoder = NULL, *found = NULL; |
6d385c0a | 416 | struct drm_encoder *encoder; |
62afb4ad | 417 | int ret; |
d5986a1c | 418 | bool switcheroo_ddc = false; |
6ee73861 | 419 | |
62afb4ad | 420 | drm_connector_for_each_possible_encoder(connector, encoder) { |
6d385c0a | 421 | nv_encoder = nouveau_encoder(encoder); |
4ca2b712 | 422 | |
a69eeb37 BS |
423 | if (nvif_object_constructed(&nv_encoder->outp.object)) { |
424 | enum nvif_outp_detect_status status; | |
425 | ||
426 | if (nv_encoder->dcb->type == DCB_OUTPUT_DP) { | |
427 | ret = nouveau_dp_detect(conn, nv_encoder); | |
428 | if (ret == NOUVEAU_DP_MST) | |
429 | return NULL; | |
430 | if (ret != NOUVEAU_DP_SST) | |
431 | continue; | |
432 | ||
433 | return nv_encoder; | |
434 | } else { | |
435 | status = nvif_outp_detect(&nv_encoder->outp); | |
436 | switch (status) { | |
437 | case PRESENT: | |
438 | return nv_encoder; | |
439 | case NOT_PRESENT: | |
440 | continue; | |
441 | case UNKNOWN: | |
442 | break; | |
443 | default: | |
444 | WARN_ON(1); | |
445 | break; | |
446 | } | |
447 | } | |
448 | } | |
d5986a1c | 449 | |
a69eeb37 BS |
450 | if (!nv_encoder->i2c) |
451 | continue; | |
d5986a1c | 452 | |
a69eeb37 | 453 | if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS) { |
d5986a1c LP |
454 | switcheroo_ddc = !!(vga_switcheroo_handler_flags() & |
455 | VGA_SWITCHEROO_CAN_SWITCH_DDC); | |
a69eeb37 | 456 | } |
d5986a1c | 457 | |
a69eeb37 BS |
458 | if (switcheroo_ddc) |
459 | vga_switcheroo_lock_ddc(pdev); | |
460 | if (nvkm_probe_i2c(nv_encoder->i2c, 0x50)) | |
461 | found = nv_encoder; | |
462 | if (switcheroo_ddc) | |
463 | vga_switcheroo_unlock_ddc(pdev); | |
d5986a1c | 464 | |
d5986a1c LP |
465 | if (found) |
466 | break; | |
6ee73861 BS |
467 | } |
468 | ||
d5986a1c | 469 | return found; |
6ee73861 BS |
470 | } |
471 | ||
c16c5707 FJ |
472 | static struct nouveau_encoder * |
473 | nouveau_connector_of_detect(struct drm_connector *connector) | |
474 | { | |
475 | #ifdef __powerpc__ | |
476 | struct drm_device *dev = connector->dev; | |
477 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | |
478 | struct nouveau_encoder *nv_encoder; | |
bfba9416 TZ |
479 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
480 | struct device_node *cn, *dn = pci_device_to_OF_node(pdev); | |
c16c5707 FJ |
481 | |
482 | if (!dn || | |
cb75d97e BS |
483 | !((nv_encoder = find_encoder(connector, DCB_OUTPUT_TMDS)) || |
484 | (nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG)))) | |
c16c5707 FJ |
485 | return NULL; |
486 | ||
487 | for_each_child_of_node(dn, cn) { | |
488 | const char *name = of_get_property(cn, "name", NULL); | |
489 | const void *edid = of_get_property(cn, "EDID", NULL); | |
490 | int idx = name ? name[strlen(name) - 1] - 'A' : 0; | |
491 | ||
492 | if (nv_encoder->dcb->i2c_index == idx && edid) { | |
493 | nv_connector->edid = | |
494 | kmemdup(edid, EDID_LENGTH, GFP_KERNEL); | |
495 | of_node_put(cn); | |
496 | return nv_encoder; | |
497 | } | |
498 | } | |
499 | #endif | |
500 | return NULL; | |
501 | } | |
502 | ||
6ee73861 BS |
503 | static void |
504 | nouveau_connector_set_encoder(struct drm_connector *connector, | |
505 | struct nouveau_encoder *nv_encoder) | |
506 | { | |
507 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | |
77145f1c | 508 | struct nouveau_drm *drm = nouveau_drm(connector->dev); |
6ee73861 | 509 | struct drm_device *dev = connector->dev; |
4c0d42f7 | 510 | struct pci_dev *pdev = to_pci_dev(dev->dev); |
6ee73861 BS |
511 | |
512 | if (nv_connector->detected_encoder == nv_encoder) | |
513 | return; | |
514 | nv_connector->detected_encoder = nv_encoder; | |
515 | ||
1167c6bc | 516 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { |
4a2cb418 LP |
517 | if (nv_encoder->dcb->type == DCB_OUTPUT_DP) |
518 | connector->interlace_allowed = | |
519 | nv_encoder->caps.dp_interlace; | |
520 | else | |
8ba92493 LP |
521 | connector->interlace_allowed = |
522 | drm->client.device.info.family < NV_DEVICE_INFO_V0_VOLTA; | |
c8334423 BS |
523 | connector->doublescan_allowed = true; |
524 | } else | |
cb75d97e BS |
525 | if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS || |
526 | nv_encoder->dcb->type == DCB_OUTPUT_TMDS) { | |
6ee73861 BS |
527 | connector->doublescan_allowed = false; |
528 | connector->interlace_allowed = false; | |
529 | } else { | |
530 | connector->doublescan_allowed = true; | |
1167c6bc BS |
531 | if (drm->client.device.info.family == NV_DEVICE_INFO_V0_KELVIN || |
532 | (drm->client.device.info.family == NV_DEVICE_INFO_V0_CELSIUS && | |
4c0d42f7 TZ |
533 | (pdev->device & 0x0ff0) != 0x0100 && |
534 | (pdev->device & 0x0ff0) != 0x0150)) | |
6ee73861 BS |
535 | /* HW is broken */ |
536 | connector->interlace_allowed = false; | |
537 | else | |
538 | connector->interlace_allowed = true; | |
539 | } | |
540 | ||
befb51e9 | 541 | if (nv_connector->type == DCB_CONNECTOR_DVI_I) { |
2db83827 | 542 | drm_object_property_set_value(&connector->base, |
6ee73861 | 543 | dev->mode_config.dvi_i_subconnector_property, |
cb75d97e | 544 | nv_encoder->dcb->type == DCB_OUTPUT_TMDS ? |
6ee73861 BS |
545 | DRM_MODE_SUBCONNECTOR_DVID : |
546 | DRM_MODE_SUBCONNECTOR_DVIA); | |
547 | } | |
548 | } | |
549 | ||
f28e32d3 LP |
550 | static void |
551 | nouveau_connector_set_edid(struct nouveau_connector *nv_connector, | |
552 | struct edid *edid) | |
553 | { | |
630f5122 AK |
554 | if (nv_connector->edid != edid) { |
555 | struct edid *old_edid = nv_connector->edid; | |
f28e32d3 | 556 | |
630f5122 AK |
557 | drm_connector_update_edid_property(&nv_connector->base, edid); |
558 | kfree(old_edid); | |
559 | nv_connector->edid = edid; | |
560 | } | |
f28e32d3 LP |
561 | } |
562 | ||
6ee73861 | 563 | static enum drm_connector_status |
930a9e28 | 564 | nouveau_connector_detect(struct drm_connector *connector, bool force) |
6ee73861 BS |
565 | { |
566 | struct drm_device *dev = connector->dev; | |
77145f1c | 567 | struct nouveau_drm *drm = nouveau_drm(dev); |
6ee73861 BS |
568 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
569 | struct nouveau_encoder *nv_encoder = NULL; | |
e19b20bb | 570 | struct nouveau_encoder *nv_partner; |
03cd06ca | 571 | int type; |
5addcf0a DA |
572 | int ret; |
573 | enum drm_connector_status conn_status = connector_status_disconnected; | |
6ee73861 | 574 | |
6833fb1e LP |
575 | /* Outputs are only polled while runtime active, so resuming the |
576 | * device here is unnecessary (and would deadlock upon runtime suspend | |
577 | * because it waits for polling to finish). We do however, want to | |
578 | * prevent the autosuspend timer from elapsing during this operation | |
579 | * if possible. | |
d61a5c10 | 580 | */ |
6833fb1e LP |
581 | if (drm_kms_helper_is_poll_worker()) { |
582 | pm_runtime_get_noresume(dev->dev); | |
583 | } else { | |
584 | ret = pm_runtime_get_sync(dev->dev); | |
990a1162 AP |
585 | if (ret < 0 && ret != -EACCES) { |
586 | pm_runtime_put_autosuspend(dev->dev); | |
f28e32d3 | 587 | nouveau_connector_set_edid(nv_connector, NULL); |
d61a5c10 | 588 | return conn_status; |
990a1162 | 589 | } |
d61a5c10 | 590 | } |
5addcf0a | 591 | |
8777c5c1 | 592 | nv_encoder = nouveau_connector_ddc_detect(connector); |
0cd7e071 BS |
593 | if (nv_encoder) { |
594 | struct edid *new_edid = NULL; | |
f28e32d3 | 595 | |
0cd7e071 BS |
596 | if (nv_encoder->i2c) { |
597 | if ((vga_switcheroo_handler_flags() & VGA_SWITCHEROO_CAN_SWITCH_DDC) && | |
598 | nv_connector->type == DCB_CONNECTOR_LVDS) | |
599 | new_edid = drm_get_edid_switcheroo(connector, nv_encoder->i2c); | |
600 | else | |
601 | new_edid = drm_get_edid(connector, nv_encoder->i2c); | |
602 | } else { | |
603 | ret = nvif_outp_edid_get(&nv_encoder->outp, (u8 **)&new_edid); | |
604 | if (ret < 0) | |
605 | return connector_status_disconnected; | |
606 | } | |
39c1c901 | 607 | |
f28e32d3 | 608 | nouveau_connector_set_edid(nv_connector, new_edid); |
6ee73861 | 609 | if (!nv_connector->edid) { |
77145f1c | 610 | NV_ERROR(drm, "DDC responded, but no EDID for %s\n", |
8c6c361a | 611 | connector->name); |
0ed3165e | 612 | goto detect_analog; |
6ee73861 BS |
613 | } |
614 | ||
6ee73861 BS |
615 | /* Override encoder type for DVI-I based on whether EDID |
616 | * says the display is digital or analog, both use the | |
617 | * same i2c channel so the value returned from ddc_detect | |
618 | * isn't necessarily correct. | |
619 | */ | |
e19b20bb | 620 | nv_partner = NULL; |
cb75d97e BS |
621 | if (nv_encoder->dcb->type == DCB_OUTPUT_TMDS) |
622 | nv_partner = find_encoder(connector, DCB_OUTPUT_ANALOG); | |
623 | if (nv_encoder->dcb->type == DCB_OUTPUT_ANALOG) | |
624 | nv_partner = find_encoder(connector, DCB_OUTPUT_TMDS); | |
625 | ||
626 | if (nv_partner && ((nv_encoder->dcb->type == DCB_OUTPUT_ANALOG && | |
627 | nv_partner->dcb->type == DCB_OUTPUT_TMDS) || | |
628 | (nv_encoder->dcb->type == DCB_OUTPUT_TMDS && | |
629 | nv_partner->dcb->type == DCB_OUTPUT_ANALOG))) { | |
6ee73861 | 630 | if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL) |
cb75d97e | 631 | type = DCB_OUTPUT_TMDS; |
6ee73861 | 632 | else |
cb75d97e | 633 | type = DCB_OUTPUT_ANALOG; |
6ee73861 | 634 | |
e19b20bb | 635 | nv_encoder = find_encoder(connector, type); |
6ee73861 BS |
636 | } |
637 | ||
638 | nouveau_connector_set_encoder(connector, nv_encoder); | |
5addcf0a | 639 | conn_status = connector_status_connected; |
ca3545cf BS |
640 | |
641 | if (nv_encoder->dcb->type == DCB_OUTPUT_DP) | |
642 | drm_dp_cec_set_edid(&nv_connector->aux, nv_connector->edid); | |
643 | ||
5addcf0a | 644 | goto out; |
f28e32d3 LP |
645 | } else { |
646 | nouveau_connector_set_edid(nv_connector, NULL); | |
6ee73861 BS |
647 | } |
648 | ||
c16c5707 FJ |
649 | nv_encoder = nouveau_connector_of_detect(connector); |
650 | if (nv_encoder) { | |
651 | nouveau_connector_set_encoder(connector, nv_encoder); | |
5addcf0a DA |
652 | conn_status = connector_status_connected; |
653 | goto out; | |
c16c5707 FJ |
654 | } |
655 | ||
0ed3165e | 656 | detect_analog: |
cb75d97e | 657 | nv_encoder = find_encoder(connector, DCB_OUTPUT_ANALOG); |
f4053509 | 658 | if (!nv_encoder && !nouveau_tv_disable) |
cb75d97e | 659 | nv_encoder = find_encoder(connector, DCB_OUTPUT_TV); |
84b8081c | 660 | if (nv_encoder && force) { |
6ee73861 | 661 | struct drm_encoder *encoder = to_drm_encoder(nv_encoder); |
d58ded76 | 662 | const struct drm_encoder_helper_funcs *helper = |
6ee73861 BS |
663 | encoder->helper_private; |
664 | ||
665 | if (helper->detect(encoder, connector) == | |
666 | connector_status_connected) { | |
667 | nouveau_connector_set_encoder(connector, nv_encoder); | |
5addcf0a DA |
668 | conn_status = connector_status_connected; |
669 | goto out; | |
6ee73861 | 670 | } |
6ee73861 BS |
671 | } |
672 | ||
5addcf0a | 673 | out: |
02bb7fe2 LP |
674 | if (!nv_connector->edid) |
675 | drm_dp_cec_unset_edid(&nv_connector->aux); | |
5addcf0a | 676 | |
6833fb1e LP |
677 | pm_runtime_mark_last_busy(dev->dev); |
678 | pm_runtime_put_autosuspend(dev->dev); | |
5addcf0a DA |
679 | |
680 | return conn_status; | |
6ee73861 BS |
681 | } |
682 | ||
d17f395c | 683 | static enum drm_connector_status |
930a9e28 | 684 | nouveau_connector_detect_lvds(struct drm_connector *connector, bool force) |
d17f395c BS |
685 | { |
686 | struct drm_device *dev = connector->dev; | |
77145f1c | 687 | struct nouveau_drm *drm = nouveau_drm(dev); |
d17f395c BS |
688 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
689 | struct nouveau_encoder *nv_encoder = NULL; | |
f28e32d3 | 690 | struct edid *edid = NULL; |
d17f395c BS |
691 | enum drm_connector_status status = connector_status_disconnected; |
692 | ||
cb75d97e | 693 | nv_encoder = find_encoder(connector, DCB_OUTPUT_LVDS); |
d17f395c | 694 | if (!nv_encoder) |
f28e32d3 | 695 | goto out; |
d17f395c | 696 | |
a6ed76d7 | 697 | /* Try retrieving EDID via DDC */ |
77145f1c | 698 | if (!drm->vbios.fp_no_ddc) { |
930a9e28 | 699 | status = nouveau_connector_detect(connector, force); |
630f5122 AK |
700 | if (status == connector_status_connected) { |
701 | edid = nv_connector->edid; | |
d17f395c | 702 | goto out; |
630f5122 | 703 | } |
d17f395c BS |
704 | } |
705 | ||
a6ed76d7 BS |
706 | /* On some laptops (Sony, i'm looking at you) there appears to |
707 | * be no direct way of accessing the panel's EDID. The only | |
708 | * option available to us appears to be to ask ACPI for help.. | |
709 | * | |
710 | * It's important this check's before trying straps, one of the | |
711 | * said manufacturer's laptops are configured in such a way | |
712 | * the nouveau decides an entry in the VBIOS FP mode table is | |
713 | * valid - it's not (rh#613284) | |
714 | */ | |
715 | if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) { | |
f28e32d3 LP |
716 | edid = nouveau_acpi_edid(dev, connector); |
717 | if (edid) { | |
a6ed76d7 BS |
718 | status = connector_status_connected; |
719 | goto out; | |
720 | } | |
721 | } | |
722 | ||
d17f395c BS |
723 | /* If no EDID found above, and the VBIOS indicates a hardcoded |
724 | * modeline is avalilable for the panel, set it as the panel's | |
725 | * native mode and exit. | |
726 | */ | |
77145f1c | 727 | if (nouveau_bios_fp_mode(dev, NULL) && (drm->vbios.fp_no_ddc || |
d17f395c BS |
728 | nv_encoder->dcb->lvdsconf.use_straps_for_mode)) { |
729 | status = connector_status_connected; | |
730 | goto out; | |
731 | } | |
732 | ||
733 | /* Still nothing, some VBIOS images have a hardcoded EDID block | |
734 | * stored for the panel stored in them. | |
735 | */ | |
77145f1c | 736 | if (!drm->vbios.fp_no_ddc) { |
f28e32d3 | 737 | edid = (struct edid *)nouveau_bios_embedded_edid(dev); |
d17f395c | 738 | if (edid) { |
f28e32d3 LP |
739 | edid = kmemdup(edid, EDID_LENGTH, GFP_KERNEL); |
740 | if (edid) | |
a441dbb1 | 741 | status = connector_status_connected; |
d17f395c BS |
742 | } |
743 | } | |
744 | ||
745 | out: | |
746 | #if defined(CONFIG_ACPI_BUTTON) || \ | |
747 | (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE)) | |
748 | if (status == connector_status_connected && | |
749 | !nouveau_ignorelid && !acpi_lid_open()) | |
750 | status = connector_status_unknown; | |
751 | #endif | |
752 | ||
f28e32d3 | 753 | nouveau_connector_set_edid(nv_connector, edid); |
55b94bb8 NP |
754 | if (nv_encoder) |
755 | nouveau_connector_set_encoder(connector, nv_encoder); | |
d17f395c BS |
756 | return status; |
757 | } | |
758 | ||
6ee73861 BS |
759 | static void |
760 | nouveau_connector_force(struct drm_connector *connector) | |
761 | { | |
77145f1c | 762 | struct nouveau_drm *drm = nouveau_drm(connector->dev); |
be079e97 | 763 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
6ee73861 BS |
764 | struct nouveau_encoder *nv_encoder; |
765 | int type; | |
766 | ||
befb51e9 | 767 | if (nv_connector->type == DCB_CONNECTOR_DVI_I) { |
6ee73861 | 768 | if (connector->force == DRM_FORCE_ON_DIGITAL) |
cb75d97e | 769 | type = DCB_OUTPUT_TMDS; |
6ee73861 | 770 | else |
cb75d97e | 771 | type = DCB_OUTPUT_ANALOG; |
6ee73861 | 772 | } else |
cb75d97e | 773 | type = DCB_OUTPUT_ANY; |
6ee73861 | 774 | |
e19b20bb | 775 | nv_encoder = find_encoder(connector, type); |
6ee73861 | 776 | if (!nv_encoder) { |
77145f1c | 777 | NV_ERROR(drm, "can't find encoder to force %s on!\n", |
8c6c361a | 778 | connector->name); |
6ee73861 BS |
779 | connector->status = connector_status_disconnected; |
780 | return; | |
781 | } | |
782 | ||
783 | nouveau_connector_set_encoder(connector, nv_encoder); | |
784 | } | |
785 | ||
786 | static int | |
787 | nouveau_connector_set_property(struct drm_connector *connector, | |
788 | struct drm_property *property, uint64_t value) | |
789 | { | |
790 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | |
791 | struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; | |
64d17f25 | 792 | struct nouveau_conn_atom *asyc = &nv_connector->properties_state; |
4a9f822f | 793 | struct drm_encoder *encoder = to_drm_encoder(nv_encoder); |
6ee73861 BS |
794 | int ret; |
795 | ||
616915ec BS |
796 | ret = connector->funcs->atomic_set_property(&nv_connector->base, |
797 | &asyc->state, | |
798 | property, value); | |
799 | if (ret) { | |
800 | if (nv_encoder && nv_encoder->dcb->type == DCB_OUTPUT_TV) | |
801 | return get_slave_funcs(encoder)->set_property( | |
802 | encoder, connector, property, value); | |
803 | return ret; | |
b29caa58 BS |
804 | } |
805 | ||
616915ec | 806 | nv_connector->scaling_mode = asyc->scaler.mode; |
616915ec | 807 | nv_connector->dithering_mode = asyc->dither.mode; |
b29caa58 | 808 | |
c2d926aa BS |
809 | if (connector->encoder && connector->encoder->crtc) { |
810 | ret = drm_crtc_helper_set_mode(connector->encoder->crtc, | |
811 | &connector->encoder->crtc->mode, | |
812 | connector->encoder->crtc->x, | |
813 | connector->encoder->crtc->y, | |
814 | NULL); | |
815 | if (!ret) | |
816 | return -EINVAL; | |
817 | } | |
6ee73861 | 818 | |
616915ec | 819 | return 0; |
6ee73861 BS |
820 | } |
821 | ||
822 | struct moderec { | |
823 | int hdisplay; | |
824 | int vdisplay; | |
825 | }; | |
826 | ||
827 | static struct moderec scaler_modes[] = { | |
828 | { 1920, 1200 }, | |
829 | { 1920, 1080 }, | |
830 | { 1680, 1050 }, | |
831 | { 1600, 1200 }, | |
832 | { 1400, 1050 }, | |
833 | { 1280, 1024 }, | |
834 | { 1280, 960 }, | |
835 | { 1152, 864 }, | |
836 | { 1024, 768 }, | |
837 | { 800, 600 }, | |
838 | { 720, 400 }, | |
839 | { 640, 480 }, | |
840 | { 640, 400 }, | |
841 | { 640, 350 }, | |
842 | {} | |
843 | }; | |
844 | ||
845 | static int | |
846 | nouveau_connector_scaler_modes_add(struct drm_connector *connector) | |
847 | { | |
848 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | |
849 | struct drm_display_mode *native = nv_connector->native_mode, *m; | |
850 | struct drm_device *dev = connector->dev; | |
851 | struct moderec *mode = &scaler_modes[0]; | |
852 | int modes = 0; | |
853 | ||
854 | if (!native) | |
855 | return 0; | |
856 | ||
857 | while (mode->hdisplay) { | |
858 | if (mode->hdisplay <= native->hdisplay && | |
f0d15402 BS |
859 | mode->vdisplay <= native->vdisplay && |
860 | (mode->hdisplay != native->hdisplay || | |
861 | mode->vdisplay != native->vdisplay)) { | |
6ee73861 BS |
862 | m = drm_cvt_mode(dev, mode->hdisplay, mode->vdisplay, |
863 | drm_mode_vrefresh(native), false, | |
864 | false, false); | |
865 | if (!m) | |
866 | continue; | |
867 | ||
6ee73861 BS |
868 | drm_mode_probed_add(connector, m); |
869 | modes++; | |
870 | } | |
871 | ||
872 | mode++; | |
873 | } | |
874 | ||
875 | return modes; | |
876 | } | |
877 | ||
63221755 BS |
878 | static void |
879 | nouveau_connector_detect_depth(struct drm_connector *connector) | |
880 | { | |
77145f1c | 881 | struct nouveau_drm *drm = nouveau_drm(connector->dev); |
63221755 BS |
882 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
883 | struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; | |
77145f1c | 884 | struct nvbios *bios = &drm->vbios; |
63221755 BS |
885 | struct drm_display_mode *mode = nv_connector->native_mode; |
886 | bool duallink; | |
887 | ||
888 | /* if the edid is feeling nice enough to provide this info, use it */ | |
889 | if (nv_connector->edid && connector->display_info.bpc) | |
890 | return; | |
891 | ||
a6a17859 BS |
892 | /* EDID 1.4 is *supposed* to be supported on eDP, but, Apple... */ |
893 | if (nv_connector->type == DCB_CONNECTOR_eDP) { | |
894 | connector->display_info.bpc = 6; | |
895 | return; | |
896 | } | |
897 | ||
898 | /* we're out of options unless we're LVDS, default to 8bpc */ | |
cb75d97e | 899 | if (nv_encoder->dcb->type != DCB_OUTPUT_LVDS) { |
c8435362 | 900 | connector->display_info.bpc = 8; |
63221755 | 901 | return; |
c8435362 BS |
902 | } |
903 | ||
904 | connector->display_info.bpc = 6; | |
63221755 BS |
905 | |
906 | /* LVDS: panel straps */ | |
907 | if (bios->fp_no_ddc) { | |
908 | if (bios->fp.if_is_24bit) | |
909 | connector->display_info.bpc = 8; | |
910 | return; | |
911 | } | |
912 | ||
913 | /* LVDS: DDC panel, need to first determine the number of links to | |
914 | * know which if_is_24bit flag to check... | |
915 | */ | |
916 | if (nv_connector->edid && | |
befb51e9 | 917 | nv_connector->type == DCB_CONNECTOR_LVDS_SPWG) |
63221755 BS |
918 | duallink = ((u8 *)nv_connector->edid)[121] == 2; |
919 | else | |
920 | duallink = mode->clock >= bios->fp.duallink_transition_clk; | |
921 | ||
922 | if ((!duallink && (bios->fp.strapless_is_24bit & 1)) || | |
923 | ( duallink && (bios->fp.strapless_is_24bit & 2))) | |
924 | connector->display_info.bpc = 8; | |
925 | } | |
926 | ||
6d757753 LP |
927 | static int |
928 | nouveau_connector_late_register(struct drm_connector *connector) | |
929 | { | |
930 | int ret; | |
931 | ||
932 | ret = nouveau_backlight_init(connector); | |
fd43ad9d LP |
933 | if (ret) |
934 | return ret; | |
6d757753 | 935 | |
fd43ad9d LP |
936 | if (connector->connector_type == DRM_MODE_CONNECTOR_eDP || |
937 | connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { | |
938 | ret = drm_dp_aux_register(&nouveau_connector(connector)->aux); | |
939 | if (ret) | |
940 | goto backlight_fini; | |
941 | } | |
942 | ||
943 | return 0; | |
944 | backlight_fini: | |
945 | nouveau_backlight_fini(connector); | |
6d757753 LP |
946 | return ret; |
947 | } | |
948 | ||
949 | static void | |
950 | nouveau_connector_early_unregister(struct drm_connector *connector) | |
951 | { | |
fd43ad9d LP |
952 | if (connector->connector_type == DRM_MODE_CONNECTOR_eDP || |
953 | connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) | |
954 | drm_dp_aux_unregister(&nouveau_connector(connector)->aux); | |
955 | ||
a4e05f41 | 956 | nouveau_backlight_fini(connector); |
6d757753 LP |
957 | } |
958 | ||
6ee73861 BS |
959 | static int |
960 | nouveau_connector_get_modes(struct drm_connector *connector) | |
961 | { | |
962 | struct drm_device *dev = connector->dev; | |
77145f1c | 963 | struct nouveau_drm *drm = nouveau_drm(dev); |
6ee73861 BS |
964 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
965 | struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; | |
4a9f822f | 966 | struct drm_encoder *encoder = to_drm_encoder(nv_encoder); |
6ee73861 BS |
967 | int ret = 0; |
968 | ||
d17f395c | 969 | /* destroy the native mode, the attached monitor could have changed. |
6ee73861 | 970 | */ |
d17f395c | 971 | if (nv_connector->native_mode) { |
6ee73861 BS |
972 | drm_mode_destroy(dev, nv_connector->native_mode); |
973 | nv_connector->native_mode = NULL; | |
974 | } | |
975 | ||
976 | if (nv_connector->edid) | |
977 | ret = drm_add_edid_modes(connector, nv_connector->edid); | |
d17f395c | 978 | else |
cb75d97e | 979 | if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS && |
d17f395c | 980 | (nv_encoder->dcb->lvdsconf.use_straps_for_mode || |
77145f1c | 981 | drm->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) { |
80dad869 BS |
982 | struct drm_display_mode mode; |
983 | ||
984 | nouveau_bios_fp_mode(dev, &mode); | |
985 | nv_connector->native_mode = drm_mode_duplicate(dev, &mode); | |
d17f395c | 986 | } |
6ee73861 | 987 | |
d4c2c99b BS |
988 | /* Determine display colour depth for everything except LVDS now, |
989 | * DP requires this before mode_valid() is called. | |
990 | */ | |
d5712cd2 | 991 | if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) |
d4c2c99b BS |
992 | nouveau_connector_detect_depth(connector); |
993 | ||
6ee73861 BS |
994 | /* Find the native mode if this is a digital panel, if we didn't |
995 | * find any modes through DDC previously add the native mode to | |
996 | * the list of modes. | |
997 | */ | |
998 | if (!nv_connector->native_mode) | |
616915ec | 999 | nv_connector->native_mode = nouveau_conn_native_mode(connector); |
6ee73861 BS |
1000 | if (ret == 0 && nv_connector->native_mode) { |
1001 | struct drm_display_mode *mode; | |
1002 | ||
1003 | mode = drm_mode_duplicate(dev, nv_connector->native_mode); | |
1004 | drm_mode_probed_add(connector, mode); | |
1005 | ret = 1; | |
1006 | } | |
1007 | ||
d4c2c99b BS |
1008 | /* Determine LVDS colour depth, must happen after determining |
1009 | * "native" mode as some VBIOS tables require us to use the | |
1010 | * pixel clock as part of the lookup... | |
63221755 | 1011 | */ |
20a2ce87 | 1012 | if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS && nv_connector->native_mode) |
d4c2c99b | 1013 | nouveau_connector_detect_depth(connector); |
63221755 | 1014 | |
cb75d97e | 1015 | if (nv_encoder->dcb->type == DCB_OUTPUT_TV) |
4a9f822f | 1016 | ret = get_slave_funcs(encoder)->get_modes(encoder, connector); |
6ee73861 | 1017 | |
befb51e9 BS |
1018 | if (nv_connector->type == DCB_CONNECTOR_LVDS || |
1019 | nv_connector->type == DCB_CONNECTOR_LVDS_SPWG || | |
1020 | nv_connector->type == DCB_CONNECTOR_eDP) | |
6ee73861 BS |
1021 | ret += nouveau_connector_scaler_modes_add(connector); |
1022 | ||
1023 | return ret; | |
1024 | } | |
1025 | ||
1f5bd443 | 1026 | static unsigned |
9340d77f | 1027 | get_tmds_link_bandwidth(struct drm_connector *connector) |
1f5bd443 FJ |
1028 | { |
1029 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | |
9340d77f | 1030 | struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; |
77145f1c | 1031 | struct nouveau_drm *drm = nouveau_drm(connector->dev); |
cb75d97e | 1032 | struct dcb_output *dcb = nv_connector->detected_encoder->dcb; |
9340d77f | 1033 | struct drm_display_info *info = NULL; |
d1084184 | 1034 | unsigned duallink_scale = |
9340d77f IM |
1035 | nouveau_duallink && nv_encoder->dcb->duallink_possible ? 2 : 1; |
1036 | ||
d1084184 | 1037 | if (drm_detect_hdmi_monitor(nv_connector->edid)) { |
9340d77f | 1038 | info = &nv_connector->base.display_info; |
d1084184 BS |
1039 | duallink_scale = 1; |
1040 | } | |
1f5bd443 | 1041 | |
9340d77f | 1042 | if (info) { |
1a0c96c0 IM |
1043 | if (nouveau_hdmimhz > 0) |
1044 | return nouveau_hdmimhz * 1000; | |
1045 | /* Note: these limits are conservative, some Fermi's | |
1046 | * can do 297 MHz. Unclear how this can be determined. | |
1047 | */ | |
9340d77f IM |
1048 | if (drm->client.device.info.chipset >= 0x120) { |
1049 | const int max_tmds_clock = | |
1050 | info->hdmi.scdc.scrambling.supported ? | |
1051 | 594000 : 340000; | |
1052 | return info->max_tmds_clock ? | |
1053 | min(info->max_tmds_clock, max_tmds_clock) : | |
1054 | max_tmds_clock; | |
1055 | } | |
1167c6bc | 1056 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_KEPLER) |
1a0c96c0 | 1057 | return 297000; |
1167c6bc | 1058 | if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_FERMI) |
1a0c96c0 IM |
1059 | return 225000; |
1060 | } | |
d1084184 | 1061 | |
1f5bd443 | 1062 | if (dcb->location != DCB_LOC_ON_CHIP || |
1167c6bc | 1063 | drm->client.device.info.chipset >= 0x46) |
9340d77f | 1064 | return 165000 * duallink_scale; |
1167c6bc | 1065 | else if (drm->client.device.info.chipset >= 0x40) |
9340d77f | 1066 | return 155000 * duallink_scale; |
1167c6bc | 1067 | else if (drm->client.device.info.chipset >= 0x18) |
9340d77f | 1068 | return 135000 * duallink_scale; |
1f5bd443 | 1069 | else |
9340d77f | 1070 | return 112000 * duallink_scale; |
1f5bd443 FJ |
1071 | } |
1072 | ||
54b202f1 | 1073 | static enum drm_mode_status |
6ee73861 BS |
1074 | nouveau_connector_mode_valid(struct drm_connector *connector, |
1075 | struct drm_display_mode *mode) | |
1076 | { | |
6ee73861 BS |
1077 | struct nouveau_connector *nv_connector = nouveau_connector(connector); |
1078 | struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; | |
4a9f822f | 1079 | struct drm_encoder *encoder = to_drm_encoder(nv_encoder); |
2d831155 | 1080 | unsigned int min_clock = 25000, max_clock = min_clock, clock = mode->clock; |
6ee73861 BS |
1081 | |
1082 | switch (nv_encoder->dcb->type) { | |
cb75d97e | 1083 | case DCB_OUTPUT_LVDS: |
26099a74 BS |
1084 | if (nv_connector->native_mode && |
1085 | (mode->hdisplay > nv_connector->native_mode->hdisplay || | |
1086 | mode->vdisplay > nv_connector->native_mode->vdisplay)) | |
6ee73861 BS |
1087 | return MODE_PANEL; |
1088 | ||
1089 | min_clock = 0; | |
1090 | max_clock = 400000; | |
1091 | break; | |
cb75d97e | 1092 | case DCB_OUTPUT_TMDS: |
9340d77f | 1093 | max_clock = get_tmds_link_bandwidth(connector); |
6ee73861 | 1094 | break; |
cb75d97e | 1095 | case DCB_OUTPUT_ANALOG: |
6ee73861 BS |
1096 | max_clock = nv_encoder->dcb->crtconf.maxfreq; |
1097 | if (!max_clock) | |
1098 | max_clock = 350000; | |
1099 | break; | |
cb75d97e | 1100 | case DCB_OUTPUT_TV: |
4a9f822f | 1101 | return get_slave_funcs(encoder)->mode_valid(encoder, mode); |
cb75d97e | 1102 | case DCB_OUTPUT_DP: |
949ab38a | 1103 | return nv50_dp_mode_valid(nv_encoder, mode, NULL); |
e7cc51c5 | 1104 | default: |
af7db03e | 1105 | BUG(); |
e7cc51c5 | 1106 | return MODE_BAD; |
6ee73861 BS |
1107 | } |
1108 | ||
2d831155 LP |
1109 | if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) |
1110 | clock *= 2; | |
1111 | ||
1112 | if (clock < min_clock) | |
1113 | return MODE_CLOCK_LOW; | |
1114 | if (clock > max_clock) | |
1115 | return MODE_CLOCK_HIGH; | |
1116 | ||
1117 | return MODE_OK; | |
6ee73861 BS |
1118 | } |
1119 | ||
1120 | static struct drm_encoder * | |
1121 | nouveau_connector_best_encoder(struct drm_connector *connector) | |
1122 | { | |
1123 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | |
1124 | ||
1125 | if (nv_connector->detected_encoder) | |
1126 | return to_drm_encoder(nv_connector->detected_encoder); | |
1127 | ||
1128 | return NULL; | |
1129 | } | |
1130 | ||
a76eb429 LP |
1131 | static int |
1132 | nouveau_connector_atomic_check(struct drm_connector *connector, struct drm_atomic_state *state) | |
1133 | { | |
1134 | struct nouveau_connector *nv_conn = nouveau_connector(connector); | |
1135 | struct drm_connector_state *conn_state = | |
1136 | drm_atomic_get_new_connector_state(state, connector); | |
1137 | ||
0a4410a7 | 1138 | if (!nv_conn->dp_encoder || !nv_conn->dp_encoder->dp.mstm) |
a76eb429 LP |
1139 | return 0; |
1140 | ||
1141 | return drm_dp_mst_root_conn_atomic_check(conn_state, &nv_conn->dp_encoder->dp.mstm->mgr); | |
1142 | } | |
1143 | ||
6ee73861 BS |
1144 | static const struct drm_connector_helper_funcs |
1145 | nouveau_connector_helper_funcs = { | |
1146 | .get_modes = nouveau_connector_get_modes, | |
1147 | .mode_valid = nouveau_connector_mode_valid, | |
1148 | .best_encoder = nouveau_connector_best_encoder, | |
a76eb429 | 1149 | .atomic_check = nouveau_connector_atomic_check, |
6ee73861 BS |
1150 | }; |
1151 | ||
1152 | static const struct drm_connector_funcs | |
1153 | nouveau_connector_funcs = { | |
7d902c05 | 1154 | .dpms = drm_helper_connector_dpms, |
616915ec | 1155 | .reset = nouveau_conn_reset, |
6ee73861 | 1156 | .detect = nouveau_connector_detect, |
616915ec | 1157 | .force = nouveau_connector_force, |
6ee73861 BS |
1158 | .fill_modes = drm_helper_probe_single_connector_modes, |
1159 | .set_property = nouveau_connector_set_property, | |
616915ec BS |
1160 | .destroy = nouveau_connector_destroy, |
1161 | .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state, | |
1162 | .atomic_destroy_state = nouveau_conn_atomic_destroy_state, | |
1163 | .atomic_set_property = nouveau_conn_atomic_set_property, | |
1164 | .atomic_get_property = nouveau_conn_atomic_get_property, | |
6d757753 LP |
1165 | .late_register = nouveau_connector_late_register, |
1166 | .early_unregister = nouveau_connector_early_unregister, | |
6ee73861 BS |
1167 | }; |
1168 | ||
d17f395c BS |
1169 | static const struct drm_connector_funcs |
1170 | nouveau_connector_funcs_lvds = { | |
7d902c05 | 1171 | .dpms = drm_helper_connector_dpms, |
616915ec | 1172 | .reset = nouveau_conn_reset, |
d17f395c | 1173 | .detect = nouveau_connector_detect_lvds, |
616915ec | 1174 | .force = nouveau_connector_force, |
d17f395c BS |
1175 | .fill_modes = drm_helper_probe_single_connector_modes, |
1176 | .set_property = nouveau_connector_set_property, | |
616915ec BS |
1177 | .destroy = nouveau_connector_destroy, |
1178 | .atomic_duplicate_state = nouveau_conn_atomic_duplicate_state, | |
1179 | .atomic_destroy_state = nouveau_conn_atomic_destroy_state, | |
1180 | .atomic_set_property = nouveau_conn_atomic_set_property, | |
1181 | .atomic_get_property = nouveau_conn_atomic_get_property, | |
6d757753 LP |
1182 | .late_register = nouveau_connector_late_register, |
1183 | .early_unregister = nouveau_connector_early_unregister, | |
d17f395c | 1184 | }; |
6ee73861 | 1185 | |
d297ce4b | 1186 | void |
016dacb6 | 1187 | nouveau_connector_hpd(struct nouveau_connector *nv_connector, u64 bits) |
d297ce4b | 1188 | { |
016dacb6 BS |
1189 | struct nouveau_drm *drm = nouveau_drm(nv_connector->base.dev); |
1190 | u32 mask = drm_connector_mask(&nv_connector->base); | |
d62f8e98 | 1191 | unsigned long flags; |
d297ce4b | 1192 | |
d62f8e98 | 1193 | spin_lock_irqsave(&drm->hpd_lock, flags); |
d297ce4b | 1194 | if (!(drm->hpd_pending & mask)) { |
016dacb6 | 1195 | nv_connector->hpd_pending |= bits; |
d297ce4b LP |
1196 | drm->hpd_pending |= mask; |
1197 | schedule_work(&drm->hpd_work); | |
1198 | } | |
d62f8e98 | 1199 | spin_unlock_irqrestore(&drm->hpd_lock, flags); |
d297ce4b LP |
1200 | } |
1201 | ||
79ca2770 | 1202 | static int |
773eb04d | 1203 | nouveau_connector_irq(struct nvif_event *event, void *repv, u32 repc) |
4f47643d | 1204 | { |
773eb04d | 1205 | struct nouveau_connector *nv_connector = container_of(event, typeof(*nv_connector), irq); |
09e53065 | 1206 | |
773eb04d BS |
1207 | schedule_work(&nv_connector->irq_work); |
1208 | return NVIF_EVENT_KEEP; | |
1209 | } | |
3e1a1275 | 1210 | |
773eb04d BS |
1211 | static int |
1212 | nouveau_connector_hotplug(struct nvif_event *event, void *repv, u32 repc) | |
1213 | { | |
1214 | struct nouveau_connector *nv_connector = container_of(event, typeof(*nv_connector), hpd); | |
1215 | struct nvif_conn_event_v0 *rep = repv; | |
09e53065 | 1216 | |
773eb04d BS |
1217 | nouveau_connector_hpd(nv_connector, rep->types); |
1218 | return NVIF_EVENT_KEEP; | |
4f47643d BS |
1219 | } |
1220 | ||
8894f491 | 1221 | static ssize_t |
2aa5eac5 | 1222 | nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg) |
8894f491 BS |
1223 | { |
1224 | struct nouveau_connector *nv_connector = | |
2aa5eac5 | 1225 | container_of(obj, typeof(*nv_connector), aux); |
8894f491 | 1226 | struct nouveau_encoder *nv_encoder; |
1af5c410 | 1227 | u8 size = msg->size; |
8894f491 BS |
1228 | int ret; |
1229 | ||
1230 | nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP); | |
bd7a61bc | 1231 | if (!nv_encoder) |
8894f491 BS |
1232 | return -ENODEV; |
1233 | if (WARN_ON(msg->size > 16)) | |
1234 | return -E2BIG; | |
8894f491 | 1235 | |
bd7a61bc BS |
1236 | ret = nvif_outp_dp_aux_xfer(&nv_encoder->outp, |
1237 | msg->request, &size, msg->address, msg->buffer); | |
8894f491 BS |
1238 | if (ret >= 0) { |
1239 | msg->reply = ret; | |
1af5c410 | 1240 | return size; |
8894f491 BS |
1241 | } |
1242 | ||
1243 | return ret; | |
1244 | } | |
1245 | ||
befb51e9 BS |
1246 | static int |
1247 | drm_conntype_from_dcb(enum dcb_connector_type dcb) | |
1248 | { | |
1249 | switch (dcb) { | |
1250 | case DCB_CONNECTOR_VGA : return DRM_MODE_CONNECTOR_VGA; | |
1251 | case DCB_CONNECTOR_TV_0 : | |
1252 | case DCB_CONNECTOR_TV_1 : | |
1253 | case DCB_CONNECTOR_TV_3 : return DRM_MODE_CONNECTOR_TV; | |
fa2c113a BS |
1254 | case DCB_CONNECTOR_DMS59_0 : |
1255 | case DCB_CONNECTOR_DMS59_1 : | |
befb51e9 BS |
1256 | case DCB_CONNECTOR_DVI_I : return DRM_MODE_CONNECTOR_DVII; |
1257 | case DCB_CONNECTOR_DVI_D : return DRM_MODE_CONNECTOR_DVID; | |
1258 | case DCB_CONNECTOR_LVDS : | |
1259 | case DCB_CONNECTOR_LVDS_SPWG: return DRM_MODE_CONNECTOR_LVDS; | |
4abb410a BS |
1260 | case DCB_CONNECTOR_DMS59_DP0: |
1261 | case DCB_CONNECTOR_DMS59_DP1: | |
7919faab | 1262 | case DCB_CONNECTOR_DP : |
d1f5a3fc | 1263 | case DCB_CONNECTOR_mDP : |
7919faab | 1264 | case DCB_CONNECTOR_USB_C : return DRM_MODE_CONNECTOR_DisplayPort; |
befb51e9 BS |
1265 | case DCB_CONNECTOR_eDP : return DRM_MODE_CONNECTOR_eDP; |
1266 | case DCB_CONNECTOR_HDMI_0 : | |
6bd9293e BS |
1267 | case DCB_CONNECTOR_HDMI_1 : |
1268 | case DCB_CONNECTOR_HDMI_C : return DRM_MODE_CONNECTOR_HDMIA; | |
df00d5da | 1269 | case DCB_CONNECTOR_WFD : return DRM_MODE_CONNECTOR_VIRTUAL; |
befb51e9 BS |
1270 | default: |
1271 | break; | |
1272 | } | |
1273 | ||
1274 | return DRM_MODE_CONNECTOR_Unknown; | |
1275 | } | |
1276 | ||
8f1a6086 | 1277 | struct drm_connector * |
8b7d92ca | 1278 | nouveau_connector_create(struct drm_device *dev, int index) |
6ee73861 | 1279 | { |
77145f1c | 1280 | struct nouveau_drm *drm = nouveau_drm(dev); |
77145f1c | 1281 | struct nouveau_display *disp = nouveau_display(dev); |
6ee73861 BS |
1282 | struct nouveau_connector *nv_connector = NULL; |
1283 | struct drm_connector *connector; | |
22b76bbe | 1284 | struct drm_connector_list_iter conn_iter; |
2fa67f12 | 1285 | int type, ret = 0; |
befb51e9 | 1286 | bool dummy; |
6ee73861 | 1287 | |
22b76bbe | 1288 | drm_connector_list_iter_begin(dev, &conn_iter); |
37afe55b | 1289 | nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { |
befb51e9 | 1290 | nv_connector = nouveau_connector(connector); |
22b76bbe LP |
1291 | if (nv_connector->index == index) { |
1292 | drm_connector_list_iter_end(&conn_iter); | |
befb51e9 | 1293 | return connector; |
22b76bbe | 1294 | } |
6ee73861 | 1295 | } |
22b76bbe | 1296 | drm_connector_list_iter_end(&conn_iter); |
6ee73861 | 1297 | |
7f612d87 BS |
1298 | nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL); |
1299 | if (!nv_connector) | |
8f1a6086 | 1300 | return ERR_PTR(-ENOMEM); |
befb51e9 | 1301 | |
7f612d87 | 1302 | connector = &nv_connector->base; |
befb51e9 | 1303 | nv_connector->index = index; |
773eb04d | 1304 | INIT_WORK(&nv_connector->irq_work, nouveau_dp_irq); |
befb51e9 | 1305 | |
8b7d92ca BS |
1306 | if (disp->disp.conn_mask & BIT(nv_connector->index)) { |
1307 | ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index, | |
1308 | &nv_connector->conn); | |
1309 | if (ret) { | |
1310 | kfree(nv_connector); | |
1311 | return ERR_PTR(ret); | |
befb51e9 | 1312 | } |
7f612d87 | 1313 | |
8b7d92ca BS |
1314 | switch (nv_connector->conn.info.type) { |
1315 | case NVIF_CONN_VGA : type = DCB_CONNECTOR_VGA; break; | |
1316 | case NVIF_CONN_DVI_I : type = DCB_CONNECTOR_DVI_I; break; | |
1317 | case NVIF_CONN_DVI_D : type = DCB_CONNECTOR_DVI_D; break; | |
1318 | case NVIF_CONN_LVDS : type = DCB_CONNECTOR_LVDS; break; | |
1319 | case NVIF_CONN_LVDS_SPWG: type = DCB_CONNECTOR_LVDS_SPWG; break; | |
1320 | case NVIF_CONN_DP : type = DCB_CONNECTOR_DP; break; | |
1321 | case NVIF_CONN_EDP : type = DCB_CONNECTOR_eDP; break; | |
1322 | case NVIF_CONN_HDMI : type = DCB_CONNECTOR_HDMI_0; break; | |
1323 | default: | |
1324 | WARN_ON(1); | |
1325 | return NULL; | |
befb51e9 | 1326 | } |
6ee73861 | 1327 | |
8b7d92ca | 1328 | nv_connector->type = type; |
befb51e9 | 1329 | } else { |
8b7d92ca | 1330 | u8 *dcb = olddcb_conn(dev, nv_connector->index); |
befb51e9 | 1331 | |
8b7d92ca BS |
1332 | if (dcb) |
1333 | nv_connector->type = dcb[0]; | |
1334 | else | |
1335 | nv_connector->type = DCB_CONNECTOR_NONE; | |
1336 | ||
1337 | /* attempt to parse vbios connector type and hotplug gpio */ | |
1338 | if (nv_connector->type != DCB_CONNECTOR_NONE) { | |
1339 | if (drm_conntype_from_dcb(nv_connector->type) == | |
1340 | DRM_MODE_CONNECTOR_Unknown) { | |
1341 | NV_WARN(drm, "unknown connector type %02x\n", | |
1342 | nv_connector->type); | |
1343 | nv_connector->type = DCB_CONNECTOR_NONE; | |
1344 | } | |
befb51e9 | 1345 | } |
6ee73861 | 1346 | |
8b7d92ca BS |
1347 | /* no vbios data, or an unknown dcb connector type - attempt to |
1348 | * figure out something suitable ourselves | |
1349 | */ | |
1350 | if (nv_connector->type == DCB_CONNECTOR_NONE && | |
1351 | !WARN_ON(drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)) { | |
1352 | struct dcb_table *dcbt = &drm->vbios.dcb; | |
1353 | u32 encoders = 0; | |
1354 | int i; | |
1355 | ||
1356 | for (i = 0; i < dcbt->entries; i++) { | |
1357 | if (dcbt->entry[i].connector == nv_connector->index) | |
1358 | encoders |= (1 << dcbt->entry[i].type); | |
1359 | } | |
1360 | ||
1361 | if (encoders & (1 << DCB_OUTPUT_TMDS)) { | |
1362 | if (encoders & (1 << DCB_OUTPUT_ANALOG)) | |
1363 | nv_connector->type = DCB_CONNECTOR_DVI_I; | |
1364 | else | |
1365 | nv_connector->type = DCB_CONNECTOR_DVI_D; | |
1366 | } else | |
1367 | if (encoders & (1 << DCB_OUTPUT_ANALOG)) { | |
1368 | nv_connector->type = DCB_CONNECTOR_VGA; | |
1369 | } else | |
1370 | if (encoders & (1 << DCB_OUTPUT_LVDS)) { | |
1371 | nv_connector->type = DCB_CONNECTOR_LVDS; | |
1372 | } else | |
1373 | if (encoders & (1 << DCB_OUTPUT_TV)) { | |
1374 | nv_connector->type = DCB_CONNECTOR_TV_0; | |
1375 | } | |
befb51e9 BS |
1376 | } |
1377 | } | |
2fa67f12 | 1378 | |
9c3361de BS |
1379 | type = drm_conntype_from_dcb(nv_connector->type); |
1380 | if (type == DRM_MODE_CONNECTOR_LVDS) | |
1381 | drm_connector_init(dev, connector, &nouveau_connector_funcs_lvds, type); | |
1382 | else | |
1383 | drm_connector_init(dev, connector, &nouveau_connector_funcs, type); | |
1384 | ||
1385 | switch (type) { | |
8894f491 | 1386 | case DRM_MODE_CONNECTOR_LVDS: |
befb51e9 | 1387 | ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &dummy); |
2fa67f12 | 1388 | if (ret) { |
77145f1c | 1389 | NV_ERROR(drm, "Error parsing LVDS table, disabling\n"); |
befb51e9 BS |
1390 | kfree(nv_connector); |
1391 | return ERR_PTR(ret); | |
2fa67f12 | 1392 | } |
befb51e9 | 1393 | |
8894f491 BS |
1394 | break; |
1395 | case DRM_MODE_CONNECTOR_DisplayPort: | |
1396 | case DRM_MODE_CONNECTOR_eDP: | |
7713c0f1 | 1397 | nv_connector->aux.dev = connector->kdev; |
6cba3fe4 | 1398 | nv_connector->aux.drm_dev = dev; |
8894f491 | 1399 | nv_connector->aux.transfer = nouveau_connector_aux_xfer; |
9c3361de | 1400 | nv_connector->aux.name = connector->name; |
ca0367ca | 1401 | drm_dp_aux_init(&nv_connector->aux); |
11d27389 | 1402 | break; |
8894f491 | 1403 | default: |
8894f491 | 1404 | break; |
7f612d87 BS |
1405 | } |
1406 | ||
0f18d276 | 1407 | /* HDMI 3D support */ |
0d4a2c57 | 1408 | if ((disp->disp.object.oclass >= G82_DISP) |
0f18d276 AB |
1409 | && ((type == DRM_MODE_CONNECTOR_DisplayPort) |
1410 | || (type == DRM_MODE_CONNECTOR_eDP) | |
1411 | || (type == DRM_MODE_CONNECTOR_HDMIA))) | |
1412 | connector->stereo_allowed = true; | |
1413 | ||
befb51e9 BS |
1414 | /* defaults, will get overridden in detect() */ |
1415 | connector->interlace_allowed = false; | |
1416 | connector->doublescan_allowed = false; | |
1417 | ||
befb51e9 | 1418 | drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); |
773eb04d | 1419 | connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
befb51e9 | 1420 | |
8b7d92ca | 1421 | if (nvif_object_constructed(&nv_connector->conn.object)) { |
773eb04d BS |
1422 | ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsHotplug", |
1423 | nouveau_connector_hotplug, | |
1424 | NVIF_CONN_EVENT_V0_PLUG | NVIF_CONN_EVENT_V0_UNPLUG, | |
1425 | &nv_connector->hpd); | |
1426 | if (ret == 0) | |
1427 | connector->polled = DRM_CONNECTOR_POLL_HPD; | |
1428 | ||
1429 | if (nv_connector->aux.transfer) { | |
1430 | ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsDpIrq", | |
1431 | nouveau_connector_irq, NVIF_CONN_EVENT_V0_IRQ, | |
1432 | &nv_connector->irq); | |
1433 | if (ret) { | |
1434 | nvif_event_dtor(&nv_connector->hpd); | |
1435 | nvif_conn_dtor(&nv_connector->conn); | |
1b254b79 | 1436 | goto drm_conn_err; |
773eb04d BS |
1437 | } |
1438 | } | |
95983aea BS |
1439 | } |
1440 | ||
56182b8b BS |
1441 | connector->funcs->reset(connector); |
1442 | nouveau_conn_attach_properties(connector); | |
df26bc9c | 1443 | |
56182b8b | 1444 | /* Default scaling mode */ |
befb51e9 | 1445 | switch (nv_connector->type) { |
0ea5fe8a BS |
1446 | case DCB_CONNECTOR_LVDS: |
1447 | case DCB_CONNECTOR_LVDS_SPWG: | |
1448 | case DCB_CONNECTOR_eDP: | |
1449 | /* see note in nouveau_connector_set_property() */ | |
0d4a2c57 | 1450 | if (disp->disp.object.oclass < NV50_DISP) { |
0ea5fe8a BS |
1451 | nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; |
1452 | break; | |
1453 | } | |
be079e97 BS |
1454 | nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; |
1455 | break; | |
1456 | default: | |
0ea5fe8a | 1457 | nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; |
7d95216e BS |
1458 | break; |
1459 | } | |
be079e97 | 1460 | |
7d95216e BS |
1461 | /* dithering properties */ |
1462 | switch (nv_connector->type) { | |
1463 | case DCB_CONNECTOR_TV_0: | |
1464 | case DCB_CONNECTOR_TV_1: | |
1465 | case DCB_CONNECTOR_TV_3: | |
1466 | case DCB_CONNECTOR_VGA: | |
1467 | break; | |
1468 | default: | |
56182b8b | 1469 | nv_connector->dithering_mode = DITHERING_MODE_AUTO; |
be079e97 | 1470 | break; |
6ee73861 BS |
1471 | } |
1472 | ||
46094b2b HV |
1473 | switch (type) { |
1474 | case DRM_MODE_CONNECTOR_DisplayPort: | |
11d27389 LP |
1475 | nv_connector->dp_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP); |
1476 | fallthrough; | |
46094b2b | 1477 | case DRM_MODE_CONNECTOR_eDP: |
ae85b0df | 1478 | drm_dp_cec_register_connector(&nv_connector->aux, connector); |
46094b2b HV |
1479 | break; |
1480 | } | |
1481 | ||
34ea3d38 | 1482 | drm_connector_register(connector); |
befb51e9 | 1483 | return connector; |
1b254b79 KH |
1484 | |
1485 | drm_conn_err: | |
1486 | drm_connector_cleanup(connector); | |
1487 | kfree(nv_connector); | |
1488 | return ERR_PTR(ret); | |
6ee73861 | 1489 | } |