diff options
Diffstat (limited to 'samsung/exynos_drm_crtc.c')
-rw-r--r-- | samsung/exynos_drm_crtc.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/samsung/exynos_drm_crtc.c b/samsung/exynos_drm_crtc.c index eff9eb8..68caafe 100644 --- a/samsung/exynos_drm_crtc.c +++ b/samsung/exynos_drm_crtc.c @@ -15,6 +15,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge.h> #include <drm/drm_encoder.h> #include <drm/drm_color_mgmt.h> #include <drm/drm_crtc_helper.h> @@ -1050,3 +1051,85 @@ void exynos_crtc_wait_for_flip_done(struct drm_atomic_state *old_state) old_crtc_state, new_crtc_state); } } + +bool exynos_crtc_needs_disable(struct drm_crtc_state *old_state, + struct drm_crtc_state *new_state) +{ + /* + * No new_state means the CRTC is off, so the only criteria is whether + * it's currently active or in self refresh mode. + */ + if (!new_state) + return drm_atomic_crtc_effectively_active(old_state); + + /* + * We need to run through the crtc_funcs->disable() function if the CRTC + * is currently on, if it's transitioning to self refresh mode, or if + * it's in self refresh mode and needs to be fully disabled. + */ + return old_state->active || + (old_state->self_refresh_active && !new_state->enable) || + new_state->self_refresh_active; +} + +void exynos_crtc_set_mode(struct drm_device *dev, + struct drm_atomic_state *old_state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *new_crtc_state; + struct drm_connector *connector; + struct drm_connector_state *new_conn_state; + int i; + + for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) { + const struct drm_crtc_helper_funcs *funcs; + + if (!new_crtc_state->mode_changed) + continue; + + funcs = crtc->helper_private; + + if (new_crtc_state->enable && funcs->mode_set_nofb) { + DRM_DEBUG_ATOMIC("modeset on [CRTC:%d:%s]\n", + crtc->base.id, crtc->name); + + funcs->mode_set_nofb(crtc); + } + } + + for_each_new_connector_in_state(old_state, connector, new_conn_state, i) { + const struct drm_encoder_helper_funcs *funcs; + struct drm_encoder *encoder; + struct drm_display_mode *mode, *adjusted_mode; + struct drm_bridge *bridge; + + if (!new_conn_state->best_encoder) + continue; + + encoder = new_conn_state->best_encoder; + funcs = encoder->helper_private; + new_crtc_state = new_conn_state->crtc->state; + mode = &new_crtc_state->mode; + adjusted_mode = &new_crtc_state->adjusted_mode; + + if (!new_crtc_state->mode_changed) + continue; + + DRM_DEBUG_ATOMIC("modeset on [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); + + /* + * Each encoder has at most one connector (since we always steal + * it away), so we won't call mode_set hooks twice. + */ + if (funcs && funcs->atomic_mode_set) { + funcs->atomic_mode_set(encoder, new_crtc_state, + new_conn_state); + } else if (funcs && funcs->mode_set) { + funcs->mode_set(encoder, mode, adjusted_mode); + } + + bridge = drm_bridge_chain_get_first_bridge(encoder); + drm_bridge_chain_mode_set(bridge, mode, adjusted_mode); + } +} |