aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2009-10-15 16:16:35 -0400
committerDave Airlie <airlied@redhat.com>2009-10-15 18:46:52 -0400
commit0294cf4f7f895ddcf284b1ce7cf27a2c9d7106f7 (patch)
tree7c69f11e946519457c08e8106c05df1a850b77fd /drivers
parent1b4d7d75ccff38008ccd40f8e2d74e33a087caaa (diff)
drm/radeon/kms: fix connector edid handling
Based partly on a patch from Christian Koenig <deathsimple@vodafone.de> - fix several memory leaks in radeon_connector->edid handling - store edid in radeon_connector->edid in detect() or get_modes() - switch hdmi detect code to use radeon_connector->edid - add support for oem boards multiple connectors that share a ddc line. - short circuit lvds_detect() if have a stored edid Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c75
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h2
4 files changed, 73 insertions, 32 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 729207a1e83e..5b6067aa08bd 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -400,7 +400,6 @@ static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connec
400 struct radeon_connector *radeon_connector = to_radeon_connector(connector); 400 struct radeon_connector *radeon_connector = to_radeon_connector(connector);
401 struct drm_encoder *encoder = radeon_best_single_encoder(connector); 401 struct drm_encoder *encoder = radeon_best_single_encoder(connector);
402 enum drm_connector_status ret = connector_status_disconnected; 402 enum drm_connector_status ret = connector_status_disconnected;
403 bool dret;
404 403
405 if (encoder) { 404 if (encoder) {
406 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); 405 struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
@@ -413,12 +412,17 @@ static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connec
413 } 412 }
414 413
415 /* check for edid as well */ 414 /* check for edid as well */
416 if (radeon_connector->ddc_bus) { 415 if (radeon_connector->edid)
417 radeon_i2c_do_lock(radeon_connector, 1); 416 ret = connector_status_connected;
418 dret = radeon_ddc_probe(radeon_connector); 417 else {
419 radeon_i2c_do_lock(radeon_connector, 0); 418 if (radeon_connector->ddc_bus) {
420 if (dret) 419 radeon_i2c_do_lock(radeon_connector, 1);
421 ret = connector_status_connected; 420 radeon_connector->edid = drm_get_edid(&radeon_connector->base,
421 &radeon_connector->ddc_bus->adapter);
422 radeon_i2c_do_lock(radeon_connector, 0);
423 if (radeon_connector->edid)
424 ret = connector_status_connected;
425 }
422 } 426 }
423 /* check acpi lid status ??? */ 427 /* check acpi lid status ??? */
424 428
@@ -432,6 +436,8 @@ static void radeon_connector_destroy(struct drm_connector *connector)
432 436
433 if (radeon_connector->ddc_bus) 437 if (radeon_connector->ddc_bus)
434 radeon_i2c_destroy(radeon_connector->ddc_bus); 438 radeon_i2c_destroy(radeon_connector->ddc_bus);
439 if (radeon_connector->edid)
440 kfree(radeon_connector->edid);
435 kfree(radeon_connector->con_priv); 441 kfree(radeon_connector->con_priv);
436 drm_sysfs_connector_remove(connector); 442 drm_sysfs_connector_remove(connector);
437 drm_connector_cleanup(connector); 443 drm_connector_cleanup(connector);
@@ -519,9 +525,32 @@ static enum drm_connector_status radeon_vga_detect(struct drm_connector *connect
519 radeon_i2c_do_lock(radeon_connector, 1); 525 radeon_i2c_do_lock(radeon_connector, 1);
520 dret = radeon_ddc_probe(radeon_connector); 526 dret = radeon_ddc_probe(radeon_connector);
521 radeon_i2c_do_lock(radeon_connector, 0); 527 radeon_i2c_do_lock(radeon_connector, 0);
522 if (dret) 528 if (dret) {
523 ret = connector_status_connected; 529 if (radeon_connector->edid) {
524 else { 530 kfree(radeon_connector->edid);
531 radeon_connector->edid = NULL;
532 }
533 radeon_i2c_do_lock(radeon_connector, 1);
534 radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
535 radeon_i2c_do_lock(radeon_connector, 0);
536
537 if (!radeon_connector->edid) {
538 DRM_ERROR("DDC responded but not EDID found for %s\n",
539 drm_get_connector_name(connector));
540 } else {
541 radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
542
543 /* some oems have boards with separate digital and analog connectors
544 * with a shared ddc line (often vga + hdmi)
545 */
546 if (radeon_connector->use_digital && radeon_connector->shared_ddc) {
547 kfree(radeon_connector->edid);
548 radeon_connector->edid = NULL;
549 ret = connector_status_disconnected;
550 } else
551 ret = connector_status_connected;
552 }
553 } else {
525 if (radeon_connector->dac_load_detect) { 554 if (radeon_connector->dac_load_detect) {
526 encoder_funcs = encoder->helper_private; 555 encoder_funcs = encoder->helper_private;
527 ret = encoder_funcs->detect(encoder, connector); 556 ret = encoder_funcs->detect(encoder, connector);
@@ -649,6 +678,10 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
649 dret = radeon_ddc_probe(radeon_connector); 678 dret = radeon_ddc_probe(radeon_connector);
650 radeon_i2c_do_lock(radeon_connector, 0); 679 radeon_i2c_do_lock(radeon_connector, 0);
651 if (dret) { 680 if (dret) {
681 if (radeon_connector->edid) {
682 kfree(radeon_connector->edid);
683 radeon_connector->edid = NULL;
684 }
652 radeon_i2c_do_lock(radeon_connector, 1); 685 radeon_i2c_do_lock(radeon_connector, 1);
653 radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); 686 radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
654 radeon_i2c_do_lock(radeon_connector, 0); 687 radeon_i2c_do_lock(radeon_connector, 0);
@@ -659,10 +692,15 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
659 } else { 692 } else {
660 radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL); 693 radeon_connector->use_digital = !!(radeon_connector->edid->input & DRM_EDID_INPUT_DIGITAL);
661 694
662 /* if this isn't a digital monitor 695 /* some oems have boards with separate digital and analog connectors
663 then we need to make sure we don't have any 696 * with a shared ddc line (often vga + hdmi)
664 TV conflicts */ 697 */
665 ret = connector_status_connected; 698 if ((!radeon_connector->use_digital) && radeon_connector->shared_ddc) {
699 kfree(radeon_connector->edid);
700 radeon_connector->edid = NULL;
701 ret = connector_status_disconnected;
702 } else
703 ret = connector_status_connected;
666 } 704 }
667 } 705 }
668 706
@@ -787,6 +825,7 @@ radeon_add_atom_connector(struct drm_device *dev,
787 struct radeon_connector *radeon_connector; 825 struct radeon_connector *radeon_connector;
788 struct radeon_connector_atom_dig *radeon_dig_connector; 826 struct radeon_connector_atom_dig *radeon_dig_connector;
789 uint32_t subpixel_order = SubPixelNone; 827 uint32_t subpixel_order = SubPixelNone;
828 bool shared_ddc = false;
790 int ret; 829 int ret;
791 830
792 /* fixme - tv/cv/din */ 831 /* fixme - tv/cv/din */
@@ -800,6 +839,13 @@ radeon_add_atom_connector(struct drm_device *dev,
800 radeon_connector->devices |= supported_device; 839 radeon_connector->devices |= supported_device;
801 return; 840 return;
802 } 841 }
842 if (radeon_connector->ddc_bus && i2c_bus->valid) {
843 if (memcmp(&radeon_connector->ddc_bus->rec, i2c_bus,
844 sizeof(struct radeon_i2c_bus_rec)) == 0) {
845 radeon_connector->shared_ddc = true;
846 shared_ddc = true;
847 }
848 }
803 } 849 }
804 850
805 radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL); 851 radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
@@ -810,6 +856,7 @@ radeon_add_atom_connector(struct drm_device *dev,
810 856
811 radeon_connector->connector_id = connector_id; 857 radeon_connector->connector_id = connector_id;
812 radeon_connector->devices = supported_device; 858 radeon_connector->devices = supported_device;
859 radeon_connector->shared_ddc = shared_ddc;
813 switch (connector_type) { 860 switch (connector_type) {
814 case DRM_MODE_CONNECTOR_VGA: 861 case DRM_MODE_CONNECTOR_VGA:
815 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 862 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index a20bf43389b3..c85df4afcb7a 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -334,27 +334,19 @@ static bool radeon_setup_enc_conn(struct drm_device *dev)
334 334
335int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) 335int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
336{ 336{
337 struct edid *edid;
338 int ret = 0; 337 int ret = 0;
339 338
340 if (!radeon_connector->ddc_bus) 339 if (!radeon_connector->ddc_bus)
341 return -1; 340 return -1;
342 if (!radeon_connector->edid) { 341 if (!radeon_connector->edid) {
343 radeon_i2c_do_lock(radeon_connector, 1); 342 radeon_i2c_do_lock(radeon_connector, 1);
344 edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); 343 radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
345 radeon_i2c_do_lock(radeon_connector, 0); 344 radeon_i2c_do_lock(radeon_connector, 0);
346 } else 345 }
347 edid = radeon_connector->edid;
348 346
349 if (edid) { 347 if (radeon_connector->edid) {
350 /* update digital bits here */ 348 drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
351 if (edid->input & DRM_EDID_INPUT_DIGITAL) 349 ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
352 radeon_connector->use_digital = 1;
353 else
354 radeon_connector->use_digital = 0;
355 drm_mode_connector_update_edid_property(&radeon_connector->base, edid);
356 ret = drm_add_edid_modes(&radeon_connector->base, edid);
357 kfree(edid);
358 return ret; 350 return ret;
359 } 351 }
360 drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); 352 drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 6cdef27be99d..b70440e8d179 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -449,7 +449,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
449 case 1: 449 case 1:
450 args.v1.ucMisc = 0; 450 args.v1.ucMisc = 0;
451 args.v1.ucAction = action; 451 args.v1.ucAction = action;
452 if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) 452 if (drm_detect_hdmi_monitor(radeon_connector->edid))
453 args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 453 args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
454 args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 454 args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
455 if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { 455 if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
@@ -474,7 +474,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
474 if (dig->coherent_mode) 474 if (dig->coherent_mode)
475 args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; 475 args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
476 } 476 }
477 if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) 477 if (drm_detect_hdmi_monitor(radeon_connector->edid))
478 args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; 478 args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
479 args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); 479 args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
480 args.v2.ucTruncate = 0; 480 args.v2.ucTruncate = 0;
@@ -532,7 +532,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
532 switch (connector->connector_type) { 532 switch (connector->connector_type) {
533 case DRM_MODE_CONNECTOR_DVII: 533 case DRM_MODE_CONNECTOR_DVII:
534 case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ 534 case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
535 if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) 535 if (drm_detect_hdmi_monitor(radeon_connector->edid))
536 return ATOM_ENCODER_MODE_HDMI; 536 return ATOM_ENCODER_MODE_HDMI;
537 else if (radeon_connector->use_digital) 537 else if (radeon_connector->use_digital)
538 return ATOM_ENCODER_MODE_DVI; 538 return ATOM_ENCODER_MODE_DVI;
@@ -542,7 +542,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
542 case DRM_MODE_CONNECTOR_DVID: 542 case DRM_MODE_CONNECTOR_DVID:
543 case DRM_MODE_CONNECTOR_HDMIA: 543 case DRM_MODE_CONNECTOR_HDMIA:
544 default: 544 default:
545 if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) 545 if (drm_detect_hdmi_monitor(radeon_connector->edid))
546 return ATOM_ENCODER_MODE_HDMI; 546 return ATOM_ENCODER_MODE_HDMI;
547 else 547 else
548 return ATOM_ENCODER_MODE_DVI; 548 return ATOM_ENCODER_MODE_DVI;
@@ -554,7 +554,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
554 /*if (radeon_output->MonType == MT_DP) 554 /*if (radeon_output->MonType == MT_DP)
555 return ATOM_ENCODER_MODE_DP; 555 return ATOM_ENCODER_MODE_DP;
556 else*/ 556 else*/
557 if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr)) 557 if (drm_detect_hdmi_monitor(radeon_connector->edid))
558 return ATOM_ENCODER_MODE_HDMI; 558 return ATOM_ENCODER_MODE_HDMI;
559 else 559 else
560 return ATOM_ENCODER_MODE_DVI; 560 return ATOM_ENCODER_MODE_DVI;
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 3d2631be073c..b6868fbe7346 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -297,6 +297,8 @@ struct radeon_connector {
297 uint32_t connector_id; 297 uint32_t connector_id;
298 uint32_t devices; 298 uint32_t devices;
299 struct radeon_i2c_chan *ddc_bus; 299 struct radeon_i2c_chan *ddc_bus;
300 /* some systems have a an hdmi and vga port with a shared ddc line */
301 bool shared_ddc;
300 bool use_digital; 302 bool use_digital;
301 /* we need to mind the EDID between detect 303 /* we need to mind the EDID between detect
302 and get modes due to analog/digital/tvencoder */ 304 and get modes due to analog/digital/tvencoder */