aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2018-01-17 14:21:46 -0500
committerLyude Paul <lyude@redhat.com>2018-03-06 17:57:24 -0500
commitdba14b27dd3ca5ce5b3a1d538862e7dce556dba7 (patch)
tree96f6385ec799f485d40b92ef2c96442978e9b142
parent1b2cb026dc8b6f5cc4043031896a27745ad6f898 (diff)
drm/i915: Reinitialize sink scrambling/TMDS clock ratio on HPD
The LG 4k TV I have doesn't deassert HPD when I turn the TV off, but when I turn it back on it will pulse the HPD line. By that time it has forgotten everything we told it about scrambling and the clock ratio. Hence if we want to get a picture out if it again we have to tell it whether we're currently sending scrambled data or not. Implement that via the encoder->hotplug() hook. v2: Force a full modeset to not follow the HDMI 2.0 spec more closely (Shashank) [pushed with whitespace fixes to make sparse happy] Cc: Shashank Sharma <shashank.sharma@intel.com> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Lyude Paul <lyude@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180117192149.17760-1-ville.syrjala@linux.intel.com
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c4
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c146
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c1
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h6
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c1
-rw-r--r--drivers/gpu/drm/i915/intel_hotplug.c25
6 files changed, 168 insertions, 15 deletions
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 391dd69ae0a4..c0a8805b277f 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -956,8 +956,10 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
956 crt->base.power_domain = POWER_DOMAIN_PORT_CRT; 956 crt->base.power_domain = POWER_DOMAIN_PORT_CRT;
957 957
958 if (I915_HAS_HOTPLUG(dev_priv) && 958 if (I915_HAS_HOTPLUG(dev_priv) &&
959 !dmi_check_system(intel_spurious_crt_detect)) 959 !dmi_check_system(intel_spurious_crt_detect)) {
960 crt->base.hpd_pin = HPD_CRT; 960 crt->base.hpd_pin = HPD_CRT;
961 crt->base.hotplug = intel_encoder_hotplug;
962 }
961 963
962 if (HAS_DDI(dev_priv)) { 964 if (HAS_DDI(dev_priv)) {
963 crt->base.port = PORT_E; 965 crt->base.port = PORT_E;
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index bfdaa5d86861..e5b5d21c3c09 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -25,6 +25,7 @@
25 * 25 *
26 */ 26 */
27 27
28#include <drm/drm_scdc_helper.h>
28#include "i915_drv.h" 29#include "i915_drv.h"
29#include "intel_drv.h" 30#include "intel_drv.h"
30 31
@@ -2798,6 +2799,147 @@ intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port)
2798 return connector; 2799 return connector;
2799} 2800}
2800 2801
2802static int modeset_pipe(struct drm_crtc *crtc,
2803 struct drm_modeset_acquire_ctx *ctx)
2804{
2805 struct drm_atomic_state *state;
2806 struct drm_crtc_state *crtc_state;
2807 int ret;
2808
2809 state = drm_atomic_state_alloc(crtc->dev);
2810 if (!state)
2811 return -ENOMEM;
2812
2813 state->acquire_ctx = ctx;
2814
2815 crtc_state = drm_atomic_get_crtc_state(state, crtc);
2816 if (IS_ERR(crtc_state)) {
2817 ret = PTR_ERR(crtc_state);
2818 goto out;
2819 }
2820
2821 crtc_state->mode_changed = true;
2822
2823 ret = drm_atomic_add_affected_connectors(state, crtc);
2824 if (ret)
2825 goto out;
2826
2827 ret = drm_atomic_add_affected_planes(state, crtc);
2828 if (ret)
2829 goto out;
2830
2831 ret = drm_atomic_commit(state);
2832 if (ret)
2833 goto out;
2834
2835 return 0;
2836
2837 out:
2838 drm_atomic_state_put(state);
2839
2840 return ret;
2841}
2842
2843static int intel_hdmi_reset_link(struct intel_encoder *encoder,
2844 struct drm_modeset_acquire_ctx *ctx)
2845{
2846 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
2847 struct intel_hdmi *hdmi = enc_to_intel_hdmi(&encoder->base);
2848 struct intel_connector *connector = hdmi->attached_connector;
2849 struct i2c_adapter *adapter =
2850 intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
2851 struct drm_connector_state *conn_state;
2852 struct intel_crtc_state *crtc_state;
2853 struct intel_crtc *crtc;
2854 u8 config;
2855 int ret;
2856
2857 if (!connector || connector->base.status != connector_status_connected)
2858 return 0;
2859
2860 ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
2861 ctx);
2862 if (ret)
2863 return ret;
2864
2865 conn_state = connector->base.state;
2866
2867 crtc = to_intel_crtc(conn_state->crtc);
2868 if (!crtc)
2869 return 0;
2870
2871 ret = drm_modeset_lock(&crtc->base.mutex, ctx);
2872 if (ret)
2873 return ret;
2874
2875 crtc_state = to_intel_crtc_state(crtc->base.state);
2876
2877 WARN_ON(!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI));
2878
2879 if (!crtc_state->base.active)
2880 return 0;
2881
2882 if (!crtc_state->hdmi_high_tmds_clock_ratio &&
2883 !crtc_state->hdmi_scrambling)
2884 return 0;
2885
2886 if (conn_state->commit &&
2887 !try_wait_for_completion(&conn_state->commit->hw_done))
2888 return 0;
2889
2890 ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
2891 if (ret < 0) {
2892 DRM_ERROR("Failed to read TMDS config: %d\n", ret);
2893 return 0;
2894 }
2895
2896 if (!!(config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40) ==
2897 crtc_state->hdmi_high_tmds_clock_ratio &&
2898 !!(config & SCDC_SCRAMBLING_ENABLE) ==
2899 crtc_state->hdmi_scrambling)
2900 return 0;
2901
2902 /*
2903 * HDMI 2.0 says that one should not send scrambled data
2904 * prior to configuring the sink scrambling, and that
2905 * TMDS clock/data transmission should be suspended when
2906 * changing the TMDS clock rate in the sink. So let's
2907 * just do a full modeset here, even though some sinks
2908 * would be perfectly happy if were to just reconfigure
2909 * the SCDC settings on the fly.
2910 */
2911 return modeset_pipe(&crtc->base, ctx);
2912}
2913
2914static bool intel_ddi_hotplug(struct intel_encoder *encoder,
2915 struct intel_connector *connector)
2916{
2917 struct drm_modeset_acquire_ctx ctx;
2918 bool changed;
2919 int ret;
2920
2921 changed = intel_encoder_hotplug(encoder, connector);
2922
2923 drm_modeset_acquire_init(&ctx, 0);
2924
2925 for (;;) {
2926 ret = intel_hdmi_reset_link(encoder, &ctx);
2927
2928 if (ret == -EDEADLK) {
2929 drm_modeset_backoff(&ctx);
2930 continue;
2931 }
2932
2933 break;
2934 }
2935
2936 drm_modeset_drop_locks(&ctx);
2937 drm_modeset_acquire_fini(&ctx);
2938 WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
2939
2940 return changed;
2941}
2942
2801static struct intel_connector * 2943static struct intel_connector *
2802intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port) 2944intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
2803{ 2945{
@@ -2914,6 +3056,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
2914 drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs, 3056 drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
2915 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port)); 3057 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
2916 3058
3059 if (init_hdmi)
3060 intel_encoder->hotplug = intel_ddi_hotplug;
3061 else
3062 intel_encoder->hotplug = intel_encoder_hotplug;
2917 intel_encoder->compute_output_type = intel_ddi_compute_output_type; 3063 intel_encoder->compute_output_type = intel_ddi_compute_output_type;
2918 intel_encoder->compute_config = intel_ddi_compute_config; 3064 intel_encoder->compute_config = intel_ddi_compute_config;
2919 intel_encoder->enable = intel_enable_ddi; 3065 intel_encoder->enable = intel_enable_ddi;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index c722a6750e90..7cc1720a437d 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -6393,6 +6393,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
6393 "DP %c", port_name(port))) 6393 "DP %c", port_name(port)))
6394 goto err_encoder_init; 6394 goto err_encoder_init;
6395 6395
6396 intel_encoder->hotplug = intel_encoder_hotplug;
6396 intel_encoder->compute_config = intel_dp_compute_config; 6397 intel_encoder->compute_config = intel_dp_compute_config;
6397 intel_encoder->get_hw_state = intel_dp_get_hw_state; 6398 intel_encoder->get_hw_state = intel_dp_get_hw_state;
6398 intel_encoder->get_config = intel_dp_get_config; 6399 intel_encoder->get_config = intel_dp_get_config;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 652b11e788cc..2ae6d5548171 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -215,7 +215,8 @@ struct intel_encoder {
215 enum intel_output_type type; 215 enum intel_output_type type;
216 enum port port; 216 enum port port;
217 unsigned int cloneable; 217 unsigned int cloneable;
218 void (*hot_plug)(struct intel_encoder *); 218 bool (*hotplug)(struct intel_encoder *encoder,
219 struct intel_connector *connector);
219 enum intel_output_type (*compute_output_type)(struct intel_encoder *, 220 enum intel_output_type (*compute_output_type)(struct intel_encoder *,
220 struct intel_crtc_state *, 221 struct intel_crtc_state *,
221 struct drm_connector_state *); 222 struct drm_connector_state *);
@@ -1704,7 +1705,8 @@ int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector);
1704void intel_dvo_init(struct drm_i915_private *dev_priv); 1705void intel_dvo_init(struct drm_i915_private *dev_priv);
1705/* intel_hotplug.c */ 1706/* intel_hotplug.c */
1706void intel_hpd_poll_init(struct drm_i915_private *dev_priv); 1707void intel_hpd_poll_init(struct drm_i915_private *dev_priv);
1707 1708bool intel_encoder_hotplug(struct intel_encoder *encoder,
1709 struct intel_connector *connector);
1708 1710
1709/* legacy fbdev emulation in intel_fbdev.c */ 1711/* legacy fbdev emulation in intel_fbdev.c */
1710#ifdef CONFIG_DRM_FBDEV_EMULATION 1712#ifdef CONFIG_DRM_FBDEV_EMULATION
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index f5d7bfb43006..1baef4ac7ecb 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -2383,6 +2383,7 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv,
2383 &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS, 2383 &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
2384 "HDMI %c", port_name(port)); 2384 "HDMI %c", port_name(port));
2385 2385
2386 intel_encoder->hotplug = intel_encoder_hotplug;
2386 intel_encoder->compute_config = intel_hdmi_compute_config; 2387 intel_encoder->compute_config = intel_hdmi_compute_config;
2387 if (HAS_PCH_SPLIT(dev_priv)) { 2388 if (HAS_PCH_SPLIT(dev_priv)) {
2388 intel_encoder->disable = pch_disable_hdmi; 2389 intel_encoder->disable = pch_disable_hdmi;
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c
index fe28c1ea84a5..0e3d3e89d66a 100644
--- a/drivers/gpu/drm/i915/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/intel_hotplug.c
@@ -274,24 +274,26 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
274 intel_runtime_pm_put(dev_priv); 274 intel_runtime_pm_put(dev_priv);
275} 275}
276 276
277static bool intel_hpd_irq_event(struct drm_device *dev, 277bool intel_encoder_hotplug(struct intel_encoder *encoder,
278 struct drm_connector *connector) 278 struct intel_connector *connector)
279{ 279{
280 struct drm_device *dev = connector->base.dev;
280 enum drm_connector_status old_status; 281 enum drm_connector_status old_status;
281 282
282 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 283 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
283 old_status = connector->status; 284 old_status = connector->base.status;
284 285
285 connector->status = drm_helper_probe_detect(connector, NULL, false); 286 connector->base.status =
287 drm_helper_probe_detect(&connector->base, NULL, false);
286 288
287 if (old_status == connector->status) 289 if (old_status == connector->base.status)
288 return false; 290 return false;
289 291
290 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", 292 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
291 connector->base.id, 293 connector->base.base.id,
292 connector->name, 294 connector->base.name,
293 drm_get_connector_status_name(old_status), 295 drm_get_connector_status_name(old_status),
294 drm_get_connector_status_name(connector->status)); 296 drm_get_connector_status_name(connector->base.status));
295 297
296 return true; 298 return true;
297} 299}
@@ -381,10 +383,9 @@ static void i915_hotplug_work_func(struct work_struct *work)
381 if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { 383 if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
382 DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", 384 DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n",
383 connector->name, intel_encoder->hpd_pin); 385 connector->name, intel_encoder->hpd_pin);
384 if (intel_encoder->hot_plug) 386
385 intel_encoder->hot_plug(intel_encoder); 387 changed |= intel_encoder->hotplug(intel_encoder,
386 if (intel_hpd_irq_event(dev, connector)) 388 intel_connector);
387 changed = true;
388 } 389 }
389 } 390 }
390 drm_connector_list_iter_end(&conn_iter); 391 drm_connector_list_iter_end(&conn_iter);