Together with the static helper functions drm_crtc_prepare_encoders and drm_encoder_disable (which will be simplified in the next patch, but for now are 1:1 copies). Again, no changes beside new names for these functions. Also call our new set_mode instead of the crtc helper one now in all the places we've done so far. v2: Call the function just intel_set_mode to better differentia it from intel_crtc_mode_set which really only does the ->mode_set step of the entire modeset sequence on one crtc. Whereas this function does the global change. Signed-Off-by: Daniel Vetter <daniel.vetter at ffwll.ch> --- drivers/gpu/drm/i915/intel_display.c | 162 +++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_dp.c | 5 +- drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_hdmi.c | 5 +- drivers/gpu/drm/i915/intel_lvds.c | 4 +- drivers/gpu/drm/i915/intel_sdvo.c | 4 +- drivers/gpu/drm/i915/intel_tv.c | 4 +- 7 files changed, 168 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9d5c575..3e119a6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5767,7 +5767,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, goto fail; } - if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) { + if (!intel_set_mode(crtc, mode, 0, 0, old_fb)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); @@ -6635,6 +6635,157 @@ intel_crtc_helper_disable(struct drm_crtc *crtc) return 0; } +static void +intel_encoder_disable_helper(struct drm_encoder *encoder) +{ + struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; + + if (encoder_funcs->disable) + (*encoder_funcs->disable)(encoder); + else + (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); +} + +static void +intel_crtc_prepare_encoders(struct drm_device *dev) +{ + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_encoder *encoder; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + encoder_funcs = encoder->helper_private; + /* Disable unused encoders */ + if (encoder->crtc == NULL) + intel_encoder_disable_helper(encoder); + /* Disable encoders whose CRTC is about to change */ + if (encoder_funcs->get_crtc && + encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) + intel_encoder_disable_helper(encoder); + } +} + +bool intel_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *old_fb) +{ + struct drm_device *dev = crtc->dev; + struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + struct drm_encoder_helper_funcs *encoder_funcs; + int saved_x, saved_y; + struct drm_encoder *encoder; + bool ret = true; + + crtc->enabled = drm_helper_crtc_in_use(crtc); + if (!crtc->enabled) + return true; + + adjusted_mode = drm_mode_duplicate(dev, mode); + if (!adjusted_mode) + return false; + + saved_hwmode = crtc->hwmode; + saved_mode = crtc->mode; + saved_x = crtc->x; + saved_y = crtc->y; + + /* Update crtc values up front so the driver can rely on them for mode + * setting. + */ + crtc->mode = *mode; + crtc->x = x; + crtc->y = y; + + /* Pass our mode to the connectors and the CRTC to give them a chance to + * adjust it according to limitations or connector properties, and also + * a chance to reject the mode entirely. + */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + if (encoder->crtc != crtc) + continue; + encoder_funcs = encoder->helper_private; + if (!(ret = encoder_funcs->mode_fixup(encoder, mode, + adjusted_mode))) { + DRM_DEBUG_KMS("Encoder fixup failed\n"); + goto done; + } + } + + if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { + DRM_DEBUG_KMS("CRTC fixup failed\n"); + goto done; + } + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); + + /* Prepare the encoders and CRTCs before setting the mode. */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + if (encoder->crtc != crtc) + continue; + encoder_funcs = encoder->helper_private; + /* Disable the encoders as the first thing we do. */ + encoder_funcs->prepare(encoder); + } + + intel_crtc_prepare_encoders(dev); + + crtc_funcs->prepare(crtc); + + /* Set up the DPLL and any encoders state that needs to adjust or depend + * on the DPLL. + */ + ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb); + if (!ret) + goto done; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + if (encoder->crtc != crtc) + continue; + + DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", + encoder->base.id, drm_get_encoder_name(encoder), + mode->base.id, mode->name); + encoder_funcs = encoder->helper_private; + encoder_funcs->mode_set(encoder, mode, adjusted_mode); + } + + /* Now enable the clocks, plane, pipe, and connectors that we set up. */ + crtc_funcs->commit(crtc); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + + if (encoder->crtc != crtc) + continue; + + encoder_funcs = encoder->helper_private; + encoder_funcs->commit(encoder); + + } + + /* Store real post-adjustment hardware mode. */ + crtc->hwmode = *adjusted_mode; + + /* Calculate and store various constants which + * are later needed by vblank and swap-completion + * timestamping. They are derived from true hwmode. + */ + drm_calc_timestamping_constants(crtc); + + /* FIXME: add subpixel order */ +done: + drm_mode_destroy(dev, adjusted_mode); + if (!ret) { + crtc->hwmode = saved_hwmode; + crtc->mode = saved_mode; + crtc->x = saved_x; + crtc->y = saved_y; + } + + return ret; +} + static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; @@ -6817,9 +6968,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) drm_mode_debug_printmodeline(set->mode); old_fb = set->crtc->fb; set->crtc->fb = set->fb; - if (!drm_crtc_helper_set_mode(set->crtc, set->mode, - set->x, set->y, - old_fb)) { + if (!intel_set_mode(set->crtc, set->mode, + set->x, set->y, old_fb)) { DRM_ERROR("failed to set mode on [CRTC:%d]\n", set->crtc->base.id); set->crtc->fb = old_fb; @@ -6873,8 +7023,8 @@ fail: /* Try to restore the config */ if (mode_changed && - !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x, - save_set.y, save_set.fb)) + !intel_set_mode(save_set.crtc, save_set.mode, + save_set.x, save_set.y, save_set.fb)) DRM_ERROR("failed to restore config after modeset failure\n"); kfree(save_connectors); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7ee954c..2abaaf6 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2312,9 +2312,8 @@ intel_dp_set_property(struct drm_connector *connector, done: if (intel_dp->base.base.crtc) { struct drm_crtc *crtc = intel_dp->base.base.crtc; - drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, - crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); } return 0; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e59cac3..c28fada 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -410,6 +410,8 @@ extern void intel_panel_disable_backlight(struct drm_device *dev); extern void intel_panel_destroy_backlight(struct drm_device *dev); extern enum drm_connector_status intel_panel_detect(struct drm_device *dev); +extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *old_fb); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_update_dpms(struct drm_crtc *crtc); extern void intel_encoder_noop(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index acddaaa..ef84097 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -869,9 +869,8 @@ intel_hdmi_set_property(struct drm_connector *connector, done: if (intel_hdmi->base.base.crtc) { struct drm_crtc *crtc = intel_hdmi->base.base.crtc; - drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, - crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); } return 0; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3baa224..fad82b2 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -560,8 +560,8 @@ static int intel_lvds_set_property(struct drm_connector *connector, * If the CRTC is enabled, the display will be changed * according to the new panel fitting mode. */ - drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); } } diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index a01c470..88fb30d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1879,8 +1879,8 @@ set_value: done: if (intel_sdvo->base.base.crtc) { struct drm_crtc *crtc = intel_sdvo->base.base.crtc; - drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, - crtc->y, crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); } return 0; diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 281e0cf..16cb114 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1471,8 +1471,8 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop } if (changed && crtc) - drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, - crtc->y, crtc->fb); + intel_set_mode(crtc, &crtc->mode, + crtc->x, crtc->y, crtc->fb); out: return ret; } -- 1.7.11.2