blob: 5ee81b6a879964eb9ee9d586f751d8b7f6c6b658 [file] [log] [blame]
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001/*
2 * Copyright 2007-8 Advanced Micro Devices, Inc.
3 * Copyright 2008 Red Hat Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors: Dave Airlie
24 * Alex Deucher
25 */
26#include "drmP.h"
27#include "drm_edid.h"
28#include "drm_crtc_helper.h"
29#include "radeon_drm.h"
30#include "radeon.h"
Alex Deucher923f6842009-09-10 17:53:39 -040031#include "atom.h"
Jerome Glisse771fe6b2009-06-05 14:42:42 +020032
33extern void
34radeon_combios_connected_scratch_regs(struct drm_connector *connector,
35 struct drm_encoder *encoder,
36 bool connected);
37extern void
38radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
39 struct drm_encoder *encoder,
40 bool connected);
41
42static void
43radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status)
44{
45 struct drm_device *dev = connector->dev;
46 struct radeon_device *rdev = dev->dev_private;
47 struct drm_encoder *best_encoder = NULL;
48 struct drm_encoder *encoder = NULL;
49 struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
50 struct drm_mode_object *obj;
51 bool connected;
52 int i;
53
54 best_encoder = connector_funcs->best_encoder(connector);
55
56 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
57 if (connector->encoder_ids[i] == 0)
58 break;
59
60 obj = drm_mode_object_find(connector->dev,
61 connector->encoder_ids[i],
62 DRM_MODE_OBJECT_ENCODER);
63 if (!obj)
64 continue;
65
66 encoder = obj_to_encoder(obj);
67
68 if ((encoder == best_encoder) && (status == connector_status_connected))
69 connected = true;
70 else
71 connected = false;
72
73 if (rdev->is_atom_bios)
74 radeon_atombios_connected_scratch_regs(connector, encoder, connected);
75 else
76 radeon_combios_connected_scratch_regs(connector, encoder, connected);
77
78 }
79}
80
81struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
82{
83 int enc_id = connector->encoder_ids[0];
84 struct drm_mode_object *obj;
85 struct drm_encoder *encoder;
86
87 /* pick the encoder ids */
88 if (enc_id) {
89 obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER);
90 if (!obj)
91 return NULL;
92 encoder = obj_to_encoder(obj);
93 return encoder;
94 }
95 return NULL;
96}
97
Dave Airlie4ce001a2009-08-13 16:32:14 +100098
99/*
100 * radeon_connector_analog_encoder_conflict_solve
101 * - search for other connectors sharing this encoder
102 * if priority is true, then set them disconnected if this is connected
103 * if priority is false, set us disconnected if they are connected
104 */
105static enum drm_connector_status
106radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,
107 struct drm_encoder *encoder,
108 enum drm_connector_status current_status,
109 bool priority)
110{
111 struct drm_device *dev = connector->dev;
112 struct drm_connector *conflict;
113 int i;
114
115 list_for_each_entry(conflict, &dev->mode_config.connector_list, head) {
116 if (conflict == connector)
117 continue;
118
119 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
120 if (conflict->encoder_ids[i] == 0)
121 break;
122
123 /* if the IDs match */
124 if (conflict->encoder_ids[i] == encoder->base.id) {
125 if (conflict->status != connector_status_connected)
126 continue;
127
128 if (priority == true) {
129 DRM_INFO("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
130 DRM_INFO("in favor of %s\n", drm_get_connector_name(connector));
131 conflict->status = connector_status_disconnected;
132 radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
133 } else {
134 DRM_INFO("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector));
135 DRM_INFO("in favor of %s\n", drm_get_connector_name(conflict));
136 current_status = connector_status_disconnected;
137 }
138 break;
139 }
140 }
141 }
142 return current_status;
143
144}
145
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200146static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder)
147{
148 struct drm_device *dev = encoder->dev;
149 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
150 struct drm_display_mode *mode = NULL;
151 struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
152
153 if (native_mode->panel_xres != 0 &&
154 native_mode->panel_yres != 0 &&
155 native_mode->dotclock != 0) {
156 mode = drm_mode_create(dev);
157
158 mode->hdisplay = native_mode->panel_xres;
159 mode->vdisplay = native_mode->panel_yres;
160
161 mode->htotal = mode->hdisplay + native_mode->hblank;
162 mode->hsync_start = mode->hdisplay + native_mode->hoverplus;
163 mode->hsync_end = mode->hsync_start + native_mode->hsync_width;
164 mode->vtotal = mode->vdisplay + native_mode->vblank;
165 mode->vsync_start = mode->vdisplay + native_mode->voverplus;
166 mode->vsync_end = mode->vsync_start + native_mode->vsync_width;
167 mode->clock = native_mode->dotclock;
168 mode->flags = 0;
169
170 mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
171 drm_mode_set_name(mode);
172
173 DRM_DEBUG("Adding native panel mode %s\n", mode->name);
174 }
175 return mode;
176}
177
Alex Deucher923f6842009-09-10 17:53:39 -0400178static void radeon_add_common_modes(struct drm_encoder *encoder, struct drm_connector *connector)
179{
180 struct drm_device *dev = encoder->dev;
181 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
182 struct drm_display_mode *mode = NULL;
183 struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
184 int i;
185 struct mode_size {
186 int w;
187 int h;
188 } common_modes[17] = {
189 { 640, 480},
190 { 720, 480},
191 { 800, 600},
192 { 848, 480},
193 {1024, 768},
194 {1152, 768},
195 {1280, 720},
196 {1280, 800},
197 {1280, 854},
198 {1280, 960},
199 {1280, 1024},
200 {1440, 900},
201 {1400, 1050},
202 {1680, 1050},
203 {1600, 1200},
204 {1920, 1080},
205 {1920, 1200}
206 };
207
208 for (i = 0; i < 17; i++) {
209 if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
Michel Dänzerfb1fbf82009-09-15 17:09:28 +0200210 if (common_modes[i].w > native_mode->panel_xres ||
211 common_modes[i].h > native_mode->panel_yres ||
212 (common_modes[i].w == native_mode->panel_xres &&
213 common_modes[i].h == native_mode->panel_yres))
Alex Deucher923f6842009-09-10 17:53:39 -0400214 continue;
215 }
216 if (common_modes[i].w < 320 || common_modes[i].h < 200)
217 continue;
218
219 mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false);
220 drm_mode_probed_add(connector, mode);
221 }
222}
223
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200224int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
225 uint64_t val)
226{
227 return 0;
228}
229
Michel Dänzer8dfaa8a2009-09-15 17:09:27 +0200230static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder,
231 struct drm_connector *connector)
232{
233 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
234 struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
235
236 /* Try to get native mode details from EDID if necessary */
237 if (!native_mode->dotclock) {
238 struct drm_display_mode *t, *mode;
239
240 list_for_each_entry_safe(mode, t, &connector->probed_modes, head) {
241 if (mode->hdisplay == native_mode->panel_xres &&
242 mode->vdisplay == native_mode->panel_yres) {
243 native_mode->hblank = mode->htotal - mode->hdisplay;
244 native_mode->hoverplus = mode->hsync_start - mode->hdisplay;
245 native_mode->hsync_width = mode->hsync_end - mode->hsync_start;
246 native_mode->vblank = mode->vtotal - mode->vdisplay;
247 native_mode->voverplus = mode->vsync_start - mode->vdisplay;
248 native_mode->vsync_width = mode->vsync_end - mode->vsync_start;
249 native_mode->dotclock = mode->clock;
250 DRM_INFO("Determined LVDS native mode details from EDID\n");
251 break;
252 }
253 }
254 }
255 if (!native_mode->dotclock) {
256 DRM_INFO("No LVDS native mode details, disabling RMX\n");
257 radeon_encoder->rmx_type = RMX_OFF;
258 }
259}
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200260
261static int radeon_lvds_get_modes(struct drm_connector *connector)
262{
263 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
264 struct drm_encoder *encoder;
265 int ret = 0;
266 struct drm_display_mode *mode;
267
268 if (radeon_connector->ddc_bus) {
269 ret = radeon_ddc_get_modes(radeon_connector);
270 if (ret > 0) {
Alex Deucher7747b712009-09-11 11:15:43 -0400271 encoder = radeon_best_single_encoder(connector);
Michel Dänzer8dfaa8a2009-09-15 17:09:27 +0200272 if (encoder) {
273 radeon_fixup_lvds_native_mode(encoder, connector);
Alex Deucher7747b712009-09-11 11:15:43 -0400274 /* add scaled modes */
275 radeon_add_common_modes(encoder, connector);
Michel Dänzer8dfaa8a2009-09-15 17:09:27 +0200276 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200277 return ret;
278 }
279 }
280
281 encoder = radeon_best_single_encoder(connector);
282 if (!encoder)
283 return 0;
284
285 /* we have no EDID modes */
286 mode = radeon_fp_native_mode(encoder);
287 if (mode) {
288 ret = 1;
289 drm_mode_probed_add(connector, mode);
Alex Deucher7747b712009-09-11 11:15:43 -0400290 /* add scaled modes */
291 radeon_add_common_modes(encoder, connector);
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200292 }
Alex Deucher923f6842009-09-10 17:53:39 -0400293
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200294 return ret;
295}
296
297static int radeon_lvds_mode_valid(struct drm_connector *connector,
298 struct drm_display_mode *mode)
299{
300 return MODE_OK;
301}
302
303static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector)
304{
305 enum drm_connector_status ret = connector_status_connected;
306 /* check acpi lid status ??? */
307 radeon_connector_update_scratch_regs(connector, ret);
308 return ret;
309}
310
311static void radeon_connector_destroy(struct drm_connector *connector)
312{
313 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
314
315 if (radeon_connector->ddc_bus)
316 radeon_i2c_destroy(radeon_connector->ddc_bus);
317 kfree(radeon_connector->con_priv);
318 drm_sysfs_connector_remove(connector);
319 drm_connector_cleanup(connector);
320 kfree(connector);
321}
322
323struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = {
324 .get_modes = radeon_lvds_get_modes,
325 .mode_valid = radeon_lvds_mode_valid,
326 .best_encoder = radeon_best_single_encoder,
327};
328
329struct drm_connector_funcs radeon_lvds_connector_funcs = {
330 .dpms = drm_helper_connector_dpms,
331 .detect = radeon_lvds_detect,
332 .fill_modes = drm_helper_probe_single_connector_modes,
333 .destroy = radeon_connector_destroy,
334 .set_property = radeon_connector_set_property,
335};
336
337static int radeon_vga_get_modes(struct drm_connector *connector)
338{
339 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
340 int ret;
341
342 ret = radeon_ddc_get_modes(radeon_connector);
343
344 return ret;
345}
346
347static int radeon_vga_mode_valid(struct drm_connector *connector,
348 struct drm_display_mode *mode)
349{
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200350 return MODE_OK;
351}
352
353static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector)
354{
355 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
356 struct drm_encoder *encoder;
357 struct drm_encoder_helper_funcs *encoder_funcs;
358 bool dret;
359 enum drm_connector_status ret = connector_status_disconnected;
360
Dave Airlie4ce001a2009-08-13 16:32:14 +1000361 encoder = radeon_best_single_encoder(connector);
362 if (!encoder)
363 ret = connector_status_disconnected;
364
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200365 radeon_i2c_do_lock(radeon_connector, 1);
366 dret = radeon_ddc_probe(radeon_connector);
367 radeon_i2c_do_lock(radeon_connector, 0);
368 if (dret)
369 ret = connector_status_connected;
370 else {
Dave Airlie4ce001a2009-08-13 16:32:14 +1000371 encoder_funcs = encoder->helper_private;
372 ret = encoder_funcs->detect(encoder, connector);
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200373 }
374
Dave Airlie4ce001a2009-08-13 16:32:14 +1000375 if (ret == connector_status_connected)
376 ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200377 radeon_connector_update_scratch_regs(connector, ret);
378 return ret;
379}
380
381struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = {
382 .get_modes = radeon_vga_get_modes,
383 .mode_valid = radeon_vga_mode_valid,
384 .best_encoder = radeon_best_single_encoder,
385};
386
387struct drm_connector_funcs radeon_vga_connector_funcs = {
388 .dpms = drm_helper_connector_dpms,
389 .detect = radeon_vga_detect,
390 .fill_modes = drm_helper_probe_single_connector_modes,
391 .destroy = radeon_connector_destroy,
392 .set_property = radeon_connector_set_property,
393};
394
Dave Airlie4ce001a2009-08-13 16:32:14 +1000395static int radeon_tv_get_modes(struct drm_connector *connector)
396{
397 struct drm_device *dev = connector->dev;
Alex Deucher923f6842009-09-10 17:53:39 -0400398 struct radeon_device *rdev = dev->dev_private;
Dave Airlie4ce001a2009-08-13 16:32:14 +1000399 struct drm_display_mode *tv_mode;
Alex Deucher923f6842009-09-10 17:53:39 -0400400 struct drm_encoder *encoder;
Dave Airlie4ce001a2009-08-13 16:32:14 +1000401
Alex Deucher923f6842009-09-10 17:53:39 -0400402 encoder = radeon_best_single_encoder(connector);
403 if (!encoder)
404 return 0;
Dave Airlie4ce001a2009-08-13 16:32:14 +1000405
Alex Deucher923f6842009-09-10 17:53:39 -0400406 /* avivo chips can scale any mode */
407 if (rdev->family >= CHIP_RS600)
408 /* add scaled modes */
409 radeon_add_common_modes(encoder, connector);
410 else {
411 /* only 800x600 is supported right now on pre-avivo chips */
412 tv_mode = drm_cvt_mode(dev, 800, 600, 60, false, false);
413 tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
414 drm_mode_probed_add(connector, tv_mode);
415 }
Dave Airlie4ce001a2009-08-13 16:32:14 +1000416 return 1;
417}
418
419static int radeon_tv_mode_valid(struct drm_connector *connector,
420 struct drm_display_mode *mode)
421{
422 return MODE_OK;
423}
424
425static enum drm_connector_status radeon_tv_detect(struct drm_connector *connector)
426{
427 struct drm_encoder *encoder;
428 struct drm_encoder_helper_funcs *encoder_funcs;
429 int ret;
430
431 encoder = radeon_best_single_encoder(connector);
432 if (!encoder)
433 ret = connector_status_disconnected;
434 else {
435 encoder_funcs = encoder->helper_private;
436 ret = encoder_funcs->detect(encoder, connector);
437 }
438 if (ret == connector_status_connected)
439 ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
440 radeon_connector_update_scratch_regs(connector, ret);
441 return ret;
442}
443
444struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
445 .get_modes = radeon_tv_get_modes,
446 .mode_valid = radeon_tv_mode_valid,
447 .best_encoder = radeon_best_single_encoder,
448};
449
450struct drm_connector_funcs radeon_tv_connector_funcs = {
451 .dpms = drm_helper_connector_dpms,
452 .detect = radeon_tv_detect,
453 .fill_modes = drm_helper_probe_single_connector_modes,
454 .destroy = radeon_connector_destroy,
455 .set_property = radeon_connector_set_property,
456};
457
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200458static int radeon_dvi_get_modes(struct drm_connector *connector)
459{
460 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
461 int ret;
462
463 ret = radeon_ddc_get_modes(radeon_connector);
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200464 return ret;
465}
466
Dave Airlie4ce001a2009-08-13 16:32:14 +1000467/*
468 * DVI is complicated
469 * Do a DDC probe, if DDC probe passes, get the full EDID so
470 * we can do analog/digital monitor detection at this point.
471 * If the monitor is an analog monitor or we got no DDC,
472 * we need to find the DAC encoder object for this connector.
473 * If we got no DDC, we do load detection on the DAC encoder object.
474 * If we got analog DDC or load detection passes on the DAC encoder
475 * we have to check if this analog encoder is shared with anyone else (TV)
476 * if its shared we have to set the other connector to disconnected.
477 */
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200478static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector)
479{
480 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
Dave Airlie4ce001a2009-08-13 16:32:14 +1000481 struct drm_encoder *encoder = NULL;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200482 struct drm_encoder_helper_funcs *encoder_funcs;
483 struct drm_mode_object *obj;
484 int i;
485 enum drm_connector_status ret = connector_status_disconnected;
486 bool dret;
487
488 radeon_i2c_do_lock(radeon_connector, 1);
489 dret = radeon_ddc_probe(radeon_connector);
490 radeon_i2c_do_lock(radeon_connector, 0);
Dave Airlie4ce001a2009-08-13 16:32:14 +1000491 if (dret) {
492 radeon_i2c_do_lock(radeon_connector, 1);
493 radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
494 radeon_i2c_do_lock(radeon_connector, 0);
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200495
Dave Airlie4ce001a2009-08-13 16:32:14 +1000496 if (!radeon_connector->edid) {
497 DRM_ERROR("DDC responded but not EDID found for %s\n",
498 drm_get_connector_name(connector));
499 } else {
500 radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200501
Dave Airlie4ce001a2009-08-13 16:32:14 +1000502 /* if this isn't a digital monitor
503 then we need to make sure we don't have any
504 TV conflicts */
505 ret = connector_status_connected;
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200506 }
507 }
508
Dave Airlie4ce001a2009-08-13 16:32:14 +1000509 if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
510 goto out;
511
512 /* find analog encoder */
513 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
514 if (connector->encoder_ids[i] == 0)
515 break;
516
517 obj = drm_mode_object_find(connector->dev,
518 connector->encoder_ids[i],
519 DRM_MODE_OBJECT_ENCODER);
520 if (!obj)
521 continue;
522
523 encoder = obj_to_encoder(obj);
524
525 encoder_funcs = encoder->helper_private;
526 if (encoder_funcs->detect) {
527 if (ret != connector_status_connected) {
528 ret = encoder_funcs->detect(encoder, connector);
529 if (ret == connector_status_connected) {
530 radeon_connector->use_digital = false;
531 }
532 }
533 break;
534 }
535 }
536
537 if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) &&
538 encoder) {
539 ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
540 }
541
542out:
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200543 /* updated in get modes as well since we need to know if it's analog or digital */
544 radeon_connector_update_scratch_regs(connector, ret);
545 return ret;
546}
547
548/* okay need to be smart in here about which encoder to pick */
549struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
550{
551 int enc_id = connector->encoder_ids[0];
552 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
553 struct drm_mode_object *obj;
554 struct drm_encoder *encoder;
555 int i;
556 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
557 if (connector->encoder_ids[i] == 0)
558 break;
559
560 obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER);
561 if (!obj)
562 continue;
563
564 encoder = obj_to_encoder(obj);
565
Dave Airlie4ce001a2009-08-13 16:32:14 +1000566 if (radeon_connector->use_digital == true) {
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200567 if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
568 return encoder;
569 } else {
570 if (encoder->encoder_type == DRM_MODE_ENCODER_DAC ||
571 encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
572 return encoder;
573 }
574 }
575
576 /* see if we have a default encoder TODO */
577
578 /* then check use digitial */
579 /* pick the first one */
580 if (enc_id) {
581 obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER);
582 if (!obj)
583 return NULL;
584 encoder = obj_to_encoder(obj);
585 return encoder;
586 }
587 return NULL;
588}
589
590struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
591 .get_modes = radeon_dvi_get_modes,
592 .mode_valid = radeon_vga_mode_valid,
593 .best_encoder = radeon_dvi_encoder,
594};
595
596struct drm_connector_funcs radeon_dvi_connector_funcs = {
597 .dpms = drm_helper_connector_dpms,
598 .detect = radeon_dvi_detect,
599 .fill_modes = drm_helper_probe_single_connector_modes,
600 .set_property = radeon_connector_set_property,
601 .destroy = radeon_connector_destroy,
602};
603
604void
605radeon_add_atom_connector(struct drm_device *dev,
606 uint32_t connector_id,
607 uint32_t supported_device,
608 int connector_type,
609 struct radeon_i2c_bus_rec *i2c_bus,
610 bool linkb,
611 uint32_t igp_lane_info)
612{
613 struct drm_connector *connector;
614 struct radeon_connector *radeon_connector;
615 struct radeon_connector_atom_dig *radeon_dig_connector;
616 uint32_t subpixel_order = SubPixelNone;
617
618 /* fixme - tv/cv/din */
Dave Airlie4ce001a2009-08-13 16:32:14 +1000619 if (connector_type == DRM_MODE_CONNECTOR_Unknown)
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200620 return;
621
622 /* see if we already added it */
623 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
624 radeon_connector = to_radeon_connector(connector);
625 if (radeon_connector->connector_id == connector_id) {
626 radeon_connector->devices |= supported_device;
627 return;
628 }
629 }
630
631 radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
632 if (!radeon_connector)
633 return;
634
635 connector = &radeon_connector->base;
636
637 radeon_connector->connector_id = connector_id;
638 radeon_connector->devices = supported_device;
639 switch (connector_type) {
640 case DRM_MODE_CONNECTOR_VGA:
641 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
642 drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
643 if (i2c_bus->valid) {
644 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
645 if (!radeon_connector->ddc_bus)
646 goto failed;
647 }
648 break;
649 case DRM_MODE_CONNECTOR_DVIA:
650 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
651 drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
652 if (i2c_bus->valid) {
653 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
654 if (!radeon_connector->ddc_bus)
655 goto failed;
656 }
657 break;
658 case DRM_MODE_CONNECTOR_DVII:
659 case DRM_MODE_CONNECTOR_DVID:
660 radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
661 if (!radeon_dig_connector)
662 goto failed;
663 radeon_dig_connector->linkb = linkb;
664 radeon_dig_connector->igp_lane_info = igp_lane_info;
665 radeon_connector->con_priv = radeon_dig_connector;
666 drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
667 drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
668 if (i2c_bus->valid) {
669 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
670 if (!radeon_connector->ddc_bus)
671 goto failed;
672 }
673 subpixel_order = SubPixelHorizontalRGB;
674 break;
675 case DRM_MODE_CONNECTOR_HDMIA:
676 case DRM_MODE_CONNECTOR_HDMIB:
677 radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
678 if (!radeon_dig_connector)
679 goto failed;
680 radeon_dig_connector->linkb = linkb;
681 radeon_dig_connector->igp_lane_info = igp_lane_info;
682 radeon_connector->con_priv = radeon_dig_connector;
683 drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
684 drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
685 if (i2c_bus->valid) {
686 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI");
687 if (!radeon_connector->ddc_bus)
688 goto failed;
689 }
690 subpixel_order = SubPixelHorizontalRGB;
691 break;
692 case DRM_MODE_CONNECTOR_DisplayPort:
693 radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
694 if (!radeon_dig_connector)
695 goto failed;
696 radeon_dig_connector->linkb = linkb;
697 radeon_dig_connector->igp_lane_info = igp_lane_info;
698 radeon_connector->con_priv = radeon_dig_connector;
699 drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
700 drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
701 if (i2c_bus->valid) {
702 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP");
703 if (!radeon_connector->ddc_bus)
704 goto failed;
705 }
706 subpixel_order = SubPixelHorizontalRGB;
707 break;
708 case DRM_MODE_CONNECTOR_SVIDEO:
709 case DRM_MODE_CONNECTOR_Composite:
710 case DRM_MODE_CONNECTOR_9PinDIN:
Dave Airlie4ce001a2009-08-13 16:32:14 +1000711 if (radeon_tv == 1) {
712 drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
713 drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
714 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200715 break;
716 case DRM_MODE_CONNECTOR_LVDS:
717 radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
718 if (!radeon_dig_connector)
719 goto failed;
720 radeon_dig_connector->linkb = linkb;
721 radeon_dig_connector->igp_lane_info = igp_lane_info;
722 radeon_connector->con_priv = radeon_dig_connector;
723 drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
724 drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
725 if (i2c_bus->valid) {
726 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
727 if (!radeon_connector->ddc_bus)
728 goto failed;
729 }
730 subpixel_order = SubPixelHorizontalRGB;
731 break;
732 }
733
734 connector->display_info.subpixel_order = subpixel_order;
735 drm_sysfs_connector_add(connector);
736 return;
737
738failed:
739 if (radeon_connector->ddc_bus)
740 radeon_i2c_destroy(radeon_connector->ddc_bus);
741 drm_connector_cleanup(connector);
742 kfree(connector);
743}
744
745void
746radeon_add_legacy_connector(struct drm_device *dev,
747 uint32_t connector_id,
748 uint32_t supported_device,
749 int connector_type,
750 struct radeon_i2c_bus_rec *i2c_bus)
751{
752 struct drm_connector *connector;
753 struct radeon_connector *radeon_connector;
754 uint32_t subpixel_order = SubPixelNone;
755
756 /* fixme - tv/cv/din */
Dave Airlie4ce001a2009-08-13 16:32:14 +1000757 if (connector_type == DRM_MODE_CONNECTOR_Unknown)
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200758 return;
759
760 /* see if we already added it */
761 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
762 radeon_connector = to_radeon_connector(connector);
763 if (radeon_connector->connector_id == connector_id) {
764 radeon_connector->devices |= supported_device;
765 return;
766 }
767 }
768
769 radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
770 if (!radeon_connector)
771 return;
772
773 connector = &radeon_connector->base;
774
775 radeon_connector->connector_id = connector_id;
776 radeon_connector->devices = supported_device;
777 switch (connector_type) {
778 case DRM_MODE_CONNECTOR_VGA:
779 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
780 drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
781 if (i2c_bus->valid) {
782 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
783 if (!radeon_connector->ddc_bus)
784 goto failed;
785 }
786 break;
787 case DRM_MODE_CONNECTOR_DVIA:
788 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
789 drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
790 if (i2c_bus->valid) {
791 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
792 if (!radeon_connector->ddc_bus)
793 goto failed;
794 }
795 break;
796 case DRM_MODE_CONNECTOR_DVII:
797 case DRM_MODE_CONNECTOR_DVID:
798 drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
799 drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
800 if (i2c_bus->valid) {
801 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
802 if (!radeon_connector->ddc_bus)
803 goto failed;
804 }
805 subpixel_order = SubPixelHorizontalRGB;
806 break;
807 case DRM_MODE_CONNECTOR_SVIDEO:
808 case DRM_MODE_CONNECTOR_Composite:
809 case DRM_MODE_CONNECTOR_9PinDIN:
Dave Airlie4ce001a2009-08-13 16:32:14 +1000810 if (radeon_tv == 1) {
811 drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
812 drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
813 }
Jerome Glisse771fe6b2009-06-05 14:42:42 +0200814 break;
815 case DRM_MODE_CONNECTOR_LVDS:
816 drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
817 drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
818 if (i2c_bus->valid) {
819 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
820 if (!radeon_connector->ddc_bus)
821 goto failed;
822 }
823 subpixel_order = SubPixelHorizontalRGB;
824 break;
825 }
826
827 connector->display_info.subpixel_order = subpixel_order;
828 drm_sysfs_connector_add(connector);
829 return;
830
831failed:
832 if (radeon_connector->ddc_bus)
833 radeon_i2c_destroy(radeon_connector->ddc_bus);
834 drm_connector_cleanup(connector);
835 kfree(connector);
836}