diff options
author | Alex Deucher <alexdeucher@gmail.com> | 2009-10-15 16:16:35 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-10-15 18:46:52 -0400 |
commit | 0294cf4f7f895ddcf284b1ce7cf27a2c9d7106f7 (patch) | |
tree | 7c69f11e946519457c08e8106c05df1a850b77fd /drivers/gpu/drm/radeon/radeon_connectors.c | |
parent | 1b4d7d75ccff38008ccd40f8e2d74e33a087caaa (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/gpu/drm/radeon/radeon_connectors.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_connectors.c | 75 |
1 files changed, 61 insertions, 14 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); |