Skip to content

Commit dba14b2

Browse files
vsyrjalaLyude
authored andcommitted
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
1 parent 1b2cb02 commit dba14b2

File tree

6 files changed

+168
-15
lines changed

6 files changed

+168
-15
lines changed

drivers/gpu/drm/i915/intel_crt.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,8 +956,10 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
956956
crt->base.power_domain = POWER_DOMAIN_PORT_CRT;
957957

958958
if (I915_HAS_HOTPLUG(dev_priv) &&
959-
!dmi_check_system(intel_spurious_crt_detect))
959+
!dmi_check_system(intel_spurious_crt_detect)) {
960960
crt->base.hpd_pin = HPD_CRT;
961+
crt->base.hotplug = intel_encoder_hotplug;
962+
}
961963

962964
if (HAS_DDI(dev_priv)) {
963965
crt->base.port = PORT_E;

drivers/gpu/drm/i915/intel_ddi.c

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*
2626
*/
2727

28+
#include <drm/drm_scdc_helper.h>
2829
#include "i915_drv.h"
2930
#include "intel_drv.h"
3031

@@ -2798,6 +2799,147 @@ intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port)
27982799
return connector;
27992800
}
28002801

2802+
static 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+
2843+
static 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+
2914+
static 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+
28012943
static struct intel_connector *
28022944
intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
28032945
{
@@ -2914,6 +3056,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
29143056
drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
29153057
DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
29163058

3059+
if (init_hdmi)
3060+
intel_encoder->hotplug = intel_ddi_hotplug;
3061+
else
3062+
intel_encoder->hotplug = intel_encoder_hotplug;
29173063
intel_encoder->compute_output_type = intel_ddi_compute_output_type;
29183064
intel_encoder->compute_config = intel_ddi_compute_config;
29193065
intel_encoder->enable = intel_enable_ddi;

drivers/gpu/drm/i915/intel_dp.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6393,6 +6393,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
63936393
"DP %c", port_name(port)))
63946394
goto err_encoder_init;
63956395

6396+
intel_encoder->hotplug = intel_encoder_hotplug;
63966397
intel_encoder->compute_config = intel_dp_compute_config;
63976398
intel_encoder->get_hw_state = intel_dp_get_hw_state;
63986399
intel_encoder->get_config = intel_dp_get_config;

drivers/gpu/drm/i915/intel_drv.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ struct intel_encoder {
215215
enum intel_output_type type;
216216
enum port port;
217217
unsigned int cloneable;
218-
void (*hot_plug)(struct intel_encoder *);
218+
bool (*hotplug)(struct intel_encoder *encoder,
219+
struct intel_connector *connector);
219220
enum intel_output_type (*compute_output_type)(struct intel_encoder *,
220221
struct intel_crtc_state *,
221222
struct drm_connector_state *);
@@ -1704,7 +1705,8 @@ int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector);
17041705
void intel_dvo_init(struct drm_i915_private *dev_priv);
17051706
/* intel_hotplug.c */
17061707
void intel_hpd_poll_init(struct drm_i915_private *dev_priv);
1707-
1708+
bool intel_encoder_hotplug(struct intel_encoder *encoder,
1709+
struct intel_connector *connector);
17081710

17091711
/* legacy fbdev emulation in intel_fbdev.c */
17101712
#ifdef CONFIG_DRM_FBDEV_EMULATION

drivers/gpu/drm/i915/intel_hdmi.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,6 +2383,7 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv,
23832383
&intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
23842384
"HDMI %c", port_name(port));
23852385

2386+
intel_encoder->hotplug = intel_encoder_hotplug;
23862387
intel_encoder->compute_config = intel_hdmi_compute_config;
23872388
if (HAS_PCH_SPLIT(dev_priv)) {
23882389
intel_encoder->disable = pch_disable_hdmi;

drivers/gpu/drm/i915/intel_hotplug.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -274,24 +274,26 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
274274
intel_runtime_pm_put(dev_priv);
275275
}
276276

277-
static bool intel_hpd_irq_event(struct drm_device *dev,
278-
struct drm_connector *connector)
277+
bool intel_encoder_hotplug(struct intel_encoder *encoder,
278+
struct intel_connector *connector)
279279
{
280+
struct drm_device *dev = connector->base.dev;
280281
enum drm_connector_status old_status;
281282

282283
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
283-
old_status = connector->status;
284+
old_status = connector->base.status;
284285

285-
connector->status = drm_helper_probe_detect(connector, NULL, false);
286+
connector->base.status =
287+
drm_helper_probe_detect(&connector->base, NULL, false);
286288

287-
if (old_status == connector->status)
289+
if (old_status == connector->base.status)
288290
return false;
289291

290292
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
291-
connector->base.id,
292-
connector->name,
293+
connector->base.base.id,
294+
connector->base.name,
293295
drm_get_connector_status_name(old_status),
294-
drm_get_connector_status_name(connector->status));
296+
drm_get_connector_status_name(connector->base.status));
295297

296298
return true;
297299
}
@@ -381,10 +383,9 @@ static void i915_hotplug_work_func(struct work_struct *work)
381383
if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
382384
DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n",
383385
connector->name, intel_encoder->hpd_pin);
384-
if (intel_encoder->hot_plug)
385-
intel_encoder->hot_plug(intel_encoder);
386-
if (intel_hpd_irq_event(dev, connector))
387-
changed = true;
386+
387+
changed |= intel_encoder->hotplug(intel_encoder,
388+
intel_connector);
388389
}
389390
}
390391
drm_connector_list_iter_end(&conn_iter);

0 commit comments

Comments
 (0)