aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2014-09-02 15:04:00 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-09-03 06:37:00 -0400
commitbeb60608477ec4ae252ec16f9b4018c015b980cb (patch)
tree9f2e3b961bc43766817cb72c6baccf772e573b6a /drivers
parentd410b56d74bc706f414158cb0149e2a149ee1650 (diff)
drm/i915/dp: Cache EDID for a detection cycle
As we may query the edid multiple times following a detect, record the EDID found during output discovery and reuse it. This is a separate issue from caching the output EDID across detection cycles. v2: Implement connector->force() callback so that edid is associated with the connector for user overrides as well (Ville) Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c156
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
2 files changed, 90 insertions, 67 deletions
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 9421cb4badf9..0a684282991e 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -3758,9 +3758,9 @@ g4x_dp_detect(struct intel_dp *intel_dp)
3758} 3758}
3759 3759
3760static struct edid * 3760static struct edid *
3761intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) 3761intel_dp_get_edid(struct intel_dp *intel_dp)
3762{ 3762{
3763 struct intel_connector *intel_connector = to_intel_connector(connector); 3763 struct intel_connector *intel_connector = intel_dp->attached_connector;
3764 3764
3765 /* use cached edid if we have one */ 3765 /* use cached edid if we have one */
3766 if (intel_connector->edid) { 3766 if (intel_connector->edid) {
@@ -3769,27 +3769,55 @@ intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
3769 return NULL; 3769 return NULL;
3770 3770
3771 return drm_edid_duplicate(intel_connector->edid); 3771 return drm_edid_duplicate(intel_connector->edid);
3772 } 3772 } else
3773 return drm_get_edid(&intel_connector->base,
3774 &intel_dp->aux.ddc);
3775}
3773 3776
3774 return drm_get_edid(connector, adapter); 3777static void
3778intel_dp_set_edid(struct intel_dp *intel_dp)
3779{
3780 struct intel_connector *intel_connector = intel_dp->attached_connector;
3781 struct edid *edid;
3782
3783 edid = intel_dp_get_edid(intel_dp);
3784 intel_connector->detect_edid = edid;
3785
3786 if (intel_dp->force_audio != HDMI_AUDIO_AUTO)
3787 intel_dp->has_audio = intel_dp->force_audio == HDMI_AUDIO_ON;
3788 else
3789 intel_dp->has_audio = drm_detect_monitor_audio(edid);
3775} 3790}
3776 3791
3777static int 3792static void
3778intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *adapter) 3793intel_dp_unset_edid(struct intel_dp *intel_dp)
3779{ 3794{
3780 struct intel_connector *intel_connector = to_intel_connector(connector); 3795 struct intel_connector *intel_connector = intel_dp->attached_connector;
3781 3796
3782 /* use cached edid if we have one */ 3797 kfree(intel_connector->detect_edid);
3783 if (intel_connector->edid) { 3798 intel_connector->detect_edid = NULL;
3784 /* invalid edid */
3785 if (IS_ERR(intel_connector->edid))
3786 return 0;
3787 3799
3788 return intel_connector_update_modes(connector, 3800 intel_dp->has_audio = false;
3789 intel_connector->edid); 3801}
3790 }
3791 3802
3792 return intel_ddc_get_modes(connector, adapter); 3803static enum intel_display_power_domain
3804intel_dp_power_get(struct intel_dp *dp)
3805{
3806 struct intel_encoder *encoder = &dp_to_dig_port(dp)->base;
3807 enum intel_display_power_domain power_domain;
3808
3809 power_domain = intel_display_port_power_domain(encoder);
3810 intel_display_power_get(to_i915(encoder->base.dev), power_domain);
3811
3812 return power_domain;
3813}
3814
3815static void
3816intel_dp_power_put(struct intel_dp *dp,
3817 enum intel_display_power_domain power_domain)
3818{
3819 struct intel_encoder *encoder = &dp_to_dig_port(dp)->base;
3820 intel_display_power_put(to_i915(encoder->base.dev), power_domain);
3793} 3821}
3794 3822
3795static enum drm_connector_status 3823static enum drm_connector_status
@@ -3799,27 +3827,22 @@ intel_dp_detect(struct drm_connector *connector, bool force)
3799 struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); 3827 struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
3800 struct intel_encoder *intel_encoder = &intel_dig_port->base; 3828 struct intel_encoder *intel_encoder = &intel_dig_port->base;
3801 struct drm_device *dev = connector->dev; 3829 struct drm_device *dev = connector->dev;
3802 struct drm_i915_private *dev_priv = dev->dev_private;
3803 enum drm_connector_status status; 3830 enum drm_connector_status status;
3804 enum intel_display_power_domain power_domain; 3831 enum intel_display_power_domain power_domain;
3805 struct edid *edid = NULL;
3806 bool ret; 3832 bool ret;
3807 3833
3808 power_domain = intel_display_port_power_domain(intel_encoder);
3809 intel_display_power_get(dev_priv, power_domain);
3810
3811 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", 3834 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
3812 connector->base.id, connector->name); 3835 connector->base.id, connector->name);
3836 intel_dp_unset_edid(intel_dp);
3813 3837
3814 if (intel_dp->is_mst) { 3838 if (intel_dp->is_mst) {
3815 /* MST devices are disconnected from a monitor POV */ 3839 /* MST devices are disconnected from a monitor POV */
3816 if (intel_encoder->type != INTEL_OUTPUT_EDP) 3840 if (intel_encoder->type != INTEL_OUTPUT_EDP)
3817 intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; 3841 intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
3818 status = connector_status_disconnected; 3842 return connector_status_disconnected;
3819 goto out;
3820 } 3843 }
3821 3844
3822 intel_dp->has_audio = false; 3845 power_domain = intel_dp_power_get(intel_dp);
3823 3846
3824 /* Can't disconnect eDP, but you can close the lid... */ 3847 /* Can't disconnect eDP, but you can close the lid... */
3825 if (is_edp(intel_dp)) 3848 if (is_edp(intel_dp))
@@ -3843,82 +3866,78 @@ intel_dp_detect(struct drm_connector *connector, bool force)
3843 goto out; 3866 goto out;
3844 } 3867 }
3845 3868
3846 if (intel_dp->force_audio != HDMI_AUDIO_AUTO) { 3869 intel_dp_set_edid(intel_dp);
3847 intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON);
3848 } else {
3849 edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc);
3850 if (edid) {
3851 intel_dp->has_audio = drm_detect_monitor_audio(edid);
3852 kfree(edid);
3853 }
3854 }
3855 3870
3856 if (intel_encoder->type != INTEL_OUTPUT_EDP) 3871 if (intel_encoder->type != INTEL_OUTPUT_EDP)
3857 intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; 3872 intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
3858 status = connector_status_connected; 3873 status = connector_status_connected;
3859 3874
3860out: 3875out:
3861 intel_display_power_put(dev_priv, power_domain); 3876 intel_dp_power_put(intel_dp, power_domain);
3862 return status; 3877 return status;
3863} 3878}
3864 3879
3865static int intel_dp_get_modes(struct drm_connector *connector) 3880static void
3881intel_dp_force(struct drm_connector *connector)
3866{ 3882{
3867 struct intel_dp *intel_dp = intel_attached_dp(connector); 3883 struct intel_dp *intel_dp = intel_attached_dp(connector);
3868 struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); 3884 struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
3869 struct intel_encoder *intel_encoder = &intel_dig_port->base;
3870 struct intel_connector *intel_connector = to_intel_connector(connector);
3871 struct drm_device *dev = connector->dev;
3872 struct drm_i915_private *dev_priv = dev->dev_private;
3873 enum intel_display_power_domain power_domain; 3885 enum intel_display_power_domain power_domain;
3874 int ret;
3875 3886
3876 /* We should parse the EDID data and find out if it has an audio sink 3887 DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
3877 */ 3888 connector->base.id, connector->name);
3889 intel_dp_unset_edid(intel_dp);
3878 3890
3879 power_domain = intel_display_port_power_domain(intel_encoder); 3891 if (connector->status != connector_status_connected)
3880 intel_display_power_get(dev_priv, power_domain); 3892 return;
3881 3893
3882 ret = intel_dp_get_edid_modes(connector, &intel_dp->aux.ddc); 3894 power_domain = intel_dp_power_get(intel_dp);
3883 intel_display_power_put(dev_priv, power_domain); 3895
3884 if (ret) 3896 intel_dp_set_edid(intel_dp);
3885 return ret; 3897
3898 intel_dp_power_put(intel_dp, power_domain);
3899
3900 if (intel_encoder->type != INTEL_OUTPUT_EDP)
3901 intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
3902}
3903
3904static int intel_dp_get_modes(struct drm_connector *connector)
3905{
3906 struct intel_connector *intel_connector = to_intel_connector(connector);
3907 struct edid *edid;
3908
3909 edid = intel_connector->detect_edid;
3910 if (edid) {
3911 int ret = intel_connector_update_modes(connector, edid);
3912 if (ret)
3913 return ret;
3914 }
3886 3915
3887 /* if eDP has no EDID, fall back to fixed mode */ 3916 /* if eDP has no EDID, fall back to fixed mode */
3888 if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) { 3917 if (is_edp(intel_attached_dp(connector)) &&
3918 intel_connector->panel.fixed_mode) {
3889 struct drm_display_mode *mode; 3919 struct drm_display_mode *mode;
3890 mode = drm_mode_duplicate(dev, 3920
3921 mode = drm_mode_duplicate(connector->dev,
3891 intel_connector->panel.fixed_mode); 3922 intel_connector->panel.fixed_mode);
3892 if (mode) { 3923 if (mode) {
3893 drm_mode_probed_add(connector, mode); 3924 drm_mode_probed_add(connector, mode);
3894 return 1; 3925 return 1;
3895 } 3926 }
3896 } 3927 }
3928
3897 return 0; 3929 return 0;
3898} 3930}
3899 3931
3900static bool 3932static bool
3901intel_dp_detect_audio(struct drm_connector *connector) 3933intel_dp_detect_audio(struct drm_connector *connector)
3902{ 3934{
3903 struct intel_dp *intel_dp = intel_attached_dp(connector);
3904 struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
3905 struct intel_encoder *intel_encoder = &intel_dig_port->base;
3906 struct drm_device *dev = connector->dev;
3907 struct drm_i915_private *dev_priv = dev->dev_private;
3908 enum intel_display_power_domain power_domain;
3909 struct edid *edid;
3910 bool has_audio = false; 3935 bool has_audio = false;
3936 struct edid *edid;
3911 3937
3912 power_domain = intel_display_port_power_domain(intel_encoder); 3938 edid = to_intel_connector(connector)->detect_edid;
3913 intel_display_power_get(dev_priv, power_domain); 3939 if (edid)
3914
3915 edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc);
3916 if (edid) {
3917 has_audio = drm_detect_monitor_audio(edid); 3940 has_audio = drm_detect_monitor_audio(edid);
3918 kfree(edid);
3919 }
3920
3921 intel_display_power_put(dev_priv, power_domain);
3922 3941
3923 return has_audio; 3942 return has_audio;
3924} 3943}
@@ -4016,6 +4035,8 @@ intel_dp_connector_destroy(struct drm_connector *connector)
4016{ 4035{
4017 struct intel_connector *intel_connector = to_intel_connector(connector); 4036 struct intel_connector *intel_connector = to_intel_connector(connector);
4018 4037
4038 intel_dp_unset_edid(intel_attached_dp(connector));
4039
4019 if (!IS_ERR_OR_NULL(intel_connector->edid)) 4040 if (!IS_ERR_OR_NULL(intel_connector->edid))
4020 kfree(intel_connector->edid); 4041 kfree(intel_connector->edid);
4021 4042
@@ -4068,6 +4089,7 @@ static void intel_dp_encoder_reset(struct drm_encoder *encoder)
4068static const struct drm_connector_funcs intel_dp_connector_funcs = { 4089static const struct drm_connector_funcs intel_dp_connector_funcs = {
4069 .dpms = intel_connector_dpms, 4090 .dpms = intel_connector_dpms,
4070 .detect = intel_dp_detect, 4091 .detect = intel_dp_detect,
4092 .force = intel_dp_force,
4071 .fill_modes = drm_helper_probe_single_connector_modes, 4093 .fill_modes = drm_helper_probe_single_connector_modes,
4072 .set_property = intel_dp_set_property, 4094 .set_property = intel_dp_set_property,
4073 .destroy = intel_dp_connector_destroy, 4095 .destroy = intel_dp_connector_destroy,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9570d688b5d8..d727d20fc512 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -214,6 +214,7 @@ struct intel_connector {
214 214
215 /* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */ 215 /* Cached EDID for eDP and LVDS. May hold ERR_PTR for invalid EDID. */
216 struct edid *edid; 216 struct edid *edid;
217 struct edid *detect_edid;
217 218
218 /* since POLL and HPD connectors may use the same HPD line keep the native 219 /* since POLL and HPD connectors may use the same HPD line keep the native
219 state of connector->polled in case hotplug storm detection changes it */ 220 state of connector->polled in case hotplug storm detection changes it */