On Mon, Jan 22, 2018 at 12:07:28PM +0530, Sharma, Shashank wrote: > Regards > > Shashank > > > On 1/13/2018 2:34 AM, Ville Syrjala wrote: > > From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > > > > 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) > > > > Cc: Shashank Sharma <shashank.sharma@xxxxxxxxx> > > Cc: Maarten Lankhorst <maarten.lankhorst@xxxxxxxxxxxxxxx> > > Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > > --- > > drivers/gpu/drm/i915/intel_ddi.c | 146 ++++++++++++++++++++++++++++++++++++++- > > 1 file changed, 145 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c > > index 1aeae3e97013..25793bdc692f 100644 > > --- a/drivers/gpu/drm/i915/intel_ddi.c > > +++ b/drivers/gpu/drm/i915/intel_ddi.c > > @@ -25,6 +25,7 @@ > > * > > */ > > > > +#include <drm/drm_scdc_helper.h> > > #include "i915_drv.h" > > #include "intel_drv.h" > > > > @@ -2756,6 +2757,146 @@ intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port) > > return connector; > > } > > > > +static int modeset_pipe(struct drm_crtc *crtc, > > + struct drm_modeset_acquire_ctx *ctx) > Should this function go to intel_atomic.c or similar ? Do you have another user for it? If not I don't see a particularly good reason for moving it out. > Also a little > documentation about > usage will be helpful for others, who want to reuse this. What should it say? To me the function name is pretty clear. > > +{ > > + struct drm_atomic_state *state; > > + struct drm_crtc_state *crtc_state; > > + int ret; > > + > > + state = drm_atomic_state_alloc(crtc->dev); > > + if (!state) > > + return -ENOMEM; > > + > > + state->acquire_ctx = ctx; > > + > > + crtc_state = drm_atomic_get_crtc_state(state, crtc); > > + if (IS_ERR(crtc_state)) { > > + ret = PTR_ERR(crtc_state); > > + goto out; > > + } > > + > > + crtc_state->mode_changed = true; > > + > > + ret = drm_atomic_add_affected_connectors(state, crtc); > > + if (ret) > > + goto out; > > + > > + ret = drm_atomic_add_affected_planes(state, crtc); > > + if (ret) > > + goto out; > > + > > + ret = drm_atomic_commit(state); > > + if (ret) > > + goto out; > > + > As this is an internal modeset trigger, should we send an event to > userspace about this ? What would userspace do with such an event? > > + return 0; > > + > > + out: > one debug message here telling us about if modeset was success/fail ? There's a WARN already higher up. > > + drm_atomic_state_put(state); > > + > > + return ret; > > +} > > + > > +static int intel_hdmi_reset_link(struct intel_encoder *encoder, > > + struct drm_modeset_acquire_ctx *ctx) > > +{ > > + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); > > + struct intel_hdmi *hdmi = enc_to_intel_hdmi(&encoder->base); > > + struct intel_connector *connector = hdmi->attached_connector; > > + struct i2c_adapter *adapter = > > + intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus); > > + struct drm_connector_state *conn_state; > > + struct intel_crtc_state *crtc_state; > > + struct intel_crtc *crtc; > > + u8 config; > > + int ret; > > + > > + if (!connector || connector->base.status != connector_status_connected) > > + return 0; > > + > > + ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, ctx); > > + if (ret) > > + return ret; > > + > > + conn_state = connector->base.state; > > + > > + crtc = to_intel_crtc(conn_state->crtc); > > + if (!crtc) > > + return 0; > > + > > + ret = drm_modeset_lock(&crtc->base.mutex, ctx); > > + if (ret) > > + return ret; > > + > > + crtc_state = to_intel_crtc_state(crtc->base.state); > > + > > + WARN_ON(!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)); > > + > > + if (!crtc_state->base.active) > > + return 0; > > + > > + if (!crtc_state->hdmi_high_tmds_clock_ratio && > > + !crtc_state->hdmi_scrambling) > > + return 0; > > + > > + if (conn_state->commit && > > + !try_wait_for_completion(&conn_state->commit->hw_done)) > > + return 0; > > + > > + ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config); > > + if (ret < 0) { > > + DRM_ERROR("Failed to read TMDS config: %d\n", ret); > > + return 0; > > + } > We can export this read as helper in scdc_helper.c, something like > drm_scdc_get_tmds_clock_ratio ? Feels like fairly pointless abstraction to me. And we'd either need to do two SCDC reads instead of one, or return two things from said function. > - Shashank > > + > > + if (!!(config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40) == > > + crtc_state->hdmi_high_tmds_clock_ratio && > > + !!(config & SCDC_SCRAMBLING_ENABLE) == > > + crtc_state->hdmi_scrambling) > > + return 0; > > + > > + /* > > + * HDMI 2.0 says that one should not send scrambled data > > + * prior to configuring the sink scrambling, and that > > + * TMDS clock/data transmission should be suspended when > > + * changing the TMDS clock rate in the sink. So let's > > + * just do a full modeset here, even though some sinks > > + * would be perfectly happy if were to just reconfigure > > + * the SCDC settings on the fly. > > + */ > > + return modeset_pipe(&crtc->base, ctx); > > +} > > + > > +static bool intel_ddi_hotplug(struct intel_encoder *encoder, > > + struct intel_connector *connector) > > +{ > > + struct drm_modeset_acquire_ctx ctx; > > + bool changed; > > + int ret; > > + > > + changed = intel_encoder_hotplug(encoder, connector); > > + > > + drm_modeset_acquire_init(&ctx, 0); > > + > > + for (;;) { > > + ret = intel_hdmi_reset_link(encoder, &ctx); > > + > > + if (ret == -EDEADLK) { > > + drm_modeset_backoff(&ctx); > > + continue; > > + } > > + > > + break; > > + } > > + > > + drm_modeset_drop_locks(&ctx); > > + drm_modeset_acquire_fini(&ctx); > > + WARN(ret, "Acquiring modeset locks failed with %i\n", ret); > > + > > + return changed; > > +} > > + > > static struct intel_connector * > > intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port) > > { > > @@ -2866,7 +3007,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) > > drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs, > > DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port)); > > > > - intel_encoder->hotplug = intel_encoder_hotplug; > > + if (init_hdmi) > > + intel_encoder->hotplug = intel_ddi_hotplug; > > + else > > + intel_encoder->hotplug = intel_encoder_hotplug; > > intel_encoder->compute_output_type = intel_ddi_compute_output_type; > > intel_encoder->compute_config = intel_ddi_compute_config; > > intel_encoder->enable = intel_enable_ddi; -- Ville Syrjälä Intel OTC _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx