diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 3f17933b1d2c..6112ec261c3b 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1886,6 +1886,83 @@ backoff: } EXPORT_SYMBOL(drm_atomic_helper_page_flip); +/** + * drm_atomic_helper_connector_dpms() - connector dpms helper implementation + * @connector: affected connector + * @mode: DPMS mode + * + * This is the main helper function provided by the atomic helper framework for + * implementing the legacy DPMS connector interface. It computes the new desired + * ->active state for the corresponding CRTC (if the connector is enabled) and + * updates it. + */ +void drm_atomic_helper_connector_dpms(struct drm_connector *connector, + int mode) +{ + struct drm_mode_config *config = &connector->dev->mode_config; + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + struct drm_connector *tmp_connector; + int ret; + bool active = false; + + if (mode != DRM_MODE_DPMS_ON) + mode = DRM_MODE_DPMS_OFF; + + connector->dpms = mode; + crtc = connector->state->crtc; + + if (!crtc) + return; + + /* FIXME: ->dpms has no return value so can't forward the -ENOMEM. */ + state = drm_atomic_state_alloc(connector->dev); + if (!state) + return; + + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); +retry: + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return; + + WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); + + list_for_each_entry(tmp_connector, &config->connector_list, head) { + if (connector->state->crtc != crtc) + continue; + + if (connector->dpms == DRM_MODE_DPMS_ON) { + active = true; + break; + } + } + crtc_state->active = active; + + ret = drm_atomic_commit(state); + if (ret != 0) + goto fail; + + /* Driver takes ownership of state on successful async commit. */ + return; +fail: + if (ret == -EDEADLK) + goto backoff; + + drm_atomic_state_free(state); + + WARN(1, "Driver bug: Changing ->active failed with ret=%i\n", ret); + + return; +backoff: + drm_atomic_state_clear(state); + drm_atomic_legacy_backoff(state); + + goto retry; +} +EXPORT_SYMBOL(drm_atomic_helper_connector_dpms); + /** * DOC: atomic state reset and initialization * diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 2095917ff8c7..cf501df9e513 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -82,6 +82,8 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags); +void drm_atomic_helper_connector_dpms(struct drm_connector *connector, + int mode); /* default implementations for state handling */ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);