diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_connector.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_connector.c | 824 |
1 files changed, 824 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c new file mode 100644 index 00000000000..032cf098fa1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c | |||
@@ -0,0 +1,824 @@ | |||
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 | |||
27 | #include "drmP.h" | ||
28 | #include "drm_edid.h" | ||
29 | #include "drm_crtc_helper.h" | ||
30 | #include "nouveau_reg.h" | ||
31 | #include "nouveau_drv.h" | ||
32 | #include "nouveau_encoder.h" | ||
33 | #include "nouveau_crtc.h" | ||
34 | #include "nouveau_connector.h" | ||
35 | #include "nouveau_hw.h" | ||
36 | |||
37 | static inline struct drm_encoder_slave_funcs * | ||
38 | get_slave_funcs(struct nouveau_encoder *enc) | ||
39 | { | ||
40 | return to_encoder_slave(to_drm_encoder(enc))->slave_funcs; | ||
41 | } | ||
42 | |||
43 | static struct nouveau_encoder * | ||
44 | find_encoder_by_type(struct drm_connector *connector, int type) | ||
45 | { | ||
46 | struct drm_device *dev = connector->dev; | ||
47 | struct nouveau_encoder *nv_encoder; | ||
48 | struct drm_mode_object *obj; | ||
49 | int i, id; | ||
50 | |||
51 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | ||
52 | id = connector->encoder_ids[i]; | ||
53 | if (!id) | ||
54 | break; | ||
55 | |||
56 | obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); | ||
57 | if (!obj) | ||
58 | continue; | ||
59 | nv_encoder = nouveau_encoder(obj_to_encoder(obj)); | ||
60 | |||
61 | if (type == OUTPUT_ANY || nv_encoder->dcb->type == type) | ||
62 | return nv_encoder; | ||
63 | } | ||
64 | |||
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | struct nouveau_connector * | ||
69 | nouveau_encoder_connector_get(struct nouveau_encoder *encoder) | ||
70 | { | ||
71 | struct drm_device *dev = to_drm_encoder(encoder)->dev; | ||
72 | struct drm_connector *drm_connector; | ||
73 | |||
74 | list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { | ||
75 | if (drm_connector->encoder == to_drm_encoder(encoder)) | ||
76 | return nouveau_connector(drm_connector); | ||
77 | } | ||
78 | |||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | |||
83 | static void | ||
84 | nouveau_connector_destroy(struct drm_connector *drm_connector) | ||
85 | { | ||
86 | struct nouveau_connector *connector = nouveau_connector(drm_connector); | ||
87 | struct drm_device *dev = connector->base.dev; | ||
88 | |||
89 | NV_DEBUG(dev, "\n"); | ||
90 | |||
91 | if (!connector) | ||
92 | return; | ||
93 | |||
94 | drm_sysfs_connector_remove(drm_connector); | ||
95 | drm_connector_cleanup(drm_connector); | ||
96 | kfree(drm_connector); | ||
97 | } | ||
98 | |||
99 | static void | ||
100 | nouveau_connector_ddc_prepare(struct drm_connector *connector, int *flags) | ||
101 | { | ||
102 | struct drm_nouveau_private *dev_priv = connector->dev->dev_private; | ||
103 | |||
104 | if (dev_priv->card_type >= NV_50) | ||
105 | return; | ||
106 | |||
107 | *flags = 0; | ||
108 | if (NVLockVgaCrtcs(dev_priv->dev, false)) | ||
109 | *flags |= 1; | ||
110 | if (nv_heads_tied(dev_priv->dev)) | ||
111 | *flags |= 2; | ||
112 | |||
113 | if (*flags & 2) | ||
114 | NVSetOwner(dev_priv->dev, 0); /* necessary? */ | ||
115 | } | ||
116 | |||
117 | static void | ||
118 | nouveau_connector_ddc_finish(struct drm_connector *connector, int flags) | ||
119 | { | ||
120 | struct drm_nouveau_private *dev_priv = connector->dev->dev_private; | ||
121 | |||
122 | if (dev_priv->card_type >= NV_50) | ||
123 | return; | ||
124 | |||
125 | if (flags & 2) | ||
126 | NVSetOwner(dev_priv->dev, 4); | ||
127 | if (flags & 1) | ||
128 | NVLockVgaCrtcs(dev_priv->dev, true); | ||
129 | } | ||
130 | |||
131 | static struct nouveau_i2c_chan * | ||
132 | nouveau_connector_ddc_detect(struct drm_connector *connector, | ||
133 | struct nouveau_encoder **pnv_encoder) | ||
134 | { | ||
135 | struct drm_device *dev = connector->dev; | ||
136 | uint8_t out_buf[] = { 0x0, 0x0}, buf[2]; | ||
137 | int ret, flags, i; | ||
138 | |||
139 | struct i2c_msg msgs[] = { | ||
140 | { | ||
141 | .addr = 0x50, | ||
142 | .flags = 0, | ||
143 | .len = 1, | ||
144 | .buf = out_buf, | ||
145 | }, | ||
146 | { | ||
147 | .addr = 0x50, | ||
148 | .flags = I2C_M_RD, | ||
149 | .len = 1, | ||
150 | .buf = buf, | ||
151 | } | ||
152 | }; | ||
153 | |||
154 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { | ||
155 | struct nouveau_i2c_chan *i2c = NULL; | ||
156 | struct nouveau_encoder *nv_encoder; | ||
157 | struct drm_mode_object *obj; | ||
158 | int id; | ||
159 | |||
160 | id = connector->encoder_ids[i]; | ||
161 | if (!id) | ||
162 | break; | ||
163 | |||
164 | obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER); | ||
165 | if (!obj) | ||
166 | continue; | ||
167 | nv_encoder = nouveau_encoder(obj_to_encoder(obj)); | ||
168 | |||
169 | if (nv_encoder->dcb->i2c_index < 0xf) | ||
170 | i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); | ||
171 | if (!i2c) | ||
172 | continue; | ||
173 | |||
174 | nouveau_connector_ddc_prepare(connector, &flags); | ||
175 | ret = i2c_transfer(&i2c->adapter, msgs, 2); | ||
176 | nouveau_connector_ddc_finish(connector, flags); | ||
177 | |||
178 | if (ret == 2) { | ||
179 | *pnv_encoder = nv_encoder; | ||
180 | return i2c; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | return NULL; | ||
185 | } | ||
186 | |||
187 | static void | ||
188 | nouveau_connector_set_encoder(struct drm_connector *connector, | ||
189 | struct nouveau_encoder *nv_encoder) | ||
190 | { | ||
191 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | ||
192 | struct drm_nouveau_private *dev_priv = connector->dev->dev_private; | ||
193 | struct drm_device *dev = connector->dev; | ||
194 | |||
195 | if (nv_connector->detected_encoder == nv_encoder) | ||
196 | return; | ||
197 | nv_connector->detected_encoder = nv_encoder; | ||
198 | |||
199 | if (nv_encoder->dcb->type == OUTPUT_LVDS || | ||
200 | nv_encoder->dcb->type == OUTPUT_TMDS) { | ||
201 | connector->doublescan_allowed = false; | ||
202 | connector->interlace_allowed = false; | ||
203 | } else { | ||
204 | connector->doublescan_allowed = true; | ||
205 | if (dev_priv->card_type == NV_20 || | ||
206 | (dev_priv->card_type == NV_10 && | ||
207 | (dev->pci_device & 0x0ff0) != 0x0100 && | ||
208 | (dev->pci_device & 0x0ff0) != 0x0150)) | ||
209 | /* HW is broken */ | ||
210 | connector->interlace_allowed = false; | ||
211 | else | ||
212 | connector->interlace_allowed = true; | ||
213 | } | ||
214 | |||
215 | if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) { | ||
216 | drm_connector_property_set_value(connector, | ||
217 | dev->mode_config.dvi_i_subconnector_property, | ||
218 | nv_encoder->dcb->type == OUTPUT_TMDS ? | ||
219 | DRM_MODE_SUBCONNECTOR_DVID : | ||
220 | DRM_MODE_SUBCONNECTOR_DVIA); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | static enum drm_connector_status | ||
225 | nouveau_connector_detect(struct drm_connector *connector) | ||
226 | { | ||
227 | struct drm_device *dev = connector->dev; | ||
228 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | ||
229 | struct nouveau_encoder *nv_encoder = NULL; | ||
230 | struct nouveau_i2c_chan *i2c; | ||
231 | int type, flags; | ||
232 | |||
233 | if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) | ||
234 | nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); | ||
235 | if (nv_encoder && nv_connector->native_mode) { | ||
236 | nouveau_connector_set_encoder(connector, nv_encoder); | ||
237 | return connector_status_connected; | ||
238 | } | ||
239 | |||
240 | i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); | ||
241 | if (i2c) { | ||
242 | nouveau_connector_ddc_prepare(connector, &flags); | ||
243 | nv_connector->edid = drm_get_edid(connector, &i2c->adapter); | ||
244 | nouveau_connector_ddc_finish(connector, flags); | ||
245 | drm_mode_connector_update_edid_property(connector, | ||
246 | nv_connector->edid); | ||
247 | if (!nv_connector->edid) { | ||
248 | NV_ERROR(dev, "DDC responded, but no EDID for %s\n", | ||
249 | drm_get_connector_name(connector)); | ||
250 | return connector_status_disconnected; | ||
251 | } | ||
252 | |||
253 | if (nv_encoder->dcb->type == OUTPUT_DP && | ||
254 | !nouveau_dp_detect(to_drm_encoder(nv_encoder))) { | ||
255 | NV_ERROR(dev, "Detected %s, but failed init\n", | ||
256 | drm_get_connector_name(connector)); | ||
257 | return connector_status_disconnected; | ||
258 | } | ||
259 | |||
260 | /* Override encoder type for DVI-I based on whether EDID | ||
261 | * says the display is digital or analog, both use the | ||
262 | * same i2c channel so the value returned from ddc_detect | ||
263 | * isn't necessarily correct. | ||
264 | */ | ||
265 | if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) { | ||
266 | if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL) | ||
267 | type = OUTPUT_TMDS; | ||
268 | else | ||
269 | type = OUTPUT_ANALOG; | ||
270 | |||
271 | nv_encoder = find_encoder_by_type(connector, type); | ||
272 | if (!nv_encoder) { | ||
273 | NV_ERROR(dev, "Detected %d encoder on %s, " | ||
274 | "but no object!\n", type, | ||
275 | drm_get_connector_name(connector)); | ||
276 | return connector_status_disconnected; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | nouveau_connector_set_encoder(connector, nv_encoder); | ||
281 | return connector_status_connected; | ||
282 | } | ||
283 | |||
284 | nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); | ||
285 | if (!nv_encoder) | ||
286 | nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); | ||
287 | if (nv_encoder) { | ||
288 | struct drm_encoder *encoder = to_drm_encoder(nv_encoder); | ||
289 | struct drm_encoder_helper_funcs *helper = | ||
290 | encoder->helper_private; | ||
291 | |||
292 | if (helper->detect(encoder, connector) == | ||
293 | connector_status_connected) { | ||
294 | nouveau_connector_set_encoder(connector, nv_encoder); | ||
295 | return connector_status_connected; | ||
296 | } | ||
297 | |||
298 | } | ||
299 | |||
300 | return connector_status_disconnected; | ||
301 | } | ||
302 | |||
303 | static void | ||
304 | nouveau_connector_force(struct drm_connector *connector) | ||
305 | { | ||
306 | struct drm_device *dev = connector->dev; | ||
307 | struct nouveau_encoder *nv_encoder; | ||
308 | int type; | ||
309 | |||
310 | if (connector->connector_type == DRM_MODE_CONNECTOR_DVII) { | ||
311 | if (connector->force == DRM_FORCE_ON_DIGITAL) | ||
312 | type = OUTPUT_TMDS; | ||
313 | else | ||
314 | type = OUTPUT_ANALOG; | ||
315 | } else | ||
316 | type = OUTPUT_ANY; | ||
317 | |||
318 | nv_encoder = find_encoder_by_type(connector, type); | ||
319 | if (!nv_encoder) { | ||
320 | NV_ERROR(dev, "can't find encoder to force %s on!\n", | ||
321 | drm_get_connector_name(connector)); | ||
322 | connector->status = connector_status_disconnected; | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | nouveau_connector_set_encoder(connector, nv_encoder); | ||
327 | } | ||
328 | |||
329 | static int | ||
330 | nouveau_connector_set_property(struct drm_connector *connector, | ||
331 | struct drm_property *property, uint64_t value) | ||
332 | { | ||
333 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | ||
334 | struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; | ||
335 | struct drm_device *dev = connector->dev; | ||
336 | int ret; | ||
337 | |||
338 | /* Scaling mode */ | ||
339 | if (property == dev->mode_config.scaling_mode_property) { | ||
340 | struct nouveau_crtc *nv_crtc = NULL; | ||
341 | bool modeset = false; | ||
342 | |||
343 | switch (value) { | ||
344 | case DRM_MODE_SCALE_NONE: | ||
345 | case DRM_MODE_SCALE_FULLSCREEN: | ||
346 | case DRM_MODE_SCALE_CENTER: | ||
347 | case DRM_MODE_SCALE_ASPECT: | ||
348 | break; | ||
349 | default: | ||
350 | return -EINVAL; | ||
351 | } | ||
352 | |||
353 | /* LVDS always needs gpu scaling */ | ||
354 | if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS && | ||
355 | value == DRM_MODE_SCALE_NONE) | ||
356 | return -EINVAL; | ||
357 | |||
358 | /* Changing between GPU and panel scaling requires a full | ||
359 | * modeset | ||
360 | */ | ||
361 | if ((nv_connector->scaling_mode == DRM_MODE_SCALE_NONE) || | ||
362 | (value == DRM_MODE_SCALE_NONE)) | ||
363 | modeset = true; | ||
364 | nv_connector->scaling_mode = value; | ||
365 | |||
366 | if (connector->encoder && connector->encoder->crtc) | ||
367 | nv_crtc = nouveau_crtc(connector->encoder->crtc); | ||
368 | if (!nv_crtc) | ||
369 | return 0; | ||
370 | |||
371 | if (modeset || !nv_crtc->set_scale) { | ||
372 | ret = drm_crtc_helper_set_mode(&nv_crtc->base, | ||
373 | &nv_crtc->base.mode, | ||
374 | nv_crtc->base.x, | ||
375 | nv_crtc->base.y, NULL); | ||
376 | if (!ret) | ||
377 | return -EINVAL; | ||
378 | } else { | ||
379 | ret = nv_crtc->set_scale(nv_crtc, value, true); | ||
380 | if (ret) | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /* Dithering */ | ||
388 | if (property == dev->mode_config.dithering_mode_property) { | ||
389 | struct nouveau_crtc *nv_crtc = NULL; | ||
390 | |||
391 | if (value == DRM_MODE_DITHERING_ON) | ||
392 | nv_connector->use_dithering = true; | ||
393 | else | ||
394 | nv_connector->use_dithering = false; | ||
395 | |||
396 | if (connector->encoder && connector->encoder->crtc) | ||
397 | nv_crtc = nouveau_crtc(connector->encoder->crtc); | ||
398 | |||
399 | if (!nv_crtc || !nv_crtc->set_dither) | ||
400 | return 0; | ||
401 | |||
402 | return nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering, | ||
403 | true); | ||
404 | } | ||
405 | |||
406 | if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV) | ||
407 | return get_slave_funcs(nv_encoder)-> | ||
408 | set_property(to_drm_encoder(nv_encoder), connector, property, value); | ||
409 | |||
410 | return -EINVAL; | ||
411 | } | ||
412 | |||
413 | static struct drm_display_mode * | ||
414 | nouveau_connector_native_mode(struct nouveau_connector *connector) | ||
415 | { | ||
416 | struct drm_device *dev = connector->base.dev; | ||
417 | struct drm_display_mode *mode, *largest = NULL; | ||
418 | int high_w = 0, high_h = 0, high_v = 0; | ||
419 | |||
420 | /* Use preferred mode if there is one.. */ | ||
421 | list_for_each_entry(mode, &connector->base.probed_modes, head) { | ||
422 | if (mode->type & DRM_MODE_TYPE_PREFERRED) { | ||
423 | NV_DEBUG(dev, "native mode from preferred\n"); | ||
424 | return drm_mode_duplicate(dev, mode); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | /* Otherwise, take the resolution with the largest width, then height, | ||
429 | * then vertical refresh | ||
430 | */ | ||
431 | list_for_each_entry(mode, &connector->base.probed_modes, head) { | ||
432 | if (mode->hdisplay < high_w) | ||
433 | continue; | ||
434 | |||
435 | if (mode->hdisplay == high_w && mode->vdisplay < high_h) | ||
436 | continue; | ||
437 | |||
438 | if (mode->hdisplay == high_w && mode->vdisplay == high_h && | ||
439 | mode->vrefresh < high_v) | ||
440 | continue; | ||
441 | |||
442 | high_w = mode->hdisplay; | ||
443 | high_h = mode->vdisplay; | ||
444 | high_v = mode->vrefresh; | ||
445 | largest = mode; | ||
446 | } | ||
447 | |||
448 | NV_DEBUG(dev, "native mode from largest: %dx%d@%d\n", | ||
449 | high_w, high_h, high_v); | ||
450 | return largest ? drm_mode_duplicate(dev, largest) : NULL; | ||
451 | } | ||
452 | |||
453 | struct moderec { | ||
454 | int hdisplay; | ||
455 | int vdisplay; | ||
456 | }; | ||
457 | |||
458 | static struct moderec scaler_modes[] = { | ||
459 | { 1920, 1200 }, | ||
460 | { 1920, 1080 }, | ||
461 | { 1680, 1050 }, | ||
462 | { 1600, 1200 }, | ||
463 | { 1400, 1050 }, | ||
464 | { 1280, 1024 }, | ||
465 | { 1280, 960 }, | ||
466 | { 1152, 864 }, | ||
467 | { 1024, 768 }, | ||
468 | { 800, 600 }, | ||
469 | { 720, 400 }, | ||
470 | { 640, 480 }, | ||
471 | { 640, 400 }, | ||
472 | { 640, 350 }, | ||
473 | {} | ||
474 | }; | ||
475 | |||
476 | static int | ||
477 | nouveau_connector_scaler_modes_add(struct drm_connector *connector) | ||
478 | { | ||
479 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | ||
480 | struct drm_display_mode *native = nv_connector->native_mode, *m; | ||
481 | struct drm_device *dev = connector->dev; | ||
482 | struct moderec *mode = &scaler_modes[0]; | ||
483 | int modes = 0; | ||
484 | |||
485 | if (!native) | ||
486 | return 0; | ||
487 | |||
488 | while (mode->hdisplay) { | ||
489 | if (mode->hdisplay <= native->hdisplay && | ||
490 | mode->vdisplay <= native->vdisplay) { | ||
491 | m = drm_cvt_mode(dev, mode->hdisplay, mode->vdisplay, | ||
492 | drm_mode_vrefresh(native), false, | ||
493 | false, false); | ||
494 | if (!m) | ||
495 | continue; | ||
496 | |||
497 | m->type |= DRM_MODE_TYPE_DRIVER; | ||
498 | |||
499 | drm_mode_probed_add(connector, m); | ||
500 | modes++; | ||
501 | } | ||
502 | |||
503 | mode++; | ||
504 | } | ||
505 | |||
506 | return modes; | ||
507 | } | ||
508 | |||
509 | static int | ||
510 | nouveau_connector_get_modes(struct drm_connector *connector) | ||
511 | { | ||
512 | struct drm_device *dev = connector->dev; | ||
513 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | ||
514 | struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; | ||
515 | int ret = 0; | ||
516 | |||
517 | /* If we're not LVDS, destroy the previous native mode, the attached | ||
518 | * monitor could have changed. | ||
519 | */ | ||
520 | if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && | ||
521 | nv_connector->native_mode) { | ||
522 | drm_mode_destroy(dev, nv_connector->native_mode); | ||
523 | nv_connector->native_mode = NULL; | ||
524 | } | ||
525 | |||
526 | if (nv_connector->edid) | ||
527 | ret = drm_add_edid_modes(connector, nv_connector->edid); | ||
528 | |||
529 | /* Find the native mode if this is a digital panel, if we didn't | ||
530 | * find any modes through DDC previously add the native mode to | ||
531 | * the list of modes. | ||
532 | */ | ||
533 | if (!nv_connector->native_mode) | ||
534 | nv_connector->native_mode = | ||
535 | nouveau_connector_native_mode(nv_connector); | ||
536 | if (ret == 0 && nv_connector->native_mode) { | ||
537 | struct drm_display_mode *mode; | ||
538 | |||
539 | mode = drm_mode_duplicate(dev, nv_connector->native_mode); | ||
540 | drm_mode_probed_add(connector, mode); | ||
541 | ret = 1; | ||
542 | } | ||
543 | |||
544 | if (nv_encoder->dcb->type == OUTPUT_TV) | ||
545 | ret = get_slave_funcs(nv_encoder)-> | ||
546 | get_modes(to_drm_encoder(nv_encoder), connector); | ||
547 | |||
548 | if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) | ||
549 | ret += nouveau_connector_scaler_modes_add(connector); | ||
550 | |||
551 | return ret; | ||
552 | } | ||
553 | |||
554 | static int | ||
555 | nouveau_connector_mode_valid(struct drm_connector *connector, | ||
556 | struct drm_display_mode *mode) | ||
557 | { | ||
558 | struct drm_nouveau_private *dev_priv = connector->dev->dev_private; | ||
559 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | ||
560 | struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; | ||
561 | unsigned min_clock = 25000, max_clock = min_clock; | ||
562 | unsigned clock = mode->clock; | ||
563 | |||
564 | switch (nv_encoder->dcb->type) { | ||
565 | case OUTPUT_LVDS: | ||
566 | BUG_ON(!nv_connector->native_mode); | ||
567 | if (mode->hdisplay > nv_connector->native_mode->hdisplay || | ||
568 | mode->vdisplay > nv_connector->native_mode->vdisplay) | ||
569 | return MODE_PANEL; | ||
570 | |||
571 | min_clock = 0; | ||
572 | max_clock = 400000; | ||
573 | break; | ||
574 | case OUTPUT_TMDS: | ||
575 | if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) || | ||
576 | (dev_priv->card_type < NV_50 && | ||
577 | !nv_encoder->dcb->duallink_possible)) | ||
578 | max_clock = 165000; | ||
579 | else | ||
580 | max_clock = 330000; | ||
581 | break; | ||
582 | case OUTPUT_ANALOG: | ||
583 | max_clock = nv_encoder->dcb->crtconf.maxfreq; | ||
584 | if (!max_clock) | ||
585 | max_clock = 350000; | ||
586 | break; | ||
587 | case OUTPUT_TV: | ||
588 | return get_slave_funcs(nv_encoder)-> | ||
589 | mode_valid(to_drm_encoder(nv_encoder), mode); | ||
590 | case OUTPUT_DP: | ||
591 | if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7) | ||
592 | max_clock = nv_encoder->dp.link_nr * 270000; | ||
593 | else | ||
594 | max_clock = nv_encoder->dp.link_nr * 162000; | ||
595 | |||
596 | clock *= 3; | ||
597 | break; | ||
598 | } | ||
599 | |||
600 | if (clock < min_clock) | ||
601 | return MODE_CLOCK_LOW; | ||
602 | |||
603 | if (clock > max_clock) | ||
604 | return MODE_CLOCK_HIGH; | ||
605 | |||
606 | return MODE_OK; | ||
607 | } | ||
608 | |||
609 | static struct drm_encoder * | ||
610 | nouveau_connector_best_encoder(struct drm_connector *connector) | ||
611 | { | ||
612 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | ||
613 | |||
614 | if (nv_connector->detected_encoder) | ||
615 | return to_drm_encoder(nv_connector->detected_encoder); | ||
616 | |||
617 | return NULL; | ||
618 | } | ||
619 | |||
620 | static const struct drm_connector_helper_funcs | ||
621 | nouveau_connector_helper_funcs = { | ||
622 | .get_modes = nouveau_connector_get_modes, | ||
623 | .mode_valid = nouveau_connector_mode_valid, | ||
624 | .best_encoder = nouveau_connector_best_encoder, | ||
625 | }; | ||
626 | |||
627 | static const struct drm_connector_funcs | ||
628 | nouveau_connector_funcs = { | ||
629 | .dpms = drm_helper_connector_dpms, | ||
630 | .save = NULL, | ||
631 | .restore = NULL, | ||
632 | .detect = nouveau_connector_detect, | ||
633 | .destroy = nouveau_connector_destroy, | ||
634 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
635 | .set_property = nouveau_connector_set_property, | ||
636 | .force = nouveau_connector_force | ||
637 | }; | ||
638 | |||
639 | static int | ||
640 | nouveau_connector_create_lvds(struct drm_device *dev, | ||
641 | struct drm_connector *connector) | ||
642 | { | ||
643 | struct nouveau_connector *nv_connector = nouveau_connector(connector); | ||
644 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
645 | struct nouveau_i2c_chan *i2c = NULL; | ||
646 | struct nouveau_encoder *nv_encoder; | ||
647 | struct drm_display_mode native, *mode, *temp; | ||
648 | bool dummy, if_is_24bit = false; | ||
649 | int ret, flags; | ||
650 | |||
651 | nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); | ||
652 | if (!nv_encoder) | ||
653 | return -ENODEV; | ||
654 | |||
655 | ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &if_is_24bit); | ||
656 | if (ret) { | ||
657 | NV_ERROR(dev, "Error parsing LVDS table, disabling LVDS\n"); | ||
658 | return ret; | ||
659 | } | ||
660 | nv_connector->use_dithering = !if_is_24bit; | ||
661 | |||
662 | /* Firstly try getting EDID over DDC, if allowed and I2C channel | ||
663 | * is available. | ||
664 | */ | ||
665 | if (!dev_priv->VBIOS.pub.fp_no_ddc && nv_encoder->dcb->i2c_index < 0xf) | ||
666 | i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); | ||
667 | |||
668 | if (i2c) { | ||
669 | nouveau_connector_ddc_prepare(connector, &flags); | ||
670 | nv_connector->edid = drm_get_edid(connector, &i2c->adapter); | ||
671 | nouveau_connector_ddc_finish(connector, flags); | ||
672 | } | ||
673 | |||
674 | /* If no EDID found above, and the VBIOS indicates a hardcoded | ||
675 | * modeline is avalilable for the panel, set it as the panel's | ||
676 | * native mode and exit. | ||
677 | */ | ||
678 | if (!nv_connector->edid && nouveau_bios_fp_mode(dev, &native) && | ||
679 | (nv_encoder->dcb->lvdsconf.use_straps_for_mode || | ||
680 | dev_priv->VBIOS.pub.fp_no_ddc)) { | ||
681 | nv_connector->native_mode = drm_mode_duplicate(dev, &native); | ||
682 | goto out; | ||
683 | } | ||
684 | |||
685 | /* Still nothing, some VBIOS images have a hardcoded EDID block | ||
686 | * stored for the panel stored in them. | ||
687 | */ | ||
688 | if (!nv_connector->edid && !nv_connector->native_mode && | ||
689 | !dev_priv->VBIOS.pub.fp_no_ddc) { | ||
690 | nv_connector->edid = | ||
691 | (struct edid *)nouveau_bios_embedded_edid(dev); | ||
692 | } | ||
693 | |||
694 | if (!nv_connector->edid) | ||
695 | goto out; | ||
696 | |||
697 | /* We didn't find/use a panel mode from the VBIOS, so parse the EDID | ||
698 | * block and look for the preferred mode there. | ||
699 | */ | ||
700 | ret = drm_add_edid_modes(connector, nv_connector->edid); | ||
701 | if (ret == 0) | ||
702 | goto out; | ||
703 | nv_connector->detected_encoder = nv_encoder; | ||
704 | nv_connector->native_mode = nouveau_connector_native_mode(nv_connector); | ||
705 | list_for_each_entry_safe(mode, temp, &connector->probed_modes, head) | ||
706 | drm_mode_remove(connector, mode); | ||
707 | |||
708 | out: | ||
709 | if (!nv_connector->native_mode) { | ||
710 | NV_ERROR(dev, "LVDS present in DCB table, but couldn't " | ||
711 | "determine its native mode. Disabling.\n"); | ||
712 | return -ENODEV; | ||
713 | } | ||
714 | |||
715 | drm_mode_connector_update_edid_property(connector, nv_connector->edid); | ||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | int | ||
720 | nouveau_connector_create(struct drm_device *dev, int index, int type) | ||
721 | { | ||
722 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
723 | struct nouveau_connector *nv_connector = NULL; | ||
724 | struct drm_connector *connector; | ||
725 | struct drm_encoder *encoder; | ||
726 | int ret; | ||
727 | |||
728 | NV_DEBUG(dev, "\n"); | ||
729 | |||
730 | nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL); | ||
731 | if (!nv_connector) | ||
732 | return -ENOMEM; | ||
733 | nv_connector->dcb = nouveau_bios_connector_entry(dev, index); | ||
734 | connector = &nv_connector->base; | ||
735 | |||
736 | switch (type) { | ||
737 | case DRM_MODE_CONNECTOR_VGA: | ||
738 | NV_INFO(dev, "Detected a VGA connector\n"); | ||
739 | break; | ||
740 | case DRM_MODE_CONNECTOR_DVID: | ||
741 | NV_INFO(dev, "Detected a DVI-D connector\n"); | ||
742 | break; | ||
743 | case DRM_MODE_CONNECTOR_DVII: | ||
744 | NV_INFO(dev, "Detected a DVI-I connector\n"); | ||
745 | break; | ||
746 | case DRM_MODE_CONNECTOR_LVDS: | ||
747 | NV_INFO(dev, "Detected a LVDS connector\n"); | ||
748 | break; | ||
749 | case DRM_MODE_CONNECTOR_TV: | ||
750 | NV_INFO(dev, "Detected a TV connector\n"); | ||
751 | break; | ||
752 | case DRM_MODE_CONNECTOR_DisplayPort: | ||
753 | NV_INFO(dev, "Detected a DisplayPort connector\n"); | ||
754 | break; | ||
755 | default: | ||
756 | NV_ERROR(dev, "Unknown connector, this is not good.\n"); | ||
757 | break; | ||
758 | } | ||
759 | |||
760 | /* defaults, will get overridden in detect() */ | ||
761 | connector->interlace_allowed = false; | ||
762 | connector->doublescan_allowed = false; | ||
763 | |||
764 | drm_connector_init(dev, connector, &nouveau_connector_funcs, type); | ||
765 | drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); | ||
766 | |||
767 | /* Init DVI-I specific properties */ | ||
768 | if (type == DRM_MODE_CONNECTOR_DVII) { | ||
769 | drm_mode_create_dvi_i_properties(dev); | ||
770 | drm_connector_attach_property(connector, dev->mode_config.dvi_i_subconnector_property, 0); | ||
771 | drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0); | ||
772 | } | ||
773 | |||
774 | if (type != DRM_MODE_CONNECTOR_LVDS) | ||
775 | nv_connector->use_dithering = false; | ||
776 | |||
777 | if (type == DRM_MODE_CONNECTOR_DVID || | ||
778 | type == DRM_MODE_CONNECTOR_DVII || | ||
779 | type == DRM_MODE_CONNECTOR_LVDS || | ||
780 | type == DRM_MODE_CONNECTOR_DisplayPort) { | ||
781 | nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; | ||
782 | |||
783 | drm_connector_attach_property(connector, dev->mode_config.scaling_mode_property, | ||
784 | nv_connector->scaling_mode); | ||
785 | drm_connector_attach_property(connector, dev->mode_config.dithering_mode_property, | ||
786 | nv_connector->use_dithering ? DRM_MODE_DITHERING_ON | ||
787 | : DRM_MODE_DITHERING_OFF); | ||
788 | |||
789 | } else { | ||
790 | nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; | ||
791 | |||
792 | if (type == DRM_MODE_CONNECTOR_VGA && | ||
793 | dev_priv->card_type >= NV_50) { | ||
794 | drm_connector_attach_property(connector, | ||
795 | dev->mode_config.scaling_mode_property, | ||
796 | nv_connector->scaling_mode); | ||
797 | } | ||
798 | } | ||
799 | |||
800 | /* attach encoders */ | ||
801 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
802 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
803 | |||
804 | if (nv_encoder->dcb->connector != index) | ||
805 | continue; | ||
806 | |||
807 | if (get_slave_funcs(nv_encoder)) | ||
808 | get_slave_funcs(nv_encoder)->create_resources(encoder, connector); | ||
809 | |||
810 | drm_mode_connector_attach_encoder(connector, encoder); | ||
811 | } | ||
812 | |||
813 | drm_sysfs_connector_add(connector); | ||
814 | |||
815 | if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) { | ||
816 | ret = nouveau_connector_create_lvds(dev, connector); | ||
817 | if (ret) { | ||
818 | connector->funcs->destroy(connector); | ||
819 | return ret; | ||
820 | } | ||
821 | } | ||
822 | |||
823 | return 0; | ||
824 | } | ||