aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_connectors.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2009-08-13 02:32:14 -0400
committerDave Airlie <airlied@redhat.com>2009-09-07 19:24:37 -0400
commit4ce001abafafe77e5dd943d1480fc9f87894e96f (patch)
tree4a22b42c58a80450992fcf5d7625b19fe045855b /drivers/gpu/drm/radeon/radeon_connectors.c
parent551ebd837c75fc75df81811a18b7136c39cab487 (diff)
drm/radeon/kms: add initial radeon tv-out support.
This ports the tv-out code from the DDX to KMS. adds a radeon.tv module option, radeon.tv=0 to disable tv Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_connectors.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c215
1 files changed, 178 insertions, 37 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 70ede6a52d4e..6a2b0296adff 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -94,6 +94,54 @@ struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
94 return NULL; 94 return NULL;
95} 95}
96 96
97
98/*
99 * radeon_connector_analog_encoder_conflict_solve
100 * - search for other connectors sharing this encoder
101 * if priority is true, then set them disconnected if this is connected
102 * if priority is false, set us disconnected if they are connected
103 */
104static enum drm_connector_status
105radeon_connector_analog_encoder_conflict_solve(struct drm_connector *connector,
106 struct drm_encoder *encoder,
107 enum drm_connector_status current_status,
108 bool priority)
109{
110 struct drm_device *dev = connector->dev;
111 struct drm_connector *conflict;
112 int i;
113
114 list_for_each_entry(conflict, &dev->mode_config.connector_list, head) {
115 if (conflict == connector)
116 continue;
117
118 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
119 if (conflict->encoder_ids[i] == 0)
120 break;
121
122 /* if the IDs match */
123 if (conflict->encoder_ids[i] == encoder->base.id) {
124 if (conflict->status != connector_status_connected)
125 continue;
126
127 if (priority == true) {
128 DRM_INFO("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
129 DRM_INFO("in favor of %s\n", drm_get_connector_name(connector));
130 conflict->status = connector_status_disconnected;
131 radeon_connector_update_scratch_regs(conflict, connector_status_disconnected);
132 } else {
133 DRM_INFO("2: conflicting encoders switching off %s\n", drm_get_connector_name(connector));
134 DRM_INFO("in favor of %s\n", drm_get_connector_name(conflict));
135 current_status = connector_status_disconnected;
136 }
137 break;
138 }
139 }
140 }
141 return current_status;
142
143}
144
97static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder) 145static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder)
98{ 146{
99 struct drm_device *dev = encoder->dev; 147 struct drm_device *dev = encoder->dev;
@@ -213,7 +261,6 @@ static int radeon_vga_get_modes(struct drm_connector *connector)
213static int radeon_vga_mode_valid(struct drm_connector *connector, 261static int radeon_vga_mode_valid(struct drm_connector *connector,
214 struct drm_display_mode *mode) 262 struct drm_display_mode *mode)
215{ 263{
216
217 return MODE_OK; 264 return MODE_OK;
218} 265}
219 266
@@ -225,22 +272,22 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect
225 bool dret; 272 bool dret;
226 enum drm_connector_status ret = connector_status_disconnected; 273 enum drm_connector_status ret = connector_status_disconnected;
227 274
275 encoder = radeon_best_single_encoder(connector);
276 if (!encoder)
277 ret = connector_status_disconnected;
278
228 radeon_i2c_do_lock(radeon_connector, 1); 279 radeon_i2c_do_lock(radeon_connector, 1);
229 dret = radeon_ddc_probe(radeon_connector); 280 dret = radeon_ddc_probe(radeon_connector);
230 radeon_i2c_do_lock(radeon_connector, 0); 281 radeon_i2c_do_lock(radeon_connector, 0);
231 if (dret) 282 if (dret)
232 ret = connector_status_connected; 283 ret = connector_status_connected;
233 else { 284 else {
234 /* if EDID fails to a load detect */ 285 encoder_funcs = encoder->helper_private;
235 encoder = radeon_best_single_encoder(connector); 286 ret = encoder_funcs->detect(encoder, connector);
236 if (!encoder)
237 ret = connector_status_disconnected;
238 else {
239 encoder_funcs = encoder->helper_private;
240 ret = encoder_funcs->detect(encoder, connector);
241 }
242 } 287 }
243 288
289 if (ret == connector_status_connected)
290 ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
244 radeon_connector_update_scratch_regs(connector, ret); 291 radeon_connector_update_scratch_regs(connector, ret);
245 return ret; 292 return ret;
246} 293}
@@ -259,21 +306,87 @@ struct drm_connector_funcs radeon_vga_connector_funcs = {
259 .set_property = radeon_connector_set_property, 306 .set_property = radeon_connector_set_property,
260}; 307};
261 308
309static struct drm_display_mode tv_fixed_mode = {
310 DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 38250, 800, 832,
311 912, 1024, 0, 600, 603, 607, 624, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC),
312};
313
314static int radeon_tv_get_modes(struct drm_connector *connector)
315{
316 struct drm_device *dev = connector->dev;
317 struct drm_display_mode *tv_mode;
318
319 tv_mode = drm_mode_duplicate(dev, &tv_fixed_mode);
320 tv_mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
321
322 drm_mode_probed_add(connector, tv_mode);
323
324 return 1;
325}
326
327static int radeon_tv_mode_valid(struct drm_connector *connector,
328 struct drm_display_mode *mode)
329{
330 return MODE_OK;
331}
332
333static enum drm_connector_status radeon_tv_detect(struct drm_connector *connector)
334{
335 struct drm_encoder *encoder;
336 struct drm_encoder_helper_funcs *encoder_funcs;
337 int ret;
338
339 encoder = radeon_best_single_encoder(connector);
340 if (!encoder)
341 ret = connector_status_disconnected;
342 else {
343 encoder_funcs = encoder->helper_private;
344 ret = encoder_funcs->detect(encoder, connector);
345 }
346 if (ret == connector_status_connected)
347 ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
348 radeon_connector_update_scratch_regs(connector, ret);
349 return ret;
350}
351
352struct drm_connector_helper_funcs radeon_tv_connector_helper_funcs = {
353 .get_modes = radeon_tv_get_modes,
354 .mode_valid = radeon_tv_mode_valid,
355 .best_encoder = radeon_best_single_encoder,
356};
357
358struct drm_connector_funcs radeon_tv_connector_funcs = {
359 .dpms = drm_helper_connector_dpms,
360 .detect = radeon_tv_detect,
361 .fill_modes = drm_helper_probe_single_connector_modes,
362 .destroy = radeon_connector_destroy,
363 .set_property = radeon_connector_set_property,
364};
365
262static int radeon_dvi_get_modes(struct drm_connector *connector) 366static int radeon_dvi_get_modes(struct drm_connector *connector)
263{ 367{
264 struct radeon_connector *radeon_connector = to_radeon_connector(connector); 368 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
265 int ret; 369 int ret;
266 370
267 ret = radeon_ddc_get_modes(radeon_connector); 371 ret = radeon_ddc_get_modes(radeon_connector);
268 /* reset scratch regs here since radeon_dvi_detect doesn't check digital bit */
269 radeon_connector_update_scratch_regs(connector, connector_status_connected);
270 return ret; 372 return ret;
271} 373}
272 374
375/*
376 * DVI is complicated
377 * Do a DDC probe, if DDC probe passes, get the full EDID so
378 * we can do analog/digital monitor detection at this point.
379 * If the monitor is an analog monitor or we got no DDC,
380 * we need to find the DAC encoder object for this connector.
381 * If we got no DDC, we do load detection on the DAC encoder object.
382 * If we got analog DDC or load detection passes on the DAC encoder
383 * we have to check if this analog encoder is shared with anyone else (TV)
384 * if its shared we have to set the other connector to disconnected.
385 */
273static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector) 386static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector)
274{ 387{
275 struct radeon_connector *radeon_connector = to_radeon_connector(connector); 388 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
276 struct drm_encoder *encoder; 389 struct drm_encoder *encoder = NULL;
277 struct drm_encoder_helper_funcs *encoder_funcs; 390 struct drm_encoder_helper_funcs *encoder_funcs;
278 struct drm_mode_object *obj; 391 struct drm_mode_object *obj;
279 int i; 392 int i;
@@ -283,32 +396,58 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
283 radeon_i2c_do_lock(radeon_connector, 1); 396 radeon_i2c_do_lock(radeon_connector, 1);
284 dret = radeon_ddc_probe(radeon_connector); 397 dret = radeon_ddc_probe(radeon_connector);
285 radeon_i2c_do_lock(radeon_connector, 0); 398 radeon_i2c_do_lock(radeon_connector, 0);
286 if (dret) 399 if (dret) {
287 ret = connector_status_connected; 400 radeon_i2c_do_lock(radeon_connector, 1);
288 else { 401 radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
289 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { 402 radeon_i2c_do_lock(radeon_connector, 0);
290 if (connector->encoder_ids[i] == 0) 403
291 break; 404 if (!radeon_connector->edid) {
405 DRM_ERROR("DDC responded but not EDID found for %s\n",
406 drm_get_connector_name(connector));
407 } else {
408 radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
409
410 /* if this isn't a digital monitor
411 then we need to make sure we don't have any
412 TV conflicts */
413 ret = connector_status_connected;
414 }
415 }
416
417 if ((ret == connector_status_connected) && (radeon_connector->use_digital == true))
418 goto out;
419
420 /* find analog encoder */
421 for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
422 if (connector->encoder_ids[i] == 0)
423 break;
292 424
293 obj = drm_mode_object_find(connector->dev, 425 obj = drm_mode_object_find(connector->dev,
294 connector->encoder_ids[i], 426 connector->encoder_ids[i],
295 DRM_MODE_OBJECT_ENCODER); 427 DRM_MODE_OBJECT_ENCODER);
296 if (!obj) 428 if (!obj)
297 continue; 429 continue;
298 430
299 encoder = obj_to_encoder(obj); 431 encoder = obj_to_encoder(obj);
300 432
301 encoder_funcs = encoder->helper_private; 433 encoder_funcs = encoder->helper_private;
302 if (encoder_funcs->detect) { 434 if (encoder_funcs->detect) {
435 if (ret != connector_status_connected) {
303 ret = encoder_funcs->detect(encoder, connector); 436 ret = encoder_funcs->detect(encoder, connector);
304 if (ret == connector_status_connected) { 437 if (ret == connector_status_connected) {
305 radeon_connector->use_digital = 0; 438 radeon_connector->use_digital = false;
306 break;
307 } 439 }
308 } 440 }
441 break;
309 } 442 }
310 } 443 }
311 444
445 if ((ret == connector_status_connected) && (radeon_connector->use_digital == false) &&
446 encoder) {
447 ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true);
448 }
449
450out:
312 /* updated in get modes as well since we need to know if it's analog or digital */ 451 /* updated in get modes as well since we need to know if it's analog or digital */
313 radeon_connector_update_scratch_regs(connector, ret); 452 radeon_connector_update_scratch_regs(connector, ret);
314 return ret; 453 return ret;
@@ -332,7 +471,7 @@ struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
332 471
333 encoder = obj_to_encoder(obj); 472 encoder = obj_to_encoder(obj);
334 473
335 if (radeon_connector->use_digital) { 474 if (radeon_connector->use_digital == true) {
336 if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) 475 if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
337 return encoder; 476 return encoder;
338 } else { 477 } else {
@@ -385,10 +524,7 @@ radeon_add_atom_connector(struct drm_device *dev,
385 uint32_t subpixel_order = SubPixelNone; 524 uint32_t subpixel_order = SubPixelNone;
386 525
387 /* fixme - tv/cv/din */ 526 /* fixme - tv/cv/din */
388 if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || 527 if (connector_type == DRM_MODE_CONNECTOR_Unknown)
389 (connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
390 (connector_type == DRM_MODE_CONNECTOR_Composite) ||
391 (connector_type == DRM_MODE_CONNECTOR_9PinDIN))
392 return; 528 return;
393 529
394 /* see if we already added it */ 530 /* see if we already added it */
@@ -480,6 +616,10 @@ radeon_add_atom_connector(struct drm_device *dev,
480 case DRM_MODE_CONNECTOR_SVIDEO: 616 case DRM_MODE_CONNECTOR_SVIDEO:
481 case DRM_MODE_CONNECTOR_Composite: 617 case DRM_MODE_CONNECTOR_Composite:
482 case DRM_MODE_CONNECTOR_9PinDIN: 618 case DRM_MODE_CONNECTOR_9PinDIN:
619 if (radeon_tv == 1) {
620 drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
621 drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
622 }
483 break; 623 break;
484 case DRM_MODE_CONNECTOR_LVDS: 624 case DRM_MODE_CONNECTOR_LVDS:
485 radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL); 625 radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
@@ -522,10 +662,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
522 uint32_t subpixel_order = SubPixelNone; 662 uint32_t subpixel_order = SubPixelNone;
523 663
524 /* fixme - tv/cv/din */ 664 /* fixme - tv/cv/din */
525 if ((connector_type == DRM_MODE_CONNECTOR_Unknown) || 665 if (connector_type == DRM_MODE_CONNECTOR_Unknown)
526 (connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
527 (connector_type == DRM_MODE_CONNECTOR_Composite) ||
528 (connector_type == DRM_MODE_CONNECTOR_9PinDIN))
529 return; 666 return;
530 667
531 /* see if we already added it */ 668 /* see if we already added it */
@@ -578,6 +715,10 @@ radeon_add_legacy_connector(struct drm_device *dev,
578 case DRM_MODE_CONNECTOR_SVIDEO: 715 case DRM_MODE_CONNECTOR_SVIDEO:
579 case DRM_MODE_CONNECTOR_Composite: 716 case DRM_MODE_CONNECTOR_Composite:
580 case DRM_MODE_CONNECTOR_9PinDIN: 717 case DRM_MODE_CONNECTOR_9PinDIN:
718 if (radeon_tv == 1) {
719 drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
720 drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
721 }
581 break; 722 break;
582 case DRM_MODE_CONNECTOR_LVDS: 723 case DRM_MODE_CONNECTOR_LVDS:
583 drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); 724 drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);