This function provides a way for the driver to redo a
modeset on the current mode and retry the link training
at a lower link rate/lane count/bpp. This will get called
incase the link training fails during the current modeset.

Cc: dri-devel at lists.freedesktop.org
Cc: Jani Nikula <jani.nikula at linux.intel.com>
Cc: Daniel Vetter <daniel.vetter at intel.com>
Cc: Ville Syrjala <ville.syrjala at linux.intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare at intel.com>
---
 drivers/gpu/drm/drm_atomic_helper.c | 58 +++++++++++++++++++++++++++++++++++++
 include/drm/drm_atomic_helper.h     |  1 +
 2 files changed, 59 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c 
b/drivers/gpu/drm/drm_atomic_helper.c
index f936276..0c1614e 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -2895,6 +2895,64 @@ int drm_atomic_helper_connector_dpms(struct 
drm_connector *connector,
 EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);

 /**
+ * drm_atomic_helper_connector_modeset - Force a modeset on a connector
+ * @connector: DRM connector
+ *
+ * Provides a way to redo a modeset with the current mode so that it can
+ * drop the bpp, link rate/lane count and retry the link training.
+ *
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
+ */
+int
+drm_atomic_helper_connector_modeset(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct drm_modeset_acquire_ctx ctx;
+       struct drm_atomic_state *state;
+       struct drm_connector_state *connector_state;
+       struct drm_crtc_state *crtc_state;
+       int ret = 0;
+
+       drm_modeset_acquire_init(&ctx, 0);
+       state = drm_atomic_state_alloc(dev);
+       if (!state) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+       state->acquire_ctx = &ctx;
+retry:
+       ret = 0;
+       connector_state = drm_atomic_get_connector_state(state, connector);
+       if (IS_ERR(connector_state)) {
+               ret = PTR_ERR(connector_state);
+               goto fail;
+       }
+       if (!connector_state->crtc)
+               goto fail;
+
+       crtc_state = drm_atomic_get_existing_crtc_state(state,
+                                                       connector_state->crtc);
+       crtc_state->connectors_changed = true;
+       ret = drm_atomic_commit(state);
+fail:
+       if (ret == -EDEADLK) {
+               drm_atomic_state_clear(state);
+               drm_modeset_backoff(&ctx);
+               goto retry;
+       }
+
+       if (state)
+               drm_atomic_state_put(state);
+
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+
+       return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_modeset);
+
+/**
  * drm_atomic_helper_best_encoder - Helper for &drm_connector_helper_funcs
  *                                  ->best_encoder callback
  * @connector: Connector control structure
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 7ff92b0..8de24dc 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -126,6 +126,7 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
                                uint32_t flags);
 int drm_atomic_helper_connector_dpms(struct drm_connector *connector,
                                     int mode);
+int drm_atomic_helper_connector_modeset(struct drm_connector *connector);
 struct drm_encoder *
 drm_atomic_helper_best_encoder(struct drm_connector *connector);

-- 
1.9.1

Reply via email to